Vocatech

By area

Messages

Read from the API’s own reference file every hour.

Plain text

Send texts and picture messages. Read text and WhatsApp history. Metered API Messaging keys also get a send queue.

Send a text

POST/v1/messages

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:

  • api or email: straight to the carrier. The answer is 201 with the carrier's message_id, the same id the message.sent and message.status_updated webhooks and GET /v1/messages carry. In email mode 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 is 201 when a new space was made, or 200 with status: sent when it went into the existing space. This answer has no carrier message_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. Check GET /v1/messages before 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, 404 or 429 is 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."
  }'

Body

FieldTypeDescription
platform requiredstringUse text. whatsapp is not available through the API and answers 422. One of text or whatsapp.
from requiredstringOne of your texting numbers. Punctuation and a leading 1 are ignored. For example 7185550100.
to requiredstringThe 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 requiredstringThe text, up to 1,600 characters. Required with media too. Up to 1,600 characters.
mediastring (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_urlstring (uri) or array, each string (uri)Another name for media.
namestringThe recipient's name, used the first time we name this contact. Defaults to Vocatech Text.
membersarray, 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.
testbooleanA dry run: check everything and send nothing. Default false.
company_idintegerOptional. If you send it, it must be your own company id.
A text
{
  "platform": "text",
  "from": "7185550100",
  "to": "7185550142",
  "message": "Hi Jordan, your appointment is confirmed for Friday at 10 AM. Reply C to confirm."
}
A picture message
{
  "platform": "text",
  "from": "7185550100",
  "to": "7185550142",
  "message": "Here is the estimate we discussed.",
  "media": [
    "https://files.example.com/estimates/estimate-2291.pdf"
  ]
}
A dry run
{
  "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

200
A dry run passed, or the text went into the contact's existing Webex space.

When status is test

A dry run passed every check. Nothing was sent.

FieldTypeDescription
status requiredstringAlways test.
message requiredobject
message.mode requiredstringOne of api, email or webex.
message.platform requiredstringAlways text.
message.from requiredstring
message.to requiredstring
message.valid requiredbooleanAlways true.
message.messages_counted requiredintegerMessage parts (segments) the send would count as.
message.would_queuebooleanMetered keys only: true when a real send would be queued now.
message.namestringapi and email modes.
message.email_recipientstring or nullapi and email modes.
message.mmsbooleanPicture messages.
message.attachmentsintegerPicture messages: how many files would go.
message.existing_spacebooleanWebex mode, when the contact has a space.
message.room_uuidstringWebex mode, when the contact has a space.
message.membersarray of stringsWebex mode, when a new space would be made.

When status is created or sent

FieldTypeDescription
status requiredstringcreated (201), or sent (200) when it went into an existing Webex space. One of created or sent.
message requiredobjectWhat was sent. Which fields appear depends on the number's mode.
message.message_idstring or nullThe 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.mode requiredstringHow the number sends. One of api, email or webex.
message.platform requiredstringAlways text.
message.from requiredstringYour number, 10 digits.
message.to requiredstringThe recipient, 10 digits.
message.message_sent requiredbooleanTrue when the message left. False means it was tried and did not leave.
message.created_at requiredstringWhen we took it, ISO 8601 with the Eastern offset, for example 2026-09-24T10:05:09-04:00.
message.messages_counted requiredintegerMessage parts (segments) this send counts as. A picture message counts as one.
message.namestringapi and email modes, and a new Webex space: the contact's name.
message.email_recipientstring or nullapi and email modes: the number's email address, which gets a copy in email mode.
message.email_sentbooleanapi and email modes: true when the email copy went out.
message.mmsbooleanPicture messages: always true.
message.attachments_sentintegerPicture messages: how many files went out.
message.mirrored_to_webexbooleanPicture messages on a Webex-mode number: true when a copy was posted in the contact's space.
message.room_uuidstringWebex mode: the id of the contact's space.
message.room_titlestringWebex mode, new space: the space's title.
message.membersarray of stringsWebex mode, new space: the members added.
message.existing_spacebooleanWebex mode: true when the message went into the contact's existing space.
Dry run
{
  "status": "test",
  "message": {
    "mode": "api",
    "platform": "text",
    "from": "7185550100",
    "to": "7185550142",
    "name": "Vocatech Text",
    "email_recipient": null,
    "valid": true,
    "messages_counted": 1
  }
}
Dry run on a metered key
{
  "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
  }
}
Webex mode, existing space
{
  "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
  }
}
201
Sent.
FieldTypeDescription
status requiredstringcreated (201), or sent (200) when it went into an existing Webex space. One of created or sent.
message requiredobjectWhat was sent. Which fields appear depends on the number's mode.
message.message_idstring or nullThe 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.mode requiredstringHow the number sends. One of api, email or webex.
message.platform requiredstringAlways text.
message.from requiredstringYour number, 10 digits.
message.to requiredstringThe recipient, 10 digits.
message.message_sent requiredbooleanTrue when the message left. False means it was tried and did not leave.
message.created_at requiredstringWhen we took it, ISO 8601 with the Eastern offset, for example 2026-09-24T10:05:09-04:00.
message.messages_counted requiredintegerMessage parts (segments) this send counts as. A picture message counts as one.
message.namestringapi and email modes, and a new Webex space: the contact's name.
message.email_recipientstring or nullapi and email modes: the number's email address, which gets a copy in email mode.
message.email_sentbooleanapi and email modes: true when the email copy went out.
message.mmsbooleanPicture messages: always true.
message.attachments_sentintegerPicture messages: how many files went out.
message.mirrored_to_webexbooleanPicture messages on a Webex-mode number: true when a copy was posted in the contact's space.
message.room_uuidstringWebex mode: the id of the contact's space.
message.room_titlestringWebex mode, new space: the space's title.
message.membersarray of stringsWebex mode, new space: the members added.
message.existing_spacebooleanWebex mode: true when the message went into the contact's existing space.
api mode
{
  "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
  }
}
A picture message
{
  "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
  }
}
Webex mode, new space
{
  "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
  }
}
202
Metered key: accepted and queued. It goes out automatically, in order.
FieldTypeDescription
status requiredstringAlways queued.
message requiredobjectA message a metered key handed over that waits its turn.
message.queue_id requiredintegerThe id in your queue. Cancel with DELETE /v1/messages/queue/{queue_id}.
message.position requiredintegerPlace in line, from 1.
message.from requiredstring
message.to requiredstring
message.messages_counted requiredintegerMessage parts (segments) this send counts as.
message.estimated_wait_minutes requiredintegerA rough wait at the key's pace.
message.info requiredstring
Example
{
  "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."
  }
}
400
A missing or invalid field, a message over 1,600 characters, a bad from or to, a media URL we refuse, or a Webex-mode number with no members allowed.
Example bodies
Example
{
  "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)."
  }
}
Example
{
  "error": {
    "code": 400,
    "type": "BAD_REQUEST",
    "message": "Missing or invalid fields. Platform must be \"text\" or \"whatsapp\", and from, to, message are required."
  }
}
Example
{
  "error": {
    "code": 400,
    "type": "BAD_REQUEST",
    "message": "Media URLs must use https. Got: http"
  }
}
Example
{
  "error": {
    "code": 400,
    "type": "BAD_REQUEST",
    "message": "Attachment type not supported: .heic"
  }
}
401
No key, or a key that is wrong or turned off.
403
Refused: outside the key's scopes, an address not allowed, 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
Not your number
{
  "error": {
    "code": 403,
    "type": "FORBIDDEN",
    "message": "Invalid from number"
  }
}
Recipient opted out
{
  "error": {
    "code": 403,
    "type": "FORBIDDEN",
    "message": "Recipient has opted out of messages from this number"
  }
}
On your blocked list
{
  "error": {
    "code": 403,
    "type": "FORBIDDEN",
    "message": "This number is on your company's blocked list."
  }
}
404
Passed on from the messaging service: the number is not set up for texting there.
Example body
Example
{
  "error": {
    "code": 404,
    "type": "NOT_FOUND",
    "message": "Number not found for this company"
  }
}
422
WhatsApp is not available through the API.
Example body
Example
{
  "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."
  }
}
429
A limit was reached: the 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).
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.
Example body
Example
{
  "error": "Rate limit exceeded",
  "period": "day",
  "limit": 200,
  "counter": "messages",
  "retry_after": 30211
}
500
Webex mode: the Webex space could not be reached or made.
Example bodies
Example
{
  "error": {
    "code": 500,
    "type": "SERVER_ERROR",
    "message": "Webex token could not be loaded or refreshed"
  }
}
Example
{
  "error": {
    "code": 500,
    "type": "SERVER_ERROR",
    "message": "Failed to create Webex Space"
  }
}
502
The messaging service answered and did not send. This is a fault on our side: retry later, or contact support if it lasts.
Example body
Example
{
  "error": {
    "code": 502,
    "type": "ERROR",
    "message": "Failed to send email message"
  }
}
503
The messaging service could not be reached and nothing was sent (safe to retry), or the key could not be checked.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.
Example body
Example
{
  "error": {
    "code": 503,
    "type": "ERROR",
    "message": "The messaging service could not be reached. The message was not sent, and it is safe to retry."
  }
}
504
The send was not confirmed. It may have gone out: check GET /v1/messages before you retry.
Example body
Example
{
  "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/messages

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 in api or email mode returns); for WhatsApp, the WhatsApp message id.
  • status: a text always reads delivered here, because this list does not carry carrier receipts. The message.status_updated webhook does. A WhatsApp message carries its own status, for example read.
  • type: media when the message has an attachment. Otherwise a text reads webex, and a WhatsApp message carries its conversation type.
  • remote_name is empty today.
  • attachments list each file's att_ id. Fetch the file with GET /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"

Parameters

NameInTypeDescription
start_datequerystring (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_datequerystring (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.
timezonequerystringIANA 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.
directionquerystringincoming or outgoing. One of any, incoming or outgoing. Default any.
statusquerystringFilters 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.
channelquerystringtext for texts, whatsapp for WhatsApp, any for both. One of any, text or whatsapp. Default any.
searchquerystringA number or words to find in your number, the other party's number, or the message text.
sortquerystringOrder by time. Rows that tie keep a stable order, so paging is safe. One of day_desc or day_asc. Default day_desc.
pagequeryintegerPage number, from 1. Default 1. At least 1.
limitqueryintegerRows per page, 1 to 500. A value outside that range is brought inside it. Default 500. From 1 to 500.
company_idqueryintegerOptional. 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

200
The messages in the window.
FieldTypeDescription
query requiredobjectThe filters that were applied, echoed back.
query.company_idinteger
query.start_datestring (date)
query.end_datestring (date)
query.directionstring
query.statusstring
query.channelstring
query.searchstring
query.timezonestring
messages requiredarray of objects
messages[].message_id requiredstring or nullFor 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[].direction requiredstringincoming or outgoing.
messages[].status requiredstringA 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[].remote_name requiredstringEmpty today.
messages[].remote_number requiredstring or nullThe other party's number, digits without the leading 1.
messages[].group_number requiredstring or nullYour number, digits without the leading 1.
messages[].sent_time requiredstring (date-time) or nullUTC, ISO 8601 with milliseconds.
messages[].channel requiredstringOne of text or whatsapp.
messages[].type requiredstringmedia when the message has an attachment. Otherwise a text reads webex, and a WhatsApp message carries its conversation type.
messages[].body requiredstringThe message text, trimmed.
messages[].attachments requiredarray of objects
messages[].attachments[].id requiredstringThe attachment's media id. Fetch it with GET /v1/media/{id}. Matches ^att_[0-9]+$.
messages[].attachments[].content_type requiredstring or nullThe file's type, for example image/jpeg.
messages[].attachments[].filename requiredstring or null
messages[].attachments[].size requiredinteger or nullBytes, when known.
meta requiredobjectPaging for list routes. Each list adds its own total.
meta.page requiredintegerThis page, from 1.
meta.limit requiredintegerRows per page, after limits were applied.
meta.total_pages requiredintegerHow many pages there are.
meta.total_messages requiredintegerMessages that match, across all pages.
Example
{
  "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
  }
}
400
A date that is not YYYY-MM-DD, an end before the start, or a window over 366 days.
Example bodies
Example
{
  "error": {
    "code": 400,
    "type": "BAD_REQUEST",
    "message": "Invalid date format or timezone."
  }
}
Example
{
  "error": {
    "code": 400,
    "type": "BAD_REQUEST",
    "message": "end_date is before start_date."
  }
}
401
No key, or a key that is wrong or turned off.
403
Refused. The key is scoped away from this route, the request came from an address not on the key's allow-list, or the route refused the request (the message says why).
429
A rate limit was reached. Wait Retry-After seconds. The body names the counter, the window and the limit.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.
500
An unexpected fault on our side, or a search that ran longer than 30 seconds and was stopped.
503
Try again shortly. The key could not be checked just now (Retry-After: 5), or a service this route needs could not be reached.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.

See the send queue

GET/v1/messages/queue

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"

Answers

200
The queue and the limits.
FieldTypeDescription
queue requiredobject
queue.pending requiredintegerMessages waiting or going out now.
queue.items requiredarray of objectsUp to 200 rows: waiting ones first, oldest first (the order they will send), then the most recent finished ones.
queue.items[].queue_id requiredinteger
queue.items[].to requiredstring
queue.items[].from requiredstring
queue.items[].status requiredstringqueued 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.items[].messages_counted requiredinteger
queue.items[].carrier requiredstring or nullThe recipient's carrier once we know it: tmobile, att, verizon, voip, landline, other or unknown.
queue.items[].attempts requiredintegerSend attempts so far, up to 3.
queue.items[].error requiredstring or nullThe last error, if any.
queue.items[].message_id requiredstring or nullThe carrier's message id once sent.
queue.items[].created_at requiredstringWhen it was queued. UTC, written YYYY-MM-DD HH:MM:SS.
queue.items[].sent_at requiredstring or nullWhen it was sent. UTC, written YYYY-MM-DD HH:MM:SS.
limits requiredobject
limits.per_minute requiredinteger or nullMessage parts a minute for this key. Null when the key has none.
limits.per_day requiredinteger or nullMessages a day for this key. Null when the key has none.
limits.used_today requiredintegerMessages this key sent in the last 24 hours.
limits.remaining_today requiredinteger or nullWhat is left of per_day, after what is already queued. Null when the key has no day limit.
limits.tmobile_day_allowance requiredintegerQueued 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.
Example
{
  "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
  }
}
401
No key, or a key that is wrong or turned off.
403
Refused. The key is scoped away from this route, the request came from an address not on the key's allow-list, or the route refused the request (the message says why).
429
A rate limit was reached. Wait Retry-After seconds. The body names the counter, the window and the limit.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.
503
Try again shortly. The key could not be checked just now (Retry-After: 5), or a service this route needs could not be reached.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.

Cancel every queued message

DELETE/v1/messages/queue

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"

Answers

200
Canceled.
FieldTypeDescription
status requiredstringAlways canceled.
canceled requiredintegerHow many waiting messages were canceled.
Example
{
  "status": "canceled",
  "canceled": 37
}
401
No key, or a key that is wrong or turned off.
403
Refused. The key is scoped away from this route, the request came from an address not on the key's allow-list, or the route refused the request (the message says why).
429
A rate limit was reached. Wait Retry-After seconds. The body names the counter, the window and the limit.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.
503
Try again shortly. The key could not be checked just now (Retry-After: 5), or a service this route needs could not be reached.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.

Cancel one queued message

DELETE/v1/messages/queue/{id}

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"

Parameters

NameInTypeDescription
id requiredpathintegerThe queue_id from the 202 answer or the queue list. For example 88412.

Answers

200
Canceled.
FieldTypeDescription
status requiredstringAlways canceled.
queue_id requiredinteger
Example
{
  "status": "canceled",
  "queue_id": 88412
}
401
No key, or a key that is wrong or turned off.
403
Refused. The key is scoped away from this route, the request came from an address not on the key's allow-list, or the route refused the request (the message says why).
404
No queued message with that id on this key.
Example body
Example
{
  "error": {
    "code": 404,
    "type": "NOT_FOUND",
    "message": "No queued message with that id on this key."
  }
}
409
The message is already going out or finished.
Example body
Example
{
  "error": {
    "code": 409,
    "type": "CONFLICT",
    "message": "This message is already sending or finished, so it cannot be canceled."
  }
}
429
A rate limit was reached. Wait Retry-After seconds. The body names the counter, the window and the limit.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.
503
Try again shortly. The key could not be checked just now (Retry-After: 5), or a service this route needs could not be reached.
HeaderTypeDescription
Retry-AfterintegerSeconds to wait before you try again.