How-to guide

Test mode

Build against the real API with a test key — every check runs, nothing reaches a carrier, and it costs nothing.

What you'll build

A test setup where simulated customers write to you and your code (or your agent) answers, through the real API, at no cost.

How test mode works

A test key (vl_test_…) runs the whole sending pipeline — validation, scopes, content checks, rate limits — except the two things that cost: the carrier and the charge. Messages leave through a simulated carrier instead of a real one.

Prerequisites

  • A test key: in the dashboard, Developers → API keys → Create key, "Your servers or the SDK", environment Testing. See Authentication and API keys.
  • Nothing else. You don't need a phone number or a connected account: without one, test mode uses your free test sender.
  • curl, Node.js 18 or later with @voicelayer/api, or Python 3.9 or later with voicelayer.

Reserved test addresses

Test keys talk only to these addresses, and only test keys may use them:

ChannelAddresses
SMS, MMS, WhatsApp+15550100 to +15550199
Telegram, Discordtest-1, test-2, … (test- and a number)
Emailany address at test.vlayers.ai

A test key that names any other address is refused with 422 test_address_required. A live key that names a test address is refused with 422 test_address_not_allowed.

Your free test sender

Every workspace gets a free test sender the first time it needs one. When you have no number, connected account or mailbox on a channel, POST /v1/test/inbound without to and a test key's POST /v1/messages without from use it. It never reaches a carrier and costs nothing.

  • It has no agent, so its conversations start with the controller api: your code answers them (see Conversations and handoff).
  • It works only in test mode: a live key never sends through it.
  • It has no reply window or registration of its own. To test your agent's replies, or a channel's real rules (WhatsApp's 24-hour window, for example), simulate the message on your real number or account by naming it in to.

Step 1: Simulate someone writing to you

POST /v1/test/inbound plays a person writing from a test address. It works with test keys only; a live key gets test_mode_only.

curl -X POST https://api.vlayers.ai/v1/test/inbound \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "from": "+15550123",
    "text": "Do you have a table for two tonight?"
  }'
Response · 202
{
  "conversationId": "0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21",
  "messageId": "0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32",
  "test": true
}

to is optional: left out, the message goes to your one sender on that channel, or to your free test sender if you have none. Name a sender in to when you have several. Email works too: send "channel": "email" with a from at test.vlayers.ai, and the message arrives on your mailbox (or the test sender).

Step 2: Reply or send

Reply as usual with POST /v1/conversations/{id}/messages, or send to a test address with POST /v1/messages:

curl -X POST https://api.vlayers.ai/v1/messages \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "to": "+15550123",
    "content": {
      "type": "text",
      "text": "Your table for two is booked for 7pm."
    }
  }'

What a test conversation does

The conversation a simulated message opens is marked test: true. That mark decides the rest:

  • every send in it — your replies, and your agent's — goes to the simulated carrier, never a real one;
  • it costs $0;
  • its events (message.received, message.sent, …) reach your webhooks and the stream like any other, with "livemode": false;
  • the dashboard hides test conversations by default: turn on Show test conversations on the Conversations page to see them.

Daily caps

Test mode is free and capped per workspace per UTC day: by default 1,000 test messages (simulated inbound messages and sends together) and 100 agent replies. Past a cap, requests are refused with 429 test_limit_reached until midnight UTC. Ask support if you need more.

Test it

Run Step 1, save the conversationId as CONVERSATION_ID, reply, then read the conversation with GET /v1/conversations/{id}/messages. The Quickstart walks through it.

Going live

Switch the test key for a live one and the test addresses for real ones. Nothing else in your code changes: the routes, bodies, events and error codes are the same.

Common errors

ErrorStatusHow to fix
test_mode_only403Use a test key (vl_test_…) from the dashboard.
test_address_required422Use a reserved test address, or a live key to reach a real person.
test_address_not_allowed422Use a test key (vl_test_…) for test addresses.
test_limit_reached429Try again after midnight UTC, or ask for a higher test limit.
sender_ambiguous409Name one of details.senders in from.

Next steps

On this page