Skip to content

API Reference

Base URL: https://api.thothato.io

The Thoth-ATO REST API drives the remote console programmatically — useful for CI/CD pipelines, GitHub Actions, and orchestrators. All endpoints require a Bearer token.

Authorization: Bearer sk_live_xxxxx

API keys are issued from https://thothato.io/dashboard/api-keys. Keys are scoped to a single tenant. Format: sk_live_* (production) or sk_test_* (sandbox — no billing impact).

The API returns standard HTTP status codes.

CodeMeaning
200 / 201 / 202Success.
400Malformed request body or invalid parameters.
401Missing or invalid Authorization header.
403Key is valid but lacks permission for the resource (e.g. another tenant’s cycle).
404Resource does not exist.
409State conflict (e.g. cycle already terminated).
422Validation failure on a structurally valid body.
429Rate limit exceeded. See rate-limit headers below.
5xxServer error. Safe to retry with exponential backoff.

Error body:

{
"error": {
"code": "quota_exceeded",
"message": "Signed-verdict quota reached; cycles continue unsigned. Upgrade for unlimited signed verdicts.",
"docsUrl": "https://docs.thothato.io/pricing"
}
}

Hitting the signed-verdict cap does not block the cycle. The cycle still runs to completion and returns an unsigned deliverable; only the cryptographic verdict signature is withheld until you upgrade.

Every response includes:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1747400000
X-RateLimit-Scope: api-key
  • Limit — requests permitted in the current window
  • Remaining — requests left in the current window
  • Reset — Unix epoch seconds when the window resets
  • Scopeapi-key (per key) or tenant (aggregate)

When you hit the limit, the API returns 429 with a Retry-After header in seconds.

Start a new governed cycle.

Request body:

{
"goal": "Build a CLI that converts CSV to JSON, with tests.",
"constitutionRef": "default",
"specRef": "github://owner/repo/issues/42",
"maxCycles": 3,
"metadata": {
"ci": "github-actions",
"runId": "8472634123"
}
}
FieldTypeRequiredDescription
goalstringYes (one of goal/specRef)Natural-language goal.
specRefstringYes (one of goal/specRef)URI to a spec: github://..., https://..., or inline:<base64>.
constitutionRefstringNoConstitution to enforce. Default: default.
maxCyclesintNoSelf-healing cap. Default: 3. Max: 10.
metadataobjectNoFree-form caller-supplied metadata. Echoed back. Up to 4 KB.

Response — 202 Accepted:

{
"cycleId": "cyc_01HXXXX",
"status": "queued",
"streamUrl": "/api/v1/cycles/cyc_01HXXXX/stream",
"createdAt": "2026-05-16T12:00:00Z"
}

Errors:

  • 401 — missing/invalid key
  • 403 — key lacks cycles:write
  • 422 — neither goal nor specRef supplied, or specRef URI invalid
  • 429 — rate limit exceeded (the signed-verdict quota does not block cycle creation; the cycle runs and returns an unsigned deliverable)

Fetch the current state of a cycle.

Response:

{
"cycleId": "cyc_01HXXXX",
"status": "running",
"phase": "execute",
"createdAt": "2026-05-16T12:00:00Z",
"completedAt": null,
"constitutionRef": "default",
"metadata": { "ci": "github-actions", "runId": "8472634123" }
}

status values: queued | running | completed | failed | rejected.

phase values: specify | plan | execute | verdict (only set while status=running).

rejected means the Judge refused to ship — the verdict explains which principle threshold was missed.

Server-Sent Events (SSE) stream of cycle progress. Emits one event per phase transition and one per worker tool call. Connection stays open until the cycle terminates.

GET /api/v1/cycles/cyc_01HXXXX/stream HTTP/1.1
Accept: text/event-stream
Authorization: Bearer sk_live_xxxxx

Event format:

event: phase
data: {"phase":"execute","worker":"thoth-develop","at":"2026-05-16T12:01:14Z"}
event: tool-call
data: {"worker":"thoth-develop","tool":"Write","target":"src/cli.ts"}
event: principle-score
data: {"principle":"security","score":0.92}
event: verdict
data: {"cycleId":"cyc_01HXXXX","status":"completed"}

The stream terminates with a final event: terminal payload carrying status and the deliverable URL.

Fetch the final deliverable bundle once the cycle is completed. Returns 409 Conflict while still running.

Response:

{
"cycleId": "cyc_01HXXXX",
"verdict": {
"cycleId": "cyc_01HXXXX",
"kmsKeyVersion": "projects/p/locations/l/keyRings/r/cryptoKeys/judge/cryptoKeyVersions/1",
"principles": { "security": 0.92, "cost": 0.88 },
"constitutionRef": "sha256:abc...",
"deliverableHash": "sha256:def...",
"issuedAt": "2026-05-16T12:04:30Z",
"verdictHash": "BASE64_ED25519_SIGNATURE"
},
"spec": {
"rootIntent": "...",
"componentIntents": [],
"taskIntents": []
}
}

The spec block contains the resolved JSON spec only — never source code, never tool-call outputs. To retrieve worker transcripts, use the editor-local .thoth/cycles/<id>/transcript.jsonl.

List API keys for the authenticated tenant. Returns key prefixes only — the secret material is never retrievable after creation.

Response:

{
"keys": [
{
"id": "key_01HXXXX",
"prefix": "sk_live_a1b2",
"name": "production-ci",
"scopes": ["cycles:read", "cycles:write"],
"createdAt": "2026-05-01T00:00:00Z",
"lastUsedAt": "2026-05-16T11:59:00Z",
"expiresAt": null
}
]
}

Create a new API key. The full secret is returned once in the response. Store it immediately.

Request body:

{
"name": "ci-production",
"scopes": ["cycles:read", "cycles:write"],
"expiresAt": "2027-05-16T00:00:00Z"
}
ScopePermits
cycles:readList and inspect cycles.
cycles:writeStart new cycles.
keys:readList API keys (the key’s own prefix only unless admin).
keys:writeCreate and revoke keys.
adminTenant-wide admin. Grant sparingly.

Response — 201 Created:

{
"id": "key_01HXXXX",
"name": "ci-production",
"secret": "sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"createdAt": "2026-05-16T12:00:00Z",
"expiresAt": "2027-05-16T00:00:00Z"
}

Revoke an API key. Returns 204 No Content. Existing in-flight cycles authenticated by the key continue to completion; new requests using the key get 401.

Usage metrics for a single key, for the current billing period or a specified period query param (YYYY-MM).

Response:

{
"id": "key_01HXXXX",
"period": "2026-05",
"remoteCycles": 7,
"localCycles": 142,
"tokensIn": 1500000,
"tokensOut": 380000,
"rejectedCycles": 2
}

localCycles is reported when the plugin is configured with this key and THOTHATO_TELEMETRY=on — it is opt-in usage counting only, not data exfiltration.

GET /api/v1/judge/public-keys/{kmsKeyVersion}

Section titled “GET /api/v1/judge/public-keys/{kmsKeyVersion}”

Fetch the Ed25519 public key for a given Cloud KMS key version. Used to verify signed verdicts. This endpoint is unauthenticated for transparency — anyone can verify a verdict without holding an API key.

Response:

{
"kmsKeyVersion": "projects/p/locations/l/keyRings/r/cryptoKeys/judge/cryptoKeyVersions/1",
"publicKey": "-----BEGIN PUBLIC KEY-----\nMCowBQ...\n-----END PUBLIC KEY-----",
"algorithm": "Ed25519",
"createdAt": "2026-01-01T00:00:00Z",
"rotatedAt": null
}

See Verdict verification for the full verification protocol and reference implementations in Node, Python, Go, and Rust.

  • CLI reference — the slash-command surface that uses this API.
  • Verdict verification — verify the signed verdicts returned by /api/v1/cycles/{id}/deliverable.
  • Pricing — quota and rate-limit tiers.