Rate limits, safe retries and request IDs
Rate limits for every endpoint
Every endpoint is now rate limited per team, and all of a team’s API keys share the limits. Requests are counted in fixed 60-second windows:Every response to an authenticated request carries
X-RateLimit-Limit, X-RateLimit-Remaining
and X-RateLimit-Reset. A 429 carries Retry-After, the seconds to wait. Before this change
only /v2/sequencer/* was limited, at 120 requests per minute. We give notice before lowering
any limit. What to do: wait for Retry-After on a 429. See
Rate limits.Idempotency-Key on every Sequencer POST
Every POST /v2/sequencer/* endpoint except the three /preview endpoints now accepts an
Idempotency-Key header. A retry with the same key replays the original response; the same key
with a different body or path, or while the first request is still running, returns 409.
Keys are kept for 24 hours per team. POST endpoints outside the Sequencer are still not
idempotent. See Retrying writes safely.Internal fields removed from sequencer settings
GET /v2/sequencer/settings no longer returns the three internal fields about the team’s
sending account: its account ID and its two provisioning timestamps. What to do: stop reading
them if you do. To find out why an email step will not enable, read the team’s mailboxes with
GET /v2/sequencer/email-accounts: enabling needs one that is connected, unpaused and able to
send.Request IDs and one error body for every error
Every response carries anX-Request-Id header. Send your own to trace a request, or let us
generate one. Every error body now has the same four fields, statusCode, error, message
and request_id, including errors raised while reading the request, such as malformed JSON or
an oversized body. Status codes and messages are unchanged. What to do: log request_id and
include it when you contact support. See Errors.Webhook event IDs
Every webhook delivery carries anx-salesfinity-event-id header that stays the same across
retries of the same event. A failed delivery is attempted up to 3 times in total. The payload is
unchanged. What to do: skip events whose ID you have already processed. See
Staying in sync.Enrichment callback_url must be public
POST /v1/api/enrichment/email and POST /v1/api/enrichment/phone now reject, with 400, a
callback_url that is not a public http or https URL: localhost, and private, loopback or
link-local IP addresses. Requests already accepted are unaffected. What to do: point callbacks
at a publicly reachable address.Reference corrections
GET /v1/follow-up is now documented with the shape it has always returned: the page position
is under pagination (total, page, next), not at the top level.