Authentication and safe retries
Exact HMAC signing, replay protection and financial intent handling.
Sign exact bytes
Using the SDK? It generates these headers automatically. You still own user authorization, credential storage, intent persistence and response handling. Manual signing below is for direct HTTP integrations; it is not an extra setup step required by the SDK.
All integration routes in the catalogue require these headers:
X-Crisp-Partner-Key: cpk_…
X-Crisp-Timestamp: ISO-8601 UTC timestamp
X-Crisp-Nonce: unique nonce, 16–128 characters
X-Crisp-Signature: base64 HMAC-SHA-256Canonical input (newline separators, no final newline):
timestamp
nonce
UPPERCASE_METHOD
/v1/exact-percent-encoded-path
sha256_hex(raw_body_bytes)The path includes /v1 and excludes the query string under the current
contract. Sign the encoded path actually sent; do not decode and rebuild it.
An empty body has the SHA-256 of zero bytes. Serialize JSON once, sign those
bytes, and send the same bytes. HTTPS is mandatory; signatures do not replace TLS.
The downloadable client implements this format.
Nonce characters: letters, digits, ., _, ~, -; length 16–128. Default
timestamp tolerance is five minutes. Nonces are single-use, including GETs.
Traffic ingestion is the designated exception: durable deduplication by organization and event ID
is used instead of persisting another nonce row. Always generate a fresh nonce.
Idempotency is not authentication
Financial and other durable mutations marked Required in the catalogue need
Idempotency-Key: 8–200 letters/digits or ., _, :, -.
- Persist one intent key before the first submit. Use it for retries of that same path, user and byte-identical body; never recycle it for another intent.
- Generate new authentication timestamp/nonce/signature for every attempt.
- A double-click, timeout or 502 does not mean the original action failed.
- Do not automatically generate a new key to get around an in-progress or ambiguous response. Correct the cause or reconcile the existing action.
- Quotes, prewarm, realtime sessions and capability minting are not durable
money movements and do not require that header. Page views use
eventId.
Idempotency responses have retention; do not assume a key is permanent history. Keep your own durable action records. Contact CRISP before retrying an old uncertain financial request whose lifecycle cannot be established.
Responses
{ "data": { "status": "ready" }, "requestId": "request-uuid" }{ "error": { "code": "account_not_ready", "message": "…", "requestId": "request-uuid" } }| Status | Handling |
|---|---|
| 200 | Successful read/action; inspect resource state |
| 202 | Durable acceptance; NOT proof of execution, settlement or final transfer |
| 400 | Correct invalid fields; do not blindly retry |
| 401 | Check key, canonical bytes, clock and nonce |
| 403 | Scope/authority denied; do not retry with another user's identity |
| 404 | Check account/resource and organization identified by your API key |
| 409 | Inspect code: in-progress, not-ready, reused nonce, conflict or ambiguous outcome are different cases |
| 429 | Honor Retry-After; retry with a fresh signature/nonce and the same intent key/body |
| 502/503 or timeout | Back off reads; preserve original financial intent and reconcile before replacement |
The example client surfaces errors/statuses and never auto-retries. Log safe request IDs, your intent ID and timestamps, not credentials or entire user payloads.
API limits and overload
Limits are shared across all API keys for your organization’s CRISP integration. The order-cell endpoint uses the same order budget as ordinary order submission. Cancellation capacity is separate from order submission; exhausting an order budget does not consume the cancellation budget.
Default sustained rates are 60 orders/second, 60 cancellations/second, 240 reads/second, 10 reporting requests/second, 10 account provisioning requests/second, 30 other writes/second, 200 traffic events/second and 60 account-update requests/second per organization. These are token-bucket rates with bounded bursts, not a guarantee that every request in a one-second interval will be admitted. Concurrency limits also apply. Confirm your production allocation with CRISP before a load test or traffic increase.
partner_rate_limited and partner_concurrency_limit return 429.
Capacity/store/restart errors may return 503, including
partner_admission_unavailable, partner_admission_capacity,
partner_concurrency_limit, partner_ingress_unavailable and
partner_api_draining. These admission responses include Retry-After.
An admission rejection concerns this attempt, not every earlier attempt
with the same key. Wait before retrying, retain the original Idempotency-Key
and exact body, and generate a new timestamp, nonce and signature. A previous
attempt may already be accepted. Never create a replacement financial intent
solely because an HTTP request timed out or returned an arbitrary 5xx.