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, 429 after Retry-After, a plan search SystemError, and the two registration server-problem sentences (An error occurred during registration… and An error occurred during verification…).
  • Log errorCode and errorNumber, 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.