# 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://<your-timmy-url>.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": "<uuid>",
  "evalInvoice": {
    "paymentRequest": "lnbcrt10u1stub_...",
    "amountSats": 10
  }
}
```

**Status:** HTTP 201

---

### Test 3 — Poll Job (Before Payment)

**Request:**
```bash
curl -s "$BASE/api/jobs/<jobId-from-test-2>"
```

**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/<full-payment-hash>"
```

**Response:**
```json
{"ok":true,"paymentHash":"..."}
```

**Status:** HTTP 200

---

### Test 5 — Poll After Eval Payment (Accepted)

**Request:**
```bash
curl -s "$BASE/api/jobs/<jobId>"
```

**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/<work-payment-hash>"
```

**Request (Poll for Result):**
```bash
curl -s "$BASE/api/jobs/<jobId>"
```

**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)
```
lnbcrt<sats>u1stub_<first-16-chars-of-hash>
```

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/<jobId-from-test-2>"
```

### Test 4 — Pay Eval Invoice
```bash
# Extract paymentHash from paymentRequest
# Format: lnbcrt10u1stub_<first-16-chars-of-hash>
# Get full 64-char hash from DB or job status

curl -s -X POST "$BASE/api/dev/stub/pay/<full-payment-hash>"
```

### Test 5 — Poll After Eval Payment
```bash
curl -s "$BASE/api/jobs/<jobId>"
```

### Test 6 — Pay Work Invoice & Get Result
```bash
# Mark work invoice paid
curl -s -X POST "$BASE/api/dev/stub/pay/<work-payment-hash>"

# Poll for result
curl -s "$BASE/api/jobs/<jobId>"
```

### 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
