Skip to content

API reference

A tiny REST API. Your agent asks a human before it acts, and you get back a signed, tamper-proof record of the decision.

Base URL: https://api.approv.dev (replace with your Supabase functions URL).

Quickstart

Create an approval. Approv messages your approver on WhatsApp or SMS and returns immediately with an id.

bash
curl -X POST https://api.approv.dev/ \
  -H "Authorization: Bearer $APPROV_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "approver_id": "apr_...",
    "action": "Refund $4,200 to customer #8831",
    "amount": 4200,
    "currency": "USD"
  }'

Authentication

Send your project API key as a Bearer token on every request. Create and rotate keys in Settings. Keep the key server-side — never ship it in a browser or app bundle.

http
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx

Create an approval

POST/

Returns 202 with an id while delivery happens in the background.

FieldTypeNotes
approver_idstringRequired. Who approves.
actionstringRequired. Human-readable description.
amountnumberOptional. Money at stake.
currencystringOptional. ISO 4217, e.g. USD.
contextobjectOptional. Extra data shown/stored.
callback_urlstringOptional. Webhook on decision.
timeout_secondsnumberOptional. Auto-expire window.
json
{
  "id": "req_9f2a…",
  "status": "pending",
  "expires_at": "2026-07-14T12:30:00Z",
  "replayed": false
}

Get status

GET/:id

Poll for the decision. decision is null until the approver replies.

json
{
  "id": "req_9f2a…",
  "status": "decided",
  "action": "Refund $4,200 to customer #8831",
  "amount": 4200,
  "currency": "USD",
  "decision": {
    "outcome": "approved",
    "decided_via": "whatsapp",
    "decided_by": "+1415…",
    "decided_at": "2026-07-14T12:04:11Z"
  }
}

Get audit trail

GET/:id/audit

Every state change is hash-chained and signed with Ed25519. The response includes the public key and the exact formula so anyone can verify it independently — you don't have to trust us.

json
{
  "verification": { "valid": true, "event_count": 4, "issues": [] },
  "algorithm": {
    "hash": "sha256",
    "signature": "ed25519",
    "hash_formula": "sha256( prev_hash | event_type | canonical_json(payload) | created_at )"
  },
  "public_key": { "key_id": "k1", "format": "spki-der-base64", "key": "MCowBQ…" },
  "events": [ { "seq": 1, "event_type": "created", "hash": "…", "signature": "…" } ]
}

Webhooks

Pass a callback_url when creating an approval. On decision, Approv sends a signed POST so your agent can continue automatically — no polling required.

json
POST <your callback_url>
{
  "id": "req_9f2a…",
  "outcome": "approved",
  "decided_via": "sms",
  "decided_at": "2026-07-14T12:04:11Z"
}

Errors

Errors return a JSON body with a stable code and a human message.

failed401 unauthorized · 400 validation · 404 not_found · 429 rate_limited
json
{ "error": { "code": "validation", "message": "Provide a name and a phone in E.164 format." } }