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

text
POST https://signedapproval.net/api/v1/approvals/request
Authorization: Bearer sa_live_...
Content-Type: application/json

Request Body

JSON
{
  "action": "Deploy v2.1.0 to production",
  "ttl_seconds": 3600,
  "metadata": {
    "environment": "production",
    "version": "2.1.0",
    "commit": "abc123"
  },
  "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).
  • metadata (optional, object) -- Arbitrary key-value data attached to the request. Shown to the approver for context. Maximum 4 KB when serialized.
  • 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):

JSON
{
  "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:

JSON
// 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:

bash
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:

bash
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,
    "metadata": {
      "amount": 2500,
      "currency": "USD",
      "vendor": "Acme Corp",
      "invoice": "INV-2026-0042"
    },
    "callback_url": "https://api.example.com/webhooks/approval"
  }'

Using internal service token with approver routing:

bash
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 metadata field to pass structured context that helps the approver. For example, include the commit SHA, environment name, dollar amount, or any other relevant details. Metadata is shown in the dashboard alongside the action text.