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

# Environments

> How test and live mode are carried on the API.

Caratuva has a single API host. There is no separate sandbox URL. Instead, every
request runs in **test** or **live** mode, and the mode is determined entirely by
the credential you present.

See the guide-side [Test & live modes](/environments) page for the conceptual
overview; this page covers the request-level details.

## Mode is carried by the key

API keys encode their mode in the prefix:

| Prefix      | Mode | Rails                                                           |
| ----------- | ---- | --------------------------------------------------------------- |
| `pk_test_…` | test | Sandbox payment instance — KYB/KYC auto-approve, no real money. |
| `pk_live_…` | live | Production payment instance — real rails, real settlement.      |

A test key can only ever read and write test data; a live key, only live data. You
don't pass a mode parameter and you can't override it with a header — the key is
the mode. Issue one key per mode (see [API keys](/api-reference/api-keys)).

The API-key resource reports its mode via the `testMode` boolean, derived from the
prefix:

```json theme={null}
{
  "keyPrefix": "pk_test_KEY_ID",
  "testMode": true
}
```

## Dashboard sessions switch; keys don't

Dashboard Bearer JWTs also carry a mode, and start in **test**. The dashboard
re-mints the token to switch:

```bash theme={null}
curl -X POST https://api.caratuva.com/v1/auth/switch-mode \
  -H "Authorization: Bearer <dashboard-jwt>" \
  -H "content-type: application/json" \
  -d '{ "mode": "live" }'
```

```json theme={null}
{ "token": "<new-jwt-bound-to-live>", "mode": "live" }
```

The new token is bound to the chosen mode; the dashboard stores it and uses it for
subsequent requests. Switching to live requires the organization's **Production
Access Request** to have been approved by Caratuva (a manual approval, distinct from
KYB); otherwise the call returns `400 ProductionAccessNotApproved`. Live KYB is
completed afterwards, on the Payout page, before the org can transact.

API-key callers **cannot** use this endpoint — they already carry their mode in
the key prefix. Calling it with an API key returns:

```json theme={null}
{
  "statusCode": 400,
  "error": "ModeSwitchNotAllowed",
  "message": "API-key callers select mode via their key prefix, not switch-mode."
}
```

## Data isolation

Test and live are separate datasets. The same scoping that isolates one
organization from another (see [Authentication → Tenancy](/api-reference/authentication#tenancy))
also isolates test from live within your organization:

* Invoices and payment intents are tagged with the mode they were created in;
  list and read endpoints only return the active mode's records.
* Buyers are scoped per mode — the same buyer email is a distinct record in test
  and in live, and KYC completed in one does not carry to the other.
* Webhook deliveries reflect only the mode of the invoice that generated them.

## Onboarding status

To check whether the caller's active mode is ready to transact:

```bash theme={null}
curl https://api.caratuva.com/v1/onboarding/status \
  -H "Authorization: Bearer <dashboard-jwt>"
```

```json theme={null}
{
  "mode": "live",
  "needsOnboarding": true,
  "tosAccepted": false,
  "kybStatus": null
}
```

* `mode` — the active mode of the credential.
* `needsOnboarding` — `true` until this mode's environment is activated. Test
  activates as soon as its sandbox KYB clears (auto-approved); live activates only
  on real KYB approval (after production access has been granted).
* `tosAccepted` — whether the payment-provider Terms have been accepted for this mode.
* `kybStatus` — the latest KYB submission status for this mode, or `null` if none
  has been started.

## Behavior parity

Test mode runs the same code path as live against a sandbox payment instance — the
same intent transitions, the same webhook event types, the same response shapes.
The only differences are that the sandbox auto-approves compliance and never moves
real funds. Build and test against `pk_test_`, then flip to `pk_live_` for
production.
