Skip to content

Go-live checklist

Every item here is something that has actually bitten an integration. Each one names the endpoint or frame that proves it, so this is a checklist you can execute rather than nod at.

  • The credential you ship with holds the narrowest tier that does the job. A reporting integration does not need fullTrading; a risk system that only flattens needs liquidation. GET /api/v1/discovery reports the tier for the ~40 endpoints it catalogs, but no scopes and not the whole surface — it cannot confirm a credential carries firm:operate, prop:manage, or tenant:config. Check the rest against the OpenAPI spec.
  • Your secret is not in the repository, the bundle, or a log line. It is shown once at issuance.
  • You have exercised rotation — issue a second credential, deploy it, revoke the first — at least once, before you need to do it under pressure.
  • A revoked token fails the way you expect: revoke one deliberately and watch your error path.
  • Every order write sends an Idempotency-Key. A network timeout on placement is indistinguishable from a rejection, and a retry without a key can double a position.
  • You track orders by intent id, and take the terminal state from /ws/risk rather than polling.
  • venue and symbol come from GET /api/v1/venues and GET /api/v1/symbols/{venue}, not from constants. Both change per deployment without an API version bump.
  • Sizes and prices are sent as decimal strings. 0.1 does not survive a JSON double round-trip exactly.
  • You have handled 422 — the venue rejected it — distinctly from 400. They mean different things and usually need different retries.
  • You send Subscribe { topics: [...] } after Authenticated. /ws/risk pushes nothing until you do, and topics must be non-empty.
  • You assert seq contiguity on /ws/risk and re-snapshot on a gap. Frames coalesce under load; a gap is normal, not exceptional.
  • You handle Resync-Required by dropping local state, not by ignoring it.
  • Your heartbeat sends Ping every 30s. The socket idles out after 60s of inbound silence.
  • You seed correctly: subscribe first, then fetch the REST snapshot, then apply buffered updates. The other order leaves a hole.
  • Reconnect mints a fresh bootstrap token, re-authenticates, re-Subscribes to its topics, and re-requests state rather than assuming the cached view survived. Topics live on the connection, so a new socket starts with an empty topic set and stays silent until it subscribes.
  • You compute volume from fills and P&L from trades. Mixing them is the most common reconciliation bug.
  • You know whether your accounts are routed or internalised, and you discriminate on the account, never on venue: "paper" — that sentinel covers both the sandbox and internalised real-money accounts. See the execution model.
  • You do not build exchange-side reconciliation on venueOrderId for internalised rows; those ids are ours and resolve nowhere off-platform.
  • Your receiver verifies x-webhook-signature — HMAC-SHA256 over the raw body bytes, hex-encoded and sha256= prefixed, compared in constant time — before parsing the body, and checks x-api-key in addition, not instead. The signature is the provenance proof; x-api-key is a static bearer that anyone who captures one delivery can replay. See Webhooks.
  • It deduplicates on eventId — delivery is at-least-once.
  • It returns 200 fast, then works. A slow receiver looks like a failing one and earns a retry.
  • You know a dead endpoint auto-disables after the retry budget (1s → 24h), and that re-enabling it is an operator action — so you have a way to notice, and someone to ask.
  • You have driven a challenge to a breach on the paper twin and watched the account go terminal and positions flatten.
  • You have driven one to a pass and confirmed no money moves at pass — only the payout ceiling is recorded.
  • You have worked a payout decision end to end.
  • Readiness reports ready: true and deployer_configured is green — ready aggregates only the required checks and ignores that one, but a live broadcast without it returns 503 deployer_unconfigured. Dry-run deploy before broadcasting; the dry run returns before the deployer key is ever checked, so it cannot catch this for you.
  • Do all of the above against a sandbox account first, then repeat the order path with the smallest possible real size before you scale it. The sandbox proves your code; a small live order proves your assumptions about fills.