Pre-launch checklist
Authentication & secrets
Authentication & secrets
- JWT private key stored in a secrets manager (1Password, AWS Secrets Manager, HashiCorp Vault), never in source control, never in long-lived env vars on a developer laptop
- Sandbox API keys carry a
sandbox_prefix (Live API keys are unprefixed); the environment is selected entirely by which key you use - Sandbox key swapped for the unprefixed Live key
- Key rotation policy documented (minimum quarterly)
- JWT minting helper centralised in one module; not duplicated across services. See Authentication.
IP allowlisting
IP allowlisting
- Live API key’s IP allowlist configured to your egress IP(s) - Egress IPs
documented (find with
curl https://api.ipify.orgfrom each environment that hits OpenFX) - Allowlist includes failover regions if applicable - OnAUTH_FORBIDDEN_IP, you alert (don’t silently retry; it’s a config bug, not a transient)
Idempotency & retries
Idempotency & retries
Idempotency-Keygenerated once per logical operation, persisted to your DB before sending the request - Retry path handles409 IDEMPOTENCY_IN_FLIGHTby backing off and re-sending the same key - 5xx on writes triggers a state check (GET the resource by ID) before retrying; seeTRADE_EXECUTION_FAILEDrule - Crash-recovery worker scans forPENDINGrows and replays them using the stored idempotency key; see Idempotency → Crash recovery
Observability
Observability
- Every request logs the response
X-Trace-Idalongside your internal request ID; see Metadata & tracing - Trace ID captured on the success path too, not just errors
RateLimit-LimitandRateLimit-Resetrecorded for capacity planning; 429 rate andRetry-Aftervalues tracked- Alerts on error-rate spikes (especially 5xx, 429, and
*_NOT_FOUNDclusters) - Dashboards group errors by
error.code(noterror.message; message text can change)
- Required Alert when 5xx rate > 0.5% sustained for 5 min — covers upstream and idempotency-store outages
- Required Alert when
AUTH_TOKEN_*error rate > 1% sustained for 2 min — almost always means the JWT minting flow is broken (bad key, wrong claims, clock drift) - Recommended Alert when
IDEMPOTENCY_IN_FLIGHTresponses are sustained — indicates upstream slowness; your write latency is elevated even when calls ultimately succeed - Recommended Alert when webhook handler queue lag > 30s if you’re using a worker queue — OpenFX retries within the dedup window (see Webhooks setup), so a slow handler multiplies your processing cost
AUTH_TOKEN_EXPIRED — if 401s spike right after a deploy or host migration, check the clock before anything else.Error handling coverage
Error handling coverage
- Catch-and-branch covers at minimum:
QUOTE_EXPIRED,QUOTE_ALREADY_CONSUMED,TRADE_INSUFFICIENT_BALANCE,WITHDRAWAL_INSUFFICIENT_BALANCE,IDEMPOTENCY_IN_FLIGHT,RATE_LIMIT_EXCEEDED,TRADE_EXECUTION_FAILED,WITHDRAWAL_INITIATION_FAILED,INTERNAL_ERROR- Unknown error codes bubble to a generic handler that logs and alerts; don’t silently retry - User-facing error messages translateerror.codeto localised prose; don’t surface raw codes to end users - 5xx on writes never gets a fresh idempotency key on retry (that risks executing the operation twice)
Sandbox parity
Sandbox parity
- End-to-end happy path runs nightly against Sandbox
- Error paths tested in Sandbox: insufficient balance, expired quote, idempotency mismatch, missing key
- Webhook handlers verified against the
X-OpenFX-Signature(HMAC-SHA256) signing contract; webhooks share the API’s convention — camelCase keys and string amounts — so one deserializer can cover both webhook payloads and API responses — see Webhook authentication - Sandbox data is treated as ephemeral; no test workflows depend on records persisting across resets
Sandbox → Live cutover
Key rotation
Use an overlap pattern, never a flip. The procedure: A quarterly cadence is the baseline; rotate immediately on any suspected compromise.Rate-limit headroom planning
The ceiling is 300 requests / 10-second window on Live (600 on Sandbox, 2× Live), shared across all endpoints for the org. To estimate headroom:- Track your own request rate per org against the
RateLimit-Limitceiling on a 1-minute rolling window - Set a soft alert when sustained throughput exceeds ~66% of
RateLimit-Limit; that’s the cue to either batch requests, raise largerlimit=values on list endpoints, or talk to OpenFX about a tier change - The back-off helper pattern lives in Rate limiting: Handling rate limits; pace well under
RateLimit-Limitand you should rarely see a 429 in Live - Need a higher ceiling? See Rate limiting → Need a higher rate limit? for what to send support to get a tier change
Support escalation
When something goes wrong in Live, the fastest path to a resolved ticket is:- Trace ID first. Every support email opens with the
X-Trace-Idfrom a failing request. Without it, triage starts with “send us your logs,” which adds hours. - Email: [email protected]
- For webhook signing issues: include the raw
x-openfx-signatureheader value alongside the trace ID - For idempotency collisions (
422 IDEMPOTENCY_MISMATCH): include both the key and the two distinct request bodies that hit it