Files
timmy-tower/attached_assets/timmy_api_technical_specs_1773854936781.md
alexpaynex 53bc93a9b4 Add automated testing script and expose payment hashes
Integrates a new bash script for automated end-to-end testing of the Timmy API. Updates API routes to expose payment hashes in stub mode for easier invoice payment simulation during testing. Modifies test plan documentation to include the new automated script.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 418bf6f8-212b-4bb0-a7a5-8231a061da4e
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 6f2776b0-a913-41d3-a988-759a82feb6f3
Replit-Helium-Checkpoint-Created: true
2026-03-18 17:30:13 +00:00

396 lines
8.2 KiB
Markdown

# 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