Errors and Rate Limits
The error envelope
Partner API responses are wrapped, except the registration endpoints (/api/v2/Partners/Register*):
their success bodies are plain objects, and Register and Verify answer 400 as one plain-text sentence.
See Registration and authentication endpoints.
In a wrapped response, response carries the payload, errorResponse carries the problems, and
exactly one of them is populated.
{
"response": null,
"errorResponse": {
"errors": [
{
"errorMessage": "Can't parse vin: invalidvin",
"errorField": "VIN",
"errorCode": "CantParseVIN",
"errorNumber": 4005,
"suggestions": [
{
"action": "CheckInput",
"message": "Verify the VIN is exactly 17 alphanumeric characters (no I, O, or Q)."
},
{
"action": "RetryWithAlternative",
"message": "Search by make, model, and year instead.",
"endpoint": "/api/v2/Partners/PlansSearch/MakeModelYear"
}
]
}
]
}
}
The field is errorResponse, and the payload field is response. Neither is called data.
| Field | Notes |
|---|---|
errorMessage |
Human readable. Safe to log, not always safe to show a customer verbatim. |
errorField |
Which input caused it. May be null. |
errorCode |
Machine readable identifier. Branch on this. |
errorNumber |
Numeric equivalent. Also stable. |
suggestions |
What to do about it. Often absent. |
affectedEntityIds |
Which entities the error relates to, where applicable. |
Suggestions
Where present, suggestions tells you what to do next without you having to encode the rules yourself.
| Field | Notes |
|---|---|
action |
CheckInput, RetryWithAlternative, UseDifferentEndpoint, or ContactSupport |
message |
Written to be shown to an end user as-is |
endpoint |
An alternative endpoint to call, on RetryWithAlternative and UseDifferentEndpoint |
This is especially useful for AI agents and automated integrations: a RetryWithAlternative with an
endpoint is a machine-followable instruction.
HTTP status codes
| Status | Meaning | What to do |
|---|---|---|
200 |
Success | |
201 |
Created. On VehicleRegistration, already cached. |
|
202 |
Accepted, still working. Async search only. | Poll the same endpoint every 1 to 2 seconds |
400 |
Validation failed | Read errorResponse.errors. Do not retry unchanged. On plan search, response is always null, and SystemError (10000) reports a search that failed on our side; that one is safe to retry. Register and Verify answer with one plain-text sentence, see Registration and authentication endpoints. Two of those sentences report a server problem and are safe to retry. |
401 |
Missing, invalid, rotated, or wrong-environment key (Rotate and Delete: any key but the current one) | See Authentication |
403 |
Authenticated but not permitted | Your account lacks the capability. Contact support. An HTML body instead of JSON means the firewall stopped the call, see Authentication |
404 |
Not found | Check the path and any id you sent |
429 |
Rate limited | Back off per Retry-After |
5xx |
Server-side failure | Safe to retry with backoff |
Only 5xx, connection failures, a plan search 400 with SystemError, and the two registration
server-problem sentences (An error occurred during registration. Please try again. and
An error occurred during verification. Please try again.) are safe to retry blindly. Never retry a slow plan search: it has
not failed, and a retry starts a second independent search that quotes the vehicle twice.
Registration and authentication endpoints
POST /api/v2/Partners/Register and POST /api/v2/Partners/Register/Verify do not use the error
envelope above. They answer 400 with one plain sentence and Content-Type: text/plain. There is no
errorResponse, so do not parse the body as JSON. If there are several problems, the sentences are
joined with a space. The Partners/Authentication endpoints answer a missing or invalid body the same way.
| Sentence | When |
|---|---|
The request body is missing, is not valid JSON, or has a field of the wrong type. |
The body is empty or is not valid JSON, for example a missing brace or colon. Or a field has the wrong type, for example "agreedToTerms": "yes" or "email": ["a@b.c"] |
Code must be a string of 6 digits. |
code is not a string of 6 digits |
Email is required. |
email and contactEmail are both missing or blank |
Verification code is required. |
code is missing or empty |
Invalid verification code. Please try again. |
Wrong code, attempts 1 to 4. Each one counts toward the limit of 5 attempts |
Verification code is invalid or expired. Please register again. |
The code has expired. Register again |
Verification failed. Please register again. |
The 5th wrong code. The registration is canceled. Register again to get a new code |
No pending registration found for this email. If you already verified it, use the API key you received (lost it? contact dev-support@chaiz.com); otherwise register first. |
No registration waits for this email: it was never registered, it is already verified, or it was canceled |
The ContactEmail field is required. (and the same for other fields) |
A required registration field is missing or empty |
The ContactEmail field is not a valid e-mail address. |
contactEmail is not a valid email address |
The field DisplayName must be a string or array type with a maximum length of '200'. (and the same for other fields) |
A registration field is too long. Limits: contactEmail 255, displayName 200, organizationName 200, websiteUrl 500, intendedUse 1000 characters |
You must agree to the terms of service. |
agreedToTerms is not true |
Registration limit reached. Please contact support. |
This IP address already has 3 active keys. Only Register checks this cap. The cap is checked first, so it also refuses a Register that would only re-send a pending code. Waiting does not free a slot. To free one, deactivate a key you do not use (DELETE /api/v2/Partners/Register), or contact dev-support@chaiz.com |
An error occurred during registration. Please try again. |
A server problem, not a problem with your request. Unlike other 400 answers, this one is safe to retry unchanged. Try again later. If it repeats, contact dev-support@chaiz.com |
An error occurred during verification. Please try again. |
A server problem, not a problem with your request. Unlike other 400 answers, this one is safe to retry unchanged. Try again later. If it repeats, contact dev-support@chaiz.com |
A 415 Unsupported Media Type means the Content-Type is not application/json.
POST /Register/Rotate and DELETE /Register answer 400, and GET /Register/Usage answers 404, with a
JSON body whose errors[0].errorMessage is No active registration found. (full shape:
{"errors":[{"errorMessage":"No active registration found.","errorField":null,"errorCode":null,"errorNumber":null}]})
when the key's partner has no active self-service registration, for example after a Delete that ran at the same
moment. This body has no response/errorResponse wrapper. The same status with an errorMessage that starts
with An error occurred is a server problem, not a missing registration: retry it later. A 401 means the key is
missing, invalid, rotated out or deleted. POST /Register/Rotate and DELETE /Register also answer 401 when the
key is valid but is not the registration's current key, for example a key that a parallel Rotate already replaced:
nothing is changed. The 401 body is empty or an application/problem+json object with title
Unauthorized, never the errors object.
Validation errors (4xxx)
| Number | Code | Field | Meaning | Fix |
|---|---|---|---|---|
| 4001 | ZipAndStateAreEmpty |
ZipAndState | Zip and state both missing | Send stateShortName or zip |
| 4002 | CarDetailsAreEmpty |
CarDetails | No vehicle identifier at all | Send a VIN, a plate, or make/model/year |
| 4005 | CantParseVIN |
VIN | VIN not valid | 17 alphanumeric characters, no I, O, or Q |
| 4006 | CantParseLicensePlate |
LicensePlate | Plate not valid | Check the format, and send stateShortName with it |
| 4009 | MileageIsLessThanZero |
Mileage | Negative mileage | Send a positive integer |
| 4013 | StateShortNameIsInvalid |
StateShortName | Not a US state code | Two-letter code, for example NY |
| 4014 | ModelIsInvalid |
Model | Model not valid for that make | Resolve it with Vehicle Lookup |
| 4015 | MakeIsInvalid |
Make | Make not in the catalog | Resolve it with Vehicle Lookup |
| 4017 | DurationFilterCantbeEmpty |
DurationFilter | Duration filter present but empty | Send from and to, or omit the filter |
| 4019 | MileageIsRequired |
Mileage | Mileage was zero | Send the actual current mileage |
4014 and 4015 are the most common errors in new integrations, and almost always mean you are
sending customer-typed text straight through. Resolve it first.
Some endpoints use a shorter form with no errorNumber, for example errorCode: "EmptyValue" with
errorMessage: "VIN is required.". Handle a missing errorNumber rather than assuming it is present.
Coverage limits
These are hard limits. Within them, a vehicle no provider wants to cover comes back as an empty
results array, not an error. See Restrictions and limitations.
| Number | Code | Field | Meaning |
|---|---|---|---|
| 2000 | ChaizRestrictedState |
StateShortName | We do not sell in this state (California) |
| 4007 | YearIsMoreThan25YearsAgo |
Year | The vehicle is more than 25 model years old |
| 4008 | YearIsInTheFuture |
Year | The model year is later than next year |
| 4010 | MileageIsTooHigh |
Mileage | Over 250,000 miles |
Tell the customer what happened rather than retrying. These do not change with a different request.
Account and plan errors (20xxx)
| Number | Code | Meaning | Fix |
|---|---|---|---|
| 20004 | DurationFilterRestictedValues |
Your account allows only specific durations | Use an allowed value, or ask support to widen it |
| 20005 | DurationFilterRestrictedRange |
Your account requires from to equal to |
Send a single duration, for example { "from": 36, "to": 36 } |
| 20006 | VinHasNotBeenRegistered |
Async search on a VIN and mileage that was never pre-registered | Call VehicleRegistration first. See make searches faster |
These are configuration talking to you, not bugs in your request. If a restriction does not match what you expected to sell, contact dev-support@chaiz.com rather than working around it.
Rate limits
Limits are per partner account, not per IP, and they apply as two simultaneous windows: hourly and daily. Both must have room for a request to pass.
| Tier | Per hour | Per day |
|---|---|---|
| Free (self-service registration) | 50 | 500 |
| Standard (commercial agreement) | 1,000 | 10,000 |
| High volume (by arrangement) | 5,000 | 20,000 |
GET /api/v2/Partners/Register/Usage returns your current tier and limits. Ask dev-support@chaiz.com
about a higher tier before launch rather than after you start hitting 429s.
Exceeding a limit returns 429 with a Retry-After header in seconds.
Retry-After is deliberately rounded and jittered, so it is a safe lower bound rather than an exact
countdown. Honor the value you are given and add your own jitter on top. Do not attempt to compute when
the window resets; several clients all retrying on the same computed second is how you get a second
429.
Retry-After appears on 429 only. A 202 from async search does not carry one; poll on your own 1 to
2 second interval instead.
Handling errors well
Read errorResponse before anything else, and use suggestions when they are there:
const body = await response.json();
const errors = body.errorResponse?.errors;
if (errors?.length) {
for (const e of errors) {
console.error(`${e.errorCode ?? 'validation'} (${e.errorNumber ?? '-'}): ${e.errorMessage}`);
for (const s of e.suggestions ?? []) {
// s.message is written to be shown to the customer as-is
console.log(`[${s.action}] ${s.message}${s.endpoint ? ` -> ${s.endpoint}` : ''}`);
}
}
return;
}
const plans = body.response.results;
A short checklist that removes most avoidable failures:
- Resolve make and model through Vehicle Lookup instead of passing customer text through.
- Require state and mileage in your own form, and validate the VIN is 17 characters.
- Search again rather than reusing a result older than 30 days.
-
Retry only on
5xx, connection errors,429afterRetry-After, a plan searchSystemError, and the two registration server-problem sentences (An error occurred during registration…andAn error occurred during verification…). -
Log
errorCodeanderrorNumber, not just the message. The message wording can change; the codes are stable.
Still stuck?
Email dev-support@chaiz.com with the full error response, the request body, and roughly when the call happened. Remove card numbers and personal data first.