By area
Messages
Read from the API’s own reference file every hour.
Send texts and picture messages. Read text and WhatsApp history. Metered API Messaging keys also get a send queue.
Send a text
POST/v1/
Sends one text (SMS) from one of your numbers, or a picture message (MMS) when you add media. from must be a number on your account with texting on.
How it goes out depends on the number's mode, set in the portal:
apioremail: straight to the carrier. The answer is201with the carrier'smessage_id, the same id themessage.sentandmessage.status_updatedwebhooks andGET /v1/messagescarry. Inemailmode a copy also goes to the number's email address.webex: into the contact's Webex space, and from there to the phone. The answer is201when a new space was made, or200withstatus: sentwhen it went into the existing space. This answer has no carriermessage_id.- With
media, in any mode: one MMS with every attachment, straight to the carrier. A Webex-mode number also gets a copy in its space.
Always check message.message_sent. false means the send was tried and did not leave.
Dry run. test: true runs every check and sends nothing. A dry run is never billed or recorded, but the request still counts toward your rate limits. On a metered key it also says would_queue.
Metered keys. A key with the messaging scope does not get a per-minute 429. When its pace is used up, the message is queued and the answer is 202 with a queue_id. It goes out automatically, in order (see GET /v1/messages/queue). Only its day limit refuses a send (429), counting what is already queued.
Counting. messages_counted is how many message parts (segments) the send counts as: 160 plain characters fit in one part and 153 in each part after that; a text that needs Unicode fits 70, then 67. A picture message counts as one.
WhatsApp. Sending WhatsApp through the API is not available. platform: whatsapp answers 422, dry runs too. WhatsApp history is in GET /v1/messages.
When a send fails:
503: the messaging service was not reached. Nothing was sent. It is safe to retry.504: the send was not confirmed. It may have gone out. CheckGET /v1/messagesbefore you retry.502: the messaging service answered and did not send.403: the recipient opted out, the number is on your blocked list, the text is too long once the signature is added, or an attachment was refused.- The messaging service's own
400,404or429is passed on as it is.
A main key may send 20 a minute and 200 a day, inside the account's included texting limit (50 an hour and 150 a day as standard). For more volume, use a metered API Messaging key: paid per message and outside that limit.
Request
curl -X POST https://api.vocatech.com/v1/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"message": "Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm."
}'const res = await fetch("https://api.vocatech.com/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
platform: "text",
from: "7185550100",
to: "7185550142",
message: "Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm.",
}),
});
console.log(res.status, await res.json());import requests
r = requests.post(
"https://api.vocatech.com/v1/messages",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"message": "Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm.",
},
timeout=30,
)
print(r.status_code, r.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client([
'base_uri' => 'https://api.vocatech.com',
'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
'http_errors' => false,
]);
$res = $client->post('/v1/messages', [
'json' => [
'platform' => 'text',
'from' => '7185550100',
'to' => '7185550142',
'message' => 'Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm.',
],
]);
echo $res->getStatusCode(), PHP_EOL, $res->getBody(), PHP_EOL;Body
| Field | Type | Description |
|---|---|---|
platform required | string | Use text. whatsapp is not available through the API and answers 422. One of text or whatsapp. |
from required | string | One of your texting numbers. Punctuation and a leading 1 are ignored. For example 7185550100. |
to required | string | The recipient: a 10-digit US or Canadian number. The area code cannot start with 0 or 1. Punctuation and a leading 1 are ignored. For example 7185550142. |
message required | string | The text, up to 1,600 characters. Required with media too. Up to 1,600 characters. |
media | string (uri) or array, each string (uri) | Makes it a picture message (MMS): one URL, or a list of up to 10. The carrier fetches each file, so it must be reachable without a login. Size is limited by the carriers (often around 1 MB). |
media_url | string (uri) or array, each string (uri) | Another name for media. |
name | string | The recipient's name, used the first time we name this contact. Defaults to Vocatech Text. |
members | array, each string (email) | Webex mode only: the Webex users to add when a new space is made. Each must be allowed on the number. Leave it out to use every allowed member. |
test | boolean | A dry run: check everything and send nothing. Default false. |
company_id | integer | Optional. If you send it, it must be your own company id. |
{
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"message": "Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm."
}{
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"message": "Here is the estimate we discussed.",
"media": [
"https://files.example.com/estimates/estimate-2291.pdf"
]
}{
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"message": "Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm.",
"test": true
}Answers
When status is test
A dry run passed every check. Nothing was sent.
| Field | Type | Description |
|---|---|---|
status required | string | Always test. |
message required | object | |
message. required | string | One of api, email or webex. |
message. required | string | Always text. |
message. required | string | |
message. required | string | |
message. required | boolean | Always true. |
message. required | integer | Message parts (segments) the send would count as. |
message. | boolean | Metered keys only: true when a real send would be queued now. |
message. | string | api and email modes. |
message. | string or null | api and email modes. |
message. | boolean | Picture messages. |
message. | integer | Picture messages: how many files would go. |
message. | boolean | Webex mode, when the contact has a space. |
message. | string | Webex mode, when the contact has a space. |
message. | array of strings | Webex mode, when a new space would be made. |
When status is created or sent
| Field | Type | Description |
|---|---|---|
status required | string | created (201), or sent (200) when it went into an existing Webex space. One of created or sent. |
message required | object | What was sent. Which fields appear depends on the number's mode. |
message. | string or null | The carrier's message id (api and email modes, and every picture message). It matches message_id on the message.sent and message.status_updated webhooks and in GET /v1/messages. Not present in Webex mode. |
message. required | string | How the number sends. One of api, email or webex. |
message. required | string | Always text. |
message. required | string | Your number, 10 digits. |
message. required | string | The recipient, 10 digits. |
message. required | boolean | True when the message left. False means it was tried and did not leave. |
message. required | string | When we took it, ISO 8601 with the Eastern offset, for example 2026-09-24T10:05:09-04:00. |
message. required | integer | Message parts (segments) this send counts as. A picture message counts as one. |
message. | string | api and email modes, and a new Webex space: the contact's name. |
message. | string or null | api and email modes: the number's email address, which gets a copy in email mode. |
message. | boolean | api and email modes: true when the email copy went out. |
message. | boolean | Picture messages: always true. |
message. | integer | Picture messages: how many files went out. |
message. | boolean | Picture messages on a Webex-mode number: true when a copy was posted in the contact's space. |
message. | string | Webex mode: the id of the contact's space. |
message. | string | Webex mode, new space: the space's title. |
message. | array of strings | Webex mode, new space: the members added. |
message. | boolean | Webex mode: true when the message went into the contact's existing space. |
{
"status": "test",
"message": {
"mode": "api",
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"name": "Vocatech Text",
"email_recipient": null,
"valid": true,
"messages_counted": 1
}
}{
"status": "test",
"message": {
"mode": "api",
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"name": "Vocatech Text",
"email_recipient": null,
"valid": true,
"messages_counted": 1,
"would_queue": true
}
}{
"status": "sent",
"message": {
"mode": "webex",
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"room_uuid": "0f6e2a91-7c4b-4d3e-9a58-1b2c3d4e5f60",
"message_sent": true,
"existing_space": true,
"created_at": "2026-09-24T10:08:02-04:00",
"messages_counted": 1
}
}| Field | Type | Description |
|---|---|---|
status required | string | created (201), or sent (200) when it went into an existing Webex space. One of created or sent. |
message required | object | What was sent. Which fields appear depends on the number's mode. |
message. | string or null | The carrier's message id (api and email modes, and every picture message). It matches message_id on the message.sent and message.status_updated webhooks and in GET /v1/messages. Not present in Webex mode. |
message. required | string | How the number sends. One of api, email or webex. |
message. required | string | Always text. |
message. required | string | Your number, 10 digits. |
message. required | string | The recipient, 10 digits. |
message. required | boolean | True when the message left. False means it was tried and did not leave. |
message. required | string | When we took it, ISO 8601 with the Eastern offset, for example 2026-09-24T10:05:09-04:00. |
message. required | integer | Message parts (segments) this send counts as. A picture message counts as one. |
message. | string | api and email modes, and a new Webex space: the contact's name. |
message. | string or null | api and email modes: the number's email address, which gets a copy in email mode. |
message. | boolean | api and email modes: true when the email copy went out. |
message. | boolean | Picture messages: always true. |
message. | integer | Picture messages: how many files went out. |
message. | boolean | Picture messages on a Webex-mode number: true when a copy was posted in the contact's space. |
message. | string | Webex mode: the id of the contact's space. |
message. | string | Webex mode, new space: the space's title. |
message. | array of strings | Webex mode, new space: the members added. |
message. | boolean | Webex mode: true when the message went into the contact's existing space. |
{
"status": "created",
"message": {
"message_id": "msg_9b2e5a",
"mode": "api",
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"name": "Jordan Reyes",
"email_recipient": null,
"message_sent": true,
"email_sent": false,
"created_at": "2026-09-24T10:05:09-04:00",
"messages_counted": 1
}
}{
"status": "created",
"message": {
"message_id": "msg_5d8f1b",
"mode": "webex",
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"mms": true,
"attachments_sent": 1,
"mirrored_to_webex": true,
"message_sent": true,
"created_at": "2026-09-24T10:06:44-04:00",
"messages_counted": 1
}
}{
"status": "created",
"message": {
"mode": "webex",
"platform": "text",
"from": "7185550100",
"to": "7185550142",
"name": "Jordan Reyes",
"room_title": "Jordan Reyes - 7185550142 - 7185550100",
"room_uuid": "0f6e2a91-7c4b-4d3e-9a58-1b2c3d4e5f60",
"members": [
"maya.chen@example.com"
],
"message_sent": true,
"created_at": "2026-09-24T10:07:30-04:00",
"messages_counted": 1
}
}| Field | Type | Description |
|---|---|---|
status required | string | Always queued. |
message required | object | A message a metered key handed over that waits its turn. |
message. required | integer | The id in your queue. Cancel with DELETE /v1/messages/queue/{queue_id}. |
message. required | integer | Place in line, from 1. |
message. required | string | |
message. required | string | |
message. required | integer | Message parts (segments) this send counts as. |
message. required | integer | A rough wait at the key's pace. |
message. required | string |
{
"status": "queued",
"message": {
"queue_id": 88412,
"position": 41,
"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/88412."
}
}from or to, a media URL we refuse, or a Webex-mode number with no members allowed.Example bodies
{
"error": {
"code": 400,
"type": "BAD_REQUEST",
"message": "Invalid to number: \"12345\" is not a valid US/Canada phone number (10 digits, area code 2-9xx)."
}
}{
"error": {
"code": 400,
"type": "BAD_REQUEST",
"message": "Missing or invalid fields. Platform must be \"text\" or \"whatsapp\", and from, to, message are required."
}
}{
"error": {
"code": 400,
"type": "BAD_REQUEST",
"message": "Media URLs must use https. Got: http"
}
}{
"error": {
"code": 400,
"type": "BAD_REQUEST",
"message": "Attachment type not supported: .heic"
}
}company_id not yours, from is not one of your texting numbers, the number's mode cannot send, a Webex member not allowed on the number, or the messaging service refused (the recipient opted out, the number is on your blocked list, the text is too long once the signature is added, an attachment was refused).Example bodies
{
"error": {
"code": 403,
"type": "FORBIDDEN",
"message": "Invalid from number"
}
}{
"error": {
"code": 403,
"type": "FORBIDDEN",
"message": "Recipient has opted out of messages from this number"
}
}{
"error": {
"code": 403,
"type": "FORBIDDEN",
"message": "This number is on your company's blocked list."
}
}Example body
{
"error": {
"code": 404,
"type": "NOT_FOUND",
"message": "Number not found for this company"
}
}Example body
{
"error": {
"code": 422,
"type": "UNPROCESSABLE_ENTITY",
"message": "Sending WhatsApp messages through the API is not available yet. WhatsApp history is in GET /v1/messages; reply from Webex or the portal."
}
}messages counter on a main key (20 a minute, 200 a day), a limit Vocatech set on this key, a metered key's day limit (which counts what is already queued), or, for a main key, the account's included texting limit on the messaging service (50 texts an hour and 150 a day as standard).| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Example body
{
"error": "Rate limit exceeded",
"period": "day",
"limit": 200,
"counter": "messages",
"retry_after": 30211
}Example bodies
{
"error": {
"code": 500,
"type": "SERVER_ERROR",
"message": "Webex token could not be loaded or refreshed"
}
}{
"error": {
"code": 500,
"type": "SERVER_ERROR",
"message": "Failed to create Webex Space"
}
}Example body
{
"error": {
"code": 502,
"type": "ERROR",
"message": "Failed to send email message"
}
}| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Example body
{
"error": {
"code": 503,
"type": "ERROR",
"message": "The messaging service could not be reached. The message was not sent, and it is safe to retry."
}
}GET /v1/messages before you retry.Example body
{
"error": {
"code": 504,
"type": "ERROR",
"message": "The messaging service did not confirm the send. The message may have gone out: check GET /v1/messages before retrying."
}
}List messages
GET/v1/
Your texts and WhatsApp messages in a date window, newest first, in one list. channel tells them apart.
Dates work as in GET /v1/calls: start_date and end_date together as local days in timezone, or neither for today, at most 366 days. The response echoes the local days you asked for.
Paging. limit is 500 by default and at most 500. Messages that tie on time keep a stable order.
Fields to know.
message_id: for a text, the carrier's id (the one a send inapioremailmode returns); for WhatsApp, the WhatsApp message id.status: a text always readsdeliveredhere, because this list does not carry carrier receipts. Themessage.status_updatedwebhook does. A WhatsApp message carries its own status, for exampleread.type:mediawhen the message has an attachment. Otherwise a text readswebex, and a WhatsApp message carries its conversation type.remote_nameis empty today.attachmentslist each file'satt_id. Fetch the file withGET /v1/media/{id}.
Each request is written to your account's HIPAA access log.
Request
curl -G https://api.vocatech.com/v1/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "start_date=2026-09-21" \
--data-urlencode "end_date=2026-09-21" \
--data-urlencode "channel=any"const params = new URLSearchParams({
start_date: "2026-09-21",
end_date: "2026-09-21",
channel: "any",
});
const res = await fetch(`https://api.vocatech.com/v1/messages?${params}`, {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
console.log(res.status, await res.json());import requests
r = requests.get(
"https://api.vocatech.com/v1/messages",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={
"start_date": "2026-09-21",
"end_date": "2026-09-21",
"channel": "any",
},
timeout=30,
)
print(r.status_code, r.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client([
'base_uri' => 'https://api.vocatech.com',
'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
'http_errors' => false,
]);
$res = $client->get('/v1/messages', [
'query' => [
'start_date' => '2026-09-21',
'end_date' => '2026-09-21',
'channel' => 'any',
],
]);
echo $res->getStatusCode(), PHP_EOL, $res->getBody(), PHP_EOL;Parameters
| Name | In | Type | Description |
|---|---|---|---|
start_date | query | string (date) | First local day of the window, YYYY-MM-DD, in timezone. Send it with end_date. Send neither for today. A single date is ignored and you get today. For example 2026-09-01. |
end_date | query | string (date) | Last local day of the window, YYYY-MM-DD, included in full. At most 366 days after start_date. For example 2026-09-07. |
timezone | query | string | IANA time zone for the dates, for example America/Chicago. An unknown zone falls back to America/New_York. The response echoes the zone used. Default America/New_York. |
direction | query | string | incoming or outgoing. One of any, incoming or outgoing. Default any. |
status | query | string | Filters WhatsApp messages by their status, for example read. Texts always read delivered here, so delivered keeps every text and any other value leaves texts out. Default any. |
channel | query | string | text for texts, whatsapp for WhatsApp, any for both. One of any, text or whatsapp. Default any. |
search | query | string | A number or words to find in your number, the other party's number, or the message text. |
sort | query | string | Order by time. Rows that tie keep a stable order, so paging is safe. One of day_desc or day_asc. Default day_desc. |
page | query | integer | Page number, from 1. Default 1. At least 1. |
limit | query | integer | Rows per page, 1 to 500. A value outside that range is brought inside it. Default 500. From 1 to 500. |
company_id | query | integer | Optional. If you send it, it must be your own company id, or the request is refused with 403. The key already decides the company. |
Answers
| Field | Type | Description |
|---|---|---|
query required | object | The filters that were applied, echoed back. |
query. | integer | |
query. | string (date) | |
query. | string (date) | |
query. | string | |
query. | string | |
query. | string | |
query. | string | |
query. | string | |
messages required | array of objects | |
messages[]. required | string or null | For a text, the carrier's message id: the one a send in api or email mode returns, and the one on message webhooks. For WhatsApp, the WhatsApp message id. |
messages[]. required | string | incoming or outgoing. |
messages[]. required | string | A text always reads delivered here: this list does not carry carrier receipts (the message.status_updated webhook does). A WhatsApp message carries its own status, for example sent, delivered, read or failed. |
messages[]. required | string | Empty today. |
messages[]. required | string or null | The other party's number, digits without the leading 1. |
messages[]. required | string or null | Your number, digits without the leading 1. |
messages[]. required | string (date-time) or null | UTC, ISO 8601 with milliseconds. |
messages[]. required | string | One of text or whatsapp. |
messages[]. required | string | media when the message has an attachment. Otherwise a text reads webex, and a WhatsApp message carries its conversation type. |
messages[]. required | string | The message text, trimmed. |
messages[]. required | array of objects | |
messages[]. required | string | The attachment's media id. Fetch it with GET /v1/media/{id}. Matches ^att_[0-9]+$. |
messages[]. required | string or null | The file's type, for example image/jpeg. |
messages[]. required | string or null | |
messages[]. required | integer or null | Bytes, when known. |
meta required | object | Paging for list routes. Each list adds its own total. |
meta. required | integer | This page, from 1. |
meta. required | integer | Rows per page, after limits were applied. |
meta. required | integer | How many pages there are. |
meta. required | integer | Messages that match, across all pages. |
{
"query": {
"company_id": 1234567890,
"start_date": "2026-09-21",
"end_date": "2026-09-21",
"direction": "any",
"status": "any",
"channel": "any",
"search": "",
"timezone": "America/New_York"
},
"messages": [
{
"message_id": "msg_4c1d7e",
"direction": "incoming",
"status": "delivered",
"remote_name": "",
"remote_number": "7185550142",
"group_number": "7185550100",
"sent_time": "2026-09-21T16:40:11.000Z",
"channel": "whatsapp",
"type": "media",
"body": "Here is the photo of the leak.",
"attachments": [
{
"id": "att_90211",
"content_type": "image/jpeg",
"filename": "photo-0921.jpg",
"size": 184233
}
]
},
{
"message_id": "msg_7f3a9c",
"direction": "incoming",
"status": "delivered",
"remote_name": "",
"remote_number": "7185550142",
"group_number": "7185550100",
"sent_time": "2026-09-21T15:22:04.000Z",
"channel": "text",
"type": "webex",
"body": "Running 10 minutes late, see you soon.",
"attachments": []
}
],
"meta": {
"page": 1,
"limit": 500,
"total_pages": 1,
"total_messages": 2
}
}YYYY-MM-DD, an end before the start, or a window over 366 days.Example bodies
{
"error": {
"code": 400,
"type": "BAD_REQUEST",
"message": "Invalid date format or timezone."
}
}{
"error": {
"code": 400,
"type": "BAD_REQUEST",
"message": "end_date is before start_date."
}
}Retry-After seconds. The body names the counter, the window and the limit.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Retry-After: 5), or a service this route needs could not be reached.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
See the send queue
GET/v1/
For metered API Messaging keys. Shows what this key has waiting to send, what finished recently, and how much of today's allowance is left.
Messages wait here when the key's per-minute pace is used up. They go out automatically, oldest first, about once a minute. A message is tried up to 3 times before it is marked failed.
items lists up to 200 rows: waiting ones first, in the order they will send, then the most recent finished ones. Finished rows are removed after 7 days.
used_today and remaining_today cover the last 24 hours. tmobile_day_allowance is how many queued messages to T-Mobile numbers your company may send in a UTC day. Once it is used, T-Mobile messages wait for the next day while the rest keep going.
A main key has no queue: its limits read null.
Request
curl https://api.vocatech.com/v1/messages/queue \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.vocatech.com/v1/messages/queue", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
console.log(res.status, await res.json());import requests
r = requests.get(
"https://api.vocatech.com/v1/messages/queue",
headers={"Authorization": "Bearer YOUR_API_KEY"},
timeout=30,
)
print(r.status_code, r.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client([
'base_uri' => 'https://api.vocatech.com',
'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
'http_errors' => false,
]);
$res = $client->get('/v1/messages/queue');
echo $res->getStatusCode(), PHP_EOL, $res->getBody(), PHP_EOL;Answers
| Field | Type | Description |
|---|---|---|
queue required | object | |
queue. required | integer | Messages waiting or going out now. |
queue. required | array of objects | Up to 200 rows: waiting ones first, oldest first (the order they will send), then the most recent finished ones. |
queue. required | integer | |
queue. required | string | |
queue. required | string | |
queue. required | string | queued waits, sending is going out now, sent left, failed gave up after 3 tries, canceled was canceled. One of queued, sending, sent, failed or canceled. |
queue. required | integer | |
queue. required | string or null | The recipient's carrier once we know it: tmobile, att, verizon, voip, landline, other or unknown. |
queue. required | integer | Send attempts so far, up to 3. |
queue. required | string or null | The last error, if any. |
queue. required | string or null | The carrier's message id once sent. |
queue. required | string | When it was queued. UTC, written YYYY-MM-DD HH:MM:SS. |
queue. required | string or null | When it was sent. UTC, written YYYY-MM-DD HH:MM:SS. |
limits required | object | |
limits. required | integer or null | Message parts a minute for this key. Null when the key has none. |
limits. required | integer or null | Messages a day for this key. Null when the key has none. |
limits. required | integer | Messages this key sent in the last 24 hours. |
limits. required | integer or null | What is left of per_day, after what is already queued. Null when the key has no day limit. |
limits. required | integer | Queued messages to T-Mobile numbers the company may send per UTC day. Once used, T-Mobile messages wait for the next day while the rest keep going. |
{
"queue": {
"pending": 2,
"items": [
{
"queue_id": 88412,
"to": "7185550142",
"from": "7185550100",
"status": "queued",
"messages_counted": 1,
"carrier": "verizon",
"attempts": 0,
"error": null,
"message_id": null,
"created_at": "2026-09-24 14:05:09",
"sent_at": null
},
{
"queue_id": 88413,
"to": "7185550143",
"from": "7185550100",
"status": "queued",
"messages_counted": 2,
"carrier": null,
"attempts": 0,
"error": null,
"message_id": null,
"created_at": "2026-09-24 14:05:09",
"sent_at": null
},
{
"queue_id": 88390,
"to": "9175550123",
"from": "7185550100",
"status": "sent",
"messages_counted": 1,
"carrier": "tmobile",
"attempts": 1,
"error": null,
"message_id": "msg_2a6c0e",
"created_at": "2026-09-24 14:01:12",
"sent_at": "2026-09-24 14:02:03"
}
]
},
"limits": {
"per_minute": 60,
"per_day": 5000,
"used_today": 1210,
"remaining_today": 3788,
"tmobile_day_allowance": 960
}
}Retry-After seconds. The body names the counter, the window and the limit.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Retry-After: 5), or a service this route needs could not be reached.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Cancel every queued message
DELETE/v1/
Cancels every message this key still has waiting. A message already going out or finished is not touched. Use it when a wrong batch went in.
Request
curl -X DELETE https://api.vocatech.com/v1/messages/queue \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.vocatech.com/v1/messages/queue", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
console.log(res.status, await res.json());import requests
r = requests.delete(
"https://api.vocatech.com/v1/messages/queue",
headers={"Authorization": "Bearer YOUR_API_KEY"},
timeout=30,
)
print(r.status_code, r.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client([
'base_uri' => 'https://api.vocatech.com',
'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
'http_errors' => false,
]);
$res = $client->delete('/v1/messages/queue');
echo $res->getStatusCode(), PHP_EOL, $res->getBody(), PHP_EOL;Answers
| Field | Type | Description |
|---|---|---|
status required | string | Always canceled. |
canceled required | integer | How many waiting messages were canceled. |
{
"status": "canceled",
"canceled": 37
}Retry-After seconds. The body names the counter, the window and the limit.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Retry-After: 5), or a service this route needs could not be reached.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Cancel one queued message
DELETE/v1/
Cancels one waiting message. Only a message still waiting can be canceled.
Request
curl -X DELETE https://api.vocatech.com/v1/messages/queue/88412 \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.vocatech.com/v1/messages/queue/88412", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
console.log(res.status, await res.json());import requests
r = requests.delete(
"https://api.vocatech.com/v1/messages/queue/88412",
headers={"Authorization": "Bearer YOUR_API_KEY"},
timeout=30,
)
print(r.status_code, r.json())<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client([
'base_uri' => 'https://api.vocatech.com',
'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
'http_errors' => false,
]);
$res = $client->delete('/v1/messages/queue/88412');
echo $res->getStatusCode(), PHP_EOL, $res->getBody(), PHP_EOL;Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | integer | The queue_id from the 202 answer or the queue list. For example 88412. |
Answers
| Field | Type | Description |
|---|---|---|
status required | string | Always canceled. |
queue_id required | integer |
{
"status": "canceled",
"queue_id": 88412
}Example body
{
"error": {
"code": 404,
"type": "NOT_FOUND",
"message": "No queued message with that id on this key."
}
}Example body
{
"error": {
"code": 409,
"type": "CONFLICT",
"message": "This message is already sending or finished, so it cannot be canceled."
}
}Retry-After seconds. The body names the counter, the window and the limit.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
Retry-After: 5), or a service this route needs could not be reached.| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds to wait before you try again. |
