Runs examples for real against your account. Test keys only; kept in this tab, never stored on our side. Get a key
ZapSMTP / Docs / Guides

Errors, limits & paging

The rules every endpoint shares. Base URL https://zapsmtp.xyz/v1, JSON in and out, timestamps in RFC 3339 (UTC), ids are time-ordered UUIDv7 strings.

API keys

Send the key as Authorization: Bearer <key>. The full key is shown once, when you create it; we store only a hash.

Key types
zap_…liveDelivers email. The From domain must be verified in your account.
zap_test_…testFull validation, email log, events and webhooks, but nothing is delivered and the monthly quota is not charged (the per-second limit still applies). Any From domain is accepted. Events carry test: true; list them with GET /emails?mode=test.
full_accesspermissionEvery endpoint.
sending_accesspermissionOnly sending: POST /emails, /emails/batch, /emails/spam-check, rescheduling and canceling. Can also be limited to one domain and one stream.

Errors

Errors use HTTP status codes and always carry both a flat shape (statusCode, name, message) and a nested one. name equals error.code. Every response has an X-Request-Id header; include it when you contact support.

{
  "statusCode": 422,
  "name": "missing_required_field",
  "message": "subject is required",
  "error": {
    "code": "missing_required_field",
    "message": "subject is required",
    "type": "invalid_request_error"
  }
}
Codes
validation_errorHTTP 400Malformed JSON or a field the endpoint does not know (unknown fields are rejected, so typos never pass silently).
invalid_idempotency_keyHTTP 400Idempotency-Key longer than 256 bytes.
missing_api_keyHTTP 401No Authorization header.
invalid_api_keyHTTP 401Unknown, revoked or expired key.
restricted_api_keyHTTP 403The key has sending access only, or is limited to another domain or stream.
domain_not_verifiedHTTP 403Live key sending from a domain that is not verified.
account_suspendedHTTP 403The account is suspended.
plan_limit_reachedHTTP 403Your plan’s limit for domains or SMTP credentials is reached.
test_key_restrictedHTTP 403A test key (zap_test_…) tried to change the account: test keys may send test email, render templates and read. Use a live key.
key_restrictedHTTP 403A restricted key creating or changing keys tried to give them more than it has: an expiry later than its own, or another stream.
email_unverifiedHTTP 403Confirm your account email address first; we sent a link to it.
session_requiredHTTP 403Team and account management needs a dashboard session, not an API key.
not_foundHTTP 404No such resource in your account (or outside your plan’s log retention).
method_not_allowedHTTP 405The path exists, but not with this HTTP method.
idempotency_key_reusedHTTP 409The Idempotency-Key was used with a different body.
idempotency_request_in_progressHTTP 409The first request with this key is still running.
not_cancellableHTTP 409The scheduled email was already dispatched or canceled.
conflictHTTP 409The resource already exists.
not_readyHTTP 409The received email is still being stored; retry the erasure in a few seconds.
link_expiredHTTP 410The download link has expired; request a new one from the API.
payload_too_largeHTTP 413Body over 40 MB.
misdirected_cellHTTP 421Your account is served by another cell of ZapSMTP. The message names the cell and its URL, and the Zap-Cell header names the cell. Send to that URL; retrying here fails the same way.
missing_required_fieldHTTP 422A required field is missing.
invalid_parameterHTTP 422A field has an invalid value; the message says which.
invalid_attachmentHTTP 422An attachment could not be decoded or fetched.
template_render_errorHTTP 422A template variable is missing, the template is invalid, or (on save) a tag is not a variable name.
template_variables_missingHTTP 422A send with a template lacks required variables that have no default; the message lists them (see Variables).
template_variables_invalidHTTP 422A send with a template gives variables of the wrong type for the template’s variable schema; the message lists them.
reserved_domainHTTP 422The domain is reserved and cannot be added.
invalid_logoHTTP 422The brand logo SVG could not be used (PUT /domains/{id}/brand); the message says why.
invalid_certificateHTTP 422The brand certificate (VMC) PEM is not valid (PUT /domains/{id}/brand).
automated_messageHTTP 422The email you reply to is automated (an auto-reply, a bounce, a list); answering it can start a mail loop. Pass allow_automated: true to reply anyway.
limit_exceededHTTP 422A per-account limit is reached, such as 20 forward destinations.
quota_exceededHTTP 422The image library is full (2,000 images or 1 GB): delete unused images first.
invalid_imageHTTP 422An uploaded image could not be used; the message says why.
rejectedHTTP 422The MTA refused the message; the message gives its reason. Not retryable as is.
rate_limit_exceededHTTP 429Over the per-second limit (Retry-After: 1), or too many failed authentications.
monthly_quota_exceededHTTP 429Free plan or spending cap reached for this month.
daily_quota_exceededHTTP 429Daily limit reached (Free plan: 100 emails a day, resets at 00:00 UTC).
overloadedHTTP 429The server is at capacity (Retry-After: 1), or a send could not be taken because the event pipeline is backed up (Retry-After: 5). Nothing was sent; retry after Retry-After with the same Idempotency-Key.
thread_reply_limitHTTP 429Too many replies in one conversation in the last hour (a mail loop?). Retry-After: 3600.
internal_errorHTTP 500Something failed on our side. Safe to retry with the same Idempotency-Key.
service_unavailableHTTP 503Temporarily unable to accept, for example while a backing service fails over after a node loss (Retry-After: 2), or while the MTA is unavailable, the suppression list is loading or too many large bodies are in flight (Retry-After: 5). Safe to retry with the same Idempotency-Key.
scanner_unavailableHTTP 503The spam checkers are temporarily unavailable (spam checks); try again.
storage_unavailableHTTP 503Object storage is not configured on this deployment, so images cannot be uploaded.
inbound_not_configuredHTTP 503Inbound email is not enabled on this deployment.

Rate limits and quotas

Sending responses report your budget in headers. Back off on 429 and honor Retry-After.

Response headers on sends
RateLimit-LimitRecipients per second for your account.
RateLimit-RemainingRecipients left in the current second.
RateLimit-ResetSeconds until the budget refills (always 1).
Zap-Quota-Monthly-LimitEmails included this month, or unlimited on paid plans without a spending cap (extra email is billed as overage).
Zap-Quota-Monthly-RemainingEmails left this month; omitted when the limit is unlimited.
Limits
Recipients per email50 across to, cc and bcc
Emails per batch100
Request size40 MB, attachments included
Free plan3,000 emails a month, at most 100 a day
Spam checks30 a minute per account

Idempotency

Send Idempotency-Key: <1–256 bytes> with POST /emails and POST /emails/batch to retry without sending twice. Keys belong to the API key and are kept for 24 hours together with a fingerprint of the request.

What happens on a retry
Same key, same body, finishedThe original response is returned with Idempotent-Replayed: true.
Same key, different body409 idempotency_key_reused
Same key, first request still running409 idempotency_request_in_progress
First attempt got 429 or 5xxThe key is released; retry with the same key.

Pagination

Lists return {"object": "list", "has_more": false, "data": [...]}, newest first.

  • GET /emails and GET /emails/receiving: limit 1–100 (default 20); pass the last id (or an RFC 3339 time) as before for older items, after for newer ones.
  • GET /suppressions: limit 1–1000 (default 100); pass next_cursor back as after while has_more is true.
  • Other lists return every item in one response.

Email statuses

An email’s status is the latest event: queued, delivered, delivery_delayed, bounced, complained, failed, opened, clicked, replied (reply tracking) or suppressed. Scheduled emails show scheduled until they are sent, or canceled.

Streams

transactional (default) and broadcast leave from separate IP pools, so a newsletter never slows down a password reset. Broadcast emails to one recipient get RFC 8058 one-click unsubscribe headers automatically; an unsubscribe adds the address to your suppressions and stops broadcast mail to it, while transactional mail still goes out. Bounces, complaints and manual suppressions stop both streams.