API, webhooks & MCP
The same product, reached from code. Send from any address you connected, get every received email pushed to you, answer it in-thread from the business address, and give an AI agent a safe, scoped way to do the same.
1 · Authentication & keys
Create a key in the panel under Developers (or via POST /v1/api-keys with a manage key). Keys belong to one organization and carry scopes: send, read, reply, manage. Send it as a bearer token:
Authorization: Bearer ayi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxBase URL: https://allyourinboxes.com/api/v1. Every error is a JSON body { statusCode, name, message } with Resend's error names (validation_error, missing_api_key, rate_limit_exceeded, monthly_quota_exceeded…), so existing error handling keeps working.
2 · Send an email (Resend-compatible)
Same request body as Resend's POST /emails. The only rule: from must be an inbox you connected (or any address on a catch-all domain) with sending enabled.
curl https://allyourinboxes.com/api/v1/emails \
-H "Authorization: Bearer ayi_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1234" \
-d '{
"from": "Acme Support <support@acme.com>",
"to": ["customer@example.com"],
"reply_to": "support@acme.com",
"subject": "Your order shipped",
"html": "<p>On its way.</p>",
"attachments": [{ "filename": "invoice.pdf", "content": "<base64>" }]
}'
# → { "id": "…" }Using the Resend Node SDK? Point it at us and keep the code:
import { Resend } from "resend";
const resend = new Resend("ayi_live_…", { baseUrl: "https://allyourinboxes.com/api/v1" }); // or RESEND_BASE_URL=https://allyourinboxes.com/api/v1
await resend.emails.send({ from: "support@acme.com", to: "customer@example.com", subject: "Hi", text: "Hello" });Also available: POST /emails/batch (up to 100, index-aligned response), GET /emails/:id (status), GET /emails (recent sends). Threading: add "in_reply_to": "<received email id>" and we set In-Reply-To/References for you.
3 · Receive: webhooks
Add a URL under Developers (or POST /v1/webhooks). Choose events: email.received, email.blocked, reply.sent, email.sent, email.failed. Optionally limit to specific inboxes. Unlike metadata-only providers, email.received carries the text body and signed attachment links, so one request is usually all you need:
POST https://your-app.example/webhooks/mail
webhook-id: dlv_… webhook-timestamp: 1725700000
webhook-signature: v1,MEUCIQ… content-type: application/json
{
"type": "email.received",
"created_at": "2026-09-07T10:12:00.000Z",
"data": {
"email_id": "cm…", "inbox_id": "cm…", "inbox": "support@acme.com", "project": "Acme",
"from": "Jane <jane@example.com>", "from_address": "jane@example.com", "to": "support@acme.com",
"subject": "Refund?", "message_id": "<…@example.com>", "received_at": "…",
"authenticated": true,
"text": "Hi, I'd like a refund for…",
"text_expires_at": "2026-09-08T10:12:00.000Z",
"attachments": [{ "id": "…", "filename": "receipt.pdf", "content_type": "application/pdf", "size": 48213,
"download_url": "https://allyourinboxes.com/api/v1/attachments/…?exp=…&sig=…", "expires_at": "…" }]
}
}Delivery: 10-second timeout, any 2xx counts as received. Failures retry after 1 min, 5 min, 30 min, 2 h and 12 h. After 20 consecutive failures the endpoint is paused and shown as such in the panel; press Resume to re-enable. Send test fires a webhook.test event immediately.
4 · Verify a webhook signature
We follow the Standard Webhooks spec, so any library for it works. By hand:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, headers, rawBody) {
const id = headers["webhook-id"], ts = headers["webhook-timestamp"], sig = headers["webhook-signature"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // 5-minute replay window
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest("base64");
return sig.split(" ").some((s) => {
const v = s.replace(/^v1,/, "");
return v.length === expected.length && timingSafeEqual(Buffer.from(v), Buffer.from(expected));
});
}Use the raw request body (before JSON parsing). webhook-id is unique per delivery — use it to de-duplicate retries.
5 · Read received mail & attachments
GET https://allyourinboxes.com/api/v1/emails/receiving?limit=20&unanswered=true&domain=acme.com&q=refund
GET https://allyourinboxes.com/api/v1/emails/receiving/:id # text + attachment links while retained
GET https://allyourinboxes.com/api/v1/emails/receiving/:id/attachments
GET https://allyourinboxes.com/api/v1/inboxes # connected addresses (alias: /domains)
GET https://allyourinboxes.com/api/v1/events?kind=blocked # the audit ledgerRetention: by design we delete message bodies once the notification is delivered. When your organization has a webhook or a read key, bodies and attachments are kept for 24 hours after arrival and then removed; text_expires_at tells you when. Metadata (from, subject, dates, answered) stays.
6 · Reply in-thread
The one thing a sending API can't do for you: answer a customer from the address they wrote to, inside the same conversation. We set In-Reply-To/References and send through that inbox's own sending path.
curl https://allyourinboxes.com/api/v1/emails/receiving/cm…/reply \
-H "Authorization: Bearer ayi_live_…" -H "Content-Type: application/json" \
-d '{ "text": "Refund issued — you will see it in 3–5 days." }'
# → { "id": "…" } (reply.sent webhook follows)Block a sender: POST /inboxes/:id/blocked with { "pattern": "@spammer.com" }.
7 · MCP server for AI agents
Give Claude, Cursor, VS Code or any MCP client a key with the scopes you want the agent to have. Endpoint: https://allyourinboxes.com/mcp (Streamable HTTP, stateless).
{
"mcpServers": {
"allyourinboxes": {
"url": "https://allyourinboxes.com/mcp",
"headers": { "Authorization": "Bearer ayi_live_…" }
}
}
}Tools: list_inboxes, list_emails (filters: inbox, domain, from, subject, unanswered), get_email (text + attachment links), reply_to_email (in-thread, html and attachments allowed), send_email, block_sender, list_events. A read-only key makes the agent read-only — scopes are enforced per tool, not by the agent's good behaviour.
8 · Limits, errors, retention
- Rate: 10 requests/second per key (600/min). Over it:
429 rate_limit_exceeded. - Monthly API sends: Starter 2,000 · Pro 10,000 · Business 50,000. Free: read-only API, 1 webhook, MCP. Over quota:
429 monthly_quota_exceeded. - Attachments: 10 MB per email, in and out.
- Idempotency-Key: ≤256 chars, remembered 24 h; the same key with a different payload returns
409 invalid_idempotent_request. - Where mail actually goes out from: your inbox's own SMTP or Google/Microsoft OAuth — we never send as you from our servers, which is why deliverability follows your domain's SPF/DKIM, not ours. Deliverability guide →
All your email. One place.
Connect any inbox. Send from the right address automatically. Free plan forever, paid from $6.99/mo, and it never touches how your mailboxes are set up.
Try it free