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.
Credentials
Section titled “Credentials”- 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 needsliquidation.GET /api/v1/discoveryreports the tier for the ~40 endpoints it catalogs, but no scopes and not the whole surface — it cannot confirm a credential carriesfirm:operate,prop:manage, ortenant: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.
Orders
Section titled “Orders”- 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/riskrather than polling. -
venueandsymbolcome fromGET /api/v1/venuesandGET /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.1does not survive a JSON double round-trip exactly. - You have handled
422— the venue rejected it — distinctly from400. They mean different things and usually need different retries.
Streams
Section titled “Streams”- You send
Subscribe { topics: [...] }afterAuthenticated./ws/riskpushes nothing until you do, andtopicsmust be non-empty. - You assert
seqcontiguity on/ws/riskand re-snapshot on a gap. Frames coalesce under load; a gap is normal, not exceptional. - You handle
Resync-Requiredby dropping local state, not by ignoring it. - Your heartbeat sends
Pingevery 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.
Money and reconciliation
Section titled “Money and reconciliation”- 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
venueOrderIdfor internalised rows; those ids are ours and resolve nowhere off-platform.
Webhooks, if you use them
Section titled “Webhooks, if you use them”- Your receiver verifies
x-webhook-signature— HMAC-SHA256 over the raw body bytes, hex-encoded andsha256=prefixed, compared in constant time — before parsing the body, and checksx-api-keyin addition, not instead. The signature is the provenance proof;x-api-keyis 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.
Prop firms
Section titled “Prop firms”- 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: trueanddeployer_configuredis green —readyaggregates only therequiredchecks and ignores that one, but a live broadcast without it returns503 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.
The last one
Section titled “The last one”- 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.