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 by which key you use - Sandbox key swapped for the unprefixed Live key
X-App-Modeheader switched from SANDBOX to LIVE alongside the key; the two must agree- Key rotation policy documented (minimum quarterly)
- JWT minting helper centralized 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
- On AUTH_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 handles
409IDEMPOTENCY_IN_FLIGHT by backing off and re-sending the same key - 5xx on writes triggers a state check (GET the resource by ID) before retrying; see TRADE_EXECUTION_FAILED rule
- Crash-recovery worker scans for PENDING rows 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_FLIGHT responses 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
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 translate
error.codeto localized 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
Key rotation
Rotate on a quarterly cadence at minimum, and immediately on any suspected compromise. Use an overlap pattern, never a flip: keep the old key valid while the new one goes live, then revoke the old one once every service has cut over.Rate-limit headroom planning
The ceiling is 300 requests / 10-second window, shared across all endpoints for the org, same in Sandbox and Live. To estimate headroom:- Track your own request rate per org against the
RateLimit-Limitceiling on a 10-second 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: support@mail.openfx.com
- For webhook signing issues: include the raw
x-openfx-signatureheader value alongside the trace ID - For idempotency collisions (
422IDEMPOTENCY_MISMATCH): include both the key and the two distinct request bodies that hit it