Getting started
Authentication
Every merchant API request is authenticated with your API key plus an HMAC-SHA256 signature. There is no JWT and no OAuth — just three headers.
Required headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Public key id for the calling key (ak_test_… or ak_live_…). The signing secret is NEVER sent. |
X-Timestamp | Yes | Request time as Unix seconds. Bound into the signature; must be within ±300s of server time. |
X-Signature | Yes | Lowercase hex HMAC-SHA256 of `${X-Timestamp}.${rawRequestBody}` using the signing secret. |
X-Request-ID | Optional | Optional correlation id, echoed into your API request logs for tracing. |
X-Idempotency-Key | Optional | Optional. Safe-retry key; a repeat with the same key replays the first response for 24h. |
X-External-Event-Id | Optional | REQUIRED for /v1/webhooks/* only — the unique merchant event id used to deduplicate webhooks. |
The signature
Compute X-Signature as the lowercase hex HMAC-SHA256 of `${X-Timestamp}.${rawRequestBody}` using your secret. Bodyless requests (e.g. GET) sign over an empty body — `${timestamp}.`. See the HMAC signing guide for code in Node.js, PHP, Python and cURL.
Timestamp expiry & replay protection
X-Timestamp is Unix seconds and must be within ±300s of server time, so keep your clock synced (NTP). The timestamp is bound into the signature, and each signature can be used only once inside that window — a resent identical request is rejected as a replay. Generate a fresh timestamp and signature for every request.
IP allowlist
A key can optionally restrict requests to specific source IPs. If an allowlist is configured, requests from other IPs are rejected; if it is empty, all IPs are allowed. Manage it on the API Keys page.
Rate limits
Each key has a per-minute and per-hour limit (defaults 600/min and 30000/hour, tunable per key). Exceeding either returns 429 Too Many Requests. There is no Retry-After header — back off and retry, and contact support to request higher limits.
Test keys vs live keys
Test keys (ak_test_) work as soon as you have an account. Live keys (ak_live_) require an approved merchant account. A disabled or revoked key is rejected with 401 (logged as INVALID_KEY in your API logs), so rotate keys by creating a new one before revoking the old.