Two shapes
/v1 errors are structured, with a stable machine-readable code. Branch on the code, never on the message.
/api errors are flatter. error is always a human-readable string; code appears only where a caller needs to branch.
Status codes
A few
/api-specific codes carry the same meaning at 424, naming which capability is missing: search_unavailable, ai_scoring_unavailable, smartlead_not_configured, heyreach_not_configured.
What to do about each
429 — rate limited
429 — rate limited
Back off until the
X-RateLimit-Reset timestamp rather than retrying immediately. If you hit this steadily rather than in bursts, the key needs a higher limit.502 — provider error
502 — provider error
The upstream data source failed. Nothing is billed — no cost event is written when the provider call throws. Safe to retry with backoff.
409 — conflict
409 — conflict
The record is in a state that forbids the action: a search that is already running cannot be expanded, and a campaign that is not
awaiting_launch cannot be launched. Read the record first, then act on its actual state.404 on a record you own
404 on a record you own
On
/api, a record in another workspace is indistinguishable from one that does not exist. Confirm the session’s active workspace is the one that owns the record.Retries and idempotency
Billed endpoints accept an idempotency key, either as theIdempotency-Key header or an idempotencyKey body field. Reusing one across a retry means the work is not double-billed.
Debugging
Quote therequest_id from the failing response. It appears in meta.request_id, in the X-Request-Id response header, and on the matching row in GET /v1/usage/costs — which is also how you confirm whether a failed call was ever billed.