APIReference
The MySendbox API.
One REST API for both products. Send transactional email from your app with Dispatch, and work with your AI agent's mailboxes: read mail, approve or reject what the agent wants to do, and write drafts.
Overview
- Base URL:
https://api.mysendbox.com. Every route is under/v1. - Requests and responses are JSON. Send
Content-Type: application/jsonwith a body. - Times are Unix timestamps in milliseconds, such as
createdAt. - The email and template routes need Dispatch (the Email product) turned on for your team. The mailbox routes are for Agents.
- Using an agent such as Claude, ChatGPT or Cursor? Connect it over MCP instead: Bring your own agent.
Endpoints
POST /v1/emails
POST /v1/emails/batch
GET /v1/emails
GET /v1/emails/{id}
POST /v1/emails/{id}/cancel
GET /v1/templates
GET /v1/templates/{id or name}
POST /v1/templates
PATCH /v1/templates/{id or name}
DELETE /v1/templates/{id or name}
GET /v1/mailboxes
GET /v1/mailboxes/{id}/storage
GET /v1/mailboxes/{id}/messages
GET /v1/mailboxes/{id}/messages/{messageId}
POST /v1/mailboxes/{id}/messages/{messageId}/agent
GET /v1/mailboxes/{id}/actions
GET /v1/mailboxes/{id}/actions/{actionId}
POST /v1/mailboxes/{id}/actions/{actionId}/approve
POST /v1/mailboxes/{id}/actions/{actionId}/reject
POST /v1/mailboxes/{id}/drafts
Authentication
A team owner creates API keys in the dashboard at app.mysendbox.com, under Integrations → API keys. The key is shown once. Send it as a bearer token on every request:
Authorization: Bearer msb_live_…
- No key, or a malformed header:
401withmissing API key. - An unknown or revoked key:
401withinvalid API key. - Keys belong to your team. A mailbox that isn't yours returns
404, the same as one that doesn't exist.
For AI agents: sign up with one call
An agent can create its own workspace with no account and no email. It gets a mailbox at once (an address on our agent domain), an API key with every scope, and an activation link. Receiving works straight away; sending starts once a person opens the link and starts the 7-day trial ($1, card required). The key and the link are shown once.
curl -X POST https://api.mysendbox.com/v1/signup \
-H "Content-Type: application/json" \
-d '{ "name": "Acme booking agent", "mailbox": "bookings", "accept_terms": true }'
{
"workspace": { "id": "tnt_01k8…", "name": "Acme booking agent", "status": "inactive" },
"mailbox": { "id": "mbx_01k8…", "address": "bookings-k3m9qx@…" },
"api_key": "msb_live_…",
"activate_url": "https://app.mysendbox.com/activate#act_…",
"next": "Receiving works now. Give activate_url to a person …"
}
name— 2 to 80 characters.mailbox— optional label, 2 to 20 lowercase letters, digits or hyphens; a random suffix is added.accept_terms— must betrue: the terms and the acceptable use policy.- The activation link lets a person start the plan, buy credits, issue a new API key if the agent lost its own, and take ownership with an email sign-in. Whoever has it can do those things: hand it only to the person who'll pay.
GET /v1/account(any key) — status (inactive,trialing,active…),can_send, credits and mailboxes.POST /v1/account/activation-link— a new link; earlier ones stop working.- The address only replies in conversations someone else started. Your own domain and Dispatch need an owner (take ownership first).
- Limits: 3 sign-ups a day per network. A workspace nobody paid for or claimed within 7 days is switched off: its key is revoked and its mailbox removed.
Scopes
Each key has scopes. Give it only the ones it needs. A request outside them gets 403 with this key lacks the … scope.
emails:send— send and cancel email.emails:read— read the email log and templates.templates:write— create, update and delete templates.messages:read— list mailboxes and read their messages.agent:run— run the agent on a message.actions:read— read agent actions.actions:write— approve and reject agent actions.drafts:write— create drafts.messages:writeandreplies:send— used by the MCP server to tidy mailboxes and send replies. No REST route uses them.
Errors
Errors return a status code and a JSON body with one message:
{ "error": "subject is required" }
400— the body isn't JSON, or a field is missing or malformed.401— no API key, or it's invalid or revoked.402— your team has no plan (no plan), or not enough credits for these emails with automatic top-up off (not enough credits). Each email uses 1 credit.403— the key lacks a scope, or Dispatch isn't turned on for your team.404— the route, email, template, mailbox, message or action doesn't exist.409— a conflict: anIdempotency-Keyreused with a different request, a template name that's taken, an email that's no longer scheduled, or an action that's no longer pending.422— the email or template doesn't pass validation, such as an unverified From domain.500— something failed on our side:{ "error": "internal error" }.
Idempotency
Send an Idempotency-Key header with POST /v1/emails or POST /v1/emails/batch so a retry never sends twice. Use something tied to the event, such as receipt-A-2291.
- 1 to 256 printable ASCII characters, no spaces. Anything else is a
400. - Keys are kept for 24 hours.
- The same key with the same body returns the same email IDs, and nothing new is sent.
- The same key with a different body is a
409. - Single sends and batches keep separate keys.
Send an email
POST /v1/emails · scope emails:send
Accepts one email for sending and returns its ID with 202. Sending happens right after; follow it with Get an email. The From address must be on a domain you've added and verified, and the domain must be active.
fromstring, required —billing@acme.exampleorAcme <billing@acme.example>. Display names up to 100 characters.tostring or array — recipients. At least one ofto,ccorbccis required, and at most 50 in total.cc,bccstring or array, optionalreply_tostring or array, optional — also accepted asreplyTo.subjectstring, required without a template — up to 998 characters.html,textstring — the body. One is required without a template. Up to 1,000,000 characters each.templatestring or object, optional — a template ID or name, or{ "id": "…", "variables": { … } }(nameworks in place ofid). See Templates.variablesobject, optional — template variables, whentemplateis a string.attachmentsarray, optional — up to 20, 10 MB in total. Each is{ "filename", "content", "content_type" }:contentis base64, andcontent_typeis optional (it's taken from the file extension when left out).headersobject, optional — up to 20. OnlyX-*headers,List-UnsubscribeandList-Unsubscribe-Post. Values up to 1,000 characters.tagsobject or array, optional — up to 10, as{ "order": "A-2291" }or[{ "name": "order", "value": "A-2291" }]. Letters, digits,_and-only.scheduled_atstring, optional — an ISO 8601 date-time up to 72 hours ahead. A time in the past sends now. Also accepted asscheduledAt.trackingboolean, optional — link click tracking for this email. Left out, the sending domain's setting applies (off unless you turn it on under Domains). See Link click tracking.
curl https://api.mysendbox.com/v1/emails \
-H "Authorization: Bearer msb_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: receipt-A-2291" \
-d '{
"from": "Acme <billing@acme.example>",
"to": ["jane@example.com"],
"subject": "Your receipt #A-2291",
"html": "<p>Thanks for your payment.</p>",
"tags": { "order": "A-2291" }
}'
{ "id": "em_01k8r2m4qd7x9c3vtw5n6hbj0e" }
The API is for transactional email. A request with more than 10 identical emails (same subject and body) is refused as a broadcast, with 422.
Link click tracking
Off by default. With it on, each http or https link in the HTML part goes through a redirect on your tracking domain (such as links.acme.example, set up under Domains), so you can see which links were clicked: in the email's clicks, in the dashboard, and as the email.clicked webhook event (once per link, on the first click by a person). Opens aren't tracked.
- Left as written: the text part,
mailto:andtel:links, the unsubscribe link, and links that look like sign-in, password reset or verification links. To leave any other link alone, adddata-msb-notrackto it:<a href="…" data-msb-notrack>(the attribute is removed before sending). - Send sign-in links, password resets and codes with
"tracking": falseto be sure they're never rewritten. - Mail filters such as Microsoft Defender open links before people do. Those visits are kept with
suspectedBot: true, aren't counted and don't fire the webhook. - Clicks are kept 90 days; tracked links keep redirecting for a year. No IP addresses are stored.
Send a batch
POST /v1/emails/batch · scope emails:send
Accepts 1 to 100 emails in one request. The body is a JSON array of emails with the same fields as Send an email, except that batch emails can't have attachments or scheduled_at. If any email fails validation, none are sent. IDs come back in the order you sent them.
curl https://api.mysendbox.com/v1/emails/batch \
-H "Authorization: Bearer msb_live_…" \
-H "Content-Type: application/json" \
-d '[
{ "from": "Acme <billing@acme.example>", "to": ["jane@example.com"],
"template": { "id": "receipt", "variables": { "name": "Jane", "total": "$42.00" } } },
{ "from": "Acme <billing@acme.example>", "to": ["sam@example.com"],
"template": { "id": "receipt", "variables": { "name": "Sam", "total": "$18.50" } } }
]'
{
"data": [
{ "id": "em_01k8r2m4qd7x9c3vtw5n6hbj0e" },
{ "id": "em_01k8r2m4qe2b8f6kz1y3a7d5gs" }
]
}
List emails
GET /v1/emails · scope emails:read
Your email log, newest first. Query parameters, all optional:
status— one ofscheduled,queued,sending,sent,delivered,bounced,complained,failed,suppressed,canceled.to— only emails to this address (in to, cc or bcc).before— an email ID. Returns emails older than it: pass the last ID of a page to get the next.limit— 1 to 100. Default 50.
curl "https://api.mysendbox.com/v1/emails?status=bounced&limit=20" \
-H "Authorization: Bearer msb_live_…"
{
"data": [
{
"id": "em_01k8r2m4qd7x9c3vtw5n6hbj0e",
"status": "bounced",
"from": { "address": "billing@acme.example", "name": "Acme" },
"to": ["jane@example.com"],
"subject": "Your receipt #A-2291",
"createdAt": 1793280000000,
…
}
]
}
Get an email
GET /v1/emails/{id} · scope emails:read
One email with its delivery events, oldest first. Add ?body=1 to include what was sent: body with html, text, attachments and headers.
status— where the email is.suppressedmeans its recipients are on your suppression list, which hard bounces and complaints add to.events[].type—sent,delivery,delivery_delay,soft_bounce,bounce,complaint,reject,deferred,suppressed,failedorclick(the first click on a link by a person, with itsurl).clicks— tracked link clicks, oldest first:index(the link's position among the tracked links),url,at,agent(browser,mail_app,scannerorother) andsuspectedBot.tracking—trueorfalsewhen the request set it, otherwisenull.error— the reason for a failure, suppression or bounce, ornull.templateId— the template it was rendered from, ornull.
curl https://api.mysendbox.com/v1/emails/em_01k8r2m4qd7x9c3vtw5n6hbj0e \
-H "Authorization: Bearer msb_live_…"
{
"id": "em_01k8r2m4qd7x9c3vtw5n6hbj0e",
"status": "delivered",
"from": { "address": "billing@acme.example", "name": "Acme" },
"to": ["jane@example.com"],
"cc": [],
"bcc": [],
"replyTo": [],
"subject": "Your receipt #A-2291",
"tags": { "order": "A-2291" },
"templateId": null,
"createdAt": 1793280000000,
"scheduledAt": null,
"sentAt": 1793280001200,
"tracking": null,
"error": null,
"events": [
{ "type": "sent", "at": 1793280001200, "detail": null },
{ "type": "delivery", "at": 1793280003900, "detail": null },
{ "type": "click", "at": 1793280912000, "detail": { "url": "https://acme.example/orders/A-2291", "index": 0 } }
],
"clicks": [
{ "index": 0, "url": "https://acme.example/orders/A-2291", "at": 1793280004100, "agent": "scanner", "suspectedBot": true },
{ "index": 0, "url": "https://acme.example/orders/A-2291", "at": 1793280912000, "agent": "browser", "suspectedBot": false }
]
}
Cancel a scheduled email
POST /v1/emails/{id}/cancel · scope emails:send
Cancels an email sent with scheduled_at before its time comes, and returns it with status canceled. An email that isn't scheduled any more is a 409.
curl -X POST https://api.mysendbox.com/v1/emails/em_01k8r2m4qd7x9c3vtw5n6hbj0e/cancel \
-H "Authorization: Bearer msb_live_…"
{
"id": "em_01k8r2m4qd7x9c3vtw5n6hbj0e",
"status": "canceled",
"scheduledAt": 1793300400000,
…
}
Templates
A template holds a subject and an HTML and/or text body with {{name}} placeholders. Send with template and the variables fill them in.
- Nested values work with dots:
{{order.total}}. - Values are HTML-escaped in the HTML body.
- A missing variable is an error (
422), never a blank. subject,htmlortextin the send request win over the template's.- Templates are addressed by ID (
tpl_…) or by name.
List templates
GET /v1/templates · scope emails:read
All your templates, by name.
curl https://api.mysendbox.com/v1/templates \
-H "Authorization: Bearer msb_live_…"
{
"data": [
{
"id": "tpl_01k8qz7c2m5v9x3b6n4d8f1h0j",
"name": "receipt",
"subject": "Your receipt, {{name}}",
"html": "<p>Thanks, {{name}}. Total: {{total}}</p>",
"text": null,
"version": 3,
"createdAt": 1793100000000,
"updatedAt": 1793250000000
}
]
}
Get a template
GET /v1/templates/{id or name} · scope emails:read
One template, in the same shape as the list.
curl https://api.mysendbox.com/v1/templates/receipt \
-H "Authorization: Bearer msb_live_…"
Create a template
POST /v1/templates · scope templates:write
namestring, required — up to 100 characters: lowercase letters, digits, dots, dashes and underscores, starting with a letter or digit. Must be unique (409if taken).subjectstring, required — up to 998 characters.html,textstring — one is required. Up to 1,000,000 characters each.
curl https://api.mysendbox.com/v1/templates \
-H "Authorization: Bearer msb_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "receipt",
"subject": "Your receipt, {{name}}",
"html": "<p>Thanks, {{name}}. Total: {{total}}</p>"
}'
{
"id": "tpl_01k8qz7c2m5v9x3b6n4d8f1h0j",
"name": "receipt",
"subject": "Your receipt, {{name}}",
"html": "<p>Thanks, {{name}}. Total: {{total}}</p>",
"text": null,
"version": 1,
"createdAt": 1793100000000,
"updatedAt": 1793100000000
}
Update a template
PATCH /v1/templates/{id or name} · scope templates:write
Send only the fields to change: name, subject, html, text, with the same rules as create. Set html or text to null to remove it. Each update adds 1 to version. Returns the updated template.
curl -X PATCH https://api.mysendbox.com/v1/templates/receipt \
-H "Authorization: Bearer msb_live_…" \
-H "Content-Type: application/json" \
-d '{ "text": "Thanks, {{name}}. Total: {{total}}" }'
Delete a template
DELETE /v1/templates/{id or name} · scope templates:write
curl -X DELETE https://api.mysendbox.com/v1/templates/receipt \
-H "Authorization: Bearer msb_live_…"
{ "id": "tpl_01k8qz7c2m5v9x3b6n4d8f1h0j", "deleted": true }
List mailboxes
GET /v1/mailboxes · scope messages:read
Your team's agent mailboxes, by address. Use the id in the mailbox routes below.
curl https://api.mysendbox.com/v1/mailboxes \
-H "Authorization: Bearer msb_live_…"
{
"mailboxes": [
{ "id": "mbx_01k8m0d3x7c9v2b5n8q4w6e1rt", "address": "bookings@acme.example", "createdAt": 1792500000000 }
]
}
GET /v1/mailboxes/{id}/storage · scope messages:read — what the mailbox stores (messages and attachments, received and sent) against its quota, 5 GB:
{ "used": 1288490188, "quota": 5368709120, "state": "ok", "retentionDays": null }
state is ok, warn (80% full) or full. When a message doesn't fit, the oldest mail in Trash, then Quarantine, is deleted to make room; if it still doesn't fit, the message is dropped and a message.dropped webhook event is sent. Owners can set a retention period in the dashboard.
List messages
GET /v1/mailboxes/{id}/messages · scope messages:read
Message summaries in one folder, newest first. Query parameters, all optional:
folder— defaultINBOX. Mailboxes also haveSent,Drafts,Archive,Trash,HeldandQuarantine.before— a messageuid. Returns older messages: pass the lastuidof a page to get the next.limit— 1 to 200. Default 50.
curl "https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/messages?limit=20" \
-H "Authorization: Bearer msb_live_…"
{
"messages": [
{
"id": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"folder": "INBOX",
"uid": 412,
"modseq": 980,
"threadId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"from": "sam@example.com",
"subject": "Booking for Friday",
"snippet": "Hi, can I move my booking to Friday at 3?",
"flags": ["seen"],
"hasAttachments": false,
"quarantineReason": null,
"receivedAt": 1793270000000
}
]
}
Get a message
GET /v1/mailboxes/{id}/messages/{messageId} · scope messages:read
The full message: the summary fields plus recipients, threading headers, the text and HTML bodies, attachment metadata, authentication results, and the agent's state.
agentState—new,queued,running,done,skippedorfailed, ornull.agentNotesays why, when there's a reason.attachments—id,filename,contentTypeandsizefor each. Contents aren't included.quarantineReason—virus,dmarc_rejectorspamfor mail kept in Quarantine, elsenull.
curl https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/messages/01K8R1T6Y3W9C2V5B8N4M7Q0XZ \
-H "Authorization: Bearer msb_live_…"
{
"id": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"folder": "INBOX",
"threadId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"from": "sam@example.com",
"to": ["bookings@acme.example"],
"cc": [],
"subject": "Booking for Friday",
"messageIdHeader": "<CAF3x9…@mail.example.com>",
"text": "Hi, can I move my booking to Friday at 3?\n\nSam",
"html": null,
"attachments": [],
"agentState": "done",
"agentNote": null,
"receivedAt": 1793270000000,
…
}
Run the agent on a message
POST /v1/mailboxes/{id}/messages/{messageId}/agent · scope agent:run
Queues the built-in agent for an INBOX message that it hasn't handled: one it never ran on, skipped, or failed on. No body.
202with"status": "queued"— the run is queued.409with"status": "busy"— a run is already queued or in progress.409with"status": "done"— the agent already handled it.404— the message isn't in INBOX.
curl -X POST https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/messages/01K8R1T6Y3W9C2V5B8N4M7Q0XZ/agent \
-H "Authorization: Bearer msb_live_…"
{ "messageId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ", "status": "queued" }
Actions
An action is something the agent does or wants to do: send an email reply (kind: "send_email") or call one of your tools (kind: "tool_call"). Actions that need a person wait as held; drafts wait as draft.
status—held,draft,approved,sending,executed,rejectedorfailed.payload— for an email:to,subject,body,inReplyTo,references. For a tool call: thetooland itsarguments.reasons— why it was held, such asrate_limit:mailbox. Empty when policy approved it.decidedBy,decidedAt— who approved or rejected it, and when. API decisions show asapikey:{key id}.providerMessageId,deliveryStatus— set once an email is sent and delivery events come in.result— a send failure, delivery details, or the tool's result.
List actions
GET /v1/mailboxes/{id}/actions · scope actions:read
The 50 newest actions in the mailbox. Add ?status=held (or any status above) to filter; without it, you get every kind of action, as an audit trail.
curl "https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/actions?status=held" \
-H "Authorization: Bearer msb_live_…"
{
"actions": [
{
"id": "01K8R1V2C7X4B9N3M6Q8W5E0TY",
"kind": "send_email",
"threadId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"sourceMessageId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"status": "held",
"payload": {
"to": ["sam@example.com"],
"subject": "Re: Booking for Friday",
"body": "Hi Sam, Friday at 3 works. See you then.",
"inReplyTo": "<CAF3x9…@mail.example.com>",
"references": "<CAF3x9…@mail.example.com>"
},
"reasons": ["rate_limit:mailbox"],
"decidedBy": null,
"createdAt": 1793270004000,
"decidedAt": null,
"providerMessageId": null,
"deliveryStatus": null,
"result": null,
…
}
]
}
Get an action
GET /v1/mailboxes/{id}/actions/{actionId} · scope actions:read
One action, in the same shape as the list.
curl https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/actions/01K8R1V2C7X4B9N3M6Q8W5E0TY \
-H "Authorization: Bearer msb_live_…"
Approve an action
POST /v1/mailboxes/{id}/actions/{actionId}/approve · scope actions:write
Approves a held action or a draft, and returns it with status approved. An approved email is sent; an approved tool call runs. An action that isn't pending is a 409. The body is optional.
payloadobject, optional — an edited email to send instead. Email actions only (400for a tool call, which is approved exactly as proposed). It replaces the whole payload:toarray, required (1 to 50 addresses),subjectstring, required (up to 998 characters),bodystring, required (plain text, up to 100,000 characters),inReplyToandreferencesstring, optional (copy them from the original payload to keep the reply in its thread).
curl -X POST https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/actions/01K8R1V2C7X4B9N3M6Q8W5E0TY/approve \
-H "Authorization: Bearer msb_live_…"
curl -X POST https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/actions/01K8R1V2C7X4B9N3M6Q8W5E0TY/approve \
-H "Authorization: Bearer msb_live_…" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"to": ["sam@example.com"],
"subject": "Re: Booking for Friday",
"body": "Hi Sam, Friday at 3 works. We have moved your booking.",
"inReplyTo": "<CAF3x9…@mail.example.com>",
"references": "<CAF3x9…@mail.example.com>"
}
}'
{
"id": "01K8R1V2C7X4B9N3M6Q8W5E0TY",
"kind": "send_email",
"status": "approved",
"decidedBy": "apikey:key_01K8M0F5Z2X8C4V7B1N9Q3W6ER",
"decidedAt": 1793271200000,
…
}
Reject an action
POST /v1/mailboxes/{id}/actions/{actionId}/reject · scope actions:write
Rejects a held action or a draft. Nothing is sent or run. Returns the action with status rejected. An action that isn't pending is a 409. No body.
curl -X POST https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/actions/01K8R1V2C7X4B9N3M6Q8W5E0TY/reject \
-H "Authorization: Bearer msb_live_…"
Create a draft
POST /v1/mailboxes/{id}/drafts · scope drafts:write
Writes an email draft from the mailbox. A draft never sends by itself: it waits as an action with status draft until a person approves it in the dashboard, or a key with actions:write approves it.
toarray, required — 1 to 50 addresses.subjectstring, required — up to 998 characters.bodystring, required — plain text, up to 100,000 characters.replyToMessageIdstring, optional — a message in this mailbox to reply to. The draft joins its thread with the right reply headers.404if it doesn't exist.
curl https://api.mysendbox.com/v1/mailboxes/mbx_01k8m0d3x7c9v2b5n8q4w6e1rt/drafts \
-H "Authorization: Bearer msb_live_…" \
-H "Content-Type: application/json" \
-d '{
"to": ["sam@example.com"],
"subject": "Re: Booking for Friday",
"body": "Hi Sam, Friday at 3 works. See you then.",
"replyToMessageId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ"
}'
{
"id": "01K8R2A9D4X7C1V6B3N8M5Q2WE",
"kind": "send_email",
"threadId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"sourceMessageId": "01K8R1T6Y3W9C2V5B8N4M7Q0XZ",
"status": "draft",
"payload": {
"to": ["sam@example.com"],
"subject": "Re: Booking for Friday",
"body": "Hi Sam, Friday at 3 works. See you then.",
"inReplyTo": "<CAF3x9…@mail.example.com>",
"references": "<CAF3x9…@mail.example.com>"
},
"reasons": ["created_by:apikey:key_01K8M0F5Z2X8C4V7B1N9Q3W6ER"],
…
}
For AI agents: MCP
Agents that speak MCP don't need this API to work in a mailbox. Point them at https://mcp.mysendbox.com/mcp to read, search, draft and reply, with the same screening, approvals and limits as the built-in agent. Setup and tools: Bring your own agent.