Create Approval Request
POST /api/v1/approvals/request -- submit an action for human approval and receive a request ID to track the decision.
Key Concepts
The create request endpoint is the entry point for the approval flow. Your application describes the action that needs human approval, specifies a time-to-live, and optionally includes metadata and a callback URL. The response includes a request ID that you use to poll for the decision.
Endpoint
POST https://signedapproval.net/api/v1/approvals/request
Authorization: Bearer sa_live_...
Content-Type: application/jsonRequest Body
{
"action": "Deploy v2.1.0 to production",
"ttl_seconds": 3600,
"context": {
"environment": "production",
"version": "2.1.0",
"commit": "abc123"
},
"requires_individual_decision": true,
"callback_url": "https://your-app.com/webhook/approval"
}Field descriptions:
- action (required, string) -- Human-readable description of the action needing approval. This is shown to the approver in the dashboard and push notification. Maximum 500 characters.
- ttl_seconds (optional, integer) -- How long the request stays pending before expiring. If omitted, the approver's default TTL is used. Must be between 60 and 604800 (1 minute to 7 days).
- context (optional, object) -- Structured key-value data attached to the request and shown to the approver. Known keys get first-class rendering on every approver surface (iOS, watch, dashboard):
agent_name,agent_purpose,tool,reason,tool_arguments(a nested object -- “what the agent will do”; redact secrets before sending),risk_arg_findings(a list of{detector, severity, snippet}),tool_arguments_fingerprint(a short hash of the arguments, shown copyable), andsource. Unknown keys are still shown as plain rows. - requires_individual_decision (optional, boolean, default
false) -- The request must be decided on its own. It is shown to the approver as “needs individual review”, excluded from select-all, andPOST /api/v1/approvals/bulk-respondreturns it as{ "skipped": true, "reason": "requires_individual_decision" }instead of deciding it. Set it for irreversible or high-blast-radius actions (production promotes, payments, data deletion). Approvals created by the GitHub, GitLab and Bitbucket integrations are treated this way automatically. - callback_url (optional, string) -- URL to POST the decision to when the approver decides. Must be HTTPS in production. The callback is HMAC-signed with your per-API-key signing secret; retrieve it from
GET /api/v1/account/webhook-secret.
Response
Success (201 Created):
{
"id": "req_abc123def456",
"status": "pending",
"action": "Deploy v2.1.0 to production",
"metadata": {
"environment": "production",
"version": "2.1.0",
"commit": "abc123"
},
"created_at": "2026-03-23T14:00:00.000Z",
"expires_at": "2026-03-23T15:00:00.000Z"
}Error responses:
// 400 Bad Request -- missing required fields
{ "error": "action is required" }
// 401 Unauthorized -- invalid or missing API key
{ "error": "Invalid API key" }
// 429 Too Many Requests -- rate limited
{ "error": "Rate limit exceeded", "retry_after": 30 }Examples
Minimal request:
curl -X POST https://signedapproval.net/api/v1/approvals/request \
-H "Authorization: Bearer sa_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"action": "Run database migration"}'Full request with all options:
curl -X POST https://signedapproval.net/api/v1/approvals/request \
-H "Authorization: Bearer sa_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"action": "Transfer $2,500 to vendor Acme Corp",
"ttl_seconds": 300,
"context": {
"agent_name": "AP Clerk",
"agent_purpose": "Pays approved vendor invoices under $5,000",
"tool": "Create Transfer (Banking)",
"tool_arguments": { "amount": 2500, "currency": "USD", "vendor": "Acme Corp", "invoice": "INV-2026-0042" },
"tool_arguments_fingerprint": "9f2c4a7d1b3e8c05"
},
"requires_individual_decision": true,
"callback_url": "https://api.example.com/webhooks/approval"
}'Using internal service token with approver routing:
curl -X POST https://signedapproval.net/api/v1/approvals/request \
-H "Authorization: Bearer internal-your_service_token" \
-H "X-Approver-Email: approver@example.com" \
-H "Content-Type: application/json" \
-d '{"action": "CleverAgent: Navigate to bank portal and initiate wire", "ttl_seconds": 300}'Note
The
action text is hashed (SHA-256, first 16 chars) and included in the signed payload. Choose descriptive action text -- it helps the approver make an informed decision and creates a clear audit trail.Tip
Use the
context field to pass structured context that helps the approver. For example, include the commit SHA, environment name, dollar amount, or any other relevant details. Context is shown in the dashboard, the iOS app and on Apple Watch alongside the action text; the keys listed above (tool_arguments, risk_arg_findings, …) get dedicated sections. Set requires_individual_decision on anything that should never be swept into an “approve all”.Related Articles