Your First Approval

End-to-end walkthrough: create an API key, send an approval request, approve it on your phone, and verify the signed decision.

Note
This tutorial assumes you've already created your account and registered at least one authentication method (passkey or TOTP). If not, start with Creating Your Account.
Step-by-Step Guide
1

Create an API key

Go to signedapproval.net/dashboard/api-keys (or navigate to Integrations → API Keys from the dashboard). Click Create Keyand give it a name like "Test Key".

Your API key will be displayed once — copy it and store it securely. Keys use the format sa_live_....

Important
Your API key is shown only once at creation time. If you lose it, you'll need to create a new one. Store it in a secrets manager, environment variable, or password manager.
2

Send an approval request

Use curl (or any HTTP client) to create an approval request:

bash
curl -X POST https://signedapproval.net/api/v1/approvals/request \
  -H "Authorization: Bearer sa_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "Deploy v2.1.0 to production",
    "ttl_seconds": 3600,
    "metadata": {
      "environment": "production",
      "version": "2.1.0"
    }
  }'

You'll get back a response with the request ID and status:

JSON
{
  "id": "req_abc123...",
  "status": "pending",
  "action": "Deploy v2.1.0 to production",
  "created_at": "2026-03-23T14:00:00.000Z",
  "expires_at": "2026-03-23T15:00:00.000Z"
}
3

Approve the request

The request appears in two places:

  • Web dashboard — Log in at signedapproval.net/dashboard to see pending requests.
  • iOS app — If you've installed the app and enabled push notifications, you'll receive an alert.

Tap or click the request to review the action details, then authenticate with your registered method (passkey, TOTP, or Face ID) and choose Approve or Reject.

4

Check the status

Poll for the decision status:

bash
curl https://signedapproval.net/api/v1/approvals/req_abc123 \
  -H "Authorization: Bearer sa_live_your_key_here"

Once approved, the response includes the signed decision:

JSON
{
  "id": "req_abc123...",
  "status": "approved",
  "decision": {
    "id": "dec_xyz789...",
    "decision": "approved",
    "method": "passkey",
    "signed_payload": "eyJ2IjoxLCJyaWQiOi...",
    "signature": "base64-ed25519-signature...",
    "decided_at": "2026-03-23T14:02:30.000Z"
  }
}
5

Verify the signature

Anyone can verify the signed decision — no authentication required:

bash
curl https://signedapproval.net/api/v1/approvals/req_abc123/verify

The response confirms whether the signature is valid:

JSON
{
  "valid": true,
  "decision": "approved",
  "method": "passkey",
  "verified_at": "2026-03-23T14:03:00.000Z",
  "public_key": "base64-ed25519-public-key...",
  "signature": "base64-ed25519-signature...",
  "payload": { ... }
}

What Happens Under the Hood

When you approve a request, SignedApproval:

  1. Verifies your authentication (passkey challenge, TOTP code, or biometric).
  2. Constructs a canonical JSON payload with the request ID, decision, method, timestamp, expiry, and a random nonce.
  3. Signs the payload with your Ed25519 private key (decrypted from AES-256-GCM encrypted storage).
  4. Stores the signed decision in the database.
  5. Fires a webhook to the caller (if configured) with the signed payload.

The signature is mathematically bound to the exact payload. Any tampering — changing the decision, timestamp, or any other field — makes the signature invalid.

Tip
You can also use the bootstrap flow to let AI agents self-provision their own API keys. See Bootstrap Flow for details.