API reference
BlueyEmail API
Send transactional email, manage contacts, run campaigns, and receive HMAC-signed webhooks — a single REST API over 132 JSON endpoints.
Base URL https://api.blueyemail.com
Building a connector? Download the OpenAPI spec to auto-generate one. Public, no auth required.
Explore the API
Authentication
Every request needs an API key. Pass it as an X-API-Key header (recommended) or a Bearer token. Create keys in Settings → Integrations.
X-API-Key: YOUR_API_KEYAuthorization: Bearer YOUR_API_KEYTest the connection
Confirm a key works with a single call to GET /api/v2/me. It needs no scope and returns the workspace, the key’s auth context, and sending: whether you can send yet, your verified domains, and the exact next step if not — ideal for a platform’s “Test connection” step.
curl -X GET "https://api.blueyemail.com/api/v2/me" \-H "X-API-Key: YOUR_API_KEY" \-H "Content-Type: application/json"
{
"success": true,
"data": {
"workspace": { "id": "uuid", "name": "Acme Inc" },
"auth": { "method": "api_key", "mode": "live", "sandbox": false, "scopes": ["leads:write", "emails:send"] },
"sending": { "ready_to_send": true, "verified_domains": ["acme.com"], "pending_domains": [], "next_step": "Ready. Send from any address on acme.com with POST /api/v2/transactional/send." }
}
}Quick start
Send your first transactional email in one request. It needs two things first: a sending domain verified in Settings → Sending Domains, and an API key with Read & write access. Every send needs a from address on that verified domain — we never choose one for you.
curl -X POST "https://api.blueyemail.com/api/v2/transactional/send" \-H "X-API-Key: YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"from": "Your Name <hello@your-verified-domain.com>","to": "you@example.com","subject": "Hello from BlueyEmail","html": "<h1>It works!</h1>"}'
The API sends transactional email — receipts, OTPs, notifications — via /api/v2/transactional/send. For marketing (newsletters, campaigns), don't send per-recipient: (POST /api/v2/campaigns/:id/leads) so unsubscribes, warmup, and segments are respected.
Sending over SMTP
BlueyEmail sends over HTTPS instead of SMTP. There is less to set up — no host, port, encryption mode or mail password — and it keeps working on hosting that blocks outbound SMTP ports, which is one of the most common reasons email quietly stops sending.
Here is how to connect, depending on what you are sending from:
Send with the REST API — one POST with your API key. Attachments, scheduling, custom headers and Reply-To are all supported. See Quick Start above to send your first email in a couple of minutes.
We are building an official BlueyEmail plugin so you can skip SMTP entirely. Install it, paste your API key, and every email your site sends goes through BlueyEmail — WooCommerce orders and invoices, password resets, contact form replies. Nothing else to configure.
Connecting something else, or a platform you would like us to support? Tell us what you are working with — it genuinely shapes what we build next.
Sending addresses
To send through the API you don’t need an email account. Put any address on a domain you have verified in from, for example "from": "Acme <hello@yourdomain.com>". Email accounts are the senders your campaigns use. There are three kinds, and the API can do different things with each:
| Kind (provider) | Add it | Change through the API | Remove it |
|---|---|---|---|
| BlueyEmail sending address (platform_smtp) | Dashboard: Settings → Email accounts | display_name, is_active, purpose | Dashboard |
| Your own SMTP server (custom_smtp) | POST /api/v2/email-accounts/smtp | Everything, including SMTP settings | DELETE /api/v2/email-accounts/:id |
| Gmail / Outlook (gmail, outlook, …) | Dashboard: sign in with Google/Microsoft | display_name, is_active, purpose | Dashboard |
Find an account’s id with . Ids are UUIDs; words like platform are not ids. Updates use PATCH with only the fields you want to change.
Rate limits & sending volume
Two different limits apply, and it helps to keep them separate.
1 · API request rate
How many HTTP calls your workspace can make. Your allowance is set by your plan and is shared across every API key and OAuth token in the workspace — creating more keys does not raise it. Both a per-minute and a per-hour cap apply. Exceeding either returns 429 RATE_LIMITED. Every response carries your live budget in headers:
| Plan | Requests / minute | Requests / hour |
|---|---|---|
| Free | 30 | 1,000 |
| Spark | 120 | 5,000 |
| Grow | 300 | 20,000 |
| Business | 600 | 50,000 |
| API Free | 60 | 3,000 |
| API Essentials | 300 | 30,000 |
| API Pro | 600 | 150,000 |
| API Premier | 1,200 | 500,000 |
X-RateLimit-Limit1000Requests allowed this hourX-RateLimit-Remaining842Requests left this hourX-RateLimit-Reset1710415260Unix time the window resetsRetry-After42Seconds to wait (on 429)2 · Email sending volume
This is separate from the request rate. How many emails you can actually send is governed by a daily sending limit (small for brand-new workspaces, rising automatically — see Sending limits) and your monthly plan limit. A send over a limit is refused with 429 and a retry_at time — it is not queued, so retry after that time.
Sending to thousands? You don't make one call per recipient. Use (POST /api/v2/transactional/batch) — up to 1,000 messages per request. So 5,000 emails is just 5 API calls, far inside any rate limit. The single-send endpoint also accepts up to 50 recipients per call.
Sending limits
Paid plans get their full limits from day one. On the free plan or a trial, a new workspace sending through BlueyEmail starts with a small daily allowance that rises on its own as the account ages. You don’t need to do anything.
| Workspace age | Emails per day |
|---|---|
| Paid plan (any age) | Your plan’s limit |
| Free / trial — first 24 hours | 50 |
| Free / trial — days 2–7 | 500 |
| Free / trial — after the first week | Your plan’s limit |
Days are counted in UTC, so the daily count also resets at 00:00 UTC. An hourly limit protects against sudden spikes. When a limit is reached, nothing is sent and nothing is queued. You get 429 with a code of DAILY_SEND_LIMIT or HOURLY_SEND_LIMIT, the exact time you can send again in retry_at, and the same wait in seconds in the Retry-After header. Retry after that time.
Check where you are
GET /api/v2/me (and GET /api/v2/emails/stats) return a sending_limits object: today’s daily_limit (limit, used, remaining, when it resets and when it rises) and the hourly_limit. While a daily limit applies, every send response also carries X-Daily-Send-Limit, X-Daily-Send-Remaining and X-Daily-Send-Reset, so your code can slow down before it is refused. The workspace owner and admins are also emailed the first time a daily limit is reached each day.
The hourly limit: while the daily limit is 1,000 or less, the whole day may be sent in one hour. Above that, the hourly limit is one-twelfth of the daily one (for example, a free plan’s 2,000 a day allows about 167 an hour).
Your plan’s own limits apply on top, at all times: API Free 100 a day and 50 an hour, API Essentials 10,000 a day and 2,000 an hour, API Pro 20,000 and 4,000, API Premier 200,000 and 20,000. These are rolling windows (any 24 hours, any hour), shown under sending_limits.plan.usage. Going over one also returns 429 with retry_at.
{
"error": {
"type": "rate_limit_error",
"code": "DAILY_SEND_LIMIT",
"reason": "new_account_ramp",
"retry_at": "2026-10-07T00:00:00.000Z",
"message": "New account: 50 emails/day for first 24 hours. ... Nothing was sent. You can send again at 2026-10-07T00:00:00Z (in about 59 minutes)."
}
}Errors
Errors return a nested error object with a type (derived from the HTTP status), a human-readable message, and a machine-readable code. The HTTP status is on the response itself. Some endpoints add extra fields (e.g. limit, reset_at, or the required scopes).
{
"error": {
"type": "auth_error",
"message": "Invalid API key",
"code": "INVALID_API_KEY"
}
}400validation_errorInvalid or missing parameters401auth_errorInvalid or missing API key403permission_errorAPI key lacks the required scope, or this sender cannot send404not_found_errorResource or endpoint does not exist405invalid_request_errorRight path, wrong method — see the Allow header409conflict_errorDuplicate idempotency key422invalid_request_errorRequest understood but refused (e.g. a suppressed recipient)429rate_limit_errorRequest rate or sending limit reached — check Retry-After500api_errorServer error — retry with backoffCommon codes and what to do
VALIDATION_ERRORSomething in the request is missing or malformed — the message names it. Invalid JSON is usually a shell line-break inside -d.ENDPOINT_NOT_FOUNDNo such endpoint. The message suggests the right one when it can.METHOD_NOT_ALLOWEDUse a method from the Allow header (updates are PATCH, not PUT).FIELD_NOT_EDITABLEThat field can’t be changed on this account; editable_fields lists what can.MANAGED_IN_DASHBOARDThis account is managed in Settings → Email accounts.SENDER_REQUIRED / DOMAIN_NOT_VERIFIEDSend from an address on a domain you have verified.DAILY_SEND_LIMIT / HOURLY_SEND_LIMITNothing was sent. Retry at retry_at (see Sending limits).RECIPIENT_SUPPRESSEDThe address bounced or complained before; remove it from your list.SENDER_NOT_ALLOWEDThis sender address or workspace can’t send right now; the message says why.MONTHLY_SEND_LIMITYour plan’s monthly emails are used. Nothing was sent; it resets with your billing period, or upgrade.CONTENT_BLOCKEDOur safety checks flagged the content (phishing-style wording, a suspicious link, or scripted HTML). Review it and send again.IDEMPOTENCY_IN_PROGRESSA request with the same idempotency key is still running. Wait a moment and retry with the same key.SEND_BLOCKEDStopped by our safety checks. Contact support with the request time if it looks wrong.