Service HTTP API
The service listens on port 4400 (configurable via SERVICE_PORT). The
browser package and fixer talk to it automatically; these endpoints are also
yours to script against — the dashboard is built entirely on the read
endpoints.
Script registration
POST /api/scripts/register
Called by the browser package on chromium.launch(). Registration is
best-effort — scripts run fine if it fails.
{ "scriptId": "portal-scraper", "repoUrl": "https://github.com/your-org/scrapers", "entryFile": "src/scraper.ts", "branch": "main", "maxFailures": 3}Returns 201 with { scriptId, state, registeredAt }. scriptId is the
only required field (400 without it).
GET /api/scripts/:id/status
Current state of one script: { scriptId, state, failureCount, maxFailures, lastError, pendingErrors, registeredAt, repoUrl, entryFile, branch }.
state is 'active' or 'fixing' — there is no blocked state.
POST /api/scripts/:id/unblock
Resets a script to { state: 'active', failureCount: 0 }. Kept for
operational hygiene; since Autowright never blocks, you rarely need it.
Error intake
POST /api/errors
Called by the browser package on failure. Body is a full
ErrorContext (scriptId and hash required).
{ "accepted": true, "deduplicated": false, "scriptId": "portal-scraper" }Every error is accepted (200). If a fix for the same hash was created
within the dedupe window (AUTOWRIGHT_DEDUPE_TTL_MS, default 24h),
deduplicated is true and no new fix job is queued — the incident is
already being handled. Unknown scriptId returns 404.
Fix queue (used by the fixer)
GET /api/errors?status=pending
How the fixer polls for work. Returns queued items with their errorContext
and the script’s registration (repo, branch, entry file). Valid statuses:
pending, in-progress, completed, failed.
GET /api/errors/:scriptId
All error metadata for one script — classification, message, step, artifact manifest per item.
GET /api/errors/:scriptId/:fixRequestId
One error in full: timestamps, complete errorContext (including the
artifact bundleUrl), and the result if the fix has finished.
PATCH /api/errors/:scriptId/:fixRequestId
How the fixer reports progress:
{ "status": "completed", "result": { "success": true, "fixType": "pr", "prUrl": "…", "summary": "…", "filesChanged": ["src/scraper.ts"], "cost": { "usd": 0.09, "turns": 6 } } }status must be in-progress, completed, or failed. Side effects on the
script record: in-progress sets state: 'fixing'; completed resets the
failure counter and returns the script to active; failed also returns it
to active — a failed fix never blocks the script.
Dashboard reads
GET /api/stats
Headline aggregates:
{ "totalRuns": 42, "running": 1, "fixed": 37, "notFixed": 4, "totalCostUsd": 4.83, "avgCostUsd": 0.13, "totalTurns": 268}running counts pending + in-progress; fixed is completed;
notFixed is failed (surfaced as “needs attention”).
GET /api/fixes
Global list of all fixes, with the fields a table needs:
{ "total": 42, "fixes": [{ "id": "fix-a1b2c3d4-1781067588938", "scriptId": "portal-scraper", "status": "completed", "classification": "SELECTOR_NOT_FOUND", "errorMessage": "Timeout 30000ms exceeded…", "step": { "name": "click", "action": "click", "selector": "#login-btn", "url": "…" }, "createdAt": "…", "startedAt": "…", "completedAt": "…", "prUrl": "https://github.com/your-org/scrapers/pull/17", "filesChanged": ["src/scraper.ts"], "costUsd": 0.09, "turns": 6 }]}GET /api/fixes/:id
The full FixQueueItem for one fix — complete error
context, result, cost breakdown, and artifact manifest. 404 if the id is
unknown.