Message API - Sending
Use these endpoints to send a draft message, to create and send a message in one request, and to cancel a scheduled send.
Endpoints
Section titled “Endpoints”| Method | URL | Description |
|---|---|---|
| POST | https://e1.envoke.com/v2/messages/{ID}/send |
Send a draft message, now or at its send time. |
| POST | https://e1.envoke.com/v2/messages/send |
Create a message and send it in one request. |
| POST | https://e1.envoke.com/v2/messages/{ID}/cancel |
Cancel a scheduled message and return it to Draft. |
Authentication is via HTTP Basic Auth using your API ID and API Key. Request bodies are JSON objects.
How sending works
Section titled “How sending works”Sending is asynchronous. A send request checks the message, estimates its recipients, and schedules it; it does not deliver any email itself. Envoke’s sending process then picks up the message at its send time and moves it through these statuses:
| Status | What is happening |
|---|---|
Draft |
The message can be edited. Send it with one of the endpoints above. |
Scheduled |
The send request succeeded. The message waits for its send time. It can be cancelled. |
Queuing |
The send time has passed and Envoke is selecting the recipients. |
Sending |
The recipients are queued and the emails are going out. |
Sent |
Every email has been handed off for delivery. |
- The response to a send request is always
Message scheduled for send, even when the message is sent straight away. - The recipient counts in the response are an estimate taken at the time of the request. The actual recipient list is selected again when the send starts, with the same consent and address checks, so contacts added to or removed from the tag, subscription, or segment in the meantime change who is emailed.
- To follow a send, read the message with
GET /v2/messages/{ID}and checkstatus.
Send a draft
Section titled “Send a draft”POST https://e1.envoke.com/v2/messages/{ID}/sendRequest. The body is optional. It can contain any field accepted by update, most often send_time; the fields are saved to the message first, exactly as a PATCH would, and the message is then sent. Fields saved this way stay saved even if the send then fails. If the body includes id, it must match {ID} (see ID Mismatch).
Requirements. The message must be a Draft, and after any update in the body it must have:
| Requirement | Error when missing |
|---|---|
| At least one recipient field | At least one of the fields 'recipient_subscription', 'recipient_tag', or 'recipient_segment' must be set |
| A subject | The field 'subject' must be set |
| A sender | The field 'sender' must be set |
The three errors are returned together. name is not required.
Send time.
| Situation | When the message is sent |
|---|---|
The body has send_time |
At that time. It must be in the future and is read as account-local time (see Dates and time zones). |
No send_time in the body, and the message has none |
Immediately: on the next run of Envoke’s sending process. |
No send_time in the body, and the message already has one |
At the stored time. It is not checked again: if it has already passed, the message is sent on the next run. |
A message keeps its send_time when it is cancelled. Sending it again with no send_time therefore reuses the old time, which may now be in the past and send the message at once. Send a new send_time when you re-send a cancelled message. A stored send_time cannot be cleared, so a message that has one cannot be switched back to “send now” except by sending a new, near-future time.
Response.
{ "success": true, "result_text": "Message scheduled for send", "result_data": { "id": "2001", "send_time": "2026-10-20 09:00:00", "recipients": { "total_selected": 412, "emails_to_be_sent": 377, "excluded_unsubscribed_contacts": 29, "excluded_invalid_emails": 2, "excluded_bounced_emails": 4, "excluded_unverified_emails": 0, "excluded_by_language": 0 } }}result_data is not the message object: it holds the message id (a string, as in the URL), the send_time in the account time zone, and the recipient counts. For an immediate send, send_time is the time of the request.
Credits. For a prepaid account, the send is refused when the account’s credit balance is lower than emails_to_be_sent: Email can't be sent, the account is out of credits. A monthly-billed account that is not yet on a paid plan, and has too few credits, gets Email can't be sent, the account has not upgraded. The message stays a Draft.
No recipients. When emails_to_be_sent is 0, the message is not scheduled and stays a Draft. The response is HTTP 400 with the counts, so you can see why, and no errors key:
{ "success": false, "result_text": "Email can't be sent, no contacts selected", "result_data": { "id": "2004", "recipients": { "total_selected": 0, "emails_to_be_sent": 0, "excluded_unsubscribed_contacts": 0, "excluded_invalid_emails": 0, "excluded_bounced_emails": 0, "excluded_unverified_emails": 0, "excluded_by_language": 0 } }}Create and send
Section titled “Create and send”POST https://e1.envoke.com/v2/messages/sendRequest. A full create body (required). The message is created as a draft and then sent as described in Send a draft, in one request. For a scheduled send, include send_time in the body; without it, the message is sent immediately. The body must therefore include content, a subject, and recipients; sender falls back to the account default.
Response. On success, the same shape as Send a draft, except that result_data.id is an integer:
{ "success": true, "result_text": "Message scheduled for send", "result_data": { "id": 2005, "send_time": "2026-10-06 14:05:31", "recipients": { "total_selected": 2, "emails_to_be_sent": 2, "excluded_unsubscribed_contacts": 0, "excluded_invalid_emails": 0, "excluded_bounced_emails": 0, "excluded_unverified_emails": 0, "excluded_by_language": 0 } }}When it fails. If the create step fails (for example, no html or template_id), nothing is created and the create error is returned. If the create step succeeds but the send step fails (for example, no subject, or out of credits), the draft created by the first step is kept, and its ID is not returned; the response is the send error only. The zero-recipient response is the one exception: its result_data.id is the new draft’s ID. Give each message a unique name so you can find a leftover draft with GET /v2/messages?name=... and fix and send it, or delete it.
Recipient counts
Section titled “Recipient counts”Both send endpoints return these seven counts in result_data.recipients. All are integers.
| Key | Meaning |
|---|---|
total_selected |
Every contact in the tag, subscription, or segment (after a subscription narrows a tag or segment). |
emails_to_be_sent |
Contacts who pass every check below. The estimated number of emails. |
excluded_unsubscribed_contacts |
Contacts whose consent does not allow sending, such as Not Provided, Revoked, or Expired. On a mandatory consent message, only contacts whose consent blocks all email (such as a spam report) are counted here. |
excluded_invalid_emails |
Contacts whose email address is not valid. |
excluded_bounced_emails |
Contacts whose address has been marked undeliverable. |
excluded_unverified_emails |
Contacts who have not confirmed their address. Only when your account requires email confirmation (double opt-in); otherwise 0. |
excluded_by_language |
Contacts whose language does not match recipient_language. |
The counts overlap: one contact can be excluded for several reasons and is counted under each. The exclusions therefore need not add up to total_selected minus emails_to_be_sent.
Cancel
Section titled “Cancel”POST https://e1.envoke.com/v2/messages/{ID}/cancelRequest. The body is optional. If it contains update fields, they are applied after the message is returned to Draft, as a PATCH would. If the body includes id, it must match {ID}.
Effect. A Scheduled message goes back to Draft and will not be sent. It can then be updated and sent again.
send_timeis kept. The cancelled draft still shows its oldsend_time. See Send time before sending it again.- Only cancel scheduled messages. The API also accepts cancel for
Queuing,Sending, andAB test in progressmessages and sets them toDraft, but emails already queued are still delivered. - If an update field in the body fails validation, the message has already been returned to
Draft, but the response is the validation error.
Response. The message in full, in the same shape as a read:
{ "success": true, "result_text": "Message reverted to draft status", "result_data": { "id": "2001", "name": "Spring Season Announcement", "status": "Draft", "send_time": "2026-10-20 09:00:00" }}(result_data shortened; the response contains every field.)
Wrong status. Cancelling a message that is not scheduled or sending fails with the status name (not quoted):
{ "success": false, "result_text": "Validation failed, see 'result_data' -> 'errors'", "result_data": { "errors": ["Sending cannot be cancelled for a message with 'status': Draft"] }}Errors
Section titled “Errors”All errors use HTTP status 400.
| Error | Endpoints | Envelope | Cause |
|---|---|---|---|
Request body may not be empty |
/send |
Validation | No body, an empty body, or {}. The other two endpoints accept an empty body. |
Invalid JSON |
All | Plain | The body is not valid JSON. |
Invalid request |
All | Plain | The request could not be processed. |
Provided 'id': 2001 does not match 'id' in request body (2002) |
/{ID}/send, /{ID}/cancel |
Plain | The body id differs from the URL. |
| Create errors | /send |
Validation | Any error listed for create. Nothing is created. |
No message found for 'id': 2099 |
/{ID}/send |
Validation | No message with that ID in your account. |
Only 'Draft' messages can be updated, this message has the status: 'Scheduled' |
/{ID}/send |
Validation | The message is not a draft. |
| Update errors | /{ID}/send, /{ID}/cancel |
Validation | Any error listed for update, for fields sent in the body. |
At least one of the fields 'recipient_subscription', 'recipient_tag', or 'recipient_segment' must be set |
/send, /{ID}/send |
Validation | No recipients. |
The field 'subject' must be set |
/send, /{ID}/send |
Validation | No subject. |
The field 'sender' must be set |
/send, /{ID}/send |
Validation | No sender. |
Email can't be sent, no contacts selected |
/send, /{ID}/send |
Plain, with counts | emails_to_be_sent is 0. See No recipients. |
Email can't be sent, the account is out of credits |
/send, /{ID}/send |
Validation | Not enough prepaid credits. |
Email can't be sent, the account has not upgraded |
/send, /{ID}/send |
Validation | Monthly-billed account not yet on a paid plan. |
Sending cannot be cancelled for a message with 'status': Draft |
/{ID}/cancel |
Validation | The message is not scheduled or sending. |
On /send, errors after the create step leave the new draft in place (see Create and send).
Examples
Section titled “Examples”Send a draft now
Section titled “Send a draft now”curl -X POST -gs \ -u "$API_ID:$API_KEY" \ "https://e1.envoke.com/v2/messages/2002/send"Message 2002 has a subject, sender, and recipients and no send_time, so it is sent on the next run of Envoke’s sending process. The response’s send_time is the time of the request.
Schedule a send
Section titled “Schedule a send”curl -X POST -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"send_time": "2026-10-20 09:00:00"}' \ "https://e1.envoke.com/v2/messages/2001/send"Sends at 9:00 a.m. on October 20 in the account time zone (for an account in America/Toronto, 9:00 a.m. Toronto time). Do not add an offset or Z; it would be ignored. The response is shown under Send a draft.
Create from a template and send
Section titled “Create from a template and send”curl -X POST -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Pirates of Penzance - Cast Notice", "template_id": 1901, "replace": {"{SHOW_TITLE}": "The Pirates of Penzance", "{CURTAIN_TIME}": "7:30 p.m."}, "subject": "Call times for opening night", "sender": "Box Office <boxoffice@example.org>", "recipient_tag": "Cast Call"}' \ "https://e1.envoke.com/v2/messages/send"Creates the message from the Playbill Template, fills in its placeholders, and sends it immediately to contacts with the Cast Call tag. result_data.id in the response is an integer (see Create and send).
Cancel a scheduled send
Section titled “Cancel a scheduled send”curl -X POST -gs \ -u "$API_ID:$API_KEY" \ "https://e1.envoke.com/v2/messages/2001/cancel"Message 2001 returns to Draft with its send_time of 2026-10-20 09:00:00 still set.
Send to an audience with no recipients
Section titled “Send to an audience with no recipients”curl -X POST -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"recipient_tag": "Understudies"}' \ "https://e1.envoke.com/v2/messages/2004/send"No contact has the Understudies tag, so the request fails with Email can't be sent, no contacts selected and the counts shown under No recipients. The message stays a Draft, but its recipients have been changed to the Understudies tag by the body.
Send a message that is not a draft
Section titled “Send a message that is not a draft”curl -X POST -gs \ -u "$API_ID:$API_KEY" \ "https://e1.envoke.com/v2/messages/2001/send"Message 2001 is already Scheduled:
{ "success": false, "result_text": "Validation failed, see 'result_data' -> 'errors'", "result_data": { "errors": ["Only 'Draft' messages can be updated, this message has the status: 'Scheduled'"] }}Note: The curl examples above are formatted for readability. All requests must use properly encoded URLs.
Full reference, OpenAPI description, and Postman collection: developers.envoke.com.

