Partner API

Realtime and webhooks

Account-scoped invalidations, resumable events and signed server delivery.

Cursor reads

GET /v1/accounts/{externalUserId}/updates?cursor=0&limit=100 requires orders:read and a ready account. It returns events, compatibility alias updates, next cursor, and hasMore. Limit 1–200. Persist cursor only after processing. Deduplicate immutable event id; delivery is at least once.

Envelope fields: id, cursor (opaque decimal string), version: 1, type, externalUserId, accountId, occurredAt, data. Supported event types: account.status_changed, order.updated, trade.recorded, balance.updated, funding.updated, withdrawal.updated, position.redeemed, settlement.updated, reconciliation.completed. Cursors can have gaps. Cursor order is delivery order; timestamps may be earlier when late upstream events reconcile.

Events are sanitized, not raw venue frames. Re-read the applicable resource for authoritative state. Confirm retention during onboarding; after a retention gap, refresh account resources instead of assuming no missed activity.

Browser realtime

Register exact frontend origins with CRISP. Your backend authenticates its user and calls POST /v1/accounts/{externalUserId}/realtime-session with realtime:session. Forward the returned short-lived session, not HMAC credentials.

// session is the data.session returned by your own authenticated backend.
const socket = new WebSocket(session.endpoint, [session.protocol, session.token]);
socket.addEventListener('open', () => {
  socket.send(JSON.stringify({ type: 'resume', after: lastProcessedCursor || '0' }));
});
socket.addEventListener('message', ({ data }) => {
  const message = JSON.parse(data);
  // event: invalidate/re-read through your backend, then persist cursor.
  // resync_required: full refresh, save supplied cursor and resume.
});

Notices contain event ID/cursor/type/time, not balances you can sum. Refresh via your BFF, coalesce bursts and reconnect with backoff. Renew expiring sessions through your authenticated backend. The browser cannot choose another tenant or account topic. A realtime failure must not cause another order submission.

Signed server webhooks

CRISP configures approved HTTPS endpoint/secret. These are optional for backend automation; not required to build the normal browser UI. Headers:

X-Crisp-Event-Id: immutable event UUID
X-Crisp-Event-Cursor: event cursor
X-Crisp-Webhook-Timestamp: UTC timestamp
X-Crisp-Webhook-Signature: v1,{base64 HMAC-SHA-256}

Signature input is timestamp + "." + exact_raw_body. It is different from request signing. Verify bounded timestamp skew, compute HMAC with webhook secret, compare equal-length digests in constant time, validate event/header identity, then durably deduplicate before applying side effects. Preserve raw bytes before JSON middleware. Return 2xx only after durable acceptance; acknowledge duplicates with 2xx. CRISP follows no redirects and retries failed delivery with bounded backoff before dead-letter handling. Agree replay/support procedures at onboarding.

Do not forward raw events containing user IDs to unauthenticated browsers or log webhook secrets. Treat external strings as data when rendering UI.

CRISP Partner Developer Documentation