Reference
SMS & voice API
Endpoints for SMS inboxes, the texts and calls they capture, and texts simulated from phones. Authentication, roles, errors and paging are described in the API overview.
An SMS inbox is a fake Twilio account: your app sends texts and places calls with its Account SID and auth token through the Twilio-compatible API, or binds to it over SMPP. The endpoints on this page are for your tests and tooling, with a team API key. They use the inbox's workspace id, which is not the Account SID.
SMS inboxes
| Method and path | Role | Description |
|---|---|---|
GET /api/sms-inboxes |
Member | Every SMS inbox of the team, with messageCount, unreadCount and credentials |
POST /api/sms-inboxes |
Admin | Create one: { "name", "projectId"?, "failureRules"? }. 201 { smsInbox } |
GET /api/sms-inboxes/:id |
Member | One SMS inbox |
PATCH /api/sms-inboxes/:id |
Admin | Change name, projectId or failureRules |
DELETE /api/sms-inboxes/:id |
Admin | Delete it with its texts and calls. Open SMPP binds are closed. 204 |
POST /api/sms-inboxes/:id/rotate |
Admin | Replace the auth token. The old token stops working at once. { smsInbox } |
POST /api/sms-inboxes/:id/smpp |
Admin | Generate SMPP credentials, or replace the SMPP password. The system_id stays the same; open binds are closed. { smsInbox } |
curl -X POST https://app.testlie.com/api/sms-inboxes \
-H "Authorization: Bearer $TESTLIE_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "Checkout SMS", "failureRules": [{ "pattern": "+1555000*", "errorCode": 30003, "mode": "async" }] }'{
"smsInbox": {
"id": "cm2a7…",
"name": "Checkout SMS",
"projectId": null,
"accountSid": "AC4f1c…",
"authToken": "9b2e…",
"baseUrl": "https://app.testlie.com/sms",
"messagesUrl": "https://app.testlie.com/sms/2010-04-01/Accounts/AC4f1c…/Messages.json",
"failureRules": [{ "pattern": "+1555000*", "errorCode": 30003, "mode": "async" }],
"smpp": { "host": "smtp.testlie.com", "port": 2775, "tlsPort": 3550, "systemId": "tl3f9a…", "password": "…" },
"messageCount": 0,
"unreadCount": 0,
"createdAt": "2026-10-23T10:30:00.000Z"
}
}Credentials are shown to every team member, like SMTP passwords. SMS inboxes and WhatsApp sandboxes share the plan's SMS inbox limit (402 with "code": "quota_exceeded" past it).
Failure rules
failureRules is a list of up to 20 rules, first match wins. Each rule matches the To number and makes the send fail with a Twilio error:
| Field | Notes |
|---|---|
pattern |
Up to 64 characters; * matches any run of characters, ? one character |
errorCode |
21211 (invalid number), 21610 (unsubscribed), 30003 (unreachable), 30005 (unknown handset) or 30007 (carrier filtering) |
mode |
sync (default): the API call fails with 400 and nothing is stored. async: the text is accepted, then ends undelivered (30xxx codes) or failed (21xxx) |
Captured texts
| Method and path | Role | Description |
|---|---|---|
GET /api/sms-inboxes/:id/messages |
Member | List texts, newest first: to (exact), q (body contains), page, limit (default 100, max 500). { total, page, limit, messages } |
PATCH /api/sms-inboxes/:id/messages |
Member | Mark every text read. { updated } |
DELETE /api/sms-inboxes/:id/messages |
Member | Empty the inbox. { deleted } |
GET /api/sms-inboxes/:id/messages/wait |
Member | Long-poll for a text (see below) |
GET /api/sms/:sid |
Member | One text by SID (or id), with extracted codes and links. { sms } |
PATCH /api/sms/:sid |
Member | { "isRead": true | false } |
DELETE /api/sms/:sid |
Member | Delete one text. 204 |
GET /api/sms/:sid/extract |
Member | { sid, codes, links } |
A text has id, sid, smsInboxId, to, from, messagingServiceSid, body, numSegments, encoding (GSM-7 or UCS-2), mediaUrls, status (queued, sent, delivered, undelivered, failed), errorCode, errorMessage, statusCallback, channel (api or smpp), isRead, receivedAt and sentAt.
Wait for a text
| Parameter | Notes |
|---|---|
to |
The destination number, matched exactly (+15551234567; URL-encode the + as %2B) |
contains |
Text the body contains (case-insensitive) |
since |
ISO time; only texts received at or after it match |
timeout |
1 to 120 seconds, default 30 |
curl -f -H "Authorization: Bearer $TESTLIE_API_KEY" \
"https://app.testlie.com/api/sms-inboxes/$SMS_INBOX_ID/messages/wait?to=%2B15551234567&contains=code&since=2026-10-23T10:30:00Z"{
"sms": {
"sid": "SM8c1d…",
"to": "+15551234567",
"from": "+15005550006",
"body": "Your sign-in code is 482913",
"numSegments": 1,
"encoding": "GSM-7",
"status": "delivered",
"channel": "api",
"receivedAt": "2026-10-23T10:30:02.114Z",
"extracted": { "codes": ["482913"], "links": [] }
}
}The response is abridged here; it has every field listed above. On timeout it answers 408. extracted.codes lists likely one-time codes, best guess first: a code next to a word such as "code", "OTP" or "PIN" ranks first.
Voice calls
Calls placed with the Twilio Voice-compatible API are captured in the SMS inbox of the same account.
| Method and path | Role | Description |
|---|---|---|
GET /api/sms-inboxes/:id/calls |
Member | List calls, newest first: to, status, q (spoken text contains), page, limit (default 100, max 500) |
DELETE /api/sms-inboxes/:id/calls |
Member | Delete every finished call; live calls keep running. { deleted } |
GET /api/sms-inboxes/:id/calls/wait |
Member | Long-poll for a call: to, status, contains (spoken text), since, timeout (1 to 120 seconds). status is final by default (completed, busy, no-answer, failed or canceled), a single status, or any. 200 { call } with the timeline, transcript and extracted.codes, or 408 |
GET /api/sms-inboxes/:id/voice |
Member | { callsUrl, rules }: the Calls URL and the simulated callee rules |
PUT /api/sms-inboxes/:id/voice |
Admin | Replace the rules: { "rules": [{ "pattern", "behavior", "inputs"? }] }. See Simulated callees |
GET /api/calls/:sid |
Member | One call with its timeline and transcript |
PATCH /api/calls/:sid |
Member | { "isRead": true | false } |
DELETE /api/calls/:sid |
Member | Delete a finished call. 409 while it is still running |
GET /api/calls/:sid/extract |
Member | { sid, status, spokenText, codes, links } |
Texts from phones
Simulate a person texting your app's number. Testlie posts the text to your app as Twilio would, and to SMPP clients bound to the inbox. See Inbound SMS & email to your app.
| Method and path | Role | Description |
|---|---|---|
GET /api/sms-inboxes/:id/inbound |
Member | Where texts go: { target } with the inbox's phone number, your webhook URL and whether SMPP clients get them |
PUT /api/sms-inboxes/:id/inbound |
Admin | { "phoneNumber"?, "url"?, "smpp"? }. url must be reachable from the internet |
POST /api/sms-inboxes/:id/inbound/messages |
Member | Send a text: { "from", "body"?, "mediaUrls"?, "to"?, "source"? }. from is an E.164 number or a short code; give a body or at least one media URL. 201 { message } with its deliveries. At most 60 per team per minute |
GET /api/sms-inboxes/:id/inbound/messages |
Member | Texts sent to the inbox, newest first, with deliveries: from, page, limit (default 100, max 500) |
GET /api/sms-inboxes/:id/conversations |
Member | One row per phone number with its latest message; ?with=<number> returns that thread, oldest first, in both directions |
GET, DELETE /api/inbound/:id |
Member | One inbound text (id or SID) with every delivery attempt |
POST /api/inbound/:id/redeliver |
Member | Deliver again: every delivery, or { "deliveryId" }. 409 while an earlier delivery is still running |
Captured texts, calls and texts from phones each count toward the plan's monthly SMS limit. A simulated text past the limit answers 402; your app's sends get Twilio error 20429 instead. See Plans & limits.