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
/v1/requestsCreates a PENDING approval request, emails the approver a magic link, and fires request.created to your webhooks.
Body
| Field | Type | Description |
|---|---|---|
| summaryrequired | string | Human-readable description of the action, ≤500 chars. This is what the approver reads first — write it like a headline. |
| payload | json | The exact action the agent wants to take. Shown — and editable — in the review UI. |
| notifyrequired | string (email) | The approver's email address. |
| agentName | string | Shown to the approver ("SupportBot requires approval"). ≤100 chars. |
| metadata | json | Opaque to us; echoed back in reads and webhooks. Use it for run IDs and trace correlation. |
| ttlMinutes | integer | Minutes until the request expires. 5–10080. Default 1440 (24h). |
Example
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
}'{
"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
| Status | Code | When |
|---|---|---|
| 400 | invalid_json / validation_error | Malformed body or failed field validation; the message names the field. |
| 401 | unauthorized | Missing, malformed, invalid, or revoked API key. |
| 402 | quota_exceeded | Hobby monthly cap reached. Upgrade or wait for the month to roll over. |
Retrieve a request
/v1/requests/:idReturns 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.
curl https://confirm.dev/api/v1/requests/clx2h8… \
-H "Authorization: Bearer $CONFIRM_API_KEY"RULE
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.