Limits and good practice
This page collects the limits of the API and the habits that keep an integration reliable.
Limits#
| Area | Limit |
|---|---|
| Request rate | 60 requests per minute per token, fixed window, one budget for all endpoints |
| Page size | limit from 1 to 100, default 50 |
Body of POST and PATCH on prospects, and of POST /campaigns/{id}/prospects |
64 KiB |
| Body of suppressions, hooks and reply classification | 4 KiB |
Items in prospect_ids or emails |
1 to 200 for each call |
| Idempotency key length | 1 to 255 characters |
| Idempotency key retention | 24 hours |
search on companies |
200 characters |
email filter on prospects |
320 characters |
visit_list of an offer |
The 200 latest visits |
recent_events of a company |
The 50 latest events |
Reply snippet |
160 characters |
| Webhook response time | 10 seconds |
| Webhook attempts | 3 |
| Webhook timestamp tolerance for your verification | 300 seconds |
| MCP proxied call | 20 seconds |
The rate limit counter lives in the memory of the application process. It resets when the service restarts, which happens on a release. The limit works as a brake on runaway loops.
Good practice#
Authenticate and store tokens well#
- Use one token per integration and revoke the one that leaks.
- Keep tokens in environment variables or a secret manager.
Retry safely#
- Send an
Idempotency-Keyon everyPOSTthat creates something, and reuse the key on each retry of the same request. - Retry
5xxand429with backoff. UseRetry-Afterfor429. - Do not retry
4xxunchanged.
Stay inside the rate limit#
- Read
X-RateLimit-Remainingand slow down before it reaches0. - Use
limit=100on lists to need fewer requests. - Filter on the server with
status,sinceorcreated_sinceand do not download a whole list to filter it yourself. - Poll with
sinceorcreated_sincefor new rows, or subscribe to a webhook instead.
Write complete state on updates#
PATCH /prospects/{id} clears the fields you omit. Read the prospect, change the fields and send the full state.
Treat enrolment as a per-person result#
POST /campaigns/{id}/prospects returns 200 even when nobody was enrolled. Read summary and the result of each item.
Receive webhooks reliably#
- Verify the signature on the raw body.
- Answer with
2xxwithin 10 seconds and process the event afterwards. - Store
X-Seegnals-Deliveryand ignore a delivery you have seen. - Point the webhook at the final URL. anymail does not follow redirects.
Read null as not measured#
opened and clicked on a campaign are null when tracking is not enabled. Do not convert null to zero.