Notideus
API Reference

Quotas and limits

Monthly allowances, batch limits and quota errors.

Send quota

Every plan includes a monthly email allowance, enforced per team. When the allowance is reached the API answers 402 Payment Required with quota_exceeded. Example response:

{
  "error": {
    "code": "quota_exceeded",
    "message": "monthly send quota exceeded"
  }
}

How the window is measured depends on the plan:

  • Free plans — a calendar month: the allowance resets on the first of each month.
  • Paid plans — the current Stripe billing period: it resets on each invoice.

Two semantics matter when you send in bulk:

  • Whole-batch up-front check. POST /v1/emails/batch is validated against the quota before anything is stored: a batch that would not fit is rejected wholesale, so a 402 never leaves a half-sent batch.
  • Idempotent replays are exempt. Re-sending with a previously stored idempotency_key returns the original row without consuming quota, so retrying after a timeout never double-counts.
Known v1 limitation: quota counts stored emails. Deleting sent emails frees allowance, so the counter and your actual sent volume can drift apart.

Contact quota

Contact storage is also allowance-based. Bulk upserts enforce it per item: contacts that do not fit come back in the item results with 402 quota_exceeded, while the items that fit are stored normally — a contact-quota failure never aborts the whole bulk call.

Limits

LimitValue
Emails per batch call100
Custom headers per email10 (names ≤ 126 chars, values 1–995 printable-ASCII chars)
WhatsApp messages per batch call100
Recipients per WhatsApp item50
Contacts per bulk upsert1000
Contacts per list page100 (default 20)
Send rate1 email/s (free), 10/s (paid), burst 5×; 429 rate_limited + Retry-After

Rate limiting

On top of the monthly quota, send requests are rate-limited per team: 1 email/s on the free plan, 10/s on paid plans (with a burst of 5× the per-second rate). Exceeding the limit answers 429 Too Many Requests with rate_limited and a Retry-After header (seconds to wait):

{
  "error": {
    "code": "rate_limited",
    "message": "send rate limit exceeded; retry after 1 seconds"
  }
}

In POST /v1/emails/batch the limit is applied per item: once the bucket is empty, the remaining items fail with rate_limited in their per-item result (no Retry-After header there). Replays with a stored idempotency_key do not consume rate. The monthly volume quota still applies on top.

Honor Retry-After on a 429: sleep (or re-queue) for the given number of seconds rather than hammering the API — and keep the same idempotency_keys when you retry so a timed-out first attempt never double-sends.
Copyright © 2026