Errors and rate limits
Key-authenticated JSON endpoints return an ok boolean. Authentication, scope, routing, and validation errors usually use HTTP status codes; messaging and public booking have documented exceptions.
Common API statuses
Section titled “Common API statuses”| Status | Meaning | Typical body |
|---|---|---|
| 200 | Success, duplicate, or a domain/provider result that must be read from ok | {"ok":true,...} or messaging {"ok":false,"reason":"..."} |
| 402 | Message blocked by one of five billing reasons | {"ok":false,"reason":"insufficient_credits",...} |
| 403 | Unknown/revoked key, wrong scope, or unbound CTI agent | forbidden, wrong_scope, no_bound_agent |
| 404 | Unknown API route or inaccessible resource | unknown_route, not_found, no_lead |
| 422 | Request validation failed | bad_channel, bad_phone, invalid_list, malformed_json |
| 429 | Fixed-window quota exceeded | {"ok":false,"error":"rate_limited"} |
| 500 | Database/insert failure | db_connect_failed, insert_failed |
There is no common request ID, error object, Retry-After, or rate-limit response header today. Error identifiers are stable machine-readable strings, but endpoints are not wrapped in a version-negotiation layer.
Fixed-window limits
Section titled “Fixed-window limits”| Surface | Limit | Bucket identity |
|---|---|---|
/hooks/api_v1.php (all five routes combined) | 300/hour | API key ID |
/hooks/lead_intake.php | 120/hour | API key ID |
/hooks/kpi_ingest.php | 600/hour | API key ID |
/hooks/dni.php (all actions combined) | 3,600/hour | salted hash of IP |
/book/api.php booking + reschedule | 10/hour | raw IP |
These are server-clock fixed windows aligned to Unix hours, not rolling windows. The increment happens before the limit check, and a request above the threshold remains counted. All three key-auth endpoint families use the same key:{id} bucket today, even though they compare it to different thresholds. For example, 121 earlier KPI/API calls can make the next lead-intake request exceed its 120 threshold. Treat the effective allowance as the strictest endpoint you need. All five api_v1.php routes also share one counter and the 300 threshold.
Retry guidance
Section titled “Retry guidance”- Retry
429after the next hour boundary; use exponential backoff plus jitter if the exact reset is unknown. - Retry provider ingress only on
5xx. Duplicate provider identities are designed to be idempotent. - Use a stable
operation_idwhen sending messages so retries do not create a second provider operation. - Do not retry deterministic
4xxuntil changing credentials, scope, route, or input. - Inspect both HTTP status and JSON
ok/reason, especially formessagesand booking.