quickstart
Everything lives under /v1 on this same origin. No auth header, no account — your OpenRouter key rides in the request body as byok_key. POST /v1/runs with a full inline config; this example uses the leanest possible shape — one builder node, no eval:
curl -s https://vrinda.dev/v1/runs \
-H 'content-type: application/json' \
-d '{
"config": {
"schema": "orch-v0",
"name": "solo-glm",
"nodes": [
{ "id": "builder", "role": "builder", "model": "z-ai/glm-5.2",
"instructions": "Build a complete, single-file HTML app for the request. Inline all CSS and JS." }
],
"eval": { "type": "none", "max_retries": 0 }
},
"prompt": "Build a single-file HTML pomodoro timer with a circular progress ring.",
"byok_key": "sk-or-...",
"idempotency_key": "b1946ac9-4c9f-4b9a-8f1e-2d3c4b5a6d7e",
"disclose": true
}'
The server accepts immediately and returns 202 — it doesn't wait for the run to finish:
{ "run_id": "946aa650f4814e89b15c52f28572274d", "status": "queued" }
Runs follow a fixed node order — plan → build → check — with exactly one builder in the pipeline. The server injects its own approved model profile per node and rejects any temperature or max_tokens override you send. Set disclose: true to echo your config and prompt on the public board (see disclose below) — leave it false or omit it to keep them private. idempotency_key dedupes retried submits: reuse the same key and a retried POST returns the original run instead of starting a new one.
poll a run
GET /v1/runs/{run_id} — poll this until status is done, failed, or cancelled. Here's a finished run:
{
"run_id": "946aa650f4814e89b15c52f28572274d",
"status": "done",
"config_name": "solo-glm",
"disclose": true,
"node_statuses": [ { "id": "builder", "role": "builder", "status": "done" } ],
"receipts": {
"nodes": [
{ "role": "builder", "model": "z-ai/glm-5.2", "turn": 1,
"prompt_tokens": 3120, "completion_tokens": 8140,
"key_fingerprint": "a1b2c3d4", "usd": 0.011834,
"gen_id": "gen-01H9Z8Q", "artifact_sha256": "60b346276a6e4c9e2f..." }
],
"usd": 0.011834,
"tokens": { "total": 11260 }
},
"timing": {
"created_at": "2026-07-18T03:09:33Z",
"started_at": "2026-07-18T03:09:34Z",
"finished_at": "2026-07-18T03:10:22Z"
},
"config": { "schema": "orch-v0", "name": "solo-glm", "nodes": [ "..." ], "eval": { "type": "none", "max_retries": 0 } },
"prompt": "Build a single-file HTML pomodoro timer with a circular progress ring."
}
status— one ofqueued,running,done,failed,cancelled.node_statuses[]— per-nodeid/role/statusfor the live pipeline, in run order.receipts— per-node metered cost straight from the provider's own generation receipts.usdis real metered spend billed to your OpenRouter account, not an estimate.key_fingerprintissha256(your key)[:8].artifact_sha256is a content hash of that node's artifact.receipts.usdis the run's total, summed across nodes.receipts.tokens.totalis summed prompt and completion tokens across nodes.timingholdscreated_at/started_at/finished_at, ISO-8601 UTC. Queue wait isstarted_atminuscreated_at; build time isfinished_atminusstarted_at.disclose— whentrue, the response also echoesconfigandprompt: the run is public-by-link, so anyone with therun_idsees your prompt, config, receipts, and artifact. Whenfalseor absent,configandpromptare omitted. Some models are free (catalog price0) — a run entirely on free models meters at zero cost, and the site renders afreetoken there, never a dollar figure.
the artifact
The final builder node's output is one HTML file, served from its own locked-down origin:
https://artifacts.vrinda.dev/runs/{run_id}/artifact.html
Every response carries a strict sandbox CSP — content-security-policy: sandbox allow-scripts — so the artifact can run its own JS but can't touch cookies, storage, or the parent page. The URL is unlisted (a random run id) but not access-controlled. Treat anything you build as shareable.
models
GET /v1/models returns the live catalog:
{
"schema": "models-v0",
"models": [
{ "slug": "z-ai/glm-5.2", "label": "glm-5.2", "tier": "workhorse",
"in_usd_per_mtok": 0.413, "out_usd_per_mtok": 1.298, "fits_run_ceiling": true },
{ "slug": "tencent/hy3:free", "label": "hy3 · free", "tier": "free",
"in_usd_per_mtok": 0, "out_usd_per_mtok": 0, "fits_run_ceiling": true }
],
"presets": [ "..." ]
}
tier distinguishes free (catalog price 0, rate-limited by OpenRouter itself) from paid tiers like workhorse. in_usd_per_mtok and out_usd_per_mtok are USD per million tokens, input and output priced separately. fits_run_ceiling is whether one run on that model can stay under the $1.00 per-run ceiling. The catalog is the source of truth for pricing and updates without notice — read it here, don't hardcode it.
limits
Bring-your-own-key. Hard ceilings, enforced server-side, checked before every call.
- Rate limit.
12 runs / hourper address, rolling. - Spend ceilings. Per-run cap
$1.00; rolling session cap$5.00— runaway spend is refused. - Size caps. Prompt
8 KB(8192 bytes, UTF-8); per-stageinstructions2 KB(2048 bytes); the whole request wire size40 KB(40960 bytes). - Time limit.
720 swall-clock deadline per run. - One worker. A single FIFO queue. A run can fail alone and honestly — you see the reason, not a generic error.
custody
- Your key rides in the request body straight to the run, is forwarded to OpenRouter, and is never written to our queue, database, logs, or receipts. Receipts keep only
sha256(key)[:8]so you can match a run to your key without us holding it. - You pay OpenRouter, not us. Every
usdis metered from the provider's own generation receipts. Estimates are used only for a pre-call budget reservation.
honesty notes
- No quality scores or winner predictions in the API — that judgment stays with you.
disclose: trueis what makes a run's board entry public. The API itself doesn't grade or rank anything.- Costs in
receiptsare metered fact. Anything called an estimate is a pre-call reservation only, never what you're billed.