Email Marketing
Limits and warm-up
A refused send always comes back with a code that names the limit that refused it. This page maps each code to the number behind it, says whether waiting helps, and shows how to read your allowance before you hit it.
The three independent limits
A send passes three gates in order. Each can refuse it on its own, and the first one that fails decides the code you receive.
| API key rate | Requests per minute for one key, independent of how much mail it asks for. Refuses with RATE_LIMITED before anything is queued. Resets within the minute. |
|---|---|
| Brand allowance | Free sends per calendar month (UTC) for the registrable domain your From address belongs to. Every workspace on that domain draws the same bin, so mail.acme.com and news.acme.com share one allowance. Past it, sends are billed per email instead of refused — unless there is also no funded wallet. |
| Sending domain state | The exact domain in the From address (not the apex) carries its own state: warm-up stage, any platform cap, paused, frozen. A new subdomain is capped even when its brand has allowance left. |
Nothing else refuses mail. Contacts are not capped, seats are not part of sending, and there is no tier to upgrade. If a send was accepted, the only thing that can still stop it is the recipient's own suppression state (a bounce or complaint), which is reported on the send row rather than as an HTTP error.
Error codes and retry semantics
| Code | Status | Meaning | What to do | Retry |
|---|---|---|---|---|
| RATE_LIMITED | 429 | This API key exceeded its request rate. | Wait for the window to reset (`X-RateLimit-Reset` / `Retry-After`). | Yes |
| FREE_ALLOWANCE_EXHAUSTED | 429 | The brand's free sends for this calendar month are used. The allowance is shared by every workspace sending from the same registrable domain. | Wait until the 1st of next month (UTC), or request an allowance increase — sends beyond the allowance are billed per email. | Yes |
| DAILY_QUOTA_EXCEEDED | 429 | The workspace's sends for this UTC day are used. | Wait until UTC midnight. | Yes |
| MONTHLY_QUOTA_EXCEEDED | 429 | The workspace's monthly sending limit — granted by the platform — is used. | Wait until the 1st of next month (UTC), or request a limit increase. | Yes |
| DOMAIN_WARMING_UP | 429 | The sending domain is in a warm-up stage and has used its cap for today. | Wait until UTC midnight. The stage advances after several days of sustained volume with a clean bounce and complaint rate. | Yes |
| DOMAIN_WARMUP_FROZEN | 429 | A deliverability review froze this domain after repeated elevated bounce or complaint rates. | Contact support. Waiting does not clear a freeze. | No |
| DOMAIN_DAILY_QUOTA_EXCEEDED | 429 | A platform-set daily cap for this sending domain is used. | Wait until UTC midnight, or contact support if the cap is wrong. | Yes |
| DOMAIN_MONTHLY_QUOTA_EXCEEDED | 429 | A platform-set monthly cap for this sending domain is used. | Wait until the 1st of next month (UTC), or contact support. | Yes |
| DOMAIN_PAUSED | 429 | The sending domain was paused by the account owner or by the platform. | Resume the domain in the app, or contact support if the platform paused it. | No |
| ORGANIZATION_PAUSED | 429 | Sending is paused for the whole workspace. | Resume sending in the app, or contact support. | No |
| ORGANIZATION_INACTIVE | 429 | Email is not set up, or the workspace is not active. | Complete email setup, or contact support about the workspace status. | No |
| CAMPAIGN_TOO_LARGE | 400 | The campaign exceeds the largest single campaign the platform will queue. | Split the campaign into smaller sends. | No |
| INSUFFICIENT_FUNDS | 402 | Sends beyond the free allowance are billed per email, and the wallet is short. | Top up Work Funds, or wait for the next month's free allowance. | No |
Retryable codes also send Retry-After (seconds) and X-RateLimit-Reset where a window applies. A non-retryable code means a retry will produce the same answer: surface it to a human instead of looping.
# 429 with a code and a Retry-After header — wait, then retry the same request.
# Idempotency-Key makes the retry safe even if the first attempt was accepted.
curl -sS -D - -o /dev/null https://api.thealtermeai.com/api/v1/email/messages \
-H "Authorization: Bearer emk_YOUR_LIVE_KEY" \
-H "Idempotency-Key: order-8812-receipt" \
-H "Content-Type: application/json" \
-d '{ "to": "[email protected]", "subject": "Receipt", "html": "<p>Thanks</p>" }'Warm-up: the ladder every new domain climbs
A newly verified sending domain starts capped and earns its way up. The expected window is two weeks. The caps are the same ones the platform uses for its shared sending IPs, so there is one table to learn:
| Stage | Expected window | Sends per UTC day |
|---|---|---|
| 1 | Day 1–3 | 50 |
| 2 | Day 4–7 | 200 |
| 3 | Day 8–11 | 1,000 |
| 4 | Day 12–14 | 5,000 |
| warmed | after stage 4 | only your own caps |
The window is what the stage expects, not what advances it. A domain climbs when it has sent a real share of its current cap on several days and its bounce and complaint rates stayed clean. A domain sending five messages a day is never blocked by the ladder — 50 is more than it wants — it simply never advances.
Two behaviours surprise integrators, both deliberate:
- A second subdomain inherits the apex's position. Adding
news.acme.comwhenmail.acme.comis already warmed does not restart you at 50 a day. Re-claiming a domain that was deleted earlier resumes where it stopped and keeps any freeze. - A spike moves you down, not just sideways. A day above the regression bounce or complaint rate drops the domain a stage and restarts its clock. Repeated spikes freeze it, and
DOMAIN_WARMUP_FROZENneeds a human: the freeze survives a delete and re-add.
Seeing the limits before they refuse you
/api/v1/email/organizationAny valid keyThe organization endpoint returns the allowance and every sending domain's warm-up state, so a client can pace itself. Read allowance.monthly.remaining for the brand's free sends and each domain's warmup.capToday minus warmup.sentToday for the tighter of the two.
curl -sS https://api.thealtermeai.com/api/v1/email/organization \
-H "Authorization: Bearer emk_YOUR_LIVE_KEY"{
"organization": { "name": "Acme Media", "profileId": "…" },
"key": { "name": "server", "environment": "live", "scopes": ["messages:write"] },
"allowance": {
"pool": "acme.com",
"monthly": { "limit": 3000, "used": 1760, "remaining": 1240, "sharedByWorkspaces": 2 },
"daily": 100,
"billing": "per_email_beyond_allowance"
},
"domains": [
{
"domain": "mail.acme.com",
"registrableDomain": "acme.com",
"status": "verified",
"warmup": { "stage": 2, "capToday": 200, "sentToday": 32, "daysQualified": 2, "daysRequired": 3, "frozen": false },
"caps": { "daily": 200, "monthly": null, "source": "warmup" }
}
]
}allowance.monthly.sharedByWorkspaces above 1 is worth surfacing in your own dashboard: when a brand has several workspaces, the allowance can be spent by a sibling and the number will move without your integration sending anything.
Three refusals, three different fixes
1. A digest to 4,000 recipients fails with 429 RATE_LIMITED. Nothing was queued. Slow the request rate down (the limit is per key, so a second key is not the fix). Retry with the same Idempotency-Key.
2. A receipt fails with 429 FREE_ALLOWANCE_EXHAUSTED. The brand has spent this month's free sends — possibly on a sibling workspace. Waiting until the 1st works; so does topping up Work Funds, after which the same send is accepted and billed per email. A transactional receipt is usually worth the second option.
3. The same receipt succeeds for mail.acme.com and fails for a brand-new promo.acme.com with 429 DOMAIN_WARMING_UP. The brand has allowance, the key is fine, and the From domain is at stage 1 with 50 sends used today. Send the receipt from the warmed domain, or wait for UTC midnight and pace the ramp: the domain needs volume on several days before it climbs, so a launch that needs 20,000 sends on day one is not going to happen from a domain created today.
Related
Authentication and key scopes: Authentication. Sending transactional mail: Transactional email. Campaign fan-out and its own bound: Campaigns. The machine-readable contract, including the code appendix, is the OpenAPI file.