Skip to content

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.


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.


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 check status.

POST https://e1.envoke.com/v2/messages/{ID}/send

Request. 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
}
}
}

POST https://e1.envoke.com/v2/messages/send

Request. 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.


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.


POST https://e1.envoke.com/v2/messages/{ID}/cancel

Request. 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_time is kept. The cancelled draft still shows its old send_time. See Send time before sending it again.
  • Only cancel scheduled messages. The API also accepts cancel for Queuing, Sending, and AB test in progress messages and sets them to Draft, 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"]
}
}

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).


Terminal window
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.

Terminal window
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.

Terminal window
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).

Terminal window
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.

Terminal window
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.

Terminal window
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.