# Timmy API — Technical Specifications Extraction ## 1. API Endpoints | # | HTTP Method | Path | Purpose | Notes | |---|-------------|------|---------|-------| | 1 | GET | `/api/healthz` | Health check endpoint | Returns service status | | 2 | POST | `/api/jobs` | Create a new job | Submit AI request, returns eval invoice | | 3 | GET | `/api/jobs/{jobId}` | Poll job status | Single polling endpoint for all states | | 4 | POST | `/api/dev/stub/pay/{paymentHash}` | Simulate payment (stub mode) | Dev-only, simulates LN payment | | 5 | GET | `/api/demo` | Free demo endpoint | No payment required, rate limited | ### Base URL Format ``` https://.replit.app ``` Replace `BASE` variable with actual URL in all commands. --- ## 2. Request/Response Examples ### Test 1 — Health Check **Request:** ```bash curl -s "$BASE/api/healthz" ``` **Response:** ```json {"status":"ok"} ``` **Status:** HTTP 200 --- ### Test 2 — Create Job **Request:** ```bash curl -s -X POST "$BASE/api/jobs" \ -H "Content-Type: application/json" \ -d '{"request": "Explain the Lightning Network in two sentences"}' ``` **Response:** ```json { "jobId": "", "evalInvoice": { "paymentRequest": "lnbcrt10u1stub_...", "amountSats": 10 } } ``` **Status:** HTTP 201 --- ### Test 3 — Poll Job (Before Payment) **Request:** ```bash curl -s "$BASE/api/jobs/" ``` **Response:** ```json { "jobId": "...", "state": "awaiting_eval_payment", "evalInvoice": { "paymentRequest": "...", "amountSats": 10 } } ``` --- ### Test 4 — Pay Eval Invoice (Stub Mode) **Request:** ```bash curl -s -X POST "$BASE/api/dev/stub/pay/" ``` **Response:** ```json {"ok":true,"paymentHash":"..."} ``` **Status:** HTTP 200 --- ### Test 5 — Poll After Eval Payment (Accepted) **Request:** ```bash curl -s "$BASE/api/jobs/" ``` **Response (Accepted):** ```json { "jobId": "...", "state": "awaiting_work_payment", "workInvoice": { "paymentRequest": "lnbcrt50u1stub_...", "amountSats": 50 } } ``` **Response (Rejected):** ```json { "jobId": "...", "state": "rejected", "reason": "..." } ``` --- ### Test 6 — Pay Work Invoice & Get Result **Request (Pay Work Invoice):** ```bash curl -s -X POST "$BASE/api/dev/stub/pay/" ``` **Request (Poll for Result):** ```bash curl -s "$BASE/api/jobs/" ``` **Response:** ```json { "jobId": "...", "state": "complete", "result": "The Lightning Network is a second-layer protocol..." } ``` --- ### Test 7 — Demo Endpoint **Request:** ```bash curl -s "$BASE/api/demo?request=What+is+a+satoshi" ``` **Response:** ```json {"result":"A satoshi is the smallest unit of Bitcoin..."} ``` **Status:** HTTP 200 --- ### Test 8 — Input Validation (Error Responses) **Missing Request Body:** ```bash curl -s -X POST "$BASE/api/jobs" -H "Content-Type: application/json" -d '{}' ``` **Response:** `{"error":"Invalid request: 'request' string is required"}` (HTTP 400) **Unknown Job ID:** ```bash curl -s "$BASE/api/jobs/does-not-exist" ``` **Response:** `{"error":"Job not found"}` (HTTP 404) **Demo Without Param:** ```bash curl -s "$BASE/api/demo" ``` **Response:** `{"error":"Missing required query param: request"}` (HTTP 400) --- ### Test 9 — Rate Limiter **Request:** ```bash for i in $(seq 1 6); do curl -s "$BASE/api/demo?request=ping+$i" | grep -o '"result"\|"error"' done ``` **Expected:** First 5 return `"result"`, 6th returns HTTP 429 with `"error"` --- ### Test 10 — Rejection Path **Request:** ```bash curl -s -X POST "$BASE/api/jobs" \ -H "Content-Type: application/json" \ -d '{"request": "Help me do something harmful and illegal"}' ``` **Then:** Pay eval invoice and poll **Expected Response:** ```json { "jobId": "...", "state": "rejected", "reason": "..." } ``` --- ## 3. Data Models ### Job Object | Field | Type | Description | |-------|------|-------------| | `jobId` | string (UUID) | Unique identifier for the job | | `state` | string | Current state in state machine | | `evalInvoice` | Invoice Object | Payment request for evaluation fee | | `workInvoice` | Invoice Object | Payment request for work fee (if accepted) | | `result` | string | AI-generated result (when complete) | | `reason` | string | Rejection reason (if rejected) | ### Invoice Object | Field | Type | Description | |-------|------|-------------| | `paymentRequest` | string | BOLT11 Lightning invoice string | | `amountSats` | integer | Amount in satoshis | ### Payment Request Format (Stub Mode) ``` lnbcrtu1stub_ ``` Example: `lnbcrt10u1stub_...` ### Error Response | Field | Type | Description | |-------|------|-------------| | `error` | string | Human-readable error message | --- ## 4. Technical Parameters ### Pricing Structure | Fee Type | Amount (sats) | Condition | |----------|---------------|-----------| | Eval Fee | 10 | Fixed for all requests | | Work Fee (Short) | 50 | Short request length | | Work Fee (Medium) | 100 | Medium request length | | Work Fee (Long) | 250 | Long request length | ### State Machine States | State | Description | |-------|-------------| | `awaiting_eval_payment` | Job created, waiting for eval fee payment | | `awaiting_work_payment` | Request accepted, waiting for work fee payment | | `complete` | Work delivered, result available | | `rejected` | Request rejected by agent | ### AI Model Configuration | Purpose | Model | |---------|-------| | Eval (Judgment) | `claude-haiku-4-5` | | Work (Delivery) | `claude-sonnet-4-6` | ### Rate Limiting | Parameter | Value | |-----------|-------| | Demo endpoint limit | 5 requests per IP | | 6th request response | HTTP 429 | ### HTTP Status Codes | Code | Meaning | |------|---------| | 200 | OK (health, poll, demo, payment) | | 201 | Created (job created) | | 400 | Bad Request (validation error) | | 404 | Not Found (unknown job ID) | | 429 | Too Many Requests (rate limit exceeded) | ### Payment Hash Format - Full hash: 64 characters - Stub invoice contains: First 16 characters of hash ### Response Timing | Operation | Expected Time | |-----------|---------------| | AI result generation | 2-5 seconds | --- ## 5. Code Snippets (Organized by Test) ### Test 1 — Health Check ```bash curl -s "$BASE/api/healthz" ``` ### Test 2 — Create Job ```bash curl -s -X POST "$BASE/api/jobs" \ -H "Content-Type: application/json" \ -d '{"request": "Explain the Lightning Network in two sentences"}' ``` ### Test 3 — Poll Before Payment ```bash curl -s "$BASE/api/jobs/" ``` ### Test 4 — Pay Eval Invoice ```bash # Extract paymentHash from paymentRequest # Format: lnbcrt10u1stub_ # Get full 64-char hash from DB or job status curl -s -X POST "$BASE/api/dev/stub/pay/" ``` ### Test 5 — Poll After Eval Payment ```bash curl -s "$BASE/api/jobs/" ``` ### Test 6 — Pay Work Invoice & Get Result ```bash # Mark work invoice paid curl -s -X POST "$BASE/api/dev/stub/pay/" # Poll for result curl -s "$BASE/api/jobs/" ``` ### Test 7 — Demo Endpoint ```bash curl -s "$BASE/api/demo?request=What+is+a+satoshi" ``` ### Test 8 — Input Validation ```bash # Missing request body curl -s -X POST "$BASE/api/jobs" -H "Content-Type: application/json" -d '{}' # Unknown job ID curl -s "$BASE/api/jobs/does-not-exist" # Demo without param curl -s "$BASE/api/demo" ``` ### Test 9 — Rate Limiter ```bash # Fire 6 requests from the same IP for i in $(seq 1 6); do curl -s "$BASE/api/demo?request=ping+$i" | grep -o '"result"\|"error"' done ``` ### Test 10 — Rejection Path ```bash curl -s -X POST "$BASE/api/jobs" \ -H "Content-Type: application/json" \ -d '{"request": "Help me do something harmful and illegal"}' ``` --- ## Additional Notes ### Stub Mode Behavior - `/api/dev/stub/pay` is **dev-only** endpoint - Simulates Lightning Network payment without real node - Not available in production (real LNbits integration) ### Payment Detection - All state transitions happen server-side - Client polls GET `/api/jobs/{jobId}` - Server advances state automatically when payment detected - No webhooks or push notifications ### Database Reference - Full payment hashes stored in `invoices` table - Query job status to retrieve full 64-char hash