Skip to main content
This page is the pre-launch sign-off checklist for moving an OpenFX integration from Sandbox to Live. It covers authentication and secrets, idempotency and retry behavior, observability, error-handling coverage, Sandbox parity, the cutover steps, key rotation, rate-limit headroom planning, and how to escalate to support.

Pre-launch checklist

  • 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.
  • Live API key’s IP allowlist configured to your egress IP(s) - Egress IPs documented (find with curl https://api.ipify.org from 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-Key generated once per logical operation, persisted to your DB before sending the request - Retry path handles 409 IDEMPOTENCY_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
  • Every request logs the response X-Trace-Id alongside your internal request ID; see Metadata & tracing
  • Trace ID captured on the success path too, not just errors
  • RateLimit-Limit and RateLimit-Reset recorded for capacity planning; 429 rate and Retry-After values tracked
  • Alerts on error-rate spikes (especially 5xx, 429, and *_NOT_FOUND clusters)
  • Dashboards group errors by error.code (not error.message; message text can change)
Suggested alert thresholds:
  • 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
Clock skew: sync your JWT-minting host’s clock via NTP. The v3 JWT TTL is 60s, so even a small drift can produce constant AUTH_TOKEN_EXPIRED — if 401s spike right after a deploy or host migration, check the clock before anything else.
  • 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.code to 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)
  • 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-Limit ceiling 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 larger limit= 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-Limit and 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-Id from 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-signature header value alongside the trace ID
  • For idempotency collisions (422 IDEMPOTENCY_MISMATCH): include both the key and the two distinct request bodies that hit it
If you’ve followed the observability checklist above, the trace ID is already in your logs next to the request that produced it; no spelunking required.

What’s next