SendBuzzPro API

Consoleopenapi.jsonllms.txt

Base URL: ${origin}/v1. Authenticate with Authorization: Bearer ml_… (create keys in the console). Every error looks like {"error":{"code","message","fix","docs_url"}}.

Send an email

curl ${origin}/v1/emails \
  -H "Authorization: Bearer ml_…" -H "Content-Type: application/json" -H "Idempotency-Key: order-1234" \
  -d '{"from":"Acme <hi@acme.com>","to":"ada@example.com","subject":"Your receipt","html":"<p>Thanks!</p>","tags":{"order":"1234"}}'

Each send is checked against the key’s budgets and your plan when it is accepted. Suppressed recipients (bounced, complained, unsubscribed) are dropped. Set request_approval: true to have a person approve it first. The loop guard holds a key’s 6th email with the same subject to the same person within 10 minutes.

Endpoints

POST/v1/emailsSend one email
Body: from, to, cc, bcc, reply_to, subject, html, text, headers, tags, attachments [{filename, content (base64), content_type}], scheduled_at, request_approval, topic, unsubscribe. Header: Idempotency-Key. Returns the email with its status: sent, queued, scheduled, held or suppressed.
POST/v1/emails/batchSend up to 500 emails
Body: an array of email objects. Returns {data, errors}; each email is accepted or refused on its own.
GET/v1/emailsList emails
Query: status (comma separated), to, key_id, broadcast_id, before, limit (≤100). Returns {data, has_more}.
GET/v1/emails/{id}Get an email
Status, reason and event timeline.
GET/v1/emails/{id}/rawRaw message
The exact MIME message (message/rfc822).
POST/v1/emails/{id}/cancelCancel
Scheduled, queued or held emails.
POST/v1/emails/{id}/approveApprove a held email
Console only (owner, admin or approver). Body: note (optional). Who approved it and the note are kept in the timeline and the audit log.
POST/v1/emails/{id}/rejectReject a held email
Console only (owner, admin or approver). Body: note (the reason).
POST/v1/inboxesCreate an inbox
Body: username (optional; random if empty), domain (your verified domain with the receiving MX record, or empty for the shared domain), name. Use username "*" on your own domain for a catch-all.
GET/v1/inboxesList inboxes
Addresses and unread conversation counts.
GET/v1/inboxes/{id}/threadsList conversations
Query: unread=true, limit, before.
POST/v1/inboxes/{id}/sendStart a conversation
Same body as /v1/emails; sent from the inbox address so replies come back to it.
GET/v1/threads/{id}Get a conversation
Every received and sent message, oldest first.
PATCH/v1/threads/{id}Mark read / unread
Body: {"read": true}.
GET/v1/messages/{id}Get a received message
Text, HTML, attachments list, SPF/DKIM/DMARC/spam verdicts, is_auto (auto-replies, lists, bounces).
GET/v1/messages/{id}/attachments/{index}Download an attachment
POST/v1/messages/{id}/replyReply in the conversation
Body: text, html, reply_all, request_approval, attachments. Sets In-Reply-To and References. Same budgets as /v1/emails.
GET/v1/budgetRemaining budget
This key's per-minute/hour/day/month use and limits, and the account plan.
GET/v1/domainsList domains
With DNS records and per-record status.
POST/v1/domains/{id}/checkCheck DNS now
GET/v1/webhooksList webhooks
POST/v1/webhooksAdd a webhook
Body: url, events (array, or ["*"]). Returns the signing secret once.
GET/v1/webhooks/deliveriesDelivery log
Query: webhook_id, status (pending | delivered | dead).
POST/v1/webhooks/replayReplay deliveries
Body: delivery_id, or webhook_id to replay every dead delivery.
POST/v1/contactsAdd or update a contact
Body: email, first_name, last_name, data, topics {topic_id: true|false}. Only people who opted in.
GET/v1/contactsList contacts
Query: search, topic, limit, offset.
GET/v1/topicsList topics
GET/v1/broadcastsList broadcasts
GET/v1/suppressionsList suppressed addresses
Query: search, reason (bounce | complaint | unsubscribed | manual).
POST/v1/suppressionsSuppress an address
Body: email.
GET/v1/approvalsRecent approval decisions
Console only. Who approved or rejected each email, their role and note.
GET/v1/membersList team members
Console only. Members, roles, pending invites and seats {used, limit}.
POST/v1/membersInvite a member
Console only (owner or admin). Body: email, role (admin | developer | approver | viewer). Emails a one-time invite link, or returns invite_url when the server has no NOTIFY_FROM.
PATCH/v1/members/{id}Change a role
Console only (owner or admin). Body: role. Applies to the member's sessions right away.
DELETE/v1/members/{id}Remove a member
Console only (owner or admin). Signs them out everywhere.
POST/v1/members/{id}/linkResend an invite / sign-in link
Console only (owner or admin). Emailed, or returned as url when the server has no NOTIFY_FROM.
POST/v1/login/emailEmail me a sign-in link
No auth. Body: email. Same answer whether or not the address is a member.
POST/v1/login/linkUse a sign-in link
No auth. Body: token. One use, 15 minutes. Sets the session cookie.
POST/v1/invites/acceptAccept an invite
No auth. Body: token, name. One use, 7 days. Sets the session cookie.
GET/v1/auditAudit log
Console only (owner or admin); API keys have no scopes, so they can't read it. Query: action (e.g. key or key.created), actor, q, since, until (YYYY-MM-DD), before, limit (≤200), format=csv (up to 10,000 rows).

Receiving email

Create an inbox, and email sent to it fires email.received with the message id, conversation id and sender. Read the conversation with GET /v1/threads/{id} and answer with POST /v1/messages/{id}/reply. Messages marked is_auto are auto-replies, mailing lists or bounces: don’t answer them automatically.

MCP for AI agents

URL ${origin}/mcp with the same Bearer key. Tools: send_email, get_email, list_emails, cancel_email, get_budget, list_domains, create_inbox, list_inboxes, list_threads, get_thread, reply_to_message, send_from_inbox, list_contacts, add_contact. Refusals come back as tool errors with the code and the fix.

claude mcp add --transport http sendbuzzpro ${origin}/mcp --header "Authorization: Bearer ml_…"

Webhooks

POST with JSON {"id","type","created_at","data"} and header ml-signature: t=<unix>,v1=<hex HMAC-SHA256 of "t.body">. Failed deliveries retry 6 times over ~20 hours, then can be replayed. Events: email.queued email.scheduled email.held email.approved email.rejected email.canceled email.sent email.delivered email.delivery_delayed email.bounced email.soft_bounced email.complained email.opened email.clicked email.failed email.suppressed email.received contact.created contact.unsubscribed domain.verified domain.failed account.warned account.paused key.budget_exceeded

Teams, roles and the audit log

People sign in to the console; apps and agents use API keys, which belong to the workspace. The license key holder is the owner. Others are invited by email and sign in with one-time emailed links. Roles: admin (everything except billing), developer (keys, budgets, webhooks, domains, inboxes, sending), approver (approve or reject held emails, read the log and inbox), viewer (read-only). Every sign-in and change to keys, budgets, the kill switch, domains, webhooks, the team, approvals, suppressions and inboxes goes in an append-only audit log, with the person, IP and browser.

Email statuses

scheduled queued held sending sent delivered delivery_delayed opened clicked bounced complained failed suppressed rejected canceled

Errors

CodeHTTPMeaningFix
agent_budget_exceeded429The API key went over one of its own budgets (minute, hour, day or month). The error says which window, the limit and what is used.Wait for the window to pass, or ask the account owner to raise the budget in the console. A key can’t raise its own budget.
plan_daily_limit429The Free plan’s 100 emails a day are used.Wait until midnight UTC or upgrade.
plan_monthly_limit429The plan’s monthly emails are used. There are no overage charges.Sending resumes on the 1st (UTC), or upgrade.
lifetime_pool_used429All emails in a lifetime plan are used.Buy a larger tier or switch to a monthly plan.
sending_paused403The account owner turned on the kill switch.The owner resumes sending on the console Overview page.
key_paused403This API key is paused.Resume it under API keys.
account_paused403Sending is paused because bounces or spam complaints were too high (4% / 0.08% over 30 days).Remove bad addresses and appeal from the console. A person reviews every appeal.
domain_not_added422The from address uses a domain that isn’t on this account.Add it under Domains.
domain_not_verified422The domain’s DNS records aren’t verified yet.Add the records under Domains and press Check now.
invalid_from422The from address is missing or invalid.Use "Name <you@your-domain.com>".
invalid_recipient422One address in to, cc, bcc or reply_to is invalid. The error names the field.Fix or remove it.
missing_recipient422There is no “to”.Add at least one address.
too_many_recipients422More than 50 recipients in one email.Use /v1/emails/batch to send one email per person.
missing_subject422The subject is empty.
subject_too_long422The subject is over 998 characters.
missing_content422There is no html or text.Send html, text or both.
invalid_header422A custom header is reserved, malformed or has a line break.Use the dedicated field (from, to, reply_to…) instead.
invalid_attachment422An attachment has no filename or isn’t base64.
message_too_large422The email is over 10 MB.Link to large files instead.
invalid_scheduled_at422scheduled_at isn’t an ISO 8601 time within 30 days.
invalid_batch422The batch body isn’t a JSON array.
batch_too_large422More than 500 emails in one batch.Split it.
idempotency_conflict409This Idempotency-Key was used for a different request in the last 24 hours.Use a new key for a new email. Retrying the same request with the same key is always safe.
invalid_idempotency_key400The Idempotency-Key is over 200 characters.
invalid_api_key401The key is missing, malformed or deleted.Send “Authorization: Bearer ml_…”.
unauthorized401Not signed in.
console_only403Keys, budgets, approvals, the kill switch, the team and the audit log are only for people signed in to the console.
role_forbidden403Your role can’t do this (e.g. a viewer creating a key, or a developer approving an email).Ask an owner or admin to change your role under Settings → Team.
seat_limit403Your plan’s seats are used (owner and pending invites count).Remove a member or invite, or upgrade.
member_exists409That person is already on the team.
member_not_found404
owner_protected403The owner can’t be changed or removed; ownership follows the license key.
invalid_role422Role must be admin, developer, approver or viewer.
invite_invalid400The invite link was used, replaced or is over 7 days old.Ask the owner to resend it.
invalid_email422Not a valid email address.
bad_origin403A cross-site request to the console API was blocked.
not_held409The email isn’t waiting for approval.
not_cancelable409Only scheduled, queued or held emails can be canceled.
email_not_found404No email with that id (old emails are removed after the plan’s history window).
provider_error502Amazon SES refused the request.Retry with the same Idempotency-Key.
invalid_domain400Not a valid domain name.
domain_taken409The domain is on another SendBuzzPro account.Contact support if it is yours.
domain_limit403Your plan’s domain limit is reached.
domain_not_found404
invalid_webhook_url400Webhook URLs must be public https addresses.
invalid_events400Unknown webhook event types.
invalid_contact_email422
empty_audience422Nobody would receive the broadcast.
broadcast_locked409Only draft broadcasts can be edited or sent.
complaint_suppression409That person marked your email as spam.Only remove it with confirm=true if they asked to be emailed again.
inbox_limit403Your plan’s inbox limit is reached.Delete an inbox or upgrade.
address_taken409That inbox address is taken.Pick another username.
username_reserved422Names like support, admin or billing are reserved on the shared domain.Use a more specific name, or your own domain.
invalid_username422Usernames use letters, numbers, dots, dashes and underscores.
no_inbound_domain400Receiving isn’t set up for that domain.Use your own domain with the receiving MX record.
catch_all_shared422Catch-all inboxes only work on your own domain.
thread_not_found404
message_not_found404
inbox_not_found404
attachment_not_found404
invalid_json400The body isn’t valid JSON.
not_found404Unknown endpoint.
server_error500Something failed on our side.Retry with the same Idempotency-Key.

What you can send

Transactional email and email to people who opted in. Cold email, bought or scraped lists are not allowed.