API reference
Read, organize and send mail from the mailboxes you belong to.
These routes act only on mailboxes the signed-in person is a member of; keys get no mailboxes. See Mail.
GET /v1/orgs/:orgId/mail/mailboxes
The mailboxes the caller is a member of, with their aliases and signature. Keys get an empty list.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
| Query parameter | Type | Required | Notes |
|---|---|---|---|
labels | string | No | up to 100 characters |
Response 200
{
mailboxes: {
mailboxId: string
address: string
domain: string
displayName: string
signature: string
reminderMail: boolean
aliases: string[]
}[]
}
| {
mailboxes: {
mailboxId: string
address: string
domain: string
displayName: string
signature: string
reminderMail: boolean
aliases: string[]
}[]
labels: null | {
mailboxId: string
labels: {
labelId: string
name: string
}[]
}
}GET /v1/orgs/:orgId/mail/preferences
The caller's Mail preferences in the organization: categories (the inbox's category bar on or off) and push per mailbox (all, primary or off; primary unless changed).
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
Response 200
{
preferences: {
categories: boolean
push: {
[key: string]: "off" | "all" | "primary"
}
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
PATCH /v1/orgs/:orgId/mail/preferences
Changes the caller's Mail preferences: categories, and push for any of their mailboxes.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
categories | boolean | No | |
push | object | No | keys up to 100 characters; values: "all" | "primary" | "off" |
Response 200
{
preferences: {
categories: boolean
push: {
[key: string]: "off" | "all" | "primary"
}
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/threads
All Mailboxes: one page of a view (inbox, starred, sent, drafts) across every mailbox the caller reads in the organization, newest first; each row names its mailboxId. In the inbox, category narrows it. With q, search results across those mailboxes (outside Spam and Trash, whatever the view), paged the same way. The cursor holds one position per mailbox, so pages merge without gaps or repeats; a page can be short while cursor is set.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
view | "inbox" | "starred" | "sent" | "drafts" | No | "inbox" | |
category | "primary" | "transactions" | "updates" | "promotions" | No | ||
q | string | No | up to 200 characters | |
cursor | string | No | up to 20,000 characters |
Response 200
{
threads: {
mailboxId: string
orgId?: string
threadId: string
subject: string
snippet: string
participants: string[]
lastAt: number
messageCount: number
unreadCount: number
starred: boolean
labels: string[]
box: "archive" | "trash" | "inbox" | "spam"
hasAttachments: boolean
category: "primary" | "transactions" | "updates" | "promotions"
sender?: string
draftId?: string
snoozedUntil?: number
sendAt?: number
}[]
cursor: null | string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
GET /v1/orgs/:orgId/mail/counts
Unread inbox conversations per category across the caller's mailboxes in the organization (counts) and for each (mailboxes), and badge: unread Primary conversations in the mailboxes they get push for, in every organization they belong to (what the Mail app shows on its icon).
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
Response 200
{
counts: {
primary: number
transactions: number
updates: number
promotions: number
}
mailboxes: {
[key: string]: {
primary: number
transactions: number
updates: number
promotions: number
}
}
badge: number
complete: boolean
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
PATCH /v1/orgs/:orgId/mail/mailboxes/:mailboxId/settings
Sets the mailbox's signature.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
signature | string | No | up to 20,000 characters |
reminderMail | boolean | No |
Response 200
{
mailbox: {
mailboxId: string
address: string
domain: string
displayName: string
signature: string
reminderMail: boolean
aliases: string[]
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/limits
The organization's sending limits: messages per day, message size and recipients per message.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Response 200
{
limits: {
sendPerDay: number
maxMessageMb: number
maxRecipients: number
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads
One page of conversations in a view (inbox, starred, sent, drafts, archive, all, spam, trash, or label with label), newest first, optionally matching q. In the inbox, category (primary, transactions, updates, promotions) narrows it to one category. Each row has its category and sender. Pass cursor to continue.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
view | "inbox" | "starred" | "snoozed" | "sent" | "drafts" | "scheduled" | "archive" | "all" | "spam" | "trash" | "label" | No | "inbox" | |
label | any JSON | No | ||
q | string | No | up to 200 characters | |
category | "primary" | "transactions" | "updates" | "promotions" | No | ||
cursor | string | No | up to 2,000 characters |
Response 200
{
threads: {
mailboxId: string
orgId?: string
threadId: string
subject: string
snippet: string
participants: string[]
lastAt: number
messageCount: number
unreadCount: number
starred: boolean
labels: string[]
box: "archive" | "trash" | "inbox" | "spam"
hasAttachments: boolean
category: "primary" | "transactions" | "updates" | "promotions"
sender?: string
draftId?: string
snoozedUntil?: number
sendAt?: number
}[]
cursor: null | string
}Errors
| Status | Message |
|---|---|
400 | Choose a label. |
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/counts
Unread conversations in the mailbox's inbox per category; complete is false when the inbox was too large to count whole.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Response 200
{
counts: {
primary: number
transactions: number
updates: number
promotions: number
}
complete: boolean
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
PUT /v1/orgs/:orgId/mail/mailboxes/:mailboxId/senders/:address/category
Moves a sender's mail to a category: remembered for the mailbox's later mail from them, and applied now to threadId and the sender's other conversations in the inbox. Returns how many moved.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:address | An email address (URL-encoded): the alias, or the forwarding address; under marketing a person's email address or mobile number. |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
category | "primary" | "transactions" | "updates" | "promotions" | Yes | |
threadId | any JSON | No |
Response 200
{
moved: number
}Errors
| Status | Message |
|---|---|
400 | Enter a valid email address. |
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/actions
Applies one action to up to 100 conversations: archive, move to inbox, trash, spam, not spam, delete (from trash or spam only), read, unread, star, unstar, label or unlabel.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
threadIds | any JSON[] | Yes | 1–100 items |
action | "archive" | "inbox" | "trash" | "spam" | "not_spam" | "delete" | "read" | "unread" | "star" | "unstar" | "label" | "unlabel" | "snooze" | "unsnooze" | Yes | |
labelId | any JSON | No | |
until | integer | No |
Response 200
{
changed: number
}Errors
| Status | Message |
|---|---|
400 | Choose a label. |
400 | Choose when the conversation comes back. |
400 | Move the conversation to trash first. |
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Label not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/:threadId
A conversation and its messages, without bodies.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:threadId | Conversation id (thr_…), or in Mirage a thread id (mth_…). |
| Query parameter | Type | Required | Notes |
|---|---|---|---|
bodies | string | No |
Response 200
{
thread: {
mailboxId: string
orgId?: string
threadId: string
subject: string
snippet: string
participants: string[]
lastAt: number
messageCount: number
unreadCount: number
starred: boolean
labels: string[]
box: "archive" | "trash" | "inbox" | "spam"
hasAttachments: boolean
category: "primary" | "transactions" | "updates" | "promotions"
sender?: string
draftId?: string
snoozedUntil?: number
sendAt?: number
}
messages: {
sendAt?: number
messageId: string
threadId: string
kind: "in" | "sent" | "draft"
from: {
name?: string
address: string
}
to: {
name?: string
address: string
}[]
cc: {
name?: string
address: string
}[]
bcc: {
name?: string
address: string
}[]
replyTo: {
name?: string
address: string
}[]
subject: string
snippet: string
at: number
unread: boolean
size: number
rfcMessageId: string
attachments: {
index: number
filename: string
contentType: string
size: number
cid?: string
inline: boolean
}[]
spam: boolean
verdicts?: {
[key: string]: string
}
deliveryStatus?: "failed" | "rejected" | "bounced" | "complained" | "sent" | "delivered" | "sending" | "delayed"
deliveryDetail?: string
meta: {
unsubscribe?: {
http?: string
mailto?: string
oneClick?: boolean
}
signedBy?: string[]
mailedBy?: string
arc?: string
calendar?: string
automated?: boolean
origin?: {
ip: string
country: string
region?: string
city?: string
}
}
}[]
}
| {
bodies: {
[key: string]: {
text: string
html?: string
inline: {
[key: string]: string
}
}
}
thread: {
mailboxId: string
orgId?: string
threadId: string
subject: string
snippet: string
participants: string[]
lastAt: number
messageCount: number
unreadCount: number
starred: boolean
labels: string[]
box: "archive" | "trash" | "inbox" | "spam"
hasAttachments: boolean
category: "primary" | "transactions" | "updates" | "promotions"
sender?: string
draftId?: string
snoozedUntil?: number
sendAt?: number
}
messages: {
sendAt?: number
messageId: string
threadId: string
kind: "in" | "sent" | "draft"
from: {
name?: string
address: string
}
to: {
name?: string
address: string
}[]
cc: {
name?: string
address: string
}[]
bcc: {
name?: string
address: string
}[]
replyTo: {
name?: string
address: string
}[]
subject: string
snippet: string
at: number
unread: boolean
size: number
rfcMessageId: string
attachments: {
index: number
filename: string
contentType: string
size: number
cid?: string
inline: boolean
}[]
spam: boolean
verdicts?: {
[key: string]: string
}
deliveryStatus?: "failed" | "rejected" | "bounced" | "complained" | "sent" | "delivered" | "sending" | "delayed"
deliveryDetail?: string
meta: {
unsubscribe?: {
http?: string
mailto?: string
oneClick?: boolean
}
signedBy?: string[]
mailedBy?: string
arc?: string
calendar?: string
automated?: boolean
origin?: {
ip: string
country: string
region?: string
city?: string
}
}
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Thread not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/:threadId/messages/:messageId/body
A message's text and HTML, with short-lived links for inline images. Reading a received message marks it read.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:threadId | Conversation id (thr_…), or in Mirage a thread id (mth_…). |
:messageId | Message id (msg_…; Mirage messages are mmg_…). |
Response 200
{
text: string
html?: string
inline: {
[key: string]: string
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Message not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/:threadId/messages/:messageId/attachments/:index
A short-lived download link for an attachment.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:threadId | Conversation id (thr_…), or in Mirage a thread id (mth_…). |
:messageId | Message id (msg_…; Mirage messages are mmg_…). |
:index | The attachment's position in the message, from 0; or a Takeout archive's place in its import's files. |
Response 200
{
url: string
filename: string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Message not found |
404 | Attachment not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/:threadId/messages/:messageId/raw
A short-lived link to the original message (.eml).
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:threadId | Conversation id (thr_…), or in Mirage a thread id (mth_…). |
:messageId | Message id (msg_…; Mirage messages are mmg_…). |
Response 200
{
url: string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Message not found |
404 | No original for this message |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/:threadId/messages/:messageId/unsubscribe
Leaves the mailing list a message came from: one-click (RFC 8058) when the sender offers it, else an unsubscribe email from this mailbox; otherwise the link for the reader to open.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:threadId | Conversation id (thr_…), or in Mirage a thread id (mth_…). |
:messageId | Message id (msg_…; Mirage messages are mmg_…). |
Response 200
{
done: true
method: string
}
| {
done: false
url: string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Message not found |
404 | This message has no unsubscribe link. |
409 | This mailbox's domain was removed. |
409 | … isn't verified for sending yet. |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/threads/:threadId/messages/:messageId/invitation
The meeting a message carries and the event it became in this mailbox's calendars.
Auth: user access token or platform agent key · Scope: calendar:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:threadId | Conversation id (thr_…), or in Mirage a thread id (mth_…). |
:messageId | Message id (msg_…; Mirage messages are mmg_…). |
Response 200
{
invitation: {
timeZone: string
recurring: boolean
recurrenceId: null | number
organizer: null | {
email: string
name?: string
}
attendees: number
from: null | {
name?: string
email: string
}
event: null | {
calendarId: string
eventId: string
status: "cancelled" | "confirmed" | "tentative"
myStatus: null | "accepted" | "delegated" | "tentative" | "needs-action" | "declined"
isOrganizer: boolean
sequence: number
start: number
end: number
allDay: boolean
}
startDate?: string
endDate?: string
method: string
uid: string
summary: string
location: string
start: number
end: number
allDay: boolean
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
404 | Message not found |
404 | This message has no invitation. |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/uploads
Compose attachments go straight to the bucket; the link only accepts the declared size and type.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
filename | string | Yes | 1–255 characters; trimmed | |
contentType | string | No | "application/octet-stream" | up to 255 characters; matches ^[\w.+-]+\/[\w.+-]+$; trimmed |
size | integer | Yes | ≥ 0 |
Response 201
{
uploadId: string
url: string
headers: {
"content-type": string
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
413 | Attachments can be at most … MB in total. |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/send
Sends a message from the mailbox and files it in Sent. The domain must be verified. With replyTo, it's threaded as a reply; with draftId, the draft is removed. The response lists recipients that bounced or complained before.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body (up to 6 MB)
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
to | object[] | No | [] | up to 500 items |
to[].name | string | No | up to 200 characters; trimmed | |
to[].address | string | Yes | trimmed; lowercased | |
cc | object[] | No | [] | up to 500 items |
cc[].name | string | No | up to 200 characters; trimmed | |
cc[].address | string | Yes | trimmed; lowercased | |
bcc | object[] | No | [] | up to 500 items |
bcc[].name | string | No | up to 200 characters; trimmed | |
bcc[].address | string | Yes | trimmed; lowercased | |
subject | string | No | "" | up to 998 characters |
html | string | No | up to 2,000,000 characters | |
text | string | No | up to 2,000,000 characters | |
attachments | (object | object)[] | No | [] | up to 50 items |
replyTo | object | No | ||
replyTo.threadId | any JSON | Yes | ||
replyTo.messageId | any JSON | Yes | ||
draftId | any JSON | No | ||
sendAt | integer | No | ||
undoSeconds | integer | No | 1–30 |
Response 201
{
suppressed: {
address: string
reason: "bounce" | "complaint"
}[]
messageId: string
threadId: string
duplicate: boolean
box?: undefined
category: "primary" | "transactions" | "updates" | "promotions"
} | {
suppressed: {
address: string
reason: "bounce" | "complaint"
}[]
messageId: string
threadId: string
duplicate: boolean
box: "archive" | "trash" | "inbox" | "spam"
category?: "primary" | "transactions" | "updates" | "promotions"
}Response 202
{
draftId: string
threadId: string
sendAt: number
}Errors
| Status | Message |
|---|---|
400 | Add at least one recipient. |
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
409 | This mailbox's domain was removed. |
409 | … isn't verified for sending yet. |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/recipients/check
Recipients that bounced or complained before, so compose can warn.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
addresses | string[] | Yes | up to 500 items; each up to 254 characters |
Response 200
{
suppressed: {
address: string
reason: "bounce" | "complaint"
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/recipients/suggest
Address suggestions for compose and guest fields: the organization's people (their own mailboxes, by name), then contacts, then recent correspondents.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
q | string | No | "" | up to 200 characters |
Response 200
{
suggestions: {
name?: string
address: string
source: "recent" | "contact" | "directory"
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/drafts
Saves a new draft.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body (up to 6 MB)
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
to | object[] | No | [] | up to 500 items |
to[].name | string | No | up to 200 characters; trimmed | |
to[].address | string | Yes | trimmed; lowercased | |
cc | object[] | No | [] | up to 500 items |
cc[].name | string | No | up to 200 characters; trimmed | |
cc[].address | string | Yes | trimmed; lowercased | |
bcc | object[] | No | [] | up to 500 items |
bcc[].name | string | No | up to 200 characters; trimmed | |
bcc[].address | string | Yes | trimmed; lowercased | |
subject | string | No | "" | up to 998 characters |
html | string | No | up to 2,000,000 characters | |
text | string | No | up to 2,000,000 characters | |
attachments | (object | object)[] | No | [] | up to 50 items |
replyTo | object | No | ||
replyTo.threadId | any JSON | Yes | ||
replyTo.messageId | any JSON | Yes |
Response 201
{
draftId: string
threadId: string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/drafts/:draftId
A draft, for editing.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:draftId | Draft id: the draft's message id (msg_…). |
Response 200
{
draft: {
failed?: string
sendAt?: number
draftId: string
threadId: string
replyTo?: {
threadId: string
messageId: string
}
to: {
name?: string
address: string
}[]
cc: {
name?: string
address: string
}[]
bcc: {
name?: string
address: string
}[]
subject?: string
html?: string
text: string
attachments: {
uploadId: string
filename: string
contentType: string
size: number
cid?: string
inline?: boolean
} | {
threadId: string
messageId: string
index: number
filename: string
contentType: string
size: number
cid?: string
inline?: boolean
}[]
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
PUT /v1/orgs/:orgId/mail/mailboxes/:mailboxId/drafts/:draftId
Replaces a draft.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:draftId | Draft id: the draft's message id (msg_…). |
Request body (up to 6 MB)
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
to | object[] | No | [] | up to 500 items |
to[].name | string | No | up to 200 characters; trimmed | |
to[].address | string | Yes | trimmed; lowercased | |
cc | object[] | No | [] | up to 500 items |
cc[].name | string | No | up to 200 characters; trimmed | |
cc[].address | string | Yes | trimmed; lowercased | |
bcc | object[] | No | [] | up to 500 items |
bcc[].name | string | No | up to 200 characters; trimmed | |
bcc[].address | string | Yes | trimmed; lowercased | |
subject | string | No | "" | up to 998 characters |
html | string | No | up to 2,000,000 characters | |
text | string | No | up to 2,000,000 characters | |
attachments | (object | object)[] | No | [] | up to 50 items |
replyTo | object | No | ||
replyTo.threadId | any JSON | Yes | ||
replyTo.messageId | any JSON | Yes |
Response 200
{
draftId: string
threadId: string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
DELETE /v1/orgs/:orgId/mail/mailboxes/:mailboxId/drafts/:draftId/schedule
Takes a scheduled draft off the schedule (it stays a draft).
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:draftId | Draft id: the draft's message id (msg_…). |
Response 204 with no body.
Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
DELETE /v1/orgs/:orgId/mail/mailboxes/:mailboxId/drafts/:draftId
Discards a draft.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:draftId | Draft id: the draft's message id (msg_…). |
Response 204 with no body.
Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/filters
Inbound filters: conditions on received mail, actions on its conversation.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Response 200
{
filters: {
filterId: string
match: {
from?: string
to?: string
subject?: string
words?: string
hasAttachment?: boolean
}
actions: {
labelId?: string
archive?: boolean
read?: boolean
star?: boolean
trash?: boolean
forward?: string
}
enabled: boolean
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/filters
Creates an inbound filter: conditions on received mail (all must match), actions on its conversation. At most 100 per mailbox.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
match | object | Yes | |
match.from | string | No | up to 200 characters; trimmed |
match.to | string | No | up to 200 characters; trimmed |
match.subject | string | No | up to 200 characters; trimmed |
match.words | string | No | up to 200 characters; trimmed |
match.hasAttachment | boolean | No | |
actions | object | Yes | |
actions.labelId | any JSON | No | |
actions.archive | boolean | No | |
actions.read | boolean | No | |
actions.star | boolean | No | |
actions.trash | boolean | No | |
actions.forward | string | No | up to 254 characters; trimmed; lowercased |
enabled | boolean | No |
Response 201
{
filter: {
filterId: string
match: {
from?: string
to?: string
subject?: string
words?: string
hasAttachment?: boolean
}
actions: {
labelId?: string
archive?: boolean
read?: boolean
star?: boolean
trash?: boolean
forward?: string
}
enabled: boolean
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
PUT /v1/orgs/:orgId/mail/mailboxes/:mailboxId/filters/:filterId
Replaces a filter's conditions and actions, or turns it on or off.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:filterId | Filter id: a mail filter (flt_…) or a saved issue filter (ifl_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
match | object | Yes | |
match.from | string | No | up to 200 characters; trimmed |
match.to | string | No | up to 200 characters; trimmed |
match.subject | string | No | up to 200 characters; trimmed |
match.words | string | No | up to 200 characters; trimmed |
match.hasAttachment | boolean | No | |
actions | object | Yes | |
actions.labelId | any JSON | No | |
actions.archive | boolean | No | |
actions.read | boolean | No | |
actions.star | boolean | No | |
actions.trash | boolean | No | |
actions.forward | string | No | up to 254 characters; trimmed; lowercased |
enabled | boolean | No |
Response 200
{
filter: {
filterId: string
match: {
from?: string
to?: string
subject?: string
words?: string
hasAttachment?: boolean
}
actions: {
labelId?: string
archive?: boolean
read?: boolean
star?: boolean
trash?: boolean
forward?: string
}
enabled: boolean
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/filters/:filterId/apply
Runs a filter over conversations already in the mailbox (a few seconds here, the rest in the background).
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:filterId | Filter id: a mail filter (flt_…) or a saved issue filter (ifl_…). |
Response 200
{
conversations: number
scanned: number
background: boolean
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/forwarding
Forwarding addresses (filter action): added pending, confirmed with the code mailed to them.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Response 200
{
addresses: {
address: string
status: "pending" | "verified"
verifiedAt?: number
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/forwarding
Adds a forwarding address (or sends a new code to a pending one): the address gets a 6-digit code by email, valid 24 hours. Needs the mailbox's domain to be active; counts toward the daily sending limit.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
address | string | Yes | up to 254 characters; trimmed; lowercased |
Response 201
{
address: {
address: string
status: "pending"
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
409 | This mailbox's domain was removed. |
409 | … isn't verified for sending yet. |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/forwarding/verify
Confirms a forwarding address with the code it received; filters can then forward to it. Five wrong codes need a new one.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
address | string | Yes | up to 254 characters; trimmed; lowercased |
code | string | Yes | 4–12 characters; trimmed |
Response 200
{
address: {
address: string
status: "pending" | "verified"
verifiedAt?: number
}
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
DELETE /v1/orgs/:orgId/mail/mailboxes/:mailboxId/forwarding/:address
Removes a forwarding address; filters forwarding to it stop forwarding.
Auth: user access token or platform agent key · Scope: mail:send
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:address | An email address (URL-encoded): the alias, or the forwarding address; under marketing a person's email address or mobile number. |
Response 204 with no body.
Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
DELETE /v1/orgs/:orgId/mail/mailboxes/:mailboxId/filters/:filterId
Deletes a filter. Mail already filed stays where it is.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:filterId | Filter id: a mail filter (flt_…) or a saved issue filter (ifl_…). |
Response 204 with no body.
Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/orgs/:orgId/mail/mailboxes/:mailboxId/labels
The mailbox's labels, by name.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Response 200
{
labels: {
labelId: string
name: string
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
POST /v1/orgs/:orgId/mail/mailboxes/:mailboxId/labels
Creates a label. Names are unique in the mailbox, ignoring case.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | 1–60 characters; trimmed |
Response 201
{
label: {
labelId: string
name: string
}
}Errors
| Status | Message |
|---|---|
400 | A mailbox can have at most 200 labels. |
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
409 | A label with this name exists. |
DELETE /v1/orgs/:orgId/mail/mailboxes/:mailboxId/labels/:labelId
Deletes a label. Conversations stop showing it.
Auth: user access token or platform agent key · Scope: mail:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:mailboxId | Mailbox id (mbx_…). |
:labelId | Label id (lbl_…). |
Response 204 with no body.
Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
404 | Mailbox not found |
GET /v1/me/mail/mailboxes
The caller's mailboxes in every organization where they read mail, each with its orgId and aliases, and those organizations (orgs: orgId, slug, name).
Auth: user access token or platform agent key
Response 200
{
mailboxes: {
orgId: string
mailboxId: string
address: string
domain: string
displayName: string
signature: string
reminderMail: boolean
aliases: string[]
}[]
orgs: {
orgId: string
slug: string
name: string
}[]
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
GET /v1/me/mail/threads
All Inboxes across organizations: one page of a view (inbox, starred, sent, drafts) across every mailbox the caller reads in every organization, newest first; each row names its mailboxId and orgId, and actions on it go to that organization's mailbox routes. In the inbox, category narrows it; with q, search results across them (outside Spam and Trash). Access is checked on every page: a mailbox the caller loses stops appearing, and one they gain starts below the rows already returned. The cursor holds one position per mailbox and the last row returned.
Auth: user access token or platform agent key
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
view | "inbox" | "starred" | "sent" | "drafts" | No | "inbox" | |
category | "primary" | "transactions" | "updates" | "promotions" | No | ||
q | string | No | up to 200 characters | |
cursor | string | No | up to 40,000 characters |
Response 200
{
threads: {
mailboxId: string
orgId?: string
threadId: string
subject: string
snippet: string
participants: string[]
lastAt: number
messageCount: number
unreadCount: number
starred: boolean
labels: string[]
box: "archive" | "trash" | "inbox" | "spam"
hasAttachments: boolean
category: "primary" | "transactions" | "updates" | "promotions"
sender?: string
draftId?: string
snoozedUntil?: number
sendAt?: number
}[]
cursor: null | string
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |
GET /v1/me/mail/counts
Unread inbox conversations per category across the caller's mailboxes in every organization (counts) and for each (mailboxes), and badge: unread Primary conversations in the mailboxes they get push for.
Auth: user access token or platform agent key
Response 200
{
counts: {
primary: number
transactions: number
updates: number
promotions: number
}
mailboxes: {
[key: string]: {
primary: number
transactions: number
updates: number
promotions: number
}
}
badge: number
complete: boolean
}Errors
| Status | Message |
|---|---|
403 | Mailboxes are only available to members. |