> ## Documentation Index
> Fetch the complete documentation index at: https://public-openfx.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Live checklist

> Pre-launch checklist, key rotation, IP allowlisting, monitoring, and ongoing operations guidance.

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

<AccordionGroup>
  <Accordion title="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-Mode` header switched from <span class="ofx-enum">SANDBOX</span> to <span class="ofx-enum">LIVE</span> 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](/v3/authentication).
  </Accordion>

  <Accordion title="IP allowlisting">
    * 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 <span class="ofx-enum">AUTH\_FORBIDDEN\_IP</span>, you alert (don't silently retry; it's a config bug, not a transient)
  </Accordion>

  <Accordion title="Idempotency & retries">
    * `Idempotency-Key` generated **once per logical operation**, persisted to your DB **before** sending the request
    * Retry path handles `409` <span class="ofx-enum">IDEMPOTENCY\_IN\_FLIGHT</span> by backing off and re-sending the same key
    * 5xx on writes triggers a **state check** (GET the resource by ID) before retrying; see [<span class="ofx-enum">TRADE\_EXECUTION\_FAILED</span> rule](/v3/errors#retrying-trade-execution-failed)
    * Crash-recovery worker scans for <span class="ofx-enum">PENDING</span> rows and replays them using the stored idempotency key; see [Idempotency → Crash recovery](/v3/idempotency#crash-recovery)
  </Accordion>

  <Accordion title="Observability">
    * Every request logs the response `X-Trace-Id` alongside your internal request ID; see [Metadata & tracing](/v3/metadata-and-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:**

    * <Badge color="red">Required</Badge> Alert when **5xx rate > 0.5%** sustained for 5 min: covers upstream and idempotency-store outages
    * <Badge color="red">Required</Badge> 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)
    * <Badge color="blue">Recommended</Badge> Alert when **<span class="ofx-enum">IDEMPOTENCY\_IN\_FLIGHT</span> responses** are sustained: indicates upstream slowness; your write latency is elevated even when calls ultimately succeed
    * <Badge color="blue">Recommended</Badge> Alert when **webhook handler queue lag > 30s** if you're using a worker queue: OpenFX retries within the dedup window (see [Webhooks setup](/v3/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 <span class="ofx-enum">AUTH\_TOKEN\_EXPIRED</span>. If 401s spike right after a deploy or host migration, check the clock before anything else.
  </Accordion>

  <Accordion title="Error handling coverage">
    * Catch-and-branch covers at minimum: <span class="ofx-enum">QUOTE\_EXPIRED</span>, <span class="ofx-enum">QUOTE\_ALREADY\_CONSUMED</span>, <span class="ofx-enum">TRADE\_INSUFFICIENT\_BALANCE</span>, <span class="ofx-enum">WITHDRAWAL\_INSUFFICIENT\_BALANCE</span>, <span class="ofx-enum">IDEMPOTENCY\_IN\_FLIGHT</span>, <span class="ofx-enum">RATE\_LIMIT\_EXCEEDED</span>, <span class="ofx-enum">TRADE\_EXECUTION\_FAILED</span>, <span class="ofx-enum">WITHDRAWAL\_INITIATION\_FAILED</span>, <span class="ofx-enum">INTERNAL\_ERROR</span>
    * Unknown error codes bubble to a generic handler that logs and alerts; don't silently retry
    * User-facing error messages translate `error.code` to 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)
  </Accordion>

  <Accordion title="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](/v3/webhooks/authentication)
    * Sandbox data is treated as ephemeral; no test workflows depend on records persisting across resets
  </Accordion>
</AccordionGroup>

## 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-Limit` ceiling 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 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](/v3/rate-limiting#handling-rate-limits-pattern); 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?](/v3/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:** [support@mail.openfx.com](mailto:support@mail.openfx.com)
* **For webhook signing issues:** include the raw `x-openfx-signature` header value alongside the trace ID
* **For idempotency collisions (`422` <span class="ofx-enum">IDEMPOTENCY\_MISMATCH</span>):** 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.
