By area
Messages
Written beside the API’s code, and read from it every hour.
| Method | Path | What it does |
|---|---|---|
| POST | /v1/messages | Send a text or an MMS |
| GET | /v1/messages | Text and WhatsApp history |
| GET | /v1/messages/queue | What an API Messaging key has waiting, and what is left of today |
| DELETE | /v1/messages/queue | Cancel everything still waiting |
| DELETE | /v1/messages/queue/{id} | Cancel one waiting message |
| GET | /v1/reports/messages | The old name for GET /v1/messages. It still answers |
Send: POST /v1/messages
| Field | Meaning |
|---|---|
platform | text. whatsapp answers 422. |
from | A texting number on your account |
to | A 10-digit US or Canadian number |
message | Up to 1,600 characters |
media | Up to 10 https links, for an MMS. media_url also works. |
name | Optional. The contact's name, for a new conversation. |
members | Webex numbers only. The email addresses of the people to add to a new conversation space. Leave it out to use the number's default members. |
test | true for a dry run |
The answer depends on how the number is set up in Textdock. A Webex number posts the text into the contact's conversation space in Webex, and opens one if needed (mode: "webex"). An API or email number sends it straight to the carrier (mode: "api" or "email"); an email number also sends a copy by email. Either way, message_sent says whether it left. The message_id a send returns is not guaranteed to match data.message_id on the webhook events for that text.
History: GET /v1/messages
| Parameter | Meaning |
|---|---|
start_date, end_date, timezone, page, limit | As for calls |
sort | day_desc (default) or day_asc |
direction | incoming or outgoing |
channel | text or whatsapp |
status | Texts always read delivered in this list, so other values return WhatsApp messages only |
search | Part of either number or of the text |
Each message has message_id, direction, status, remote_number, group_number, sent_time, channel, type (media when it carries attachments), body and attachments. Fetch an attachment by its att_ id through Media.
The API Messaging queue
An API Messaging key never gets a per-minute 429 on sends. Its whole batch is accepted and sent in order at the key's pace:
- A send that fits the pace goes out at once (
201). Once anything is waiting, new sends join the back of the line (202). - The pace counts message parts in the last 60 seconds, 60 to start. The day counts messages in the last 24 hours, the waiting ones included, 5,000 to start. Vocatech sets both per key.
- Only the day can refuse a send:
429when today's allowance, with what is waiting, is spoken for. - Every number a key texts is looked up for its carrier before the send. Messages to T-Mobile numbers are also held to 960 a day per account (
limits.tmobile_day_allowance), shared with the account's broadcasts; T-Mobile's day resets at midnight Pacific. When those are spent, a send to a T-Mobile number, or to a number whose carrier is not known yet, joins the queue (202) even with the minute open, and T-Mobile messages wait for the next day while the rest keep flowing. - These sends are paid per message. The account's included texting limit (50 texts an hour and 150 a day as standard) is for the texts its people and the main key send. It never holds an API Messaging key back, and the key's sends never use it up. Incoming texts are free and count toward nothing.
- The queue works through the line about once a minute. A message gets up to 3 tries. Finished messages stay in the list for 7 days.
# What this key has waiting, and what is left of today
curl https://api.vocatech.com/v1/messages/queue \
-H "Authorization: Bearer $VOCATECH_API_KEY"
# Cancel one waiting message
curl -X DELETE https://api.vocatech.com/v1/messages/queue/48213 \
-H "Authorization: Bearer $VOCATECH_API_KEY"
# Cancel everything still waiting: the wrong batch went in
curl -X DELETE https://api.vocatech.com/v1/messages/queue \
-H "Authorization: Bearer $VOCATECH_API_KEY"import { vt } from './vocatech.mjs';
const { queue, limits } = await vt('GET', '/v1/messages/queue');
console.log(queue.pending, 'waiting,', limits.remaining_today, 'left today');
await vt('DELETE', '/v1/messages/queue/48213'); // one message
const all = await vt('DELETE', '/v1/messages/queue'); // everything still waiting
console.log(all.canceled, 'canceled');from vocatech import vt
q = vt("GET", "/v1/messages/queue")
print(q["queue"]["pending"], "waiting,", q["limits"]["remaining_today"], "left today")
vt("DELETE", "/v1/messages/queue/48213") # one message
done = vt("DELETE", "/v1/messages/queue") # everything still waiting
print(done["canceled"], "canceled")<?php
require __DIR__ . '/vocatech.php';
$q = vt('GET', '/v1/messages/queue');
echo $q['queue']['pending'], ' waiting, ', $q['limits']['remaining_today'], " left today\n";
vt('DELETE', '/v1/messages/queue/48213'); // one message
$done = vt('DELETE', '/v1/messages/queue'); // everything still waiting
echo $done['canceled'], " canceled\n";{
"status": "queued",
"message": {
"queue_id": 48213,
"position": 61,
"from": "7185550100",
"to": "7185550142",
"messages_counted": 1,
"estimated_wait_minutes": 2,
"info": "Accepted and queued. It goes out automatically, in order, as sending capacity frees up. Track it with GET /v1/messages/queue or cancel it with DELETE /v1/messages/queue/48213."
}
}{
"queue": {
"pending": 2,
"items": [
{
"queue_id": 48213,
"to": "7185550142",
"from": "7185550100",
"status": "queued",
"messages_counted": 1,
"carrier": "tmobile",
"attempts": 0,
"error": null,
"message_id": null,
"created_at": "2026-09-24 13:15:02",
"sent_at": null
}
]
},
"limits": {
"per_minute": 60,
"per_day": 5000,
"used_today": 812,
"remaining_today": 4186,
"tmobile_day_allowance": 960
}
}The list shows up to 200 items: everything waiting first, then finished ones, newest first. An item's status is queued, sending, sent, failed or canceled, and its times are UTC. Only a queued message can be canceled: one already sending or finished answers 409, and an id that is not this key's answers 404.
