Errors
Every error from the Motorbay API has the same shape, so one error handler covers the whole API.
The shape of an error
Errors are RFC 9457 problem details, sent as application/problem+json:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "Vehicle not found",
"status": 404,
"instance": "/v1/vehicles/plate/AB12345",
"code": "VehicleNotFound",
"requestId": "0HN7Q3C2V4K1M:00000001",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}
| Field | What it is |
|---|---|
status |
The HTTP status, repeated in the body |
code |
What went wrong, in PascalCase. Branch on this and on status |
title |
A short summary. The same for every error with that code |
detail |
What happened this time, in words you can show a user. Not always present |
instance |
The path you called |
requestId |
The same value as the X-Request-Id header |
traceId |
Our internal trace. Send it with the request ID if you contact us |
errors |
On ValidationFailed only. See below |
Branch on status and code, never on title or detail: the text can change, and a published code does not. Handle codes you don't know by their status, since we may add codes for new situations.
X-Request-Id
Every response carries an X-Request-Id header, successful or not. On an error, the body repeats it as requestId. Log it. It's the first thing support asks for, and it lets us find your request.
Every error code
| Status | Code | When | What to do |
|---|---|---|---|
| 400 | ValidationFailed |
A parameter is malformed or out of range | Fix the request. The same request fails again |
| 401 | ApiKeyMissing |
No X-Api-Key header |
Send the header |
| 401 | ApiKeyInvalid |
The key is unknown, deleted, expired, or from the other environment | Check the key, or create a new one |
| 402 | PaymentRequired |
The key's account has no active plan or trial | Choose a plan in the console |
| 404 | VehicleNotFound |
No vehicle with that ID, VIN or registration number | Don't retry now. The vehicle may appear after a later import |
| 404 | MakeNotFound |
No make with that ID | Check the ID |
| 404 | ModelNotFound |
No model with that ID under that make | Check the IDs |
| 404 | VariantNotFound |
No variant with that ID under that model | Check the IDs |
| 404 | DesignationTypeNotFound |
No designation type with that ID under that model | Check the IDs |
| 404 | ColorNotFound |
No color with that ID | Check the ID |
| 404 | KindNotFound |
No kind with that ID | Check the ID |
| 404 | UsageNotFound |
No usage with that ID | Check the ID |
| 404 | EmissionStandardNotFound |
No emission standard with that ID | Check the ID |
| 404 | EquipmentNotFound |
No equipment with that ID | Check the ID |
| 404 | RouteNotFound |
No such path | Check the URL and the /v1 prefix |
| 405 | MethodNotAllowed |
A method other than GET |
Use GET. The Allow header lists what the path accepts |
| 429 | RateLimitExceeded |
More than 60 requests this minute with this key | Wait the Retry-After seconds, then retry |
| 429 | QuotaExceeded |
The plan's requests for this month are used up | Upgrade the plan, or wait. Retry-After runs to the start of next month (UTC) |
| 500 | InternalError |
A fault on our side | Retry with the backoff below. If it keeps failing, send us the requestId |
| 503 | DatasetNotLoaded |
GET /v1/dataset before the first import has finished |
Try again later |
| 503 | ServiceUnavailable |
Your API key couldn't be checked just now. The key is not the problem | Wait the Retry-After seconds, then retry |
A list endpoint under a parent, such as /v1/makes/{makeId}/models, answers 404 with the parent's code (MakeNotFound) when the parent doesn't exist.
Validation errors
A 400 with ValidationFailed says which rule failed in errors, with a message for each:
{
"title": "The request is not valid",
"status": 400,
"code": "ValidationFailed",
"errors": {
"PageSizeOutOfRange": ["Page size must be at least 1 and at most 50."]
}
}
The keys in errors are these rules:
| Rule | When |
|---|---|
PageOutOfRange |
page is below 1, or past the last page of a non-empty result |
PageSizeOutOfRange |
pageSize is below 1 or above the endpoint's maximum |
SortByInvalid |
sortBy isn't one of the documented values |
SearchTooDeep |
page × pageSize is more than 10,000 on vehicle search |
RegistrationNumberInvalid |
A registration number, in /v1/vehicles/plate/{plate} or ?registrationNumber=, has characters other than A to Z, 0 to 9, Æ, Ø and Å, or is longer than 10 once spaces and hyphens are removed |
A parameter that isn't a number where one is expected, such as makeId=abc, is a 400 with ValidationFailed and no errors.
Responses that aren't errors
- 204 No Content. A vehicle's
/engine,/inspectionand/environmental-informationanswer204when the vehicle exists but the register has no such record for it. - An empty list. A search that matches nothing is a
200with"data": []andtotalCount0.
When to retry
Every endpoint is a GET, so every request is safe to retry. Retry only these:
- 429: wait the number of seconds in
Retry-After, then retry. - 500 or 503: back off 1, 2, then 4 seconds, and stop after three tries.
Never retry any other 4xx. The same request gets the same answer.