Errors, limits and idempotency

Errors

Errors return JSON with a plain-English message and a code:

{"error":"Accept the lead before reporting an outcome","code":"conflict"}
StatusCodeMeaning
200, 201, 202Worked (201 created, 202 queued).
400bad_requestA filter, date or cursor is wrong, or a key was sent in the address.
401unauthorizedKey or token missing, wrong, expired, turned off, or the app was disconnected.
403insufficient_scopeThe credential lacks the scope this call needs.
404not_foundWrong address, or the lead is not yours.
405method_not_allowedWrong method for this address.
409conflictNot allowed right now: lead not accepted, status move not allowed, credit already asked, customer has no account for messages.
415unsupported_media_typeWrite without Content-Type: application/json.
422invalidA field value is wrong (the message says which).
429rate_limitedToo many requests. See Retry-After.
500server_errorFailed on our side. Retry with backoff.

Rate limits

Every response carries:

HeaderMeaning
X-RateLimit-LimitRequests allowed per hour
X-RateLimit-RemainingLeft in this hour
X-RateLimit-ResetUnix time the hour resets
Retry-AfterOn 429: seconds to wait

Limits: API keys 600 requests an hour per business, shared by all its keys. Partner apps 600 (sandbox) or 3,000 (verified) an hour per app per pro.

Idempotency

Send Idempotency-Key: <your unique value> (up to 200 characters) on any write. If you retry with the same key and the same request within 24 hours, you get the first answer back with Idempotent-Replayed: true, and nothing happens twice (no second message, no second charge). The same key with a different request returns 422. Use a new key for each new action.

Without a key: GET is always safe to retry; setting the status a lead already has returns 200 and changes nothing; accepting twice is safe. Sending a message twice sends it twice, so use a key for messages.

Retries

Retry 429 and 5xx with growing waits (1, 2, 4, 8 seconds plus a little randomness). Do not retry 400, 401, 403, 404, 409 or 422 without changing something.

Versions

The version is in the address (/v1) and in the API-Version response header. Within v1 we only add: fields, events, filters, endpoints. Removing or renaming anything gets at least 6 months' notice in the changelog and a new version (/v2), while /v1 keeps running.