API reference

The API is deliberately small: one endpoint to pause an agent, one to check the verdict. Base URL https://confirm.dev/api, JSON in and out.

Authentication

Pass your API key as a bearer token. Keys are created in Dashboard → API Keys and scoped to one workspace.

Authorization: Bearer cfm_live_...

Errors share one envelope everywhere: { "error": { "code": "...", "message": "..." } }.

Create a request

POST/v1/requests

Creates a PENDING approval request, emails the approver a magic link, and fires request.created to your webhooks.

Body

FieldTypeDescription
summaryrequiredstringHuman-readable description of the action, ≤500 chars. This is what the approver reads first — write it like a headline.
payloadjsonThe exact action the agent wants to take. Shown — and editable — in the review UI.
notifyrequiredstring (email)The approver's email address.
agentNamestringShown to the approver ("SupportBot requires approval"). ≤100 chars.
metadatajsonOpaque to us; echoed back in reads and webhooks. Use it for run IDs and trace correlation.
ttlMinutesintegerMinutes until the request expires. 5–10080. Default 1440 (24h).

Example

request
curl -X POST https://confirm.dev/api/v1/requests \
  -H "Authorization: Bearer $CONFIRM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "summary": "Send 50 outbound emails (batch q3-outbound)",
    "payload": { "batchId": "q3-outbound", "count": 50 },
    "notify": "sdr-lead@company.com",
    "agentName": "OutreachBot",
    "metadata": { "runId": "run_442" },
    "ttlMinutes": 120
  }'
response · 201
{
  "id": "clx2h8…",
  "object": "approval_request",
  "status": "PENDING",
  "summary": "Send 50 outbound emails (batch q3-outbound)",
  "payload": { "batchId": "q3-outbound", "count": 50 },
  "modifiedPayload": null,
  "effectivePayload": { "batchId": "q3-outbound", "count": 50 },
  "metadata": { "runId": "run_442" },
  "agentName": "OutreachBot",
  "approverEmail": "sdr-lead@company.com",
  "resolvedAt": null,
  "resolvedByEmail": null,
  "resolutionNote": null,
  "expiresAt": "2026-07-15T22:00:00.000Z",
  "createdAt": "2026-07-15T20:00:00.000Z"
}

Errors

StatusCodeWhen
400invalid_json / validation_errorMalformed body or failed field validation; the message names the field.
401unauthorizedMissing, malformed, invalid, or revoked API key.
402quota_exceededHobby monthly cap reached. Upgrade or wait for the month to roll over.

Retrieve a request

GET/v1/requests/:id

Returns the same shape as create, with current status. Expiry is applied lazily on read — you will never see a stale PENDING past its expiresAt. Requests belonging to other workspaces return 404.

request
curl https://confirm.dev/api/v1/requests/clx2h8… \
  -H "Authorization: Bearer $CONFIRM_API_KEY"
When status is APPROVED, execute effectivePayload — it already resolves the human-edit-wins precedence for you. payload is the historical record of what the agent originally wanted.

Webhook events

State changes push to your registered endpoints as signed POSTs — usually the better pattern than polling. Payload shape, headers, signature verification, and retry behavior are documented on the Webhooks page.