For the complete documentation index, see llms.txt. This page is also available as Markdown.

Messages

Overview

The Messages API provides programmatic access to email messages ingested by Material Security. Retrieve a specific message by ID, run an asynchronous search across messages using MQL (Material Query Language) to find messages matching criteria such as sender, subject, or date range, and move messages back to the inbox when a remediation turns out to be a false positive.

These endpoints make up the Messages API:

  • Get Message (GET /api/v1/messages/{id}): retrieves a single message by its encoded ID.

  • Search Messages (POST /api/v1/messages/search): starts an asynchronous search.

  • Get Message Search Results (GET /api/v1/messages/search/{id}): retrieves the status and results of a search.

  • Move Messages to Inbox (POST /api/v1/messages/move-to-inbox): queues a move of messages back to the inbox in every mailbox your token can reach.

Moving Messages Back to the Inbox

Move to Inbox is the one endpoint in this API that changes mailboxes, and it undoes a placement rather than creating one: it returns messages Material moved to spam, trash, or Surge Protection to the inbox. The work runs in the background across every mailbox your token can reach that holds the message, so a 200 means the request was accepted, not that any message has moved. Copies that are already in the inbox are skipped, so the mailboxCount in the response is an upper bound. In the audit log, the message_moved_to_inbox entries carrying a uAcctId are the authoritative record of what actually moved; a single further entry carrying numRequested is written when the request is queued and records the scope of the request rather than any completed move.

Response Structure

Message responses return an ID and a headers object containing date, subject, sender, recipients, and authentication results by default. The search endpoints follow the standard paginated two-part structure similar to the Issues endpoints:

  • meta: metadata about the result set, including totalCount, limit, hasMore, and nextCursor for pagination.

  • items: an array of message objects matching the search query.

Note that search is asynchronous. The Search Messages endpoint returns a search ID (format job.1.<base64>) and status immediately; results are only present in the Get Message Search Results response once status is "DONE".

The include Parameter

By default, message responses return the message ID and a headers object (date, subject, sender, recipients, authentication results). To keep responses lightweight, related data is excluded unless explicitly requested with the include parameter on the Get Message endpoint. Supported values are content, attachments, issue, mailboxes, and links. Pass multiple values as a comma-separated list (e.g. include=content,attachments,links).

Want a walkthrough?

Review Hello World.

Pagination and Rate Limiting

  • Material APIs use cursor-based pagination: you pass the nextCursor value from one response as the cursor parameter in the next request.

  • The limit parameter controls page size on all paginated endpoints.

  • Every paginated response includes a meta object with totalCount, limit, hasMore, and nextCursor to help you know where you are in the result set.

  • When hasMore is false and nextCursor is null, you've reached the last page.

  • Move Messages to Inbox is rate limited per tenant by the number of messages a request targets, not by the number of requests. Over the limit, the response is a 429 with a Retry-After header giving the seconds to wait before retrying.

Get Message

get

Retrieves the full details of a single email message by its encoded ID, including sender, recipients, subject, date, and attachment metadata.

Authorizations
x-material-client-secretstringRequired

Material Security API key

Path parameters
idstringRequired

The encoded ID of the message to retrieve. Format: msg.1.<base64>.

Example: msg.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$
Query parameters
includestringOptional

A comma-separated list of additional fields to include in the response. Valid values: content, attachments, issue, mailboxes, links.

Example: links
Responses
200

Successful response

application/json

An email message.

idstringRequired

The encoded message ID. Format: msg.1.<base64>.

Example: msg.1.ZXhhbXBsZV9pZF8xMjM
get/api/v1/messages/{id}
GET /api/v1/messages/{id} HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Accept: */*
{
  "id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
  "headers": {
    "messageId": "text",
    "date": "2024-01-15T12:00:00.000Z",
    "subject": "text",
    "from": "sender@example.com",
    "to": [
      "text"
    ],
    "cc": [
      "text"
    ],
    "bcc": [
      "text"
    ],
    "authResults": {
      "spf": "pass",
      "dkim": "pass",
      "dmarc": "pass"
    }
  },
  "links": {
    "meta": {
      "totalCount": 1,
      "limit": 1,
      "hasMore": true,
      "nextCursor": "text"
    },
    "items": [
      {
        "href": "https://example.com/login",
        "text": "text",
        "type": "a.href"
      }
    ]
  },
  "issue": {
    "id": "iss.1.ZXhhbXBsZV9pZF8xMjM"
  },
  "content": {
    "parts": [
      {
        "mime": "text/html",
        "body": "text"
      }
    ]
  },
  "attachments": {
    "meta": {
      "totalCount": 1,
      "limit": 1,
      "hasMore": true,
      "nextCursor": "text"
    },
    "items": [
      {
        "id": "text",
        "filename": "text",
        "mime": "application/pdf",
        "size": 1,
        "hashes": {
          "sha256": "text",
          "md5": "text"
        }
      }
    ]
  },
  "mailboxes": {
    "meta": {
      "totalCount": 1,
      "limit": 1,
      "hasMore": true,
      "nextCursor": "text"
    },
    "items": [
      {
        "accountId": "acct.1.ZXhhbXBsZV9pZF8xMjM",
        "email": "user@example.com",
        "tags": [
          "text"
        ]
      }
    ]
  }
}

Search Messages

post

Starts an asynchronous search across ingested email messages using an MQL query and a date range. Returns a search ID (format job.1.<base64>) to use when polling for results.

Authorizations
x-material-client-secretstringRequired

Material Security API key

Body

Parameters for starting a message search.

mqlSearchStringstringRequired

The MQL (Material Query Language) query used to filter messages. For example, message.from.addresses=="attacker@example.com" and message.subject:~"urgent payment" finds messages from that sender whose subject contains "urgent payment." The API accepts the same queries as message search in Material, so the easiest way to get valid syntax is to build your query there. Navigate to Explorer > Messages, then write your query in Query, which suggests field names and operators as you type. You can also set up your search in Quick or Prompt, then switch to Query to copy the query it creates. When you send the query in a JSON body, escape its double quotes.

Example: message.from.addresses=="attacker@example.com" and message.subject:~"urgent payment"
startDatestring · date-timeRequired

The start of the search time window in ISO 8601 format.

Example: 2024-01-01T00:00:00.000Z
endDatestring · date-timeRequired

The end of the search time window in ISO 8601 format.

Example: 2024-02-01T00:00:00.000Z
uDomainIdsstring[]Optional

A list of tenant domain IDs to filter results by. If omitted, searches across all tenants the caller has access to.

Responses
200

Successful response

application/json
idstringRequired

The encoded ID of the search. Format: job.1.<base64>.

Example: job.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$
statusstring · enumRequired

The current status of the search. Valid values: CREATED (queued), STARTED (running), DONE (results ready).

Possible values:
post/api/v1/messages/search
POST /api/v1/messages/search HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 186

{
  "mqlSearchString": "message.from.addresses==\"attacker@example.com\" and message.subject:~\"urgent payment\"",
  "startDate": "2026-01-01T00:00:00.000Z",
  "endDate": "2026-01-02T00:00:00.000Z"
}
{
  "id": "job.1.ZXhhbXBsZV9pZF8xMjM",
  "status": "CREATED"
}

Move Messages to Inbox

post

Moves up to 200 messages back to the inbox in every mailbox your token can reach that holds them, clearing the spam, trash, and Surge Protection placements Material applied. Use this to undo a remediation that turned out to be a false positive. The move runs in the background, so a 200 means the request was accepted and queued, not that any message has moved yet. It is best-effort and safe to repeat: each copy is re-checked against the mail provider at move time, and copies already in the inbox, in mailboxes Material can no longer reach, or on unsupported providers are skipped without failing the request. Because of that, mailboxCount is an upper bound rather than a result. The message_moved_to_inbox audit log entries carrying a uAcctId are the authoritative record of what actually moved; one further entry carrying numRequested is written when the request is queued and records its scope, not that anything moved. Message IDs that do not resolve to a message your token can reach come back in notFound and are simply not queued; if none of them resolve, the response is a 404 and nothing is queued. Requires the Modify Messages permission. An API token carries the permissions of the user who created it, so a token minted by a user without that permission receives a 403. Requests are rate limited by the number of messages they target, not by request count, against a single organization-wide budget shared by every token; over the limit the response is a 429 with a Retry-After header.

Authorizations
x-material-client-secretstringRequired

Material Security API key

Body
messageIdsstring[] · min: 1 · max: 200Required

The encoded IDs of the messages to move back to the inbox. Up to 200 per request.

Example: msg.1.ZXhhbXBsZV9pZF8xMjM
Responses
200

Successful response

application/json
idstringRequired

The encoded ID of the queued move job. Format: job.1.<base64>. Quote this when contacting support; it is not pollable through this API.

Example: job.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$
statusconst: CREATEDRequired

Always CREATED. The move runs in the background and this endpoint never reports it finishing.

acceptedinteger · min: -9007199254740991 · max: 9007199254740991Required

How many of the supplied message IDs resolved to a message you can reach, and were queued for the move.

notFoundstring[]Required

The supplied message IDs that did not resolve to a message you can reach. These were not queued. An ID appears here whether the message does not exist or is outside the tenants your token covers.

Example: msg.1.ZXhhbXBsZV9pZF8xMjM
mailboxCountinteger · min: -9007199254740991 · max: 9007199254740991Required

Upper bound on the mailbox copies the move was queued against, summed across accepted messages. Copies already in the inbox are skipped at move time, so fewer may actually change.

post/api/v1/messages/move-to-inbox
POST /api/v1/messages/move-to-inbox HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 44

{
  "messageIds": [
    "msg.1.ZXhhbXBsZV9pZF8xMjM"
  ]
}
{
  "id": "job.1.ZXhhbXBsZV9pZF8xMjM",
  "status": "text",
  "accepted": 1,
  "notFound": [
    "msg.1.ZXhhbXBsZV9pZF8xMjM"
  ],
  "mailboxCount": 1
}

Get Message Search Results

get

Retrieves the status and results of a message search. Poll this endpoint until status is DONE, at which point the response includes a paginated list of matching messages.

Authorizations
x-material-client-secretstringRequired

Material Security API key

Path parameters
idstringRequired

The encoded ID of the search job to retrieve. Format: job.1.<base64>.

Example: job.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$
Query parameters
cursorstringOptional

The pagination cursor returned in a previous response. Pass this value to retrieve the next page of results.

Example: eyJ2IjoxLCJvIjoyNSwibCI6MjV9
limitintegerOptional

The maximum number of items to return per page.

Example: 25
Responses
200

Successful response

application/json
idstringRequired

The encoded ID of the search. Format: job.1.<base64>.

Example: job.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$
statusstring · enumRequired

The current status of the search. Valid values: CREATED (queued), STARTED (running), DONE (results ready).

Possible values:
get/api/v1/messages/search/{id}
GET /api/v1/messages/search/{id} HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Accept: */*
{
  "id": "job.1.ZXhhbXBsZV9pZF8xMjM",
  "status": "CREATED",
  "data": {
    "meta": {
      "totalCount": 1,
      "limit": 1,
      "hasMore": true,
      "nextCursor": "text",
      "truncated": true
    },
    "items": [
      {
        "id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
        "headers": {
          "date": "2024-01-15T12:00:00.000Z",
          "from": "text"
        }
      }
    ]
  }
}

Last updated

Was this helpful?