ZevCampaign Docs
Sign up

API Reference

Rate limits

The per-route limits, and what to do when you hit one.

Limits are per API key, per minute, and vary by route.

RoutePer minute
POST /v1/subscribe30
POST /v1/contacts120
GET endpoints120
POST/DELETE on list members60
POST/DELETE on suppressions120
GET /v1/reports/*30

Subscribe is the tightest because it is the one route a browser can reach, and an unlimited public endpoint that sends email is an invitation to use your form to mail a stranger repeatedly.

Reports are lower than other GET routes because each one adds up figures across your whole workspace rather than fetching a single record. Send back the ETag as If-None-Match and an unchanged report answers 304 Not Modified, which is cheap enough that 30 a minute comfortably covers a dashboard refreshing every few seconds.

Requests count against the limit whether they return 200 or 304.

When you hit one

{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "Too many requests. Retry after 24 seconds."
  }
}

429, with a Retry-After header in seconds. Wait that long, then retry.

Backing off properly

async function call(url, options, attempt = 0) {
  const res = await fetch(url, options);
  if (res.status !== 429 || attempt >= 5) return res;

  const after = Number(res.headers.get('Retry-After') ?? 1);
  // Jitter, so a fleet of workers that hit the limit together does
  // not come back together and hit it again.
  const wait = after * 1000 + Math.random() * 1000;
  await new Promise((r) => setTimeout(r, wait));
  return call(url, options, attempt + 1);
}

Importing a large audience

For a bulk import, prefer the dashboard’s CSV import. It is built for volume and gives you a report of what merged, what was skipped and why.

If you must do it over the API, 120 contacts a minute is about two a second. Space the calls rather than firing them in parallel and retrying the failures, which just converts one limit into a slower version of the same limit.

Confirmation emails have their own limit

Separately from the route limit, we will not send a second confirmation email to the same address within a short window, however many times the form is submitted.

Your call still succeeds and still returns confirmation_sent. We simply do not mail them again. A signup box that emails on every submission is a way to mail a stranger repeatedly by pressing a button.

Updated at, Saturday, October 10, 2026