Authentication

Every server-side request must send a secret API key in the Authorization header or the X-Merchant-API-Key header. Keys come in pairs: a public key (pk_live_*) and a secret key (sk_live_*). Only the secret is sent; the public key is an internal label.

Creating a key

Open the cabinet at /cabinet/merchant/api-keys, give it a label, choose scopes, and (optionally) lock it to a CIDR allowlist. The secret is shown exactly once on creation. Store it in your server secret manager. We cannot recover it.

Scopes

Every endpoint declares the scope it needs. Issue narrow keys per integration role.

ScopeWhat it unlocks
invoices.writePOST /invoices, cancel
invoices.readGET /invoices, /invoices/:id
payouts.writePOST /payouts
payouts.readGET payouts
refunds.writePOST /refunds
refunds.readGET refunds
balance.readGET /balance, /balance/ledger
webhooks.writeManage webhooks (cabinet only)

Header forms

http
Authorization: Bearer sk_live_abcdef...
# or
X-Merchant-API-Key: sk_live_abcdef...

Idempotency

Every POST / PUT that creates or mutates state requires the Idempotency-Key header. Send a UUIDv4 per logical operation. Retrying with the same key returns the same response without doing the work twice.

Rate limits

Per-key. Default 60 requests / minute. Configurable up to 6000 via the cabinet. Exceeded requests get 429 with a Retry-After header.

IP allowlist

Per-key. Comma-separated CIDRs (e.g. 10.0.0.0/8) or single IPs. Empty = no restriction. Production servers should always pin to a known IP — a leaked secret then cannot be used from an attacker's network.

Brute-force lockout

5 consecutive bad-secret attempts on the same public key lock that key for 1 hour. The lockout is per-key, not per-source.