Page sizes, validated queries and fixes
A limit above the maximum is treated as the maximum
A list request whose limit is above its maximum now gets the maximum instead of 400: 100 on
every list, 200 for sending mailboxes and 25 for enrollment runs. GET /v1/call-log,
GET /v1/scored-calls and the contact-list pages had no maximum before and now return at most
100 per page. Every page reports the limit it used; the call-log page without filters, the
contact-list and follow-up pages and the snoozed-contact list gained the field. A limit that is
not a positive number still fails with 400. What to do: if you ask for more than 100,
compare the limit in the response with what you sent and keep paging.Call-log and scored-call queries are validated
GET /v1/call-log and GET /v1/scored-calls now check and convert their query parameters:- A list filter takes a single value without
[], such asfilters[user_ids]=ID. It used to fail with 500. filters[exclude_negative_dispositions]=falseleaves the filter off. It used to turn it on.start_date,end_date,min_scoreandmax_scoreon scored calls work. They used to return an empty page.- A value that does not fit its parameter, such as an unknown
outcome, a date that does not parse or a score that is not a number, fails with 400. Unknown parameters are still dropped.
Fixes
PUT /v1/snoozed-contacts/{id}acceptssnooze_until, so a snooze’s end date can be changed.- Creating, editing and pinning a note, and reading or updating one snoozed contact, return the record in the documented shape. They used to wrap it in internal fields.
GET /v1/snoozed-contactsreturns each record’s real_id,teamandcontact_list. They used to be regenerated on every request.- An ID that is not valid answers 400, not 500, on the contact-list, snoozed-contact and
note endpoints and in analytics
user_ids. - Phone lookup callbacks no longer include the contact’s email addresses. Use an email lookup for those.
Reference corrections
Errors the API could already return
The Errors page now covers every status the API can answer with, not only the common ones: 413 for a body over the size limit (10 MB on/v1/contact-lists and
/v2/sequencer, 1 MB elsewhere), 422 when the Sequencer’s rules refuse a request, 502
and 504 when a service behind the API cannot be reached or does not answer within 55
seconds, and 405 on /v2/sequencer during planned maintenance. It also says which 403s are
about the acting user_id rather than the key, and the order the checks run in. Nothing in the
API changed. What to do: treat 413 and 422 as not retryable, and 502 and 504 like a 5xx.Pagination envelopes and IDs
The API Reference now lists the five pagination envelopes the v1 and v2 lists use, and the IDs that are not 24-character hexadecimal strings: disposition and sending-mailbox IDs are integers, CRM sequence IDs are the CRM’s own, and enrollment-run IDs start withenroll_. Nothing in the API changed.Webhook delivery
Webhooks are now documented in one place, with the events, the payload shape and the delivery rules. Two facts were missing before: aCALL_LOGGED subscription is sent only for calls whose disposition is ticked on it, and the
dashboard does not display the signing secret, so x-salesfinity-signature cannot be checked
yet. Keys and webhooks are created under Settings → Connections → API & Webhooks.The OpenAPI description
The OpenAPI description now matches what the API sends, with no operation, parameter or field removed:- Every successful response documents the
X-Request-IdandX-RateLimit-*headers, and every error response documentsX-Request-Id. request_idis a required field of the error body, and every error example carries it.- Every
/v2/sequenceroperation documents 502 and 504. - Sequencer events list the fields they already returned:
team,sequence_state,task,user,external_id,created_atandupdated_at. - Request fields carry the length limits the API already enforced, and descriptions state the
defaults, units and conditions that were missing, such as
primary_reply_pause_durationbeing in seconds and ascheduleneeding all five fields.
Known issues now documented
Some endpoints do not behave as documented before, and their reference pages now say so with a workaround: a snoozed contact’ssnooze_until cannot be changed, the date and score filters on
GET /v1/scored-calls return no results, and a few Sequencer responses expand fields that the
schema types as IDs. The contact-list, snoozed-contact and note endpoints answer 500, not
400, for an ID that is not 24 hexadecimal characters, and so do the analytics endpoints for such
an ID in user_ids. What to do: read the warning on the reference page of any of these
endpoints you call, and check IDs before sending them.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 one-minute windows that start on the minute: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 a sequence with email steps will not enable, read the team’s
mailboxes with GET /v2/sequencer/email-accounts: enabling needs at least one mailbox the
sequence sends from with is_connected and can_send true and is_paused false.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 delivery that times out, cannot connect, or gets a 429 or a 5xx is
attempted up to 3 times in total. The payload is unchanged. What to do: skip events whose ID
you have already processed. See Webhooks.Webhook URLs must be public
Creating a webhook, or changing its URL, is refused unless the URL is a publichttp or https
address: not localhost, and not a private, loopback or link-local IP address. Existing
webhooks keep working until their URL is changed. What to do: point webhooks at a publicly
reachable address.Rate-limit and request-ID headers readable in browsers
Responses now listX-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
Retry-After and X-Request-Id in Access-Control-Expose-Headers, so browser code can read
them. Nothing changes for server-side clients.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.Next steps
Handle API errors
Status codes, error bodies, and what to retry.
Stay under the rate limits
Read the limit headers and back off before you hit a 429.