Credits & rate limits
Credits
| Action | Credits |
|---|---|
Manual POST …/leads with status: "created" | −1 |
Manual POST …/leads/batch | −1 per item with status: "created" |
Manual lead duplicate / excluded | 0 |
Manual POST …/leads/batch-update | 0 |
Manual POST …/leads/batch-delete | 0 (no credit refund) |
Maps POST /campaigns launch | 0 at launch; −1 per email lead found later |
| Start / pause / send / list / get | 0 |
POST /tools/validate-email with mode=mx | 0 |
POST /tools/validate-email with mode=full | −1 only when ZeroBounce HTTP API returns a usable status; cache / disabled / error / short-circuit → 0 |
POST /tools/validate-emails | Sum of per-item rules (max 100). Out of credits → HTTP 200 with per-item insufficient_credits |
POST /tools/enrich-website | 0 |
Insufficient credits → single add 403 insufficient_credits (never HTTP 402); add-batch → HTTP 200 with per-item insufficient_credits (not envelope 403). Single validate insufficient for a needed ZeroBounce call → 403 insufficient_credits (never 402).
Check balance with GET /credits.
Rate limits
Fixed 60-second windows. On 429, the response includes Retry-After (seconds) and often details.retryAfterSeconds.
Per API key (defaults)
| Class | Applies to | Default RPM |
|---|---|---|
global | All authenticated routes (including GET /activity, GET /insights/overview) | 120 |
add_lead | POST …/leads | 60 |
add_leads_batch | POST …/leads/batch | 10 |
update_leads_batch | POST …/leads/batch-update | 6 |
delete_leads_batch | POST …/leads/batch-delete | 10 |
patch_lead | PATCH …/leads/:id | 60 |
create_campaign | POST /campaigns | 6 |
campaign_control | POST …/start, POST …/pause | 20 |
inbox_send | POST /inbox/messages | 10 |
validate_email | POST /tools/validate-email | 60 |
validate_emails_batch | POST /tools/validate-emails | 10 |
enrich_website | POST /tools/enrich-website | 20 |
inbox_send RPM is not the only 429 on POST /inbox/messages. Daily send quota and a high-bounce pause also return rate_limited with Retry-After (bounce pause is often about 86400 seconds).
Pre-auth (before key resolves)
Protects against credential stuffing: IP and key-fingerprint buckets (defaults 60/min and 30/min). Failures still return 429 rate_limited.
Idempotency
Optional header on:
POST /campaigns/:id/leadsPOST /campaigns/:id/leads/batchPOST /campaigns/:id/leads/batch-updatePOST /campaigns/:id/leads/batch-deletePOST /inbox/messagesPOST /tools/validate-emailPOST /tools/validate-emails
POST /tools/enrich-website has no idempotency header. Single validate stores a replay only for HTTP 200; a 403 does not stick to the key.
Idempotency-Key: <client-unique-string>
| Rule | Detail |
|---|---|
| Max length | 128 characters |
| Replay | Same key + same body → same 200 response |
| Mismatch | Same key + different body → 409 conflict |
| In progress | Same key still running → 409 conflict (retry shortly) |
| TTL | About 24 hours |
| Add-batch persist | Only if any item is created | duplicate | excluded |
| Update-batch persist | When summary.updated > 0 |
| Delete-batch persist | When summary.deleted > 0 |
| Validate persist | Single POST /tools/validate-email stores a replay only for HTTP 200. A 403 does not stick. Enrich has no idempotency header |
Invalid / too-long keys → 400 validation_error.
Related
- POST /tools/validate-email
- POST /tools/validate-emails
- POST /tools/enrich-website
- POST …/leads/batch
- POST …/leads/batch-update
- POST …/leads/batch-delete
Pagination
| Query | Default | Max |
|---|---|---|
limit | 50 | 100 |
cursor | — | Opaque string from previous nextCursor |
Response field: nextCursor (string or null). Invalid/expired cursor → 400 validation_error.
Request size
Max body size: 131072 bytes (128 KiB). Over → 413 validation_error with details.maxBytes.