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

HeaderRequiredDescription
X-API-KeyYesPublic key id for the calling key (ak_test_… or ak_live_…). The signing secret is NEVER sent.
X-TimestampYesRequest time as Unix seconds. Bound into the signature; must be within ±300s of server time.
X-SignatureYesLowercase hex HMAC-SHA256 of the signing string using the signing secret. v1 (default): `${X-Timestamp}.${rawRequestBody}`. v2: `${X-Timestamp}.${METHOD}.${path}.${rawRequestBody}`.
X-Signature-VersionOptionalOptional signing scheme selector: `v2` binds the HTTP method and request path (e.g. `/api/v1/conversions`) into the signature. Omit (or send `v1`) for the default scheme. Both schemes remain supported.
X-Request-IDOptionalOptional correlation id, echoed into your API request logs for tracing.
X-Idempotency-KeyOptionalOptional. Safe-retry key; a repeat with the same key replays the first response for 24h.
X-External-Event-IdOptionalREQUIRED for /v1/webhooks/* only — the unique merchant event id used to deduplicate webhooks.
Your signing secret is shown only once, at key creation. It is never sent in a request and never returned again — store it securely (e.g. a server-side secret manager).

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 with a Retry-After header (seconds to wait). Every response — success or 429 — also carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (unix seconds) for the tighter of the two windows, so you can self-throttle. 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.

See the full error reference for every authentication failure code and how to fix it.