RIG API
Every agent run returns a verdict and a refutable receipt. This page is the whole contract: four endpoints, one error model, zero happy-path-only examples. Base URL https://api.rig.run.
Quickstart
Zero to a verified run in four steps. Every command below is real — paste it, expect the output shown.
Authenticate — device flow
No browser dance on headless boxes. rig auth login prints a code, you approve it once, the CLI holds the session.
$ rig auth login → open https://rig.run/device and enter code WDXK-72Q4 waiting for approval… ✓ authenticated as ops@acme.dev (workspace: acme-prod) session written to ~/.rig/session (0600)
Install an agent
Installs are pinned to a content hash. The workspace token printed here is what your services send as Authorization — it is shown once.
$ rig install prior prior@2.4.1 hash a91f3e2 2.1 MB ✓ installed · 12,412 active installs · 99.4% sealed rate workspace token (shown once, store it now): rig_ws_7Kd29mXq4FvN8bL0hJ3cP1sR
First invoke
Synchronous for runs under the timeout. The response always carries a proof_packet — that's the receipt, not a nice-to-have.
$ curl -s https://api.rig.run/v1/invoke \
-H "Authorization: Bearer rig_ws_7Kd29mXq4FvN8bL0hJ3cP1sR" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: fc-2026-08-05-q3-rev" \
-d '{
"agent": "prior",
"version": "2.4.1",
"input": { "question": "Q3 revenue, services line, ±5% band" }
}'
{
"run_id": "run_f41c8a2",
"agent": "prior",
"version": "2.4.1",
"verdict": "APPROVED",
"output": { "forecast": 4120000, "band": [3914000, 4326000], "brier": 0.041 },
"proof_packet": {
"id": "pkt_9d2b7c1",
"hash": "9d2b7c1",
"prev_hash": "e58a0d4",
"sealed_at": "2026-08-05T14:22:07Z",
"verifier": "gate@1.4.7"
},
"duration_ms": 1843
}
Verify the packet yourself
Don't take the API's word. Fetch the packet and re-check the hash chain — three lines of shell:
$ curl -s https://api.rig.run/v1/proof/pkt_9d2b7c1 \
-H "Authorization: Bearer rig_ws_7Kd29mXq4FvN8bL0hJ3cP1sR"
{
"id": "pkt_9d2b7c1",
"hash": "9d2b7c1",
"prev_hash": "e58a0d4",
"payload_sha": "3f8c…",
"status": "SEALED"
}
# chain check: hash must equal sha256(prev_hash + payload_sha)[:7]
$ echo -n "e58a0d43f8c…" | shasum -a 256 | cut -c1-7
9d2b7c1 ✓ matches — chain intact
If those 7 chars don't match, the packet was tampered with or the ledger forked. Either way: stop, don't ship.
Auth
One token type, sent one way:
Authorization: Bearer rig_ws_7Kd29mXq4FvN8bL0hJ3cP1sR
rig_ws_*workspace tokens — full API access, shown once atrig install, rotate withrig auth rotate.- Tokens are scoped per workspace; a token from
acme-prodreturns401againstacme-stagingresources, not a confusing empty list. - Last four characters are returned in every error body and log line for correlation — the rest never leaves the wire.
- Rotation invalidates the old token after a 60s overlap window. In-flight runs finish; new invokes need the new token.
Errors
Every error body has the same shape: code, message, request_id, plus error-specific fields. The status code is never the whole story — read the body.
| Status | Code | Meaning / extra fields |
|---|---|---|
| 401 | invalid_token | Token missing, expired, or wrong workspace. extra: token_last4 |
| 402 | limit_reached | Monthly run quota exhausted. extra: upgrade_url — go to /site/pricing.html or the runs hard-stop at the boundary |
| 409 | idempotency_conflict | Same Idempotency-Key, different payload. extra: original_run_id |
| 422 | schema_violation | Input failed the agent's schema. extra: pointer (JSON Pointer to the offending field) |
| 423 | verifier_refuted | The run executed but the verifier refuted the output. extra: reason, packet_id |
| 429 | rate_limited | Too many requests. extra: retry_after (seconds) |
| 500 | runtime_fault | Our side broke. extra: incident_id — quote it to support |
423 verifier_refuted — the error that is the product
Any agent framework can return 200 with plausible garbage. RIG returns 423 when the independent verifier replays the run and the output doesn't hold. The response tells you why, and hands you the packet that proves the refutation — so your pipeline fails closed instead of shipping a confident lie.
HTTP/1.1 423 Locked Content-Type: application/json { "code": "verifier_refuted", "message": "gate@1.4.7 refuted prior@2.4.1 output: forecast band excludes stated evidence range", "reason": "claimed band [3914000, 4326000] but cited source rng_7c2e914 reports [4031000, 4480000]; lower bound contradicts evidence", "packet_id": "pkt_4a7e1f0", "packet_hash": "4a7e1f0", "run_id": "run_b82d5c3", "request_id": "req_2f60aa9", "refuted_at": "2026-08-05T14:26:41Z", "dispute_url": "https://api.rig.run/v1/proof/pkt_4a7e1f0/dispute" }
reason field is written for engineers, not logs. If you believe the verifier is wrong, POST to dispute_url; the dispute and its resolution are appended to the same hash chain./v1/invoke
POST Run an agent. Synchronous up to 120s; longer runs return 202 with a run_id to poll via /v1/status.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| agent | string | required | Agent name: prior · judge · gate · route · harvest · guard · draft · mesh |
| version | string | optional | Pin, e.g. "2.4.1". Default: latest installed in workspace |
| input | object | required | Agent-specific; must satisfy the agent's published schema or 422 |
| timeout_ms | integer | optional | 1,000–120,000. Default 30,000 |
| Idempotency-Key | header | recommended | Safe retries; see Idempotency |
$ curl -s https://api.rig.run/v1/invoke \
-H "Authorization: Bearer rig_ws_7Kd2…" \
-H "Idempotency-Key: daily-brief-2026-08-05" \
-d '{"agent":"harvest","version":"0.8.3",
"input":{"target":"competitor.io","since":"2026-07-29"}}'
{
"run_id": "run_6e1c04b",
"verdict": "APPROVED",
"output": { "signals": 14, "sourced": 14 },
"proof_packet": { "id": "pkt_7f3b9a2", "hash": "7f3b9a2", "prev_hash": "9d2b7c1" },
"duration_ms": 2210
}
/v1/status
GET /v1/status/{run_id} — poll an async run. Poll no faster than 1/s; the packet appears exactly once, on the terminal state.
| Field | Type | Required | Description |
|---|---|---|---|
| run_id | path | required | From invoke, e.g. run_6e1c04b |
$ curl -s https://api.rig.run/v1/status/run_6e1c04b \
-H "Authorization: Bearer rig_ws_7Kd2…"
{
"run_id": "run_6e1c04b",
"state": "verifying", // queued → running → verifying → sealed | refuted
"elapsed_ms": 1104
}
/v1/proof
GET /v1/proof/{packet_id} — the receipt. Hash, parent hash, payload digest, verifier version, timestamps. Everything you need to verify without trusting us.
| Field | Type | Required | Description |
|---|---|---|---|
| packet_id | path | required | e.g. pkt_9d2b7c1 |
| format | query | optional | json (default) · pem (signed bundle for audit archives) |
{
"id": "pkt_9d2b7c1",
"hash": "9d2b7c1",
"prev_hash": "e58a0d4",
"payload_sha": "3f8c2a91d07e…",
"agent": "prior@2.4.1",
"verifier": "gate@1.4.7",
"status": "sealed",
"sealed_at": "2026-08-05T14:22:07Z",
"chain_height": 184,207
}
POST /v1/proof/{packet_id}/dispute — contest a sealed or refuted packet. The dispute joins the chain; it is never edited in place.
/v1/export
GET /v1/export — bulk-dump packets for your own audit trail. Streams NDJSON; resume with the cursor.
| Field | Type | Required | Description |
|---|---|---|---|
| since | query | optional | ISO-8601, e.g. 2026-08-01T00:00:00Z |
| agent | query | optional | Filter to one agent |
| status | query | optional | sealed · refuted · disputed |
| cursor | query | optional | From previous page's next_cursor |
| limit | query | optional | 1–1,000. Default 500 |
$ curl -s "https://api.rig.run/v1/export?since=2026-08-01T00:00:00Z&status=refuted&limit=100" \
-H "Authorization: Bearer rig_ws_7Kd2…"
{"id":"pkt_4a7e1f0","hash":"4a7e1f0","prev_hash":"b31c8e6","status":"refuted",…}
{"id":"pkt_c90d2f4","hash":"c90d2f4","prev_hash":"4a7e1f0","status":"refuted",…}
# headers: X-RIG-Next-Cursor: cur_8841de2 · X-RIG-Chain-Head: 184,207
Webhooks
Register an endpoint with rig webhooks add <url>. Events delivered at-least-once, ordered per workspace, retried with backoff for 24h.
| Event | Fires when |
|---|---|
| agent.completed | Run reaches a terminal state (sealed or refuted) |
| verifier.refuted | A 423 occurred — payload includes reason + packet_id |
| packet.sealed | A packet joins the hash chain |
| drift.alert | guard detects output drift beyond its determinism band |
POST /your-endpoint
X-RIG-Signature: t=1754413327,v1=8f2c1a4b…
X-RIG-Event: packet.sealed
{
"event": "packet.sealed",
"packet_id": "pkt_9d2b7c1",
"hash": "9d2b7c1",
"prev_hash": "e58a0d4",
"agent": "prior@2.4.1",
"sealed_at": "2026-08-05T14:22:07Z"
}
Verify the signature
Every delivery is HMAC-signed with your webhook secret (rig webhooks reveal). Four lines, no SDK required:
import hmac, hashlib signed = f"{t}.{raw_body}".encode() expect = hmac.new(SECRET, signed, hashlib.sha256).hexdigest() assert hmac.compare_digest(expect, v1) # reject if it raises
t more than 5 minutes old before comparing — that's your replay protection.SDKs
$ npm install @rig/sdk $ pip install rig-sdk
import { Rig } from "@rig/sdk";
const rig = new Rig({ token: process.env.RIG_TOKEN! });
const run = await rig.invoke("prior", {
version: "2.4.1",
input: { question: "Q3 revenue, services line" },
idempotencyKey: "q3-rev-2026-08-05",
});
if (run.verdict !== "APPROVED") {
throw new Error(`refuted: ${run.refutation?.reason} (pkt ${run.refutation?.packetId})`);
}
await rig.verifyPacket(run.proofPacket.id); // re-checks the hash chain locally
The SDK never swallows a 423 — it surfaces as a typed RefutedError with reason and packetId. Retries with backoff are built in for 429/500 only.
Rate limits
- 60 requests/min per workspace token; 10 concurrent invokes.
- Every response carries
X-RIG-RateLimit-RemainingandX-RIG-RateLimit-Reset(unix seconds). - On 429, honor
retry_afterin the body — it's exact, not advisory. Exponential backoff on top of it is fine; ignoring it gets the token throttled to 10/min for an hour. - Webhooks and
/v1/exportdon't count against the invoke limit.
Idempotency
Send Idempotency-Key on every invoke. Keys are scoped to (workspace, agent) and live 24h.
- Same key + same payload → the original response replayed, header
X-RIG-Replay: true, no second run, no second charge. - Same key + different payload →
409 idempotency_conflictwith theoriginal_run_id. Never silently reuses your key. - A replayed response includes the original proof packet — the receipt is stable, that's the point.
Pagination
Cursor-based everywhere (/v1/export, run history, dispute lists). No offsets — offsets lie on a moving ledger.
$ curl -s "https://api.rig.run/v1/export?limit=2" \
-H "Authorization: Bearer rig_ws_7Kd2…"
{"id":"pkt_9d2b7c1",…}
{"id":"pkt_7f3b9a2",…}
# → X-RIG-Next-Cursor: cur_8841de2
$ curl -s "https://api.rig.run/v1/export?limit=2&cursor=cur_8841de2" \
-H "Authorization: Bearer rig_ws_7Kd2…"
An empty X-RIG-Next-Cursor header means you're at the chain head. Cursors expire after 1h — re-issue with since to resume.