Issues
The Issues API provides programmatic access to security issues detected by Material. Query and paginate issues, filter by status, drill down into a specific issue for details including severity and classification, and retrieve the associated email messages along with link and attachment counts.
These endpoints make up the Issues API:
List Issues (
GET /api/v1/issues): filter and retrieve a paginated list of issuesGet Issue (
GET /api/v1/issues/{id}): retrieve a single issue by its encoded IDList Issue Messages (
GET /api/v1/issues/{id}/messages): retrieve the email messages associated with a specific issueUpdate Issue (
PATCH /api/v1/issues/{id}): update the status, classification, assignee, or remediation actions on an existing issue
Response Structure
Most Issues API responses (except Update Issue) follow a consistent two-part structure:
meta: metadata about the result set, includingtotalCount,limit,hasMore, andnextCursorfor pagination.items: an array containing the actual results, such as issues or messages.
This pattern applies to all paginated endpoints, as well as to nested collections within a single issue response, for example, comments, accounts, messages, and files each return their own meta and items when requested via the include parameter.
The include Parameter
By default, issue responses return a core set of fields: ID, name, status, severity, classification, detection rule, primary entity, and key lifecycle timestamps. To keep responses lightweight, related data is excluded unless explicitly requested with the include parameter. Supported values are comments, accounts, messages, and files. Pass multiple values as a comma-separated list (e.g. include=comments,accounts).
Want a walkthrough?
Review Hello World.
Pagination and Rate Limiting
Material APIs use cursor-based pagination: you pass the
nextCursorvalue from one response as thecursorparameter in the next request.The
limitparameter controls page size on all paginated endpoints.Every paginated response includes a
metaobject withtotalCount,limit,hasMore, andnextCursorto help you know where you are in the result set.When
hasMoreis false andnextCursoris null, you've reached the last page.
Retrieves a paginated list of security issues detected by Material. Filter by status to surface open or in-progress threats, and use the include parameter to pull in related data such as comments, accounts, and messages in a single request.
Material Security API key
A comma-separated list of additional fields to include in the response. Valid values: comments, accounts, messages, files. Use dot notation to select sub-fields (for example, accounts.email). Use * to include all available fields.
comments,accountsIssue statuses to filter the response by, specified as a comma-separated list.
open,in_progressComma-separated list of severity levels to filter by.
04_high,05_criticalComma-separated list of primary entity types to filter by: tenant, account, group, file, message, or oauth_app. app is accepted as a deprecated alias for oauth_app and will be removed in a future release.
account,messageComma-separated list of detection types to filter by.
threat,email_threatComma-separated list of encoded detection IDs (det.1.<base64>) to filter by.
det.1.ZXhhbXBsZV9pZF8xMjMComma-separated list of fields to sort by, applied in the order given, with a stable secondary sort by issue ID. Each field may be suffixed with :asc or :desc to specify direction; a bare field uses the natural default direction for that field, which is descending for severity and any keyEvents.* timestamp. Valid fields: severity, keyEvents.created, keyEvents.statusChanged. Default when omitted: severity,keyEvents.statusChanged (both descending).
severity,keyEvents.statusChangedThe pagination cursor returned in a previous response. Pass this value to retrieve the next page of results.
eyJ2IjoxLCJvIjoyNSwibCI6MjV9The maximum number of items to return per page.
25Successful response
Bad request: invalid parameters or request body
Unauthorized: missing or invalid API key
Forbidden: the API key doesn't have permission to perform this action
Not found: the requested resource doesn't exist
Too many requests: the client has exceeded a rate limit and should retry later
Internal server error
GET /api/v1/issues HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Accept: */*
{
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "iss.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Credential phishing attempt",
"status": "open",
"severity": "01_info",
"classification": "safe",
"recommendedClassification": "malicious",
"recommendedClassificationStatus": "staged",
"analysis": {
"insights": [
"category.credential_phishing",
"ttp.link_based"
]
},
"primaryEntity": {
"type": "tenant",
"account": {
"id": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"email": "user@example.com",
"displayName": "Jane Doe"
},
"message": {
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"date": "2024-01-15T12:00:00.000Z",
"from": "sender@example.com"
},
"file": {
"id": "file.1.ZXhhbXBsZV9pZF8xMjM",
"name": "invoice.pdf",
"mimeType": "application/pdf"
},
"tenant": {
"csp": "microsoft"
},
"group": {
"id": "grp.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Engineering"
},
"oauthApp": {
"id": "oapp.1.MDAwMDAwMDAtMDAwMC00MDAwLTgwMDAtMDAwMDAwMDAwMDAw",
"name": "Acme CRM"
}
},
"keyEvents": {
"created": {
"at": "2026-01-01T00:00:00.000Z"
},
"opened": {
"at": "2026-01-01T00:00:00.000Z"
},
"statusChanged": {
"at": "2026-01-01T00:00:00.000Z"
}
},
"tenantId": "tnt.1.ZXhhbXBsZV9pZF8xMjM",
"detection": {
"id": "det.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Credential phishing",
"description": "Detects messages containing links to credential harvesting pages.",
"type": "vulnerability"
},
"assigneeId": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"ignoreReason": "false_positive",
"snoozedUntil": "2026-01-01T00:00:00.000Z",
"supportedRemediations": [
"email_threat"
],
"remediation": [
{
"type": "text",
"action": "text"
}
],
"comments": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"comment": "Confirmed email threat, remediated mailboxes.",
"author": "admin@example.com",
"timestamp": "2026-01-01T00:00:00.000Z"
}
]
},
"accounts": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"email": "user@example.com",
"displayName": "Jane Doe"
}
]
},
"messages": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text",
"numLinks": 1,
"numAttachments": 1
},
"items": [
{
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"headers": {
"date": "2024-01-15T12:00:00.000Z",
"from": "text"
}
}
]
},
"files": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "file.1.ZXhhbXBsZV9pZF8xMjM",
"name": "invoice.pdf",
"mimeType": "application/pdf"
}
]
}
}
]
}Retrieves the full details of a single issue by its encoded ID, including severity, classification, primary entity, detection rule, and key lifecycle timestamps.
Material Security API key
The encoded ID of the issue to retrieve. Format: iss.1.<base64>.
iss.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$A comma-separated list of additional fields to include in the response. Valid values: comments, accounts, messages, files. Use dot notation to select sub-fields (for example, accounts.email). Use * to include all available fields.
comments,accountsSuccessful response
A security issue representing a detected threat or anomaly. In app, view these under Issues.
The encoded issue ID. Format: iss.1.<base64>.
iss.1.ZXhhbXBsZV9pZF8xMjMIssue display name derived from the detection rule that triggered it
Credential phishing attemptCurrent issue status: open, in_progress, resolved, ignored, or snoozed.
Issue severity level: 01_info, 02_low, 03_medium, 04_high, or 05_critical.
Issue classification (safe, malicious, spam, unknown), or null if not yet classified.
The classification Material suggests, shown in the console as "Suggested classification". Read-only, and null when nothing is suggested. Check recommendedClassificationStatus before treating a value here as a live suggestion: on an OAuth app issue a rejected suggestion keeps its value so the disagreement stays readable. The four issue values are narrower than the five an OAuth app carries, so two different app verdicts can read the same here and a suggestion that escalates the committed classification can look like agreement. For the exact suggestion read recommendedClassification on the app named by primaryEntity.oauthApp.id, which needs OAuth app read access, and check that its issueId is this issue before relying on it.
maliciousPossible values: Whether the suggestion in recommendedClassification is still live. staged means it is awaiting a decision, and is what the console displays in place of classification. accepted means it became the committed classification, whether an admin accepted it or Material committed it automatically. rejected means an admin decided otherwise; only reachable on an OAuth app issue, because an email threat withdraws a rejected suggestion instead. Null whenever recommendedClassification is null.
stagedPossible values: The encoded tenant ID. Format: tnt.1.<base64>. Null if no tenant is associated.
tnt.1.ZXhhbXBsZV9pZF8xMjMThe encoded account ID of the assignee. Format: acct.1.<base64>. Null if the issue is unassigned.
acct.1.ZXhhbXBsZV9pZF8xMjMWhy the status was set to "ignored", or null if status is not "ignored".
When the snoozed issue will reopen. Null if the issue is not snoozed.
The remediation to apply to the issue. The order does not matter. Each must have a type from supportedRemediations.
Bad request: invalid parameters or request body
Unauthorized: missing or invalid API key
Forbidden: the API key doesn't have permission to perform this action
Not found: the requested resource doesn't exist
Too many requests: the client has exceeded a rate limit and should retry later
Internal server error
GET /api/v1/issues/{id} HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Accept: */*
{
"id": "iss.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Credential phishing attempt",
"status": "open",
"severity": "01_info",
"classification": "safe",
"recommendedClassification": "malicious",
"recommendedClassificationStatus": "staged",
"analysis": {
"insights": [
"category.credential_phishing",
"ttp.link_based"
]
},
"primaryEntity": {
"type": "tenant",
"account": {
"id": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"email": "user@example.com",
"displayName": "Jane Doe"
},
"message": {
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"date": "2024-01-15T12:00:00.000Z",
"from": "sender@example.com"
},
"file": {
"id": "file.1.ZXhhbXBsZV9pZF8xMjM",
"name": "invoice.pdf",
"mimeType": "application/pdf"
},
"tenant": {
"csp": "microsoft"
},
"group": {
"id": "grp.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Engineering"
},
"oauthApp": {
"id": "oapp.1.MDAwMDAwMDAtMDAwMC00MDAwLTgwMDAtMDAwMDAwMDAwMDAw",
"name": "Acme CRM"
}
},
"keyEvents": {
"created": {
"at": "2026-01-01T00:00:00.000Z"
},
"opened": {
"at": "2026-01-01T00:00:00.000Z"
},
"statusChanged": {
"at": "2026-01-01T00:00:00.000Z"
}
},
"tenantId": "tnt.1.ZXhhbXBsZV9pZF8xMjM",
"detection": {
"id": "det.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Credential phishing",
"description": "Detects messages containing links to credential harvesting pages.",
"type": "vulnerability"
},
"assigneeId": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"ignoreReason": "false_positive",
"snoozedUntil": "2026-01-01T00:00:00.000Z",
"supportedRemediations": [
"email_threat"
],
"remediation": [
{
"type": "text",
"action": "text"
}
],
"comments": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"comment": "Confirmed email threat, remediated mailboxes.",
"author": "admin@example.com",
"timestamp": "2026-01-01T00:00:00.000Z"
}
]
},
"accounts": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"email": "user@example.com",
"displayName": "Jane Doe"
}
]
},
"messages": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text",
"numLinks": 1,
"numAttachments": 1
},
"items": [
{
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"headers": {
"date": "2024-01-15T12:00:00.000Z",
"from": "text"
}
}
]
},
"files": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "file.1.ZXhhbXBsZV9pZF8xMjM",
"name": "invoice.pdf",
"mimeType": "application/pdf"
}
]
}
}Updates the status, classification, assignee, or remediation actions on an existing issue. Only fields included in the request body are changed. Supports setting ignore reasons, snooze windows, and email threat remediation actions such as deleting messages, adding warning banners, or redirecting links and attachments.
Material Security API key
The encoded ID of the issue to retrieve. Format: iss.1.<base64>.
iss.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$Fields to update on the issue. Only provided fields are changed.
New issue status: open, in_progress, resolved, ignored, or snoozed. To ignore or snooze, you must set ignoreReason or snoozedUntil.
New issue classification: safe, malicious, spam, or unknown. When set without an explicit remediation, the default remediation for that classification is applied automatically.
The encoded account ID of the new assignee. Format: acct.1.<base64>. Null to unassign.
acct.1.ZXhhbXBsZV9pZF8xMjMWhy the status was set to "ignored". Setting this will also set the status to "ignored".
When the snoozed issue will reopen. Setting this will also set the status to "snoozed".
The remediation to apply to the issue. The order does not matter. Each must have a type from supportedRemediations. If conflicting actions are included, only the strictest will be kept. This replaces the list entirely, it is not merged.
Successful response
A security issue representing a detected threat or anomaly. In app, view these under Issues.
The encoded issue ID. Format: iss.1.<base64>.
iss.1.ZXhhbXBsZV9pZF8xMjMIssue display name derived from the detection rule that triggered it
Credential phishing attemptCurrent issue status: open, in_progress, resolved, ignored, or snoozed.
Issue severity level: 01_info, 02_low, 03_medium, 04_high, or 05_critical.
Issue classification (safe, malicious, spam, unknown), or null if not yet classified.
The classification Material suggests, shown in the console as "Suggested classification". Read-only, and null when nothing is suggested. Check recommendedClassificationStatus before treating a value here as a live suggestion: on an OAuth app issue a rejected suggestion keeps its value so the disagreement stays readable. The four issue values are narrower than the five an OAuth app carries, so two different app verdicts can read the same here and a suggestion that escalates the committed classification can look like agreement. For the exact suggestion read recommendedClassification on the app named by primaryEntity.oauthApp.id, which needs OAuth app read access, and check that its issueId is this issue before relying on it.
maliciousPossible values: Whether the suggestion in recommendedClassification is still live. staged means it is awaiting a decision, and is what the console displays in place of classification. accepted means it became the committed classification, whether an admin accepted it or Material committed it automatically. rejected means an admin decided otherwise; only reachable on an OAuth app issue, because an email threat withdraws a rejected suggestion instead. Null whenever recommendedClassification is null.
stagedPossible values: The encoded tenant ID. Format: tnt.1.<base64>. Null if no tenant is associated.
tnt.1.ZXhhbXBsZV9pZF8xMjMThe encoded account ID of the assignee. Format: acct.1.<base64>. Null if the issue is unassigned.
acct.1.ZXhhbXBsZV9pZF8xMjMWhy the status was set to "ignored", or null if status is not "ignored".
When the snoozed issue will reopen. Null if the issue is not snoozed.
The remediation to apply to the issue. The order does not matter. Each must have a type from supportedRemediations.
Bad request: invalid parameters or request body
Unauthorized: missing or invalid API key
Forbidden: the API key doesn't have permission to perform this action
Not found: the requested resource doesn't exist
Too many requests: the client has exceeded a rate limit and should retry later
Internal server error
PATCH /api/v1/issues/{id} HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 205
{
"status": "open",
"classification": "safe",
"assigneeId": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"ignoreReason": "false_positive",
"snoozedUntil": "2026-01-01T00:00:00.000Z",
"remediation": [
{
"type": "text",
"action": "text"
}
]
}{
"id": "iss.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Credential phishing attempt",
"status": "open",
"severity": "01_info",
"classification": "safe",
"recommendedClassification": "malicious",
"recommendedClassificationStatus": "staged",
"analysis": {
"insights": [
"category.credential_phishing",
"ttp.link_based"
]
},
"primaryEntity": {
"type": "tenant",
"account": {
"id": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"email": "user@example.com",
"displayName": "Jane Doe"
},
"message": {
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"date": "2024-01-15T12:00:00.000Z",
"from": "sender@example.com"
},
"file": {
"id": "file.1.ZXhhbXBsZV9pZF8xMjM",
"name": "invoice.pdf",
"mimeType": "application/pdf"
},
"tenant": {
"csp": "microsoft"
},
"group": {
"id": "grp.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Engineering"
},
"oauthApp": {
"id": "oapp.1.MDAwMDAwMDAtMDAwMC00MDAwLTgwMDAtMDAwMDAwMDAwMDAw",
"name": "Acme CRM"
}
},
"keyEvents": {
"created": {
"at": "2026-01-01T00:00:00.000Z"
},
"opened": {
"at": "2026-01-01T00:00:00.000Z"
},
"statusChanged": {
"at": "2026-01-01T00:00:00.000Z"
}
},
"tenantId": "tnt.1.ZXhhbXBsZV9pZF8xMjM",
"detection": {
"id": "det.1.ZXhhbXBsZV9pZF8xMjM",
"name": "Credential phishing",
"description": "Detects messages containing links to credential harvesting pages.",
"type": "vulnerability"
},
"assigneeId": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"ignoreReason": "false_positive",
"snoozedUntil": "2026-01-01T00:00:00.000Z",
"supportedRemediations": [
"email_threat"
],
"remediation": [
{
"type": "text",
"action": "text"
}
],
"comments": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"comment": "Confirmed email threat, remediated mailboxes.",
"author": "admin@example.com",
"timestamp": "2026-01-01T00:00:00.000Z"
}
]
},
"accounts": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "acct.1.ZXhhbXBsZV9pZF8xMjM",
"email": "user@example.com",
"displayName": "Jane Doe"
}
]
},
"messages": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text",
"numLinks": 1,
"numAttachments": 1
},
"items": [
{
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"headers": {
"date": "2024-01-15T12:00:00.000Z",
"from": "text"
}
}
]
},
"files": {
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text"
},
"items": [
{
"id": "file.1.ZXhhbXBsZV9pZF8xMjM",
"name": "invoice.pdf",
"mimeType": "application/pdf"
}
]
}
}Retrieves the paginated list of email messages associated with a specific issue. The response includes link and attachment counts across all related messages, useful for quickly assessing the scope of a threat.
Material Security API key
The encoded ID of the issue to retrieve. Format: iss.1.<base64>.
iss.1.ZXhhbXBsZV9pZF8xMjMPattern: ^[a-z]{1,6}\.[0-9]{1,2}\.[A-Za-z0-9_-]+$A comma-separated list of additional fields to include in the response. Valid values: comments, accounts, messages, files. Use dot notation to select sub-fields (for example, accounts.email). Use * to include all available fields.
comments,accountsThe pagination cursor returned in a previous response. Pass this value to retrieve the next page of results.
eyJ2IjoxLCJvIjoyNSwibCI6MjV9The maximum number of items to return per page.
25Successful response
Bad request: invalid parameters or request body
Unauthorized: missing or invalid API key
Forbidden: the API key doesn't have permission to perform this action
Not found: the requested resource doesn't exist
Too many requests: the client has exceeded a rate limit and should retry later
Internal server error
GET /api/v1/issues/{id}/messages HTTP/1.1
Host: your-instance.on.material.security
x-material-client-secret: YOUR_API_KEY
Accept: */*
{
"meta": {
"totalCount": 1,
"limit": 1,
"hasMore": true,
"nextCursor": "text",
"numLinks": 1,
"numAttachments": 1
},
"items": [
{
"id": "msg.1.ZXhhbXBsZV9pZF8xMjM",
"headers": {
"date": "2024-01-15T12:00:00.000Z",
"from": "text"
}
}
]
}Last updated
Was this helpful?

