Skip to content

Message API - Read

Use the read endpoints to retrieve messages from your account. You can list messages with filtering, sorting, and pagination, or retrieve a single message by ID, optionally with its HTML.


Method URL Description
GET https://e1.envoke.com/v2/messages Return a list of messages.
GET https://e1.envoke.com/v2/messages/{ID} Return a single message.

Authentication is via HTTP Basic Auth using your API ID and API Key.


GET https://e1.envoke.com/v2/messages

Returns a JSON array of messages, most recently modified first. Supports filtering, sorting, pagination, and field selection.

The list contains every message in your account that has not been deleted, in every status: drafts, scheduled and sent messages, messages published to the archive, and the Nurture and Transactional messages set up in Envoke. Templates and deleted messages are not included. There is no filter by message type.

Parameter Type Default Description
limit integer 10 Maximum number of results to return. Hard cap is 100 unless ?fields= or ?result_type=kvp is also set (see note below). limit=1 returns a single object, not an array (see below).
skip integer 0 Number of records to skip. Use with limit and sort to paginate.
fields string (all) Comma-separated list of fields to include in each result, e.g. id,name,status. Use names from the Fields reference.
result_type string (array) Set to kvp to receive an object of message ID to name ({ "2001": "Spring Season Announcement" }).
filter[{field}] string — Filter on a field. See Filterable and sortable fields and Filter Operators.
sort[{field}] string modified_time descending Sort on a field. Value: asc or desc (case-insensitive), or 1 or -1. Repeat for a secondary sort. A sort replaces the default order.

Note — limit behaviour with ?fields= and ?result_type=kvp: When either of these parameters is present, the default limit increases to 10,000 (returning every record up to that number if no explicit limit is specified) and a ?limit= value above 100 is honoured as-is.

Note — limit=1 returns an object. With limit=1 the response is the matching message as a bare JSON object, not an array of one. result_type=kvp has no effect when limit=1; fields still applies. When nothing matches, the response is [].

Note — filters without filter[...]. When the request has no filter parameter, every query parameter other than limit, skip, sort, fields, result_type, and include_html is treated as a filter, so ?status=Sent is the same as ?filter[status]=Sent. Any other parameter is rejected as an unknown filter field (for example Field 'folder' is not valid for filtering). When filter is present, the other parameters are ignored as filters.

include_html has no effect on the list; HTML is returned only for a single message.

Field Filter operators Sortable
id, external_id, name, subject equals, (ne) Yes
status equals, (ne) Yes, by status code
language, recipient_language equals, (ne) Yes, by language ID
publish_archive, utm_tag_links equals, (ne) Yes
create_time, modified_time — Yes

Fields not in this table cannot be filtered or sorted, including group, send_time, sender, reply_to, recipient_subscription, recipient_tag, and recipient_segment. To find messages by one of these, list with fields and select on your side.

  • name and subject match the whole value. Case is ignored.
  • status takes a status name or code; see Filter by status.
  • language and recipient_language take the language ID, not the code: 1 for English, 3 for French. filter[language]=en does not match English messages.
  • publish_archive takes the stored value: 2 for messages published to the archive, 1 for the rest. true and false do not work in filters.
  • utm_tag_links takes 1 for messages with UTM tagging on and 0 for off. true and false do not work in filters; use 1 or 0.
Operator Example Description
(none) ?filter[subject]=Our spring season is here Equals.
(ne) ?filter[status][(ne)]=Draft Not equal.
(or) ?filter[(or)][0][status]=Sent&filter[(or)][1][status]=Scheduled Matches if any of the grouped conditions match.
(not) ?filter[(not)][status]=Sent Matches if the grouped conditions do not all match.

Note: URL-encode brackets in production requests (e.g. %5B for [).

Each operator also has a $ spelling ($ne, $or, $not) that behaves the same way. These docs use the (op) spelling.

The (in), (regex), (gt), (lt), (gte), and (lte) operators are not supported on any message field. They fail with an error that names the SQL operator, e.g. 'IN' is not a valid operator for the field 'status' (REGEXP for (regex); >, <, >=, <= for the range operators). To match one of several values, use (or).

Combining conditions.

  • Separate filters are ANDed: ?filter[status]=Draft&filter[language]=3.
  • A query string cannot repeat a key, so to use the same field twice, put each condition in its own numbered group: ?filter[0][status][(ne)]=Draft&filter[1][status][(ne)]=Sent. Groups inside (or) are numbered the same way.
  • (not) wraps everything inside it: ?filter[(not)][status]=Sent&filter[(not)][language]=3 excludes messages that are both sent and French.

status can be filtered by name or by code.

Name Code
Draft 0
Scheduled 1
AB test in progress 2
Queuing 4
Sending 5
Transactional 7
Nurture 8
Sent 9
  • Names are matched ignoring case and surrounding spaces, and a space and an underscore are treated as the same: Sent, sent, AB test in progress, and ab_test_in_progress all work.
  • A code is used as given. A number that is not a status code (e.g. 3) is accepted and matches nothing.
  • An unknown name fails with the list of names: Invalid 'status' provided (possible values: 'Draft', 'Scheduled', 'AB test in progress', 'Queuing', 'Sending', 'Transactional', 'Nurture', 'Sent').
  • (ne) works with names and codes.
  • To match several statuses, use (or): ?filter[(or)][0][status]=Sent&filter[(or)][1][status]=Scheduled. (in) is not supported.

Invalid list parameters return HTTP 400. The limit, skip, and sort format errors are returned first; filter and sort field errors are then listed together:

{
"success": false,
"result_text": "Validation failed, see 'result_data' -> 'errors'",
"result_data": {
"errors": [
"Field 'folder' is not valid for filtering",
"'IN' is not a valid operator for the field 'status'"
]
}
}
Error Cause
Invalid 'limit': 'ten' limit is not a whole number.
Invalid 'skip': 'abc' skip is not a whole number.
Invalid 'sort': 'name' sort was sent without a field, e.g. ?sort=name.
'up' is not a valid sort direction Sort direction is not asc, desc, 1, or -1.
Field 'folder' is not valid for sorting The field does not exist.
Field 'folder' is not valid for filtering The field does not exist. Also returned for an unrecognised operator: ?filter[name][(foo)]=x gives Field '(foo)' is not valid for filtering.
'IN' is not a valid operator for the field 'status' The operator is not supported. The message names the SQL operator: IN, REGEXP, >, <, >=, or <=.
Invalid 'status' provided (possible values: ...) Not a status name. The message lists the valid names.
Field 'name' requires a scalar value An operator is given a list or group where a single value is expected, e.g. filter[name][(ne)][]=Gala.

A JSON array of message objects. Returns an empty array ([]) if no messages match.

[
{
"id": "2001",
"external_id": "3e8b1f6c9a2d4e7b0c5f8a1d3e6b9c2f",
"preview_url": "https://engage.envoke.com/m/a7c3e9f1b5d2/m/3e8b1f6c9a2d4e7b0c5f8a1d3e6b9c2f",
"create_time": "2026-10-06 10:15:42",
"modified_time": "2026-10-06 11:02:08",
"name": "Spring Season Announcement",
"group": "Productions",
"status": "Scheduled",
"send_time": "2026-10-20 09:00:00",
"sender": "Box Office <boxoffice@example.org>",
"reply_to": "Front of House <frontofhouse@example.org>",
"subject": "Our spring season is here",
"language": "en",
"recipient_subscription": "Season News",
"recipient_tag": "",
"recipient_segment": "",
"recipient_language": "",
"publish_archive": true,
"utm_tag_links": true
}
]

Times are in the account time zone with no offset (see Dates and time zones). html is never included in list responses.


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

Returns a single message object (the same shape as one item in the list response). Replace {ID} with the Envoke message ID. fields can be used to select fields; filter, sort, paging, and result_type parameters are ignored.

Add ?include_html=1 to include the message HTML. It is added as the last key, html. With include_html=0 or without the parameter, the HTML is left out. When fields is also set, list html in it to keep the HTML.

If the ID is not found, or belongs to a deleted message or a template, the API returns an empty array ([]).

{
"id": "2003",
"external_id": "9c4d2a7e1f5b3d8a6c0e4f2b7d9a1c5e",
"preview_url": "https://engage.envoke.com/m/a7c3e9f1b5d2/m/9c4d2a7e1f5b3d8a6c0e4f2b7d9a1c5e",
"create_time": "2026-10-06 10:40:11",
"modified_time": "2026-10-06 10:40:11",
"name": "Pirates of Penzance - Opening Night",
"group": "",
"status": "Draft",
"send_time": "",
"sender": "Box Office <boxoffice@example.org>",
"reply_to": null,
"subject": "",
"language": "en",
"recipient_subscription": "",
"recipient_tag": "",
"recipient_segment": "",
"recipient_language": "",
"publish_archive": false,
"utm_tag_links": false,
"html": "<html><body><h1>The Pirates of Penzance</h1><p>Curtain at 7:30 p.m.</p></body></html>"
}

Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages"

Returns the 10 most recently modified messages. Use limit (up to 100) and skip to page through the rest.

Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?sort%5Bid%5D=asc&limit=100&skip=100"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?sort%5Bname%5D=asc&limit=5"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5Bname%5D=Spring%20Season%20Announcement"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5Bsubject%5D=Our%20spring%20season%20is%20here"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5Bstatus%5D=Sent"

The same filter by status code:

Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5Bstatus%5D=9"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5Bstatus%5D%5B%28ne%29%5D=Draft"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5B%28or%29%5D%5B0%5D%5Bstatus%5D=Sent&filter%5B%28or%29%5D%5B1%5D%5Bstatus%5D=Scheduled"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?filter%5Bpublish_archive%5D=2"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?fields=id,name,status,send_time"

Response:

[
{ "id": "2002", "name": "Auditions Open", "status": "Draft", "send_time": "" },
{ "id": "2001", "name": "Spring Season Announcement", "status": "Scheduled", "send_time": "2026-10-20 09:00:00" }
]

With fields set and no limit, this returns up to 10,000 messages.

Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?result_type=kvp"

Response:

{ "2002": "Auditions Open", "2001": "Spring Season Announcement" }
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages?name=Auditions%20Open&fields=id,status&limit=1"

Response (an object, because limit=1):

{ "id": "2002", "status": "Draft" }
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages/2001"
Terminal window
curl -X GET -gs -u "$API_ID:$API_KEY" \
"https://e1.envoke.com/v2/messages/2003?include_html=1"

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.