Skip to main content
All CRM+ API errors return JSON with a consistent structure — most of the time. HTTP status codes indicate the general category of failure; the response body provides machine-readable codes and human-readable descriptions. A small number of endpoints still return plain-text error bodies in legacy formats, so robust integrations always inspect response.status first before parsing the body. This page covers the canonical error shape, every standard HTTP status code, and a worked example of defensive client code.

Target error shape

The canonical error response the CRM+ API is moving toward is:
The CRM+ API is in the process of migrating to this canonical shape. Some endpoints currently return plain-text error messages or non-standard JSON structures — particularly for 401 Unauthorized responses, which may return Authorization has been denied for this request. as plain text. Write your error handling to inspect response.status first, then attempt to parse the body. Do not assume the body is always valid JSON or always matches the canonical shape.
The CRM+ spec does not yet document 401, 403, 422, 429, or 500 responses on any individual endpoint. These errors can and do occur. Build your integration to handle all standard HTTP error codes defensively, not just the ones explicitly listed in the reference documentation.

Standard error codes

404 means the specific resource does not exist. An empty search result on a list endpoint is not a 404 — it returns 200 with list: [] and total: 0. Code that treats 404 as “no records matched” will misinterpret real missing-resource errors.

Handling errors in code

A production-grade CRM+ client should: inspect the status before parsing the body, fall back gracefully when the body is plain text, branch on status for actionable error types, and respect the Retry-After header on 429.

Validation error details

When the API returns 422 VALIDATION_FAILED, the error.details array contains one entry per field that failed validation. Use these entries to surface specific error messages to your users or to identify the exact field that needs correction.
When error.details is an empty array ([]), the error applies to the request as a whole, not to any specific field.
Surface error.details[].message directly to end users in your integration’s UI. The messages are written for human consumption and do not leak internal system details. Use error.details[].code for programmatic branching (for example, to retry differently for a REQUIRED field versus a MUST_BE_POSITIVE value).

Retryable vs. non-retryable errors

Not every error is worth retrying. Categorize errors before deciding whether to retry: See Rate Limits for the canonical retry-with-backoff pattern for 429 responses.

Cross-API error handling

If your integration uses both Raise and CRM+, note that the two APIs return different error shapes. CRM+ uses an error.code / error.message / error.details[] envelope. Raise uses an RFC 7807–style title / status / detail envelope with field-level errors in a flat errors map. Detect which shape you have by checking whether the response root contains error (CRM+) or title (Raise). See Raise Error Handling for the Raise-specific details.

Next steps

Rate Limits

The retry-with-backoff pattern for handling 429 Too Many Requests responses.

Pagination and Filtering

How to iterate large result sets and how empty-result responses differ from 404.

Authentication

How to fix 401 and 403 responses by checking credentials and permission groups.

Reconcile Failed Syncs

Patterns for retrying, deduplicating, and recovering from partial failures in bulk operations.
Last modified on May 27, 2026