> For the complete documentation index, see [llms.txt](https://docs.material.security/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.material.security/reference/api-v1/messages.md).

# 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**](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id) (`GET /api/v1/messages/{id}`): retrieves a single message by its encoded ID.
* [**Search Messages**](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search) (`POST /api/v1/messages/search`): starts an asynchronous search.
* [**Get Message Search Results**](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id) (`GET /api/v1/messages/search/{id}`): retrieves the status and results of a search.
* [**Move Messages to Inbox**](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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, plus `truncated` on search results.
* **`items`**: an array of message objects matching the search query.

Search results can be capped. When `meta.truncated` is true, the query matched more messages than the search returns, and `totalCount` reports that limit rather than the real number of matches. Narrow the query or the date range to see the rest.

Note that search is asynchronous. The [**Search Messages**](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search) endpoint returns a search ID (format `job.1.<base64>`) and status immediately; results are only present in the [**Get Message Search Results**](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id) 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**](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id) 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](https://docs.material.security/reference/api-v1/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**](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.
* [**Search Messages**](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search) can be limited by a daily budget counted in days searched, so each search uses one unit for every day its date range covers. Over the budget, the response is a `429` with a `Retry-After` header giving the seconds to wait before retrying. Check `X-RateLimit-Remaining` on each response to see how much budget is left, and shorten the date range to fit.

## Get Message

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

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Messages","description":"**Overview**\n\nThe 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.\n\nThese endpoints make up the Messages API:\n\n* **[Get Message](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** (`GET /api/v1/messages/{id}`): retrieves a single message by its encoded ID.  \n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** (`POST /api/v1/messages/search`): starts an asynchronous search.  \n* **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** (`GET /api/v1/messages/search/{id}`): retrieves the status and results of a search.  \n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n\n**Moving Messages Back to the Inbox**\n\nMove 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.\n\n**Response Structure**\n\nMessage 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:\n\n* **`meta`**: metadata about the result set, including `totalCount`, `limit`, `hasMore`, and `nextCursor` for pagination, plus `truncated` on search results.  \n* **`items`**: an array of message objects matching the search query.\n\nSearch results can be capped. When `meta.truncated` is true, the query matched more messages than the search returns, and `totalCount` reports that limit rather than the real number of matches. Narrow the query or the date range to see the rest.\n\nNote that search is asynchronous. The **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** endpoint returns a search ID (format `job.1.<base64>`) and status immediately; results are only present in the **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** response once `status` is `\"DONE\"`.\n\n**The `include` Parameter**\n\nBy 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](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** endpoint. Supported values are `content`, `attachments`, `issue`, `mailboxes`, and `links`. Pass multiple values as a comma-separated list (e.g. `include=content,attachments,links`).\n\n**Want a walkthrough?** \n\nReview [Hello World](https://docs.material.security/reference/api-v1/hello-world).\n\n**Pagination and Rate Limiting**\n\n* Material APIs use **cursor-based pagination**: you pass the `nextCursor` value from one response as the `cursor` parameter in the next request.  \n* The `limit` parameter controls page size on all paginated endpoints.  \n* Every paginated response includes a `meta` object with `totalCount`, `limit`, `hasMore`, and `nextCursor` to help you know where you are in the result set.  \n* When `hasMore` is false and `nextCursor` is null, you've reached the last page.\n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** can be limited by a daily budget counted in days searched, so each search uses one unit for every day its date range covers. Over the budget, the response is a `429` with a `Retry-After` header giving the seconds to wait before retrying. Check `X-RateLimit-Remaining` on each response to see how much budget is left, and shorten the date range to fit.\n"}],"servers":[{"url":"https://{domain}","description":"Material Security instance","variables":{"domain":{"default":"your-instance.on.material.security","description":"Your Material Security instance domain"}}}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-material-client-secret","description":"Material Security API key"}},"schemas":{"APIMessage":{"title":"APIMessage","description":"An email message.","type":"object","properties":{"id":{"description":"The encoded message ID. Format: `msg.1.<base64>`.","type":"string"},"headers":{"$ref":"#/components/schemas/APIMessageHeaders"},"links":{"description":"The links found in the message body. Populated only when `include=links` is specified.","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APILink"}}},"required":["meta","items"]},"issue":{"description":"The issue associated with this message. Populated only when `include=issue` is specified. Null if no issue is associated.","anyOf":[{"$ref":"#/components/schemas/APIIssueRef"},{"type":"null"}]},"content":{"description":"The body content of the message. Populated only when `include=content` is specified. Null if unavailable.","anyOf":[{"$ref":"#/components/schemas/APIMessageContent"},{"type":"null"}]},"attachments":{"description":"The attachments for this message. Populated only when `include=attachments` is specified.","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APIAttachment"}}},"required":["meta","items"]},"mailboxes":{"description":"The mailboxes in which this message appears. Populated only when `include=mailboxes` is specified.","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APIMailbox"}}},"required":["meta","items"]}},"required":["id","headers"]},"APIMessageHeaders":{"title":"APIMessageHeaders","description":"Header-derived fields for the message.","type":"object","properties":{"messageId":{"description":"The RFC 2822 Message-ID header value for this message.","type":"string"},"date":{"description":"The date the message was sent, in ISO 8601 format.","type":"string","format":"date-time"},"subject":{"description":"The subject line of the email. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"from":{"description":"The sender address of the message. Typically the From header, but may be the original sender for messages forwarded through customer-owned infrastructure. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"to":{"description":"The recipients on the To header. Addresses only; display names are not included.","type":"array","items":{"type":"string"}},"cc":{"description":"The recipients on the Cc header. Addresses only; display names are not included.","type":"array","items":{"type":"string"}},"bcc":{"description":"The recipients on the Bcc header. Addresses only; display names are not included. May include recipients reconstructed from envelope-level data when the `Bcc:` header was stripped before delivery.","type":"array","items":{"type":"string"}},"authResults":{"description":"Resolved SPF, DKIM, and DMARC results. `null` when no domain context is available to resolve your SEG settings against.","anyOf":[{"$ref":"#/components/schemas/APIAuthResults"},{"type":"null"}]}},"required":["messageId","date","subject","from","to","cc","bcc","authResults"]},"APIAuthResults":{"title":"APIAuthResults","description":"Resolved [authentication results](https://docs.material.security/learn-more/risk-areas/email-threats/investigate/issue-details) (SPF, DKIM, and DMARC) for the message. When you have a Secure Email Gateway (SEG) configured, values are pulled from the SEG’s preserved authentication-results header rather than the inline auth headers.","type":"object","properties":{"spf":{"description":"The resolved SPF authentication result.","anyOf":[{"type":"string","enum":["pass","none","neutral","temperror","permerror","softfail","policy","fail"]},{"type":"null"}]},"dkim":{"description":"The resolved DKIM authentication result.","anyOf":[{"type":"string","enum":["pass","none","neutral","temperror","permerror","policy","fail"]},{"type":"null"}]},"dmarc":{"description":"The resolved DMARC authentication result.","anyOf":[{"type":"string","enum":["pass","none","temperror","permerror","fail"]},{"type":"null"}]}},"required":["spf","dkim","dmarc"]},"CollectionMeta":{"title":"CollectionMeta","type":"object","properties":{"totalCount":{"description":"The total number of items matching the query.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"description":"The page size used for this response.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hasMore":{"description":"True if more items exist beyond the current page; false otherwise.","type":"boolean"},"nextCursor":{"description":"The cursor to fetch the next page of results. Pass this value to the `cursor` query parameter. Null if no more pages exist.","anyOf":[{"type":"string"},{"type":"null"}]}}},"APILink":{"title":"APILink","type":"object","properties":{"href":{"description":"The URL of the link.","type":"string"},"text":{"description":"The visible text of the link. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"type":{"description":"What kind of content the link comes from. Null if unavailable.","anyOf":[{"type":"string","enum":["a.href","img.src","script.src"]},{"type":"null"}]}},"required":["href","text","type"]},"APIIssueRef":{"title":"APIIssueRef","type":"object","properties":{"id":{"description":"The encoded ID of the associated issue. Format: `iss.1.<base64>`.","type":"string"}},"required":["id"]},"APIMessageContent":{"title":"APIMessageContent","type":"object","properties":{"parts":{"description":"The content parts that make up the message body.","type":"array","items":{"type":"object","properties":{"mime":{"description":"The MIME type of this content part (for example, `text/html`).","type":"string"},"body":{"description":"The body text of this content part.","type":"string"}},"required":["mime","body"]}}},"required":["parts"]},"APIAttachment":{"title":"APIAttachment","type":"object","properties":{"id":{"description":"The identifier for this attachment.","type":"string"},"filename":{"description":"The original filename of the attachment. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"mime":{"description":"The MIME type of the attachment (for example, `application/pdf`).","type":"string"},"size":{"description":"The size of the attachment in bytes.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hashes":{"description":"File hashes, if available","type":"object","properties":{"sha256":{"description":"The SHA-256 hash of the attachment. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"md5":{"description":"The MD5 hash of the attachment. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["sha256","md5"]}},"required":["id","filename","mime","size"]},"APIMailbox":{"title":"APIMailbox","type":"object","properties":{"accountId":{"description":"The encoded ID of the account that owns this mailbox. Format: `acct.1.<base64>`.","type":"string"},"email":{"description":"The email address of the mailbox.","type":"string"},"tags":{"description":"The tags associated with this mailbox.","type":"array","items":{"type":"string"}}},"required":["accountId","email","tags"]},"ValidationErrorResponse":{"title":"Validation Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"},"validationFailures":{"description":"List of individual validation failures when request parameters fail schema validation.","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["error"]},"ErrorResponse":{"title":"Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"}},"required":["error"]}}},"paths":{"/api/v1/messages/{id}":{"get":{"operationId":"getMessage","summary":"Get Message","description":"Retrieves the full details of a single email message by its encoded ID, including sender, recipients, subject, date, and attachment metadata.","tags":["Messages"],"parameters":[{"in":"path","name":"id","schema":{"description":"The encoded ID of the message to retrieve. Format: `msg.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"required":true,"description":"The encoded ID of the message to retrieve. Format: `msg.1.<base64>`."},{"in":"query","name":"include","schema":{"description":"A comma-separated list of additional fields to include in the response. Valid values: `content`, `attachments`, `issue`, `mailboxes`, `links`.","type":"string"},"description":"A comma-separated list of additional fields to include in the response. Valid values: `content`, `attachments`, `issue`, `mailboxes`, `links`."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIMessage"}}}},"400":{"description":"Bad request: invalid parameters or request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized: missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: the API key doesn't have permission to perform this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found: the requested resource doesn't exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests: you've reached a rate limit. When the response includes a `Retry-After` header, wait that many seconds before you try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Search Messages

> 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. If your instance has a daily search budget, each search uses one unit of it for every day its date range covers, not one per request. Successful and 429 responses then carry \`X-RateLimit-Limit\`, \`X-RateLimit-Remaining\`, and \`X-RateLimit-Reset\` (Unix seconds), counted in days searched. Over the budget, the response is a 429 with a \`Retry-After\` header. A rejected search uses no budget, so a search with a shorter date range can still go through. The budget resets at midnight UTC.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Messages","description":"**Overview**\n\nThe 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.\n\nThese endpoints make up the Messages API:\n\n* **[Get Message](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** (`GET /api/v1/messages/{id}`): retrieves a single message by its encoded ID.  \n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** (`POST /api/v1/messages/search`): starts an asynchronous search.  \n* **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** (`GET /api/v1/messages/search/{id}`): retrieves the status and results of a search.  \n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n\n**Moving Messages Back to the Inbox**\n\nMove 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.\n\n**Response Structure**\n\nMessage 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:\n\n* **`meta`**: metadata about the result set, including `totalCount`, `limit`, `hasMore`, and `nextCursor` for pagination, plus `truncated` on search results.  \n* **`items`**: an array of message objects matching the search query.\n\nSearch results can be capped. When `meta.truncated` is true, the query matched more messages than the search returns, and `totalCount` reports that limit rather than the real number of matches. Narrow the query or the date range to see the rest.\n\nNote that search is asynchronous. The **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** endpoint returns a search ID (format `job.1.<base64>`) and status immediately; results are only present in the **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** response once `status` is `\"DONE\"`.\n\n**The `include` Parameter**\n\nBy 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](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** endpoint. Supported values are `content`, `attachments`, `issue`, `mailboxes`, and `links`. Pass multiple values as a comma-separated list (e.g. `include=content,attachments,links`).\n\n**Want a walkthrough?** \n\nReview [Hello World](https://docs.material.security/reference/api-v1/hello-world).\n\n**Pagination and Rate Limiting**\n\n* Material APIs use **cursor-based pagination**: you pass the `nextCursor` value from one response as the `cursor` parameter in the next request.  \n* The `limit` parameter controls page size on all paginated endpoints.  \n* Every paginated response includes a `meta` object with `totalCount`, `limit`, `hasMore`, and `nextCursor` to help you know where you are in the result set.  \n* When `hasMore` is false and `nextCursor` is null, you've reached the last page.\n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** can be limited by a daily budget counted in days searched, so each search uses one unit for every day its date range covers. Over the budget, the response is a `429` with a `Retry-After` header giving the seconds to wait before retrying. Check `X-RateLimit-Remaining` on each response to see how much budget is left, and shorten the date range to fit.\n"}],"servers":[{"url":"https://{domain}","description":"Material Security instance","variables":{"domain":{"default":"your-instance.on.material.security","description":"Your Material Security instance domain"}}}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-material-client-secret","description":"Material Security API key"}},"schemas":{"SearchMessagesBody":{"title":"SearchMessagesBody","description":"Parameters for starting a message search.","type":"object","properties":{"mqlSearchString":{"description":"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.","type":"string"},"startDate":{"description":"The start of the search time window in ISO 8601 format.","type":"string","format":"date-time"},"endDate":{"description":"The end of the search time window in ISO 8601 format.","type":"string","format":"date-time"},"tenant":{"description":"The encoded IDs of the tenants to search (format `tnt.1.<base64>`). If you leave this out, the search covers every tenant your API token can reach. If you include a tenant your token can't reach, the response is a 403. Call `GET /tenants` for the IDs.","minItems":1,"type":"array","items":{"type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"}}},"required":["mqlSearchString","startDate","endDate"]},"SearchMessagesResponse":{"title":"SearchMessagesResponse","type":"object","properties":{"id":{"description":"The encoded ID of the search. Format: `job.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"status":{"description":"The current status of the search. Valid values: `CREATED` (queued), `STARTED` (running), `DONE` (results ready).","type":"string","enum":["CREATED","STARTED","DONE"]}},"required":["id","status"]},"ValidationErrorResponse":{"title":"Validation Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"},"validationFailures":{"description":"List of individual validation failures when request parameters fail schema validation.","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["error"]},"ErrorResponse":{"title":"Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"}},"required":["error"]}}},"paths":{"/api/v1/messages/search":{"post":{"operationId":"searchMessages","summary":"Search Messages","description":"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. If your instance has a daily search budget, each search uses one unit of it for every day its date range covers, not one per request. Successful and 429 responses then carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (Unix seconds), counted in days searched. Over the budget, the response is a 429 with a `Retry-After` header. A rejected search uses no budget, so a search with a shorter date range can still go through. The budget resets at midnight UTC.","tags":["Messages"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMessagesBody"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchMessagesResponse"}}}},"400":{"description":"Bad request: invalid parameters or request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized: missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: the API key doesn't have permission to perform this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found: the requested resource doesn't exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests: you've reached a rate limit. When the response includes a `Retry-After` header, wait that many seconds before you try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Move Messages to Inbox

> 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 don't resolve to a message your token can reach come back in \`notFound\` and aren't 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 whoever created it, so a token created by someone 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. Successful and 429 responses carry \`X-RateLimit-Limit\`, \`X-RateLimit-Remaining\`, and \`X-RateLimit-Reset\` (Unix seconds), counted in messages. A 429 also carries \`Retry-After\` and spends no budget, so a smaller batch within \`X-RateLimit-Remaining\` can still go through.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Messages","description":"**Overview**\n\nThe 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.\n\nThese endpoints make up the Messages API:\n\n* **[Get Message](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** (`GET /api/v1/messages/{id}`): retrieves a single message by its encoded ID.  \n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** (`POST /api/v1/messages/search`): starts an asynchronous search.  \n* **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** (`GET /api/v1/messages/search/{id}`): retrieves the status and results of a search.  \n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n\n**Moving Messages Back to the Inbox**\n\nMove 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.\n\n**Response Structure**\n\nMessage 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:\n\n* **`meta`**: metadata about the result set, including `totalCount`, `limit`, `hasMore`, and `nextCursor` for pagination, plus `truncated` on search results.  \n* **`items`**: an array of message objects matching the search query.\n\nSearch results can be capped. When `meta.truncated` is true, the query matched more messages than the search returns, and `totalCount` reports that limit rather than the real number of matches. Narrow the query or the date range to see the rest.\n\nNote that search is asynchronous. The **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** endpoint returns a search ID (format `job.1.<base64>`) and status immediately; results are only present in the **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** response once `status` is `\"DONE\"`.\n\n**The `include` Parameter**\n\nBy 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](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** endpoint. Supported values are `content`, `attachments`, `issue`, `mailboxes`, and `links`. Pass multiple values as a comma-separated list (e.g. `include=content,attachments,links`).\n\n**Want a walkthrough?** \n\nReview [Hello World](https://docs.material.security/reference/api-v1/hello-world).\n\n**Pagination and Rate Limiting**\n\n* Material APIs use **cursor-based pagination**: you pass the `nextCursor` value from one response as the `cursor` parameter in the next request.  \n* The `limit` parameter controls page size on all paginated endpoints.  \n* Every paginated response includes a `meta` object with `totalCount`, `limit`, `hasMore`, and `nextCursor` to help you know where you are in the result set.  \n* When `hasMore` is false and `nextCursor` is null, you've reached the last page.\n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** can be limited by a daily budget counted in days searched, so each search uses one unit for every day its date range covers. Over the budget, the response is a `429` with a `Retry-After` header giving the seconds to wait before retrying. Check `X-RateLimit-Remaining` on each response to see how much budget is left, and shorten the date range to fit.\n"}],"servers":[{"url":"https://{domain}","description":"Material Security instance","variables":{"domain":{"default":"your-instance.on.material.security","description":"Your Material Security instance domain"}}}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-material-client-secret","description":"Material Security API key"}},"schemas":{"MoveMessagesToInboxBody":{"title":"MoveMessagesToInboxBody","type":"object","properties":{"messageIds":{"description":"The encoded IDs of the messages to move back to the inbox. Up to 200 per request.","minItems":1,"maxItems":200,"type":"array","items":{"description":"An encoded message ID. Format: `msg.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"}}},"required":["messageIds"]},"MoveMessagesToInboxResponse":{"title":"MoveMessagesToInboxResponse","type":"object","properties":{"id":{"description":"The encoded ID of the queued move job. Format: `job.1.<base64>`. Quote this when you contact support. You can't check the job's progress through this API.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"status":{"description":"Always `CREATED`. The move runs in the background and this endpoint never reports it finishing.","type":"string","const":"CREATED"},"accepted":{"description":"How many of the supplied message IDs resolved to a message you can reach, and were queued for the move.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"notFound":{"description":"The supplied message IDs that didn't resolve to a message you can reach. These weren't queued. An ID appears here whether the message doesn't exist or sits outside the tenants your token covers.","type":"array","items":{"description":"An encoded message ID. Format: `msg.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"}},"mailboxCount":{"description":"This is the highest number of mailbox copies the move could touch, summed across the accepted messages. Copies already in the inbox are skipped when the move runs, so fewer may actually change.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","status","accepted","notFound","mailboxCount"]},"ValidationErrorResponse":{"title":"Validation Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"},"validationFailures":{"description":"List of individual validation failures when request parameters fail schema validation.","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["error"]},"ErrorResponse":{"title":"Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"}},"required":["error"]}}},"paths":{"/api/v1/messages/move-to-inbox":{"post":{"operationId":"moveMessagesToInbox","summary":"Move Messages to Inbox","description":"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 don't resolve to a message your token can reach come back in `notFound` and aren't 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 whoever created it, so a token created by someone 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. Successful and 429 responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (Unix seconds), counted in messages. A 429 also carries `Retry-After` and spends no budget, so a smaller batch within `X-RateLimit-Remaining` can still go through.","tags":["Messages"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveMessagesToInboxBody"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveMessagesToInboxResponse"}}}},"400":{"description":"Bad request: invalid parameters or request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized: missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: the API key doesn't have permission to perform this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found: the requested resource doesn't exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests: you've reached a rate limit. When the response includes a `Retry-After` header, wait that many seconds before you try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get Message Search Results

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

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Messages","description":"**Overview**\n\nThe 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.\n\nThese endpoints make up the Messages API:\n\n* **[Get Message](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** (`GET /api/v1/messages/{id}`): retrieves a single message by its encoded ID.  \n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** (`POST /api/v1/messages/search`): starts an asynchronous search.  \n* **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** (`GET /api/v1/messages/search/{id}`): retrieves the status and results of a search.  \n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n\n**Moving Messages Back to the Inbox**\n\nMove 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.\n\n**Response Structure**\n\nMessage 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:\n\n* **`meta`**: metadata about the result set, including `totalCount`, `limit`, `hasMore`, and `nextCursor` for pagination, plus `truncated` on search results.  \n* **`items`**: an array of message objects matching the search query.\n\nSearch results can be capped. When `meta.truncated` is true, the query matched more messages than the search returns, and `totalCount` reports that limit rather than the real number of matches. Narrow the query or the date range to see the rest.\n\nNote that search is asynchronous. The **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** endpoint returns a search ID (format `job.1.<base64>`) and status immediately; results are only present in the **[Get Message Search Results](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-search-id)** response once `status` is `\"DONE\"`.\n\n**The `include` Parameter**\n\nBy 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](https://docs.material.security/reference/api-v1/messages#get-api-v1-messages-id)** endpoint. Supported values are `content`, `attachments`, `issue`, `mailboxes`, and `links`. Pass multiple values as a comma-separated list (e.g. `include=content,attachments,links`).\n\n**Want a walkthrough?** \n\nReview [Hello World](https://docs.material.security/reference/api-v1/hello-world).\n\n**Pagination and Rate Limiting**\n\n* Material APIs use **cursor-based pagination**: you pass the `nextCursor` value from one response as the `cursor` parameter in the next request.  \n* The `limit` parameter controls page size on all paginated endpoints.  \n* Every paginated response includes a `meta` object with `totalCount`, `limit`, `hasMore`, and `nextCursor` to help you know where you are in the result set.  \n* When `hasMore` is false and `nextCursor` is null, you've reached the last page.\n* **[Move Messages to Inbox](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-move-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.\n* **[Search Messages](https://docs.material.security/reference/api-v1/messages#post-api-v1-messages-search)** can be limited by a daily budget counted in days searched, so each search uses one unit for every day its date range covers. Over the budget, the response is a `429` with a `Retry-After` header giving the seconds to wait before retrying. Check `X-RateLimit-Remaining` on each response to see how much budget is left, and shorten the date range to fit.\n"}],"servers":[{"url":"https://{domain}","description":"Material Security instance","variables":{"domain":{"default":"your-instance.on.material.security","description":"Your Material Security instance domain"}}}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-material-client-secret","description":"Material Security API key"}},"schemas":{"MessageSearchResponse":{"title":"MessageSearchResponse","type":"object","properties":{"id":{"description":"The encoded ID of the search. Format: `job.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"status":{"description":"The current status of the search. Valid values: `CREATED` (queued), `STARTED` (running), `DONE` (results ready).","type":"string","enum":["CREATED","STARTED","DONE"]},"data":{"description":"The search results. Present only when `status` is `\"DONE\"`.","type":"object","properties":{"meta":{"description":"The pagination metadata for the search results, including `totalCount`, `limit`, `hasMore`, `nextCursor`, and `truncated`.","type":"object","properties":{"totalCount":{"description":"The total number of items matching the query.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"description":"The page size used for this response.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hasMore":{"description":"True if more items exist beyond the current page; false otherwise.","type":"boolean"},"nextCursor":{"description":"The cursor to fetch the next page of results. Pass this value to the `cursor` query parameter. Null if no more pages exist.","anyOf":[{"type":"string"},{"type":"null"}]},"truncated":{"description":"True when the query matched more messages than the search returns, so `items` holds only the first part of the matches and `totalCount` reports that limit rather than the real number of matches. Narrow the query or the date range to see the rest.","type":"boolean"}}},"items":{"description":"The list of messages matching the search query.","type":"array","items":{"$ref":"#/components/schemas/APIMessageItem"}}},"required":["meta","items"]}},"required":["id","status"]},"APIMessageItem":{"title":"APIMessageItem","type":"object","properties":{"id":{"description":"The encoded message ID. Format: `msg.1.<base64>`.","type":"string"},"headers":{"$ref":"#/components/schemas/APIMessageItemHeaders"}},"required":["id"]},"APIMessageItemHeaders":{"title":"APIMessageItemHeaders","type":"object","properties":{"date":{"description":"The date the message was sent, in ISO 8601 format.","type":"string","format":"date-time"},"from":{"description":"The sender address of the message. Null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["date","from"]},"ValidationErrorResponse":{"title":"Validation Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"},"validationFailures":{"description":"List of individual validation failures when request parameters fail schema validation.","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["error"]},"ErrorResponse":{"title":"Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"}},"required":["error"]}}},"paths":{"/api/v1/messages/search/{id}":{"get":{"operationId":"getMessageSearch","summary":"Get Message Search Results","description":"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.","tags":["Messages"],"parameters":[{"in":"path","name":"id","schema":{"description":"The encoded ID of the search job to retrieve. Format: `job.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"required":true,"description":"The encoded ID of the search job to retrieve. Format: `job.1.<base64>`."},{"in":"query","name":"cursor","schema":{"description":"The pagination cursor returned in a previous response. Pass this value to retrieve the next page of results.","type":"string"},"description":"The pagination cursor returned in a previous response. Pass this value to retrieve the next page of results."},{"in":"query","name":"limit","schema":{"description":"The maximum number of items to return per page.","type":"integer"},"description":"The maximum number of items to return per page."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageSearchResponse"}}}},"400":{"description":"Bad request: invalid parameters or request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized: missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: the API key doesn't have permission to perform this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found: the requested resource doesn't exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests: you've reached a rate limit. When the response includes a `Retry-After` header, wait that many seconds before you try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.material.security/reference/api-v1/messages.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
