OdyOdy Help

Build safely with test mode

Updated Mon Aug 17 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

Test-mode API keys (ody_test_…) behave exactly like live keys except that anything that would spend money or reach the outside world is simulated — message sends, number purchases, outbound AI calls, agent publishing, and 10DLC registrations (which run in mock mode) — which makes them perfect for development and CI.

Before you start

  • You must be a workspace admin or owner to create keys.
  • Know what test mode does and doesn't isolate: a test key works against your real workspace data. Contact creates, updates, and deletes are real, conversation status changes are real, and agent draft saves (PATCH /v1/api/agent) are real. What's simulated is the spending: sends, number purchases, outbound AI calls, agent publishing, and 10DLC filings.

Step-by-step

  1. Click Settings in the sidebar, then Developer API.

  2. Fill in the create form as usual — name and scopes (see Get your Ody API key).

  3. Under Key type, select Test. The hint confirms it: test keys read real data but never send real texts — sends are recorded as simulated.

  4. Click Create key and copy the ody_test_… secret from the one-time banner.

  5. Use it exactly like a live key — same base URL, endpoints, scopes, and rate limits:

curl https://api.ody.co/v1/api/messages \
  -H "Authorization: Bearer ody_test_…" \
  -H "Content-Type: application/json" \
  -d '{"to":"+15125550123","body":"CI smoke test"}'

The response is a normal 201 with "simulated": true, and the message appears in the thread with deliveryStatus: "simulated".

What's identical, what's simulated

Behavior With an ody_test_… key
Reading contacts, conversations, calls, numbers Real data, identical to live
Creating/updating/deleting contacts Real — changes your workspace
Setting conversation status Real
POST /v1/api/messages / MCP send_message Simulated — recorded, never transmitted
POST /v1/api/numbers / MCP buy_number Simulated"simulated": true, nothing ordered, provisioned, or charged
POST /v1/api/calls / MCP place_call Simulated — a sim_… call id, nothing dialed, no credits used
POST /v1/api/agent/publish Simulated — your config stays a draft, nothing goes live
PATCH /v1/api/agent (draft saves) Real — same as live
POST /v1/api/messaging/registration Mock mode — the full 10DLC pipeline runs, but nothing is submitted to the registry and there's no fee
Scopes, rate limits, errors, pagination, idempotency Identical to live
Webhook endpoint management Real endpoints, same as live

In the key list, test keys show a Test badge and an ody_test_…WXYZ hint so you can't confuse them with live keys.

Using test mode in CI

  • Create a dedicated test key per pipeline (for example "GitHub Actions") so you can revoke it independently and the "last used" column stays meaningful.
  • Store it as a CI secret (e.g. ODY_API_KEY) — your code doesn't change between environments, only the key.
  • Assert on simulated: true in send responses to catch a live key accidentally configured in CI.
  • Remember that contact writes are real: point CI at a dedicated workspace, or clean up the contacts your tests create.

Related articles

Frequently asked questions

Do test keys use a separate sandbox workspace?

No — a test key reads and writes your real workspace data. Message sends, number purchases, outbound AI calls, agent publishing, and 10DLC filings are simulated; everything else behaves exactly like a live key.

How do I tell a simulated message apart?

The send response includes "simulated": true, and the recorded message carries deliveryStatus "simulated" instead of queued/sent/delivered.

Do test keys work with MCP?

Yes. Connect an AI assistant with an ody_test_ key and every tool works normally, but send_message records a simulated message instead of texting anyone.

More in Developer API