> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs-v3.openfx.dev/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 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](/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
      `AUTH_FORBIDDEN_IP`, 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
        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](/v3/errors#retrying-trade-execution-failed) - Crash-recovery worker
      scans for `PENDING` 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 **`IDEMPOTENCY_IN_FLIGHT` 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 `AUTH_TOKEN_EXPIRED` — 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: `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)
  </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>

## 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](/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@openfx.com](mailto:support@openfx.com)
* **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

<CardGroup cols={2} />
