Prometheus
Reference

API reference

The agent-to-agent HTTP surface. Send a prompt, get back verified, runnable Firecrawl code plus a data sample — then optionally save it as a self-healing script and deploy it on a schedule or as an on-demand data endpoint.

  • Base URL: your instance, e.g. http://localhost:3000 — all paths below are under /api/v1.
  • Content type: application/json for request bodies and most responses.
  • Auth: none by default. Behind a gateway, send Authorization: Bearer <token>.

Build

POST /api/v1/build

Run the agent headlessly and return a verified collector. No clarifying questions are asked — the agent makes reasonable assumptions and reports them in howItWorks. Runs the full agent (experiment → author → verify → deliver), typically 30–180 seconds.

Request:

jsonc
{  "prompt": "top 5 Hacker News stories with title, url, and points",  // required  "schema": { "type": "object", "properties": { /* … */ } },           // optional: enforce output shape  "urls":   ["https://news.ycombinator.com/"],                          // optional: starting URLs  "model":  { "provider": "openai", "model": "gpt-5.5" }          // optional: override the model}

model.provider doubles as the engine selector: anthropic models run on the Claude Agent SDK, openai models on the Codex SDK.

Response 200:

jsonc
{  "sessionId": "build-XCFpO8Z…",        // pass to POST /scripts to save this collector  "language": "typescript",  "script": "import Firecrawl from '@mendable/firecrawl-js'; …",  // the verified generator  "sample": [ { "title": "…", "url": "…", "points": 412 }, … ],   // verified output it produced  "rowCount": 5,  "summary": "Top 5 current Hacker News front-page stories …",  "howItWorks": "Visits news.ycombinator.com, reads the ranked rows, … Assumes 'points' = the story score.",  "expectedOutput": "A list of 5 objects, each with title, url, points.",  "schema": null,  "integration": {    "dependencies": ["@mendable/firecrawl-js"],    "env": ["FIRECRAWL_API_KEY"],    "run": "tsx script.ts"  }}

To use the result: write script to a file, npm i @mendable/firecrawl-js tsx, set FIRECRAWL_API_KEY, then tsx script.ts — it prints the same JSON shape as sample to stdout.

Errors:

StatusMeaning
400prompt is missing or empty.
500FIRECRAWL_API_KEY not configured on the instance.
502build_incomplete — the agent didn't deliver a verified script. Retry with a sharper prompt or pass urls.

Example:

bash
curl -s localhost:3000/api/v1/build \  -H 'content-type: application/json' \  -d '{"prompt":"top 5 Hacker News stories with title, url, points"}' \| jq '{rowCount, script}'

GET /api/v1/build/:sessionId

Re-fetch a previous build's { script, sample, rowCount, integration } without re-running the agent. The prose fields (summary/howItWorks) are only on the original POST response. 404 if the session is unknown.

Overview

GET /api/v1/overview

Cross-script rollups for a fleet dashboard, in one read. The window is the last 7 UTC calendar days including today; only data-collection runs (kind: "refresh") count toward the throughput numbers — heal and build runs are excluded.

jsonc
{  "stats": {    "runs7d": 42,            // refresh runs started in the window    "successRate7d": 0.95,   // success / (success + error); null when none finished    "rows7d": 1280,          // rows collected by successful refresh runs    "activeSchedules": 5,    "totalScripts": 7  },  "series": [                // exactly 7 entries, oldest UTC day first    { "date": "2026-06-05", "success": 6, "error": 1 }, …  ],  "fleet": [                 // per-script slices for sparklines    { "scriptId": "…", "days": [ …7 entries… ], "rows7d": 240 }, …  ],  "attention": [             // loudest first; empty = all healthy    { "kind": "failing", "scriptId": "…", "scriptName": "…", "detail": "…", "since": "…" },    { "kind": "auto_paused", "scheduleId": "…", … },   // also: webhook_failing, healing  ],  "recentRuns": [ /* last 20 Run objects + scriptId/scriptName, newest first */ ]}

Script objects themselves stay on GET /scripts — this endpoint never duplicates them.

Scripts

A script is the versioned collector: it self-heals when the target site changes, and a successful heal appends a new version. A deployment is one way a script runs for you: on a cron schedule, on demand via POST /deployments/:id/run, or both.

Schedules

every (on deployments) accepts friendly forms or a raw cron. All times are UTC. Null/absent = on-demand only.

FormMeaning
hourlytop of every hour
30mevery 30 minutes (1–59)
6hevery 6 hours (1–23)
daily00:00 UTC daily
daily@14:0014:00 UTC daily
weeklyMonday 00:00 UTC
monday@09:00that weekday at HH:MM UTC
0 9 * * 1any raw 5-field cron

Self-heal

heal (default repair_then_rebuild): when a run fails, Prometheus re-invokes the agent to fix the collector and appends the fix as a new script version, which every track-latest deployment picks up.

ValueBehavior
offno recovery
repairpatch the existing script
rebuildregenerate from the original request
repair_then_rebuildtry repair, escalate to rebuild

POST /api/v1/scripts

Mint a script from one of: a prompt (Prometheus builds the collector now — slow, runs the agent), a sessionId from a prior /build (fast — just pins it), or a script you already hold (the import path). Pass deployment to also deploy it in the same call.

jsonc
{  "prompt": "OpenAI blog post titles + urls",   // or "sessionId": "build-…" or "script": "…"  "name": "OpenAI blog",                         // optional (derived if omitted)  "schema": { /* … */ },                          // optional  "heal": "repair_then_rebuild",                  // optional; default on  "deployment": { "every": "daily@09:00" }        // optional; null/absent `every` = on-demand only}

Response 201{ "script": Script, "deployment"?: Deployment }.

GET /api/v1/scripts

List all scripts (deployments nested) → { "scripts": Script[] }.

GET /api/v1/scripts/:id

Script detail + versions + recent runs:

jsonc
{ "script": Script, "versions": [ ScriptVersion, … ], "runs": [ Run, … ] }

?include=content adds the latest version's source as a top-level content field (&version=n selects another).

PATCH /api/v1/scripts/:id

Update mutable fields → { "script": Script }:

jsonc
{ "name": "…", "summary": "…", "heal": "rebuild", "mode": "fork" }   // all optional

mode: "fork" stops subscribing to a marketplace listing (one-way).

DELETE /api/v1/scripts/:id

Archive (soft delete) → { "ok": true, "archived": true }. Cascades to the script's deployments; history is preserved.

GET/POST /api/v1/scripts/:id/versions

GET lists versions (newest first). POST { "script": "…" } appends a manual version → 201 { "script": Script } (re-gated when published; rejected while subscribed to a listing).

POST /api/v1/scripts/:id/heal

"Fix now" — repair/rebuild a broken script immediately (bypasses cooldown/cap). If self-heal is off, a manual call still attempts repair_then_rebuild. → { "healed": boolean, "runs": [...] }.

GET /api/v1/scripts/:id/data

The latest successfully collected JSON across all the script's runs, straight from storage. Returns the raw collector output (any shape). 404 if nothing has been collected yet. Headers X-Run-Id and X-Run-Row-Count identify the run.

Deployments

POST /api/v1/deployments

Deploy an existing script → 201 { "deployment": Deployment }:

jsonc
{ "scriptId": "…", "name": "…", "every": "6h", "pinnedVersion": 3, "enabled": true }// every absent/null = on-demand only; pinnedVersion omitted/null = run the latest version

GET /api/v1/deployments

List all deployments → { "deployments": Deployment[] }.

GET /api/v1/deployments/:id

Deployment detail + recent runs → { "deployment": Deployment, "runs": Run[] }.

PATCH /api/v1/deployments/:id

Update mutable fields → { "deployment": Deployment }:

jsonc
{ "name": "…", "every": null, "enabled": false, "pinnedVersion": null }   // all optional

every: null clears the schedule (on-demand only); pinnedVersion: null tracks the latest version again. Schedule/enabled changes recompute nextRunAt (UTC).

DELETE /api/v1/deployments/:id

Archive (soft delete) → { "ok": true, "archived": true }.

POST /api/v1/deployments/:id/run

The API-endpoint trigger. Executes the script synchronously (up to ~2 minutes) and returns { "run": Run, "data": … } with the collected JSON inline — 200 on success, 502 with data: null when the run failed (run.error explains). Optional body { "trigger": "manual" }; default trigger is api. Failures feed the script's self-heal.

POST /api/v1/scripts/:id/run-async

The asynchronous variant: don't hold the connection — get a 202 immediately and the outcome at your webhook.

Request:

jsonc
{  "params": { "city": "Paris" },                   // optional, validated up front  "webhookUrl": "https://example.com/hooks/run"    // required; hosted instances demand https + a public host}

params and webhookUrl are validated before the acknowledgement — bad params are the same 400 with per-key errors as the sync route, and no run is recorded.

Response 202:

jsonc
{  "runId": "fRk2…",                 // also visible in GET /scripts/:id/runs  "scriptId": "RxTLhAZ31…",  "webhook": { "secret": "whsec_…" }  // per-run signing secret — shown only here}

The run executes after the response; when it settles, your webhook receives one POST with the same signed envelope scheduled runs use (minus the schedule block):

jsonc
// header x-prometheus-event: run.succeeded | run.failed{  "event": "run.succeeded",  "timestamp": "ISO",  "script": { "id": "RxTLhAZ31…" },  "run": { "id": "fRk2…", "status": "success", "startedAt": "ISO", "finishedAt": "ISO", "rowCount": 5, "error": null, "errorClass": null },  "data": [ /* collected JSON inline on success; null on failure */ ],  "error": null,  "heal": { "status": "declined", "reason": "…" }   // run.failed only, when self-heal settled the failure}

Verify authenticity with the x-prometheus-signature header — t=<unix seconds>,v1=<hex hmac-sha256(secret, "<t>.<body>")> — using the whsec_… secret from the 202.

Heal-wait semantics. A failed run does not immediately deliver run.failed when the script's self-heal is on: the delivery parks while self-heal fixes the script; once a heal succeeds, the run re-executes with your original params and you get a fresh run.succeeded (or, if it fails again, it parks again). You receive run.failed only when the failure is final: self-heal is off (delivered immediately), the failure is classified out_of_credits or out_of_scope (delivered immediately with the class in run.errorClass — billing and out-of-scope input are terminal for the request; heal-wait is for broken script logic), the heal declined your params as out of the script's scope (heal.status: "declined" with the reason), the heal exhausted its attempts ("exhausted"), or no heal settled within 24 hours of the failure ("stale" — the safety valve, checked on every heal pass).

GET /api/v1/deployments/:id/runs?limit=

Run history (newest first; default 20, max 100) → { "runs": Run[] }.

GET /api/v1/deployments/:id/data

The latest dataset this deployment produced — no fresh run. Same raw-JSON shape and headers as the script-level data endpoint. 404 if nothing collected yet.

Script object

jsonc
{  "id": "RxTLhAZ31…",  "name": "HN top 5",  "summary": "Top 5 Hacker News front-page stories.",  "prompt": "top 5 HN stories",        // originating request, when known  "schema": null,                        // pinned output schema, when given  "engine": "claude",                    // engine pinned from the build; null = server default  "model": "claude-opus-4-8",  "heal": "repair_then_rebuild",  "latestVersion": 3,  "health": "healthy",                  // healthy | failing | healing | pending  "createdAt": "2026-06-08T19:55:02.352Z",  "source": { "listingId": "…", "mode": "subscribe", "version": 3 },  // marketplace lineage, when present  "publishedListingId": null,  "deployments": [ Deployment, … ]}

health is derived from the most recent run across all deployments: successhealthy, errorfailing, a repair/rebuild in flight → healing, none yet → pending.

Deployment object

jsonc
{  "id": "dXf91k…",  "scriptId": "RxTLhAZ31…",  "name": "Hourly pull",  "schedule": { "cron": "0 * * * *", "description": "every hour" },  // null = on-demand only  "enabled": true,  "pinnedVersion": null,                // null = runs the script's latest version  "health": "healthy",  "createdAt": "ISO",  "lastRunAt": null,  "nextRunAt": "2026-06-15T09:00:00.000Z",  "latestRun": {    "status": "success",                // success | error | running    "kind": "refresh",                  // create | refresh | repair | rebuild    "trigger": "schedule",              // schedule | api | manual | self_heal    "finishedAt": "ISO|null",    "rowCount": 5,    "error": null  }}

Full run records (Run) add id, deploymentId (null for script-level heal runs), versionRan, startedAt, dataBlobUrl, and errorClass — the failure taxonomy for error runs: out_of_credits (the team's Firecrawl account couldn't fund the run; self-heal skips these), out_of_scope (the input is outside what the script supports, per its declared error patterns; self-heal declines instead of rewriting), or logic_broken (the script itself no longer works — the default, and what self-heal repairs). errorClass is null for non-error runs.

Notes

  • Latency: /build, /scripts with a prompt, and /scripts/:id/heal run the agent (slow, up to several minutes); /deployments/:id/run executes the script (up to ~2 minutes). All other endpoints are fast DB/storage reads. The agent-backed routes set maxDuration = 800; on Vercel that needs a Pro plan.
  • Artifacts persist by sessionId, so a /build response can be minted later via POST /scripts with { sessionId } — no rebuild needed.
  • See also: the CLI reference and the MCP reference.