> ## Documentation Index
> Fetch the complete documentation index at: https://v2.docs.conduit.financial/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> API keys, environments, and request headers

## Environments

Conduit provides two environments. Both expose the same API and use the same authentication mechanism.

| Environment | Base URL                                   | Purpose                             |
| ----------- | ------------------------------------------ | ----------------------------------- |
| Sandbox     | `https://api.sandbox.conduit.financial/v2` | Integration development and testing |
| Production  | `https://api.conduit.financial/v2`         | Live operations                     |

Sandbox is available immediately after sign-up — generate a sandbox key and start integrating right away. Production access requires completing Conduit's organization onboarding and activation process; once your organization is activated, switch the dashboard toggle to live and generate live keys.

## API Keys

All requests require an API key passed in the `x-api-key` header.

```bash theme={null}
curl https://api.conduit.financial/v2/customers \
  -H "x-api-key: ck_live_<64-hex-chars>"
```

Keys are prefixed to indicate their environment:

| Prefix        | Environment | Example                  |
| ------------- | ----------- | ------------------------ |
| `ck_sandbox_` | Sandbox     | `ck_sandbox_aabbccdd...` |
| `ck_live_`    | Production  | `ck_live_aabbccdd...`    |

The prefix is validated on every request. A `ck_sandbox_` key presented to the production API (or vice versa) is rejected with `401 API_KEY_INVALID`. Keys are scoped to a single organization and environment. Generate and revoke keys from the Conduit dashboard.

### Access level

Each key is **read-only** or **read-write**:

| Access level | Allowed requests                                                                |
| ------------ | ------------------------------------------------------------------------------- |
| Read-only    | `GET` requests only. Any other method is rejected with `403 API_KEY_READ_ONLY`. |
| Read-write   | All requests, including those that move money (payouts, order execution).       |

You choose the access level when creating a key in the dashboard; new keys are **read-only** by default. A key's access level is fixed for its lifetime — to change it, revoke the key and create a new one. Use read-only keys for reporting and reconciliation integrations that never need to write.

<Warning>
  API keys are shown once at creation and hashed server-side (SHA-256). Conduit
  cannot recover a lost key — revoke it and create a new one. When rotating a
  key, create the new key first, update your integration, then revoke the old
  key.
</Warning>

## Request Headers

| Header                    | Required                                                                                                                         | Description                                                                |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `x-api-key`               | Yes                                                                                                                              | Your API key                                                               |
| `Content-Type`            | Yes (POST/PATCH)                                                                                                                 | `application/json` for JSON bodies, `multipart/form-data` for file uploads |
| `idempotency-key`         | Yes on money-moving POSTs (orders, payouts, sender-information, execute, and order/payout cancel). Optional on idempotent reads. | Prevents duplicate operations on POST requests. Cached for 5 minutes.      |
| `x-client-correlation-id` | No                                                                                                                               | Your trace ID. Echoed back in the response for request correlation.        |

Conduit also returns an `x-correlation-id` header on every response — a server-generated trace ID useful for support requests.

## Sandbox-specific behavior

Use your sandbox API key (`ck_sandbox_...`) against `https://api.sandbox.conduit.financial`. Sandbox and production keys are not interchangeable — a production key on the sandbox host returns `401 API_KEY_INVALID`.

**Idempotency cache:** The `idempotency-key` header is required on all money-moving `POST` requests. In both sandbox and production the cache TTL is **300 seconds (5 minutes)**. A replay of a successful request within that window returns the cached response, marked with an `Idempotency-Replayed: true` header; error responses are not cached, and a replay after expiry re-executes the request. Use `crypto.randomUUID()` (or `uuidgen` in bash) to generate a fresh key for each new operation.

**Rate limits.** Responses on rate-limited routes carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (seconds until the bucket refills). These headers are present on both successful responses and 429 errors; they are omitted only when the rate-limit service is temporarily unreachable and the request is allowed through anyway. When a request exceeds the limit you receive `429 RATE_LIMITED` with a `Retry-After` header and a `retryAfterSeconds` body field; sleep that many seconds then retry. Limits use a token bucket: live keys get 50 requests/second sustained with a burst of 100; sandbox is more permissive (200 req/s sustained, 400 burst). Per-organization overrides are available through your support contact when your sustained workload exceeds the defaults. A handful of expensive endpoints (order execute, document upload, application submit) carry tighter dedicated buckets (5 req/s, 10 burst on live).

**Cross-environment errors:** A `401 API_KEY_INVALID` against the sandbox base URL means you are using a live key, not a sandbox key. If your sandbox key is valid but your organization's sandbox environment has not been provisioned yet, you receive `409 SANDBOX_NOT_PROVISIONED` (not a `401`) — provisioning happens automatically after sign-up and is retried, so wait a few moments and retry; contact support if it persists. Do not rotate or regenerate the key for this case — the key is valid.

## Errors

| Status | Meaning                    | What to do                                                                                                                                                                                                                 |
| ------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Validation failed          | Check the `errors` array in the response body for field-level details                                                                                                                                                      |
| `401`  | Missing or invalid API key | Verify your `x-api-key` header                                                                                                                                                                                             |
| `403`  | Forbidden                  | A read-only key attempted a write (`API_KEY_READ_ONLY`); your key's organization cannot access the resource; or the request originated from an IP address not in the key's configured allowlist (`API_KEY_IP_NOT_ALLOWED`) |
| `404`  | Resource not found         | Check the resource ID and ensure it belongs to your organization                                                                                                                                                           |
| `409`  | Conflict                   | A resource with the same unique constraint already exists                                                                                                                                                                  |
| `429`  | Rate limited               | Slow down and retry after `Retry-After` seconds. See the Rate limits section above.                                                                                                                                        |
| `500`  | Internal error             | Retry with exponential backoff. If persistent, contact support with the `x-correlation-id` from the response                                                                                                               |
