API Authentication

How to authenticate with the SignedApproval API using API keys or internal service tokens.

Key Concepts

SignedApproval uses bearer token authentication. There are two types of tokens: API keys (for external callers) and internal service tokens (for trusted Floyd Media services). Public endpoints like verification require no authentication at all.

API Keys

API keys are the standard way for external callers to authenticate. They use the prefix sa_live_ and are passed in the Authorization header:

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

API keys have three scopes:

  • approval:create -- Create new approval requests.
  • approval:read -- Read approval status and details.
  • approval:verify -- Verify signed decisions (note: the public verify endpoint requires no auth).

Create API keys in your dashboard at Settings → API Keys. Keys are shown only once at creation time -- store them securely in a secrets manager or environment variable.

Internal Service Token

Internal service tokens are used by trusted Floyd Media services (like Clevername/CleverAgent) to create approval requests on behalf of specific approvers. They use the format:

bash
curl -X POST https://signedapproval.net/api/v1/approvals/request \
  -H "Authorization: Bearer internal-your_service_token_here" \
  -H "X-Approver-Email: alex@sportsball.news" \
  -H "Content-Type: application/json" \
  -d '{"action": "Run browser automation task", "ttl_seconds": 300}'

Key differences from API keys:

  • Prefixed with internal- instead of sa_live_.
  • Requires the X-Approver-Email header to specify which approver should receive the request.
  • Only available to services with the INTERNAL_SERVICE_TOKEN environment variable.
  • Not available through the dashboard -- these are server-to-server credentials.

Public Endpoints (No Auth Required)

These endpoints require no authentication:

  • GET /api/v1/approvals/:id/verify -- Verify a signed decision.
  • POST /api/v1/bootstrap -- Start the bootstrap flow (requires an existing account).
  • GET /api/v1/bootstrap/:id/status -- Check bootstrap status.

Rate Limiting

API requests are rate-limited using Upstash Redis. Current limits:

  • Approval creation -- 60 requests per minute per API key.
  • Status checks -- 120 requests per minute per API key.
  • Verification -- 300 requests per minute per IP address.
  • Bootstrap -- 5 requests per hour per email address.

Rate limit headers are included in responses:

text
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1709000060
Important
API keys are hashed with API_KEY_HASH_SECRET before being stored. SignedApproval never stores API keys in plaintext. If you lose your key, you must create a new one.
Tip
For automated agents, use the bootstrap flow to let the agent self-provision its own API key with user consent, rather than manually creating keys and embedding them in configuration.