Authentication

Soren Pay uses workspace-scoped API keys prefixed apk_. Every authenticated request carries one in the Authorization: Bearer … header.

Header format

curl https://api.sorenpay.com/api/treasury \
-H "authorization: Bearer apk_<your key>"

Token lifecycle

| Action | Where | |---|---| | Create | Dashboard → Developers → API keys → "Create key" | | Reveal | Once on creation. Store immediately. | | List | GET /api/auth/keys | | Rotate | Create a new key → switch traffic → revoke the old one | | Revoke | DELETE /api/auth/keys?id=… or dashboard |

One-time reveal

The full token is shown only at creation. If you lose it, you must create a new key and rotate.

Scopes

By default new keys have * (all scopes). For production we recommend scoping each key to its exact role.

| Scope | What it grants | |---|---| | read:treasury | View balances + ledger | | read:cards | List cards + lookup by id | | write:cards | Mint + freeze + terminate cards | | read:agents | List agents + view intent log | | write:agents | Register agents + submit intents | | read:checkout | View checkout sessions | | write:checkout | Create checkout sessions | | write:payments | Originate intl payments | | write:api_keys | Create/revoke other keys | | * | All of the above |

Rate limits

The default per-key limit is 100 requests / minute sliding window. Hit the ceiling and you'll get HTTP 429 with x-ratelimit-reset-ms telling you when to retry.

For higher limits, contact us — we have per-key overrides in the database.

Idempotency

All POST and PATCH endpoints accept an Idempotency-Key header. Use a UUIDv4:

curl -X POST https://api.sorenpay.com/api/cards \
-H "authorization: Bearer apk_<your key>" \
-H "idempotency-key: $(uuidgen)" \
-H "content-type: application/json" \
-d '{...}'

Replays within 24h return the cached response. Conflicting bodies on the same key return HTTP 422 idempotency_key_mismatch so you can detect bugs.

KYB gating

In live mode, money-movement routes (cards, intl payments, ramp) require the workspace's kyb_status === 'approved'. Sandbox skips this gate so you can build against the full API surface before keys arrive.

Webhook signing (inbound)

Every webhook we receive carries a provider-specific signature header. We verify HMAC-SHA256 over the raw body with a ±5min replay window. Dedup is enforced by a unique (provider, event_id) index on webhooks_inbound.

Webhook signing (outbound)

When you register an outbound endpoint we generate a signing secret. Each delivery carries Soren-Signature: t=<unix>,v1=<hmac> so you can verify on your side. See Notifications.