Read the response envelope

Most responses, successful or not, share one envelope. isSuccess is true only when errors is empty, message carries a short summary, and data holds the result. Check isSuccess before reading data.

{
  "errors": [
    { "propertyName": "CompanyName", "errorMessage": "Company name is required." }
  ],
  "isSuccess": false,
  "message": "Validation failed.",
  "data": null
}

Each entry in errors has a propertyName and an errorMessage. For a validation failure, propertyName names the field and errorMessage is text you can show to a dealer user. Validation rules for some fields are configured per dealership, so treat errors as the source of truth instead of hard-coding which fields can be rejected.

Error codes

When an error isn't tied to a field, propertyName holds a code that matches the HTTP status.

BAD_REQUEST400. A required value is missing or the request can't be processed as sent.
NOT_FOUND404. The record doesn't exist in your dealership, or has been deleted.
UNAUTHORIZED401. crmSeries couldn't confirm access to your dealership's data for this request. Get a new token and retry once; if it repeats, contact crmSeries.
INTERNAL_ERROR500. Something failed on the crmSeries side. See retries below.

Responses without the envelope

Three kinds of failure happen before crmSeries can build the envelope, so handle them by status code:

  • 401 or 403 with an empty body means the credential itself was rejected: missing, expired, malformed, or not allowed for this operation. A bearer-token 401 includes a WWW-Authenticate header with the reason. See troubleshooting.
  • 400 with title and errors as an object means the body couldn’t be read: invalid JSON, or a value of the wrong type, such as text where a number belongs. errors maps each field to a list of messages.
  • 500 with an unexpected body can happen when an error isn’t handled. Don’t depend on parsing it; treat the status code as the signal.
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": { "$.phone": ["The JSON value could not be converted to System.String."] },
  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Keep the trace ID

Most responses carry an X-Trace-Id header. Log it with the status code and the operation path for every failed request. When you contact crmSeries, the trace ID lets the team find your exact request.

Retry thoughtfully

400, 404Don't retry. Fix the request or the data first.
401Request a new access token once, then retry. If it fails again, stop and check your credentials.
403Don't retry. The operation needs a different credential type or access.
500-599Retry reads with exponential backoff, for example 1, 2, 4 and 8 seconds, then give up and alert.

Be careful with writes. crmSeries doesn't support idempotency keys, so a create request that timed out may already have succeeded. Before replaying it, check whether the record exists, or use an operation that matches records by your system's own identifier.

Rate limits

crmSeries doesn't currently limit request rates. Build your client to handle a 429 status anyway: wait for the number of seconds in the Retry-After header before trying again.