Skip to content
Critique/docs
Platform

Coding Agent API

Run OpenCode-backed coding agents over HTTP — prompt in, sandbox execution, patch and optional draft PR out.

The Coding Agent API exposes the same OpenCode + E2B runtime as Builder for automation: CI bots, internal tools, and agents that already use Critique crt_ keys.

Marketing overview and copy-paste examples also live at /coding-agent-api.

Need token-in/token-out chat only (no sandbox)? See the sibling Inference APIPOST /api/v1/chat/completions on the same crt_ keys and credit pool.

Authentication

ItemValue
AuthAuthorization: Bearer crt_…
Create keysSettings → ConnectionsCritique API keys
Scopesread:builder, write:builder (included on new keys by default)

Keys act as your Critique user. The repository must already be on a GitHub App installation you control.

Endpoints

MethodPathScopePurpose
POST/api/v1/coding-agent/runswrite:builderStart a run
GET/api/v1/coding-agent/modelsread:builderList allowed models, credit floors, and capabilities
GET/api/v1/coding-agent/runs?limit=20&cursor=RUN_IDread:builderList recent runs with cursor pagination
GET/api/v1/coding-agent/runs/{id}read:builderStatus, summary, optional events
GET/api/v1/coding-agent/runs/{id}/statusread:builderLightweight polling status
GET/api/v1/coding-agent/runs/{id}?patch=1read:builderInclude patch text when ready
GET/api/v1/coding-agent/runs/{id}?events=1read:builderInclude OpenCode activity timeline
POST/api/v1/coding-agent/runs/{id}/messageswrite:builderSend a follow-up on the same run (live session when status is idle)
GET/api/v1/coding-agent/runs/{id}/streamread:builderServer-Sent Events stream of run activity
POST / PATCH/api/v1/coding-agent/runs/{id}/cancelwrite:builderCancel a run and tear down its sandbox when possible

Create run body

FieldRequiredNotes
repository or repositoryFullNameOne of repo id/nameowner/repo form
repositoryIdAlternativeCritique repository id
titleNoOperator-facing run title, max 120 chars
tagsNoUp to 20 normalized labels for CI jobs, owners, incidents, or queues
metadataNoClient metadata echoed on the run; max 16KB serialized
promptYesTask instruction (max 120k chars)
modelIdNoOpenRouter id from Remedy/Builder catalog
taskKindNocode or plan
baseRef / gitCheckoutRefNoBranch or ref to check out
validationModeNobasic, tests, or minimal
publish.modeNodraft_pr or none
publish.branchNoBranch name when publishing
billing.modeNomanaged (Critique credits) or openrouter
billing.openRouterApiKeyWhen openrouterEncrypted and saved as your OpenRouter BYOK key for future API runs
idempotencyKeyNoAlternative to the Idempotency-Key header; max 160 chars
webhook.urlNoPublic HTTPS endpoint for signed run status callbacks
webhook.secretWith webhook.urlAt least 32 chars; encrypted at rest and used for HMAC-SHA256 signing
webhook.eventsNoAny of run.idle, run.completed, run.failed, run.cancelled; defaults to all
safety.network.modeNodefault, restricted, or disabled; injected into sandbox instructions
safety.network.allowlistNoHostnames/URLs the agent should treat as allowed when network is restricted
safety.tools.permissionModeNodefault, suggest, or readonly; injected into sandbox instructions
safety.tools.allowedWritePathsNoPath/glob hints limiting where the agent should edit
safety.tools.blockedCommandsNoCommands the agent is instructed not to run
safety.resources.maxTurnsNoServer-enforced cap on follow-up turns for the run
safety.resources.maxRuntimeMsNoUsed as sandbox timeout when sandboxTimeoutMs is omitted
safety.resources.maxCreditsNoManaged-billing preflight fails if the selected model floor exceeds this cap

Idempotent create

Use an idempotency key when creating runs from CI, job queues, or webhook handlers. Retries with the same key and same payload return the original run instead of creating another sandbox or branch. Reusing the same key with a different payload returns 409.

curl https://critique.sh/api/v1/coding-agent/runs \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Idempotency-Key: stripe-webhook-fix-2026-06-05" \
  -H "Content-Type: application/json" \
  -d '{
    "repository": "acme/web",
    "prompt": "Add Stripe webhook signature verification and tests.",
    "publish": { "mode": "draft_pr" }
  }'

Example — managed billing

curl https://critique.sh/api/v1/coding-agent/runs \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "repository": "acme/web",
    "prompt": "Add Stripe webhook signature verification and tests.",
    "modelId": "anthropic/claude-sonnet-4.6",
    "billing": { "mode": "managed" },
    "publish": { "mode": "draft_pr" },
    "validationMode": "tests",
    "safety": {
      "network": { "mode": "restricted", "allowlist": ["api.stripe.com"] },
      "tools": { "permissionMode": "suggest" },
      "resources": { "maxTurns": 3, "maxCredits": 12 }
    },
    "webhook": {
      "url": "https://example.com/webhooks/critique-agent",
      "secret": "replace-with-at-least-32-random-characters"
    }
  }'

Example — OpenRouter billing

Pass your OpenRouter key in the body; Critique runs the sandbox and OpenRouter bills tokens on your account.

curl https://critique.sh/api/v1/coding-agent/runs \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "repository": "acme/web",
    "prompt": "Migrate the settings page to server actions.",
    "modelId": "openai/gpt-5.4",
    "billing": {
      "mode": "openrouter",
      "openRouterApiKey": "sk-or-v1-..."
    },
    "publish": {
      "mode": "draft_pr",
      "branch": "critique-agent/settings-server-actions"
    }
  }'

Follow-up messages (persistent session)

When a run finishes its first turn, status becomes idle and the E2B sandbox + OpenCode session stay warm until sessionExpiresAt. Send another prompt on the same run id — no new sandbox, no chained summary prompt.

curl https://critique.sh/api/v1/coding-agent/runs/RUN_ID/messages \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Add a regression test for expired signatures.",
    "publish": { "mode": "draft_pr" }
  }'

Close the session explicitly (kills the sandbox) with { "endSession": true }.

If the session expired or the run predates persistent sessions, the API falls back to a chained new run (prior context in the prompt, new sandbox) when the parent run is idle, completed, or failed.

Status responses include convenience fields for automation:

FieldMeaning
lifecycleStable lifecycle enum: queued, running, idle, completed, failed, cancelled, or unknown
terminalTrue for completed, failed, or cancelled runs
awaitingFollowUpTrue when the run is idle and the live sandbox session is still active
canFollowUpTrue when the run can accept either a live follow-up or a chained follow-up
nextActionsSuggested client actions such as stream, poll, send_message, end_session, open_builder, open_pull_request, or inspect_error
intentDeterministic category derived from the prompt for filtering and reporting

Cancel a run

curl -X POST https://critique.sh/api/v1/coding-agent/runs/RUN_ID/cancel \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Superseded by a newer CI job." }'

Live event stream (SSE)

curl -N "https://critique.sh/api/v1/coding-agent/runs/RUN_ID/stream?after=EVENT_ID" \
  -H "Authorization: Bearer crt_YOUR_KEY"

Events: builder.event (OpenCode activity rows), run.status when the turn reaches idle, completed, failed, or cancelled.

The after cursor is the last received event id. Reconnects resume from the durable event ledger order. run.status events include the same lifecycle fields as the compact status endpoint.

Signed webhooks

When webhook is set on create, Critique sends HTTPS POST callbacks to a public endpoint for selected run events. Each delivery includes:

HeaderValue
User-AgentCritique-Coding-Agent-Webhook/1.0
X-Critique-Webhook-IDUnique delivery id
X-Critique-Webhook-Eventrun.idle, run.completed, run.failed, or run.cancelled
X-Critique-Webhook-Signaturesha256=<hex HMAC> over the raw JSON body using webhook.secret

Verify the signature with a constant-time comparison before trusting the payload.

import crypto from 'node:crypto'

export function verifyCritiqueWebhook(secret: string, rawBody: string, signature: string) {
  const expected = `sha256=${crypto.createHmac('sha256', secret).update(rawBody).digest('hex')}`
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}

Response shape

Completed runs return (among other fields):

  • statusqueued, running, idle (session warm), completed, failed
  • lifecycle, terminal, awaitingFollowUp, canFollowUp, nextActions — stable automation state
  • sessionActivetrue when idle and inside sessionExpiresAt
  • turnCount — number of user turns on this run
  • tags, metadata, intent — client attribution and deterministic task classification
  • repository — full name and ids
  • modelId — selected model
  • summary — assistant-facing completion text
  • changedPaths, diffStats — when a patch exists
  • patch — when requested with ?patch=1
  • events — OpenCode activity when requested with ?events=1
  • pullRequest — GitHub metadata when publish.mode was draft_pr

Poll GET /api/v1/coding-agent/runs/{id}?patch=1 until status is terminal.

GET /api/v1/openapi is the canonical machine contract for generated clients. The examples on this page are intentionally shorter than the schema.

Billing modes

ModeWho pays modelsWho pays sandbox
managedCritique credits (plan gates apply)Critique
openrouterYour OpenRouter accountCritique credits for orchestration only

Managed mode uses the same catalog as Builder and Remedy. See Billing & credits.

Runtime

  • Engine: OpenCode headless server inside an ephemeral E2B sandbox
  • Isolation: Repo clone at the requested ref; sandbox stays alive between turns while idle, then until expiry or endSession
  • Output: No automatic push unless publish.mode is draft_pr and GitHub permissions allow it

This API is not the same as BYOA review-run queueing (Cursor / Claude / Codex on a completed PR review). Use BYOA when you want Critique to hand off a fix blueprint from a review; use the Coding Agent API when you want a general coding task on a repo.

For judging whether an agent’s PR should merge (verdict + structured findings), use the Merge Gate API instead.