API Limits
This page lists the per-request limits enforced by the Zyphr API. For per-account usage limits (monthly emails, MAU, daily caps), see your plan details and rate limiting.
Request Body Size
| Limit | Value |
|---|---|
| Maximum JSON request body | 25 MB |
| Maximum form-encoded body | 25 MB |
This matches the body-size cap used by major email-platform competitors (SendGrid, Mailgun) so integrations port cleanly without redesign.
The cap applies to the entire JSON envelope — including the html
field, all metadata, tags, and any inlined content — not just the body
of one field. If you exceed it, the API returns:
{
"error": {
"code": "payload_too_large",
"message": "Request body exceeds the maximum allowed size. See https://zyphr.dev/resources/api-limits for current limits.",
"details": {
"limit_bytes": 26214400,
"received_bytes": 30000000
}
},
"meta": {
"request_id": "req_xyz789"
}
}
HTTP status: 413 Payload Too Large.
Handling Oversize Payloads
If your HTML body approaches the limit (e.g. large reports, newsletters with inlined assets), consider:
- Templates — store the HTML as a template
and pass
template_id+template_datainstead of inlining the full HTML in every request. Templates do not count against the request body limit at send time. - External assets — host images on a CDN and reference them by URL rather than base64-inlining them.
- Splitting — for reports that genuinely need multi-MB of unique HTML, split into multiple sends.
Field-Level Limits
| Field | Limit |
|---|---|
subject | 998 characters (RFC 5322) |
tags | 10 tags max, each ≤ 100 characters |
to (batch) | 100 recipients per request |
from.name / to.name | 255 characters |
| Attachment total size | 10 MB |
Template design_json | 1 MB |
Headers
| Header | Limit |
|---|---|
idempotency-key | 255 characters |
x-request-id | Auto-generated UUIDv4 if not supplied |
Account Sending Status
Every authenticated API response carries your account's current sending state, so you can surface it in your own tooling without an extra call — the same way rate-limit headers are returned on every response.
| Header | Values | Description |
|---|---|---|
X-Account-Sending-Status | active, throttled, frozen | The account's current sending state (reputation-driven). |
X-Account-Sending-Status-Reason | free text | Human-readable reason. Present only when the status is throttled or frozen. |
X-Account-Sending-Status: throttled
X-Account-Sending-Status-Reason: Bounce rate (6.20%) exceeded throttle threshold (5%)
These headers are informational and non-blocking on non-send endpoints (reads, billing, and deliverability stay available even when frozen). Send-capable endpoints additionally enforce the state:
- Frozen →
403 account_frozen - Throttled →
429 account_throttled
See Error Codes → Sending Status (Reputation) Errors for how to resolve each.
Related
- Error Codes — full list of API error codes
- Rate Limiting — per-second/minute request caps
- Templates — the recommended way to send large HTML payloads