Send API - Fields Reference
This article describes all fields accepted by the Send API. Use this as a reference when sending a message to a list of recipients.
Overview
Section titled “Overview”The Send API sends one email message to a list of people in a single request. Each request creates one message and sends it immediately to up to 1,000 recipients. There is no draft, schedule, or review step: when the request succeeds, the emails are already queued for delivery.
Recipients are given either by email address (recipients) or by Envoke contact ID (recipient_contact_ids). An email address that matches no contact in your account becomes a new contact and is sent the message (see Consent). To send to more than 1,000 people, send the first batch, then add further batches of up to 1,000 to the same message with id (see Send to more recipients).
The Transactional API preference must be set first. In Envoke, go to Account settings → Integrations → Transactional API and choose a Consent status and enter a Consent description. They are the consent given to contacts the API creates. Until a consent status is set, every request fails with A default consent status and description is required in order to use this API. The section is shown once the API is enabled for your account, to users who can manage the API.
The Send API answers on /v1 only and has a single endpoint, described in Send. It has no read, update, or delete endpoints of its own: a sent message can be read, and deleted once it has finished sending, through the Message API. Sender identities are managed with the Sender API, message groups with the Group API, contacts with the Contact API, and templates whose HTML a message can copy with the Template API.
All requests require HTTP Basic Auth using your API ID and API Key.
Fields
Section titled “Fields”| Field | Type | Read-only | Required on Create | Description |
|---|---|---|---|---|
id |
integer | No | No | ID of an earlier Send API message, to send it to more recipients. When set, only recipients may also be sent. |
name |
string | No | No | Internal name. Generated if omitted. |
subject |
string | No | Yes | Subject line, at least 6 characters. |
group |
string | No | No | Message group (folder) by name or ID. Defaults to API Messages. |
sender |
string | No | No | Sender identity. Defaults to the account’s default sender. |
reply_to |
string | No | No | Reply-to identity. No default. |
language |
string | No | No | Language of the message, en or fr. Defaults to en. |
recipients |
array | No | One of recipients or recipient_contact_ids |
Email addresses, or objects with email and optional replace. At most 1,000. |
recipient_contact_ids |
array | No | One of recipients or recipient_contact_ids |
Contact IDs, or objects with id and optional replace. At most 1,000. |
html |
string | No | One of html or template_id |
The message HTML, at most 200 kB. |
template_id |
integer | No | One of html or template_id |
ID of a template or message to copy HTML from. |
is_mandatory |
boolean | No | No | Send as a mandatory consent message. Defaults to false. |
track_recipient_activity |
boolean | No | No | Track opens and clicks. Defaults to false. |
enable_merge_fields |
boolean | No | No | Replace Envoke merge fields. Defaults to false. |
publish_archive |
boolean | No | No | Publish the message to the account’s web archive. Defaults to false. |
Field Details
Section titled “Field Details”Every field is write-only: the response returns the message id, counts, and one entry per recipient (see Response), not the fields sent. To see the stored message, read it with the Message API. Any key not listed above fails with '{field}' is not a valid field (see Not supported).
- Type: Integer
- Read-only: No
- Required on create: No — omit it to create a new message.
- Accepted values (write): The ID of a message created by the Send API.
0,"", andnullcount as not sent. - Returned value:
result_data.idin the response. For a new message it is an integer. When you sendid, the response echoes your value with its JSON type unchanged:3006comes back as3006,"3006"as"3006". - Example:
3006
When id is set, the request adds recipients to that message instead of creating one, and only recipients may be sent with it. The message’s content and settings are reused. See Send to more recipients for the rules and errors.
In the Message API, the same message has id "3006" as a string.
- Type: String, at least 3 characters
- Read-only: No
- Required on create: No — if omitted, the message is named
API Message {Y-m-d H:i:s}from the time of the request. - Example:
"Head of the Valley - Crew Call-up"
The internal name shown in the Envoke message list and in the Message API; recipients do not see it. Too short: The field 'name' must be at least 3 characters long. The API sets no maximum; a longer name is cut to its first 300 characters without an error.
The generated name uses Envoke’s server clock, which can differ from your account time zone.
subject
Section titled “subject”- Type: String, at least 6 characters
- Read-only: No
- Required on create: Yes
- Example:
"Crew call-up: Head of the Valley"
Missing or empty: The field 'subject' must be set. Too short: The field 'subject' must be at least 6 characters long. An empty string "" returns both errors. The API sets no maximum; a longer subject is cut to its first 360 characters without an error.
The subject is required even when template_id is used, because a template’s subject is not copied. Per-recipient replace does not change the subject.
language
Section titled “language”- Type: String
- Read-only: No
- Required on create: No — defaults to
en. - Accepted values (write):
enorfr(case-insensitive), or the IDs1(English) or3(French).""or"0"setsen. - Example:
"fr"
The language the message is written in. Envoke uses it for the text it adds, such as the unsubscribe footer and merge fields. It does not choose recipients: every recipient is sent the message whatever their language. Any other value fails with Invalid 'language': 'de' and allowed_values {"1":"en","3":"fr"}.
The default is English, not your account’s default language.
publish_archive
Section titled “publish_archive”- Type: Boolean
- Read-only: No
- Required on create: No — defaults to
false. - Accepted values (write):
true,"true",1,"1","yes", or"on"publishes. Anything else is treated asfalse. - Example:
true
When true, the message is published to your account’s public message archive.
is_mandatory
Section titled “is_mandatory”- Type: Boolean
- Read-only: No
- Required on create: No — defaults to
false. - Accepted values (write): As for
publish_archive. Anything not read as true isfalse, with no error. - Example:
true
When true, the message is sent as a mandatory consent message and only reaches contacts who hold your account’s mandatory consent subscription. See Consent.
Recipients
Section titled “Recipients”Two fields say who the message is sent to. Send one of them.
| Field | Simple form | Object form |
|---|---|---|
recipients |
["stroke.seat@example.org", "bow.seat@example.org"] |
[{ "email": "stroke.seat@example.org", "replace": { "{SEAT}": "8" } }] |
recipient_contact_ids |
[7001, 7002] (IDs may also be numeric strings) |
[{ "id": 7001, "replace": { "{SEAT}": "8" } }] |
Use the object form when each recipient needs their own replace values. An object has the key field (email or id) and, optionally, replace. Any other key, such as first_name, is ignored: contact details cannot be set through this API (use the Contact API).
| Rule | Behaviour |
|---|---|
| One form per list | Only the first item decides the form. If it is a string or number, every item is read as an address or ID. If it is an object, every item must be an object. Use the same form for the whole list. |
| First item | An object first item without the key field fails with Invalid 'recipients': items must have the field 'email' (or Invalid 'recipient_contact_ids': items must have the field 'id'). |
| Later items | A later object without the key field is not sent and is returned as {"missing_key_field": true}. It is counted in total_selected only. |
| Empty | Missing or []: The field 'recipients' must be set. "recipient_contact_ids": []: The field 'recipient_contact_ids' must not be empty. |
| Not a list | The field 'recipients' must be an array (or The field 'recipient_contact_ids' must be an array). |
| Limit | At most 1,000 items: The field 'recipients' may not contain more than 1000 (or The field 'recipient_contact_ids' may not contain more than 1000). Every item counts toward the limit, including invalid ones and repeats. Exactly 1,000 is allowed. |
| Both sent | recipient_contact_ids wins and recipients is ignored, with no error. |
| By email | Each address is matched against your contacts. An address that matches no contact becomes a new contact and is sent the message. An invalid address is not sent and no contact is created. |
| By ID | Each ID must be a contact in your account. An ID that matches no contact is not sent and is returned as {"excluded_invalid_ids": true}. No contacts are created. |
Which recipients are actually sent the message depends on their consent and address status (see Consent). The response reports the outcome for each item (see Response).
Send each address once, spelled exactly as it is stored in Envoke. Recipients are not de-duplicated: a repeated item and an address in a different letter case (Stroke.Seat@example.org for a contact stored as stroke.seat@example.org) are treated as separate recipients.
html, template_id, and replace
Section titled “html, template_id, and replace”html or template_id sets the content of the message; replace personalises it per recipient.
- Type: String, at most 200 kB (204,800 bytes)
- Read-only: No
- Required on create: One of
htmlortemplate_id. - Example:
"<html><body><p>You are in {BOAT_NAME}, seat {SEAT}.</p></body></html>"
The complete HTML of the message, stored as sent. Envoke does not check or clean it. If it contains the <meta name="TEMPLATE_VERSION" tag that Envoke’s drag-and-drop editor writes, the message opens in that editor in Envoke; otherwise it opens in the HTML editor.
| Rule | Behaviour |
|---|---|
| Size | Over 200 kB fails with The field 'html' may not be longer than 200kB. Only the html you send is checked: HTML copied through template_id, and the HTML after replace, are not. |
| Empty value | "" counts as not sent. |
| Neither sent | Without html or template_id (or with "", 0, or "0"): One of the fields 'template_id' or 'html' must be provided in order to create a message. |
With template_id |
When both are sent, html is used and template_id is ignored, with no error. |
template_id
Section titled “template_id”- Type: Integer (a numeric string such as
"1951"is also accepted) - Read-only: No
- Required on create: One of
htmlortemplate_id. - Example:
1951
The ID of a template, or of another message in your account (including an earlier Send API message), whose HTML the new message copies. Templates shared with your account can be used as well as your own. An ID that matches nothing fails with Nothing found for 'template_id': 1999.
Only the HTML (and which editor the content opens in) is copied. The source’s subject, sender, reply-to, language, and group are not; set them in the same request. The copy is independent: later changes to the template do not change the message.
replace
Section titled “replace”- Type: Object of strings, on a recipient object only
- Read-only: No
- Required on create: No
- Format:
{ "{PLACEHOLDER}": "replacement text" } - Example:
{ "{BOAT_NAME}": "Heron", "{SEAT}": "8 (stroke)" }
Replaces placeholder text in the message HTML for one recipient. replace belongs on an item of recipients or recipient_contact_ids in the object form; each recipient can have different values, or none. There is no request-level replace: a top-level replace key fails with 'replace' is not a valid field.
The replacement is made when each email is delivered. The message is stored with its placeholders, so the HTML read through the Message API still shows {BOAT_NAME}, and a later batch sent with id can fill the same placeholders with new values.
| Rule | Behaviour |
|---|---|
| Keys | Every key must start with { and end with }, e.g. {SEAT}. |
| Values | Every value must be a string. It is inserted as is, without escaping, so it can contain HTML. |
| Unmatched keys | A key that does not appear in the HTML is ignored. |
| Order | Keys are applied in the order sent, so a later key can match text inserted by an earlier value. |
| Protected links | A key may not contain {@pref-, {@consent-url, or {@consent-prefpage-url, so the preference and consent links in your footer cannot be replaced. |
| Empty | {} is ignored; the recipient is sent the HTML unchanged. |
| Merge fields | replace runs before merge fields. With enable_merge_fields on, merge tags inside a replacement value are filled in too. A merge tag used as a key, such as {@first_name}, is replaced by your value instead. |
| Subject | Only the HTML is changed; the subject is not. |
An invalid replace does not fail the request. Any other shape (a list, a non-string value, a key without braces, a protected key) excludes that one recipient: they are not sent the message, no contact is created for a new address, and their entry in the response is marked excluded_invalid_replace_data. The other recipients are sent as normal, and the excluded_invalid_replace_data count appears in the summary. If no one else can be sent the message, the request fails as having no valid recipients (see Partial and failed sends).
sender and reply_to
Section titled “sender and reply_to”- Type: String (an identity ID may also be sent as an integer)
- Read-only: No
- Required on create: No.
senderdefaults to the account’s default sender;reply_tohas no default. - Accepted values (write): An identity ID, the identity as
Name <email>, or the email address alone. - Example:
"Boathouse <boathouse@example.org>"
Both fields take one of the sender identities (From addresses) set up in your account; list them with the Sender API. A value is resolved in this order:
| Step | Value | Result |
|---|---|---|
| 1 | Digits that match an identity ID, e.g. "512" or 512 |
That identity. |
| 2 | Name <email> matching an identity, ignoring case and treating a space and an underscore as the same, e.g. "boathouse <boathouse@example.org>" |
That identity. |
| 3 | "" or "0" |
The field is not set. |
| 4 | A valid email address, e.g. "boathouse@example.org" |
The first identity with that address. The address must match exactly, including case. If none matches: No sender identity found for email: 'regatta@example.org' (or No reply_to identity found for email: ...). |
| 5 | Anything else | Invalid 'sender': 'Boathouse' (or Invalid 'reply_to': ...). |
Errors from steps 4 and 5 include the account’s identities in allowed_values, keyed by ID, as Name <email>.
When sender is omitted, "", or "0", the message uses the identity marked as the account default. reply_to is optional; when it is not set, replies go to the sender address. The identity is used as configured.
- Type: String (a group ID may also be sent as an integer)
- Read-only: No
- Required on create: No — defaults to the
API Messagesgroup. - Accepted values (write): The name or ID of an existing message group. Names are matched ignoring case, and a space and an underscore are treated as the same.
""or"0"uses the default. - Example:
"Crew Notices"
The message group (folder) the message is filed in. Only message groups can be used; template groups and contact groups are not accepted. A group is not created automatically: an unknown value fails with Invalid 'group': 'Regattas' and the list of valid groups in allowed_values (see Error Responses). Create groups with the Group API.
The API Messages group. Without group, the message is filed in a message group named API Messages, which Envoke creates the first time it is needed. In Envoke, messages in this group are shown in the API Messages folder and are left out of the All folder and the status folders. A message sent with a custom group appears in that group’s folder and also in All. Through the Message API, the message’s group reads API Messages (or the custom group’s name).
Consent
Section titled “Consent”Who is sent the message is decided when the request is made, from each recipient’s consent and address status.
Default (without is_mandatory).
| Recipient | Sent when | Otherwise counted as |
|---|---|---|
| Existing contact | Their consent allows sending (for example Express or Implied, but not Not Provided, Revoked, or Expired). |
excluded_unsubscribed_contacts |
| Existing contact | Their address has not been marked undeliverable. | excluded_bounced_emails |
| Existing contact | Your account does not require email confirmation (double opt-in), or they have confirmed their address. | excluded_unverified_emails |
| Existing contact | Their stored address is valid. | excluded_invalid_emails |
| New address | It is a valid address. The contact is created with the consent status and description from your Transactional API preference, and sent the message. | excluded_invalid_emails |
Mandatory (is_mandatory: true).
| Rule | Behaviour |
|---|---|
| The message | Sent as a mandatory (consent-exempt) message, with the mandatory subscription’s description, in the message’s language, as the stated reason. |
| Existing contacts | Sent only when they hold your account’s mandatory consent subscription and have not reported the account’s email as spam. Their other consent does not matter. |
| Without the subscription | A contact who does not hold it is counted as excluded_mandatory_consent. A contact who holds it but has reported spam is counted as excluded_unsubscribed_contacts. |
| No mandatory subscription | When your account has no mandatory consent subscription, every existing contact is excluded as excluded_mandatory_consent, and the message is not marked consent-exempt. |
| New addresses | Created with the consent status and description from your Transactional API preference, given the mandatory consent subscription, and sent the message. |
| Bounced, unverified | Excluded as in the default rules. |
| Counter | The excluded_mandatory_consent count in the summary, and the per-recipient excluded_mandatory_consent key, appear only when is_mandatory is true, or when id refers to a message first sent with is_mandatory. |
New contacts are completed in the background: the contact is created at once with its email address only, and its consent, mandatory subscription, and the account’s new-contact automation (such as lists added to every new contact) follow shortly after (see How sending works).
Tracking and merge fields
Section titled “Tracking and merge fields”| Field | Default | When false |
When true |
|---|---|---|---|
track_recipient_activity |
false |
Links are left as written and no open-tracking image is added. | Links are rewritten to record clicks, and an open-tracking image is added. |
enable_merge_fields |
false |
Only the basic tags in the table below are replaced. | All Envoke merge fields (such as {@first_name}) and the older {fname}-style tags are replaced. |
Both accept the same values as publish_archive.
With enable_merge_fields off, these tags are still replaced:
| Tag | Replaced with |
|---|---|
{@pref-0}, {@pref-1}, {@consent-url}, {@consent-prefpage-url} |
The link to the recipient’s email preferences page. |
{fname}, {lname} |
The contact’s first and last name. |
{eid} |
The contact’s external_id (as returned by the Contact API). |
Footer. When the message HTML contains none of {@pref-, {@consent-url, or {@consent-prefpage-url, Envoke adds its standard unsubscribe footer to the end of every email. To place the unsubscribe link yourself, include one of these tags in your HTML; the footer is then not added. This works whether merge fields are on or off. Tags inserted through replace values do not count.
UTM tracking parameters are never added to links in Send API messages.
Not supported
Section titled “Not supported”The following keys are not part of this API and fail with '{field}' is not a valid field, for example 'send_time' is not a valid field:
| Key | Notes |
|---|---|
send_time |
Every send is immediate. To schedule a message, use the Message API. |
utm_tag_links |
UTM tracking parameters are always off. |
preheader_text |
Not available. |
replace at the top level |
'replace' is not a valid field. Put replace on each recipient object instead (see replace). |
recipient_subscription, recipient_tag, recipient_segment, recipient_language |
Recipients are listed one by one with recipients or recipient_contact_ids. To send to a tag, subscription, or segment, use the Message API. |
Error Responses
Section titled “Error Responses”Validation errors (missing or invalid fields, rule violations):
{ "success": false, "result_text": "Validation failed, see 'result_data' -> 'errors'", "result_data": { "errors": [ "The field 'subject' must be set", "'send_time' is not a valid field" ] }}Four checks return a single error at once, in this order: the Transactional API preference, the size of html, a template_id that is not found, and a request with neither html nor template_id. All other errors are collected and returned together.
When group, sender, reply_to, or language has an unknown value, result_data also carries allowed_values, an object of the valid options keyed by ID. It is included only when the account has 50 or fewer options for that field:
{ "success": false, "result_text": "Validation failed, see 'result_data' -> 'errors'", "result_data": { "errors": ["Invalid 'group': 'Regattas'"], "allowed_values": { "group": { "41": "Crew Notices", "42": "API Messages" } } }}allowed_values is not returned when id is sent.
No valid recipients. When none of the recipients can be sent the message, nothing is created and the response carries the counts and per-recipient entries instead of an errors list (see Partial and failed sends):
{ "success": false, "result_text": "Message not sent, there are no valid recipients", "result_data": { "summary": { "total_selected": 1, "emails_to_be_sent": 0, "excluded_unsubscribed_contacts": 1, "excluded_invalid_emails": 0, "excluded_bounced_emails": 0, "excluded_unverified_emails": 0 }, "recipients": [ { "id": 7003, "email": "cox@example.org", "excluded_unsubscribed_contacts": true } ] }}Plain errors. Invalid JSON, Invalid request, and Message content error use result_data: [] with the message in result_text:
{ "success": false, "result_data": [], "result_text": "Message content error"}Internal errors. When the message or its recipients cannot be saved, the response has no result_data key at all. Contact Envoke support if it persists:
{ "success": false, "result_text": "Internal error; please contact Envoke support"}Empty or unreadable body. No body, an empty body, {}, [], null, 0, or false returns the validation envelope with Request body may not be empty. A body that is not valid JSON returns the plain envelope with Invalid JSON.
All error responses above use HTTP status 400. An invalid API ID or key returns 401 with the body {"success":false,"result_data":[],"result_text":"Invalid credentials"}. A valid key on a closed or inactive account returns 403 with the JSON body {"success":false,"result_data":[],"result_text":"This account has been closed."} (or "This account is not active.") Exceeding your account’s API limit returns 429 with success: false and a result_text naming the limit.
Errors by scenario
Section titled “Errors by scenario”| Scenario | result_text |
result_data |
|---|---|---|
| Empty body | Validation failed, see 'result_data' -> 'errors' |
{"errors":["Request body may not be empty"]} |
| Body is not valid JSON | Invalid JSON |
[] |
| Request could not be processed | Invalid request |
[] |
| Transactional API preference not set | Validation failed, ... |
{"errors":["A default consent status and description is required in order to use this API"]} |
html over 200 kB |
Validation failed, ... |
{"errors":["The field 'html' may not be longer than 200kB"]} |
template_id not found |
Validation failed, ... |
{"errors":["Nothing found for 'template_id': 1999"]} |
Neither html nor template_id |
Validation failed, ... |
{"errors":["One of the fields 'template_id' or 'html' must be provided in order to create a message"]} |
| Field errors | Validation failed, ... |
{"errors":[...]}, with allowed_values for lookup fields. The full list is in Validation Errors. |
id not found |
Validation failed, ... |
{"errors":["No message found for 'id': 3099"]} |
id is not a Send API message |
Validation failed, ... |
{"errors":["Only messages created by the API are valid when providing an 'id'"]} |
id sent with other fields |
Validation failed, ... |
{"errors":["The field 'subject' is not valid when providing an 'id'"]} |
| Not enough credits | Validation failed, ... |
{"errors":["Message not sent, the account is out of credits"]} or {"errors":["Message not sent, the account has not upgraded"]} |
| No recipient can be sent the message | Message not sent, there are no valid recipients |
{"summary":{...},"recipients":[...]} |
| Content could not be saved | Message content error |
[] |
| Message or recipients could not be saved | Internal error; please contact Envoke support |
(no key) |
Not found
Section titled “Not found”The Send API has one endpoint, so the only not-found case is an id that does not match a Send API message in your account. It returns the validation error No message found for 'id': 3099, with the value as sent. A message deleted through the Message API, a template, and another account’s message are all not found.
Full reference, OpenAPI description, and Postman collection: developers.envoke.com.

