Skip to main content
Every error has a consistent JSON shape:
The HTTP status and the error.code are always consistent. Switch on code, surface message to your end user.

Codes

Plan-limit errors

Plan-limit FORBIDDEN errors carry a localized message such as “You have reached the maximum number of leads for your plan.” — surface it to your end users as-is, since they’re the ones who can take action (upgrade or remove records). These come from the billing guards on:
  • POST /leads — when maxLeads is exceeded.
  • POST /projects — when maxProjects is exceeded.
  • POST /webhooks/subscriptions — when maxWebhookEndpoints is exceeded.

Validation errors

VALIDATION_ERROR messages list every field that failed in path: reason form, joined by ; :
Parse the message if you need to surface field-level errors in your own UI, or just show the whole string.

Idempotency and retries

  • 5xx and 429 are safe to retry. Use exponential backoff capped at the Retry-After value when present.
  • 4xx (other than 429) means the request itself is wrong. Don’t retry without changing it.
  • POST /webhooks/subscriptions is idempotent when you pass external_id — see Create a subscription.
  • Other writes are not idempotent. If you retry a POST /leads blindly, you’ll create duplicates. Use Search a lead first to de-dupe.