Skip to main content

Error Handling

The API uses standard HTTP status codes and returns errors in a consistent JSON format.

Error response format

Error codes

Handling errors

Check the HTTP status code first, then use error.code for programmatic handling:

Validation errors

When request validation fails, the message field describes which fields are invalid:

Conflict errors

Delete operations on configuration resources (stages, tiers, categories, tags, custom fields) return 409 Conflict if the resource is currently in use:
Reassign the records to a different stage/tier/category before retrying the delete.

Custom field validation

Creating or updating a lead, deal, or partner with custom field values — whether inline on the entity itself, or via POST/PATCH/DELETE /v1/custom-field-values and the per-entity custom-field endpoints (PUT/ PATCH/DELETE /v1/leads/:uuid/custom-fields, .../deals/:uuid/custom-fields, .../partners/:uuid/custom-fields) — is validated server-side against each field’s required flag, its partner_type scope, and any active custom field rules (visibility, locking, auto-population). A violation returns a 400 validation_error with a details array — one entry per rejected field: reason is one of:

Deleting a custom field value

DELETE is treated as submitting an empty value for the field, so the same checks apply:
  • Deleting a visible, required value returns required_cannot_blank — clearing it would leave the entity without a value a required field demands.
  • Deleting a value that’s currently locked by an active custom field rule returns locked_by_rule — the value can’t be changed (including to empty) while the rule that sets it is active.
  • Deleting a hidden field’s value, or a value with no active constraints, succeeds normally (204).
Example response (400):

Partnership locks

On the partner API, a vendor can disable editing of lead status or deal stage for a partnership. While a lock is on, a request that would change the locked value returns 403 forbidden and nothing in the request is saved. The lock that applies is the calling partner’s own partnership. The details array holds one entry with reason locked_by_partnership, and field is one of: Re-sending the current value, or omitting stage_uuid on create (the deal then starts in the default stage), still succeeds. For rejected_reason and accepted_reason, the current value is the one the lead response shows you: it is null when the vendor hides the reason from partners or the lead is not in that reason’s status, so echoing null back is not a change. Example response (403):