# Test mode

> ody_test_ keys work against your real workspace data while sends, purchases, AI calls, publishing and 10DLC filings are simulated.

Source: https://dev.ody.co/get-started/test-mode

A test key (`ody_test_…`) behaves exactly like a live key — same base URL, endpoints, scopes, rate limits and errors — except that anything that would **spend money or reach the outside world is simulated**. Use test keys for local development, CI, demos, and while connecting an AI assistant for the first time.

> **Test keys use real data:**
There is no separate sandbox workspace. Reads are real, and so are contact writes, conversation status changes and agent **draft** saves. What's simulated is the spending and the outside world.

## What is real and what is simulated

| Action | With an `ody_test_…` key |
|---|---|
| Reading contacts, conversations, calls, numbers, agent | Real data |
| Creating, updating, deleting contacts | **Real** — changes your workspace |
| `PATCH /conversations/:id` | **Real** |
| `PATCH /agent` (draft saves) | **Real** |
| Webhook endpoint management | **Real** endpoints |
| `POST /messages` · MCP `send_message` | **Simulated** — recorded in the thread with `deliveryStatus: "simulated"`, never transmitted |
| `POST /numbers` · MCP `buy_number` | **Simulated** — nothing ordered, provisioned or charged |
| `POST /calls` · MCP `place_call` | **Simulated** — a `sim_…` call id, nothing dialed, no credits used |
| `POST /agent/publish` · `configure_agent` with `publish: true` | **Simulated** — the config stays a draft |
| `POST /messaging/registration` · MCP `submit_10dlc_registration` | **Mock mode** — the 10DLC pipeline runs, nothing reaches the registry, no fee, a trial isn't ended |

Every simulated response carries `"simulated": true`:

```json
{
  "message": { "id": "6a1e…", "type": "message", "direction": "outbound", "body": "CI smoke test", "deliveryStatus": "simulated" },
  "conversationId": "c0d3…",
  "simulated": true
}
```

## Create a test key

In **Settings → Developer API**, set **Key type** to **Test** before clicking **Create key**. Test keys show a **Test** badge and an `ody_test_…WXYZ` hint in the key list.

## Using test mode in CI

- Create one test key per pipeline (for example "GitHub Actions") and store it as a CI secret such as `ODY_API_KEY`. Your code doesn't change between environments — only the key does.
- Assert `simulated === true` on send responses, so a live key accidentally configured in CI fails loudly.
- Contact writes are real: point CI at a dedicated workspace, or delete the contacts your tests create.
