Query messages
const url = 'https://api.inboxcnx.com/v1/messages/query';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"filter":{"operator":"OR","conditions":[{"q":"invoice"},{"from":"accounts@example.com"}]},"sort":[{"property":"receivedAt","isAscending":false}],"limit":25}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.inboxcnx.com/v1/messages/query \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "filter": { "operator": "OR", "conditions": [ { "q": "invoice" }, { "from": "accounts@example.com" } ] }, "sort": [ { "property": "receivedAt", "isAscending": false } ], "limit": 25 }'Finds stored mail with a filter tree that combines conditions with AND, OR and NOT, for searches a flat query string cannot express. Conditions nest to any depth. Every condition field a plain GET /v1/messages accepts is also valid inside a filter tree.
A condition object (for example { "from": "alice@example.com" }) matches messages satisfying all of its fields. Wrap conditions in an operator node to combine them explicitly:
{
"operator": "OR",
"conditions": [
{
"q": "invoice"
},
{
"from": "accounts@example.com"
}
]
}
This matches messages where the search text matches “invoice” OR the sender is accounts@example.com.
Omit filter entirely to match every message the caller can see. The filter tree is limited to 6 levels of nesting and 40 conditions in total; a tree that exceeds either limit is rejected with filter_depth_exceeded or filter_condition_count_exceeded.
Results are paginated the same way as GET /v1/messages; include: ["total"] adds the number of matches.
Requires the read:messages scope.
Authorizations
Section titled “Authorizations”Request Body
Section titled “Request Body”object
object
How to combine conditions. AND matches only if every condition matches; OR matches if any condition matches; NOT matches only if none of the conditions match.
object
Full-text search across subject, body, and every address field (from/to/cc/bcc). Matches inflected word forms in the message’s own language, not only the exact word typed.
Exact sender address match (not a substring search). Matches only if this exact address appears in From.
Exact recipient address match (not a substring search). Matches only if this exact address appears in To.
Only messages received at or after this instant (inclusive).
Only messages received strictly before this instant.
Only messages whose total size in bytes is at least this value.
Only messages whose total size in bytes is at most this value.
Only messages carrying this JMAP keyword, e.g. $flagged or $seen.
Only messages that do NOT carry this JMAP keyword.
Only messages carrying this label: either a system role (e.g. inbox, sent) or a source-specific custom label (e.g. a Gmail label).
Only messages that do NOT carry this label, e.g. trash to leave out trashed mail.
Only messages belonging to this source provider’s own thread id (Gmail/M365/IMAP thread id).
Only messages belonging to this InboxCNX thread id, as returned by GET /v1/threads.
Only messages ingested through this connection grant.
Only messages whose source-specific payload object contains this shape. Every field given here must be present in payload, matching at any nesting depth; extra fields elsewhere in payload do not disqualify a match. This checks containment only: ranges (greater/less than, between) and substring matches against nested values are not supported.
object
How to sort the results, as an array with exactly one entry: [{ property, isAscending }]. A longer array is rejected. Omit to sort by receivedAt descending (newest first). Relevance sorting is not available here; use sort=relevance on GET /v1/messages instead.
object
Opaque pagination cursor: a previous response’s nextCursor or prevCursor, passed back verbatim. A cursor issued under one sort order is rejected if reused with another.
Page size, between 1 and 200. Default 50.
total adds the number of matching results, counted up to 10000.
Example
{ "filter": { "operator": "OR", "conditions": [ { "q": "invoice" }, { "from": "accounts@example.com" } ] }, "sort": [ { "property": "receivedAt", "isAscending": false } ], "limit": 25}Responses
Section titled “Responses”A page of message summaries, without body and attachments
object
object
object
object
object
object
object
object
object
object
object
object
object
Pass back as cursor for the next page. Null on the last page.
Pass back as cursor for the previous page. Null on the first page.
Present only when requested with include. exact is false once the count reaches 10000 (or the depth cap of a relevance search); count is then that cap.
object
Example
{ "data": [ { "source": "gmail", "labels": { "system": [ "inbox" ] } } ]}Invalid filter tree, malformed cursor, or a tree past the depth/count limit
object
object
Example generated
{ "error": { "code": "example", "message": "example" }}The credential lacks the read:messages scope
object
object
Example generated
{ "error": { "code": "example", "message": "example" }}The query exceeded the read timeout
object
object
Example generated
{ "error": { "code": "example", "message": "example" }}