Guides
Errors
Errors are returned in the standard problem details format with the content type application/problem+json. Check the HTTP status first; use type to tell causes apart.
Note
The explanatory texts in error responses (
detail, message) are in English and may be reworded. Base your code on status and type, not on the text.#The format
A validation error
Validation reports every problem at once, so you can fix them in one go.
curl -X POST "$API/v1/locations" \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "",
"latitude": 95,
"longitude": 24.0536
}'const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/locations`, {
method: "POST",
headers: { Authorization: auth, "Content-Type": "application/json" },
body: JSON.stringify({
"name": "",
"latitude": 95,
"longitude": 24.0536
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.post(
f"{API}/v1/locations",
auth=(CLIENT_ID, CLIENT_SECRET),
json={
"name": "",
"latitude": 95,
"longitude": 24.0536,
},
)
print(r.status_code, r.json())422 Unprocessable Content
{
"type": "https://api.boxlatvia.lv/problems/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields are invalid.",
"request_id": "5f22a099-b84d-48eb-b078-6c5423a2175e",
"errors": [
{
"field": "name",
"message": "must not be empty"
},
{
"field": "latitude",
"message": "Number must be less than or equal to 90"
}
]
}| Field | Meaning |
|---|---|
type | A stable identifier for the kind of problem (see the table below). Match on this, not on the text. |
title, detail | A short, human-readable explanation. The wording may improve over time. |
status | The HTTP status, repeated. |
request_id | A unique id of this request, also in the X-Request-Id header. Quote it when you contact support. |
errors | Only on 422: a list of { field, message }, one per problem. |
#Problem types
Every type starts with https://api.boxlatvia.lv/problems/. These are identifiers, not web pages.
| Type | Status | Meaning |
|---|---|---|
bad-request | 400 | The body is not valid JSON, or a parameter such as cursor cannot be read. |
unauthorized | 401 | Missing, wrong, expired or revoked credentials, or an expired token. |
forbidden | 403 | The IP address is not allowed for these credentials, or the action is not available to suppliers. |
insufficient-scope | 403 | The credentials lack the scope the call needs; required_scope names it. |
not-found | 404 | No such object of yours. Other suppliers' objects look exactly the same. |
conflict / duplicate-external-id | 409 | The external_id is taken (existing_id names the other object). |
location-has-boxes | 409 | The location still has boxes. |
box-has-orders | 409 | The box has orders and cannot be deleted. |
box-already-published | 409 | A published box cannot be submitted; withdraw it first. |
image-limit | 409 | More than 20 pictures; limit and existing tell you the numbers. |
request-in-progress | 409 | Your earlier call with the same Idempotency-Key is still running. |
precondition-failed | 412 | If-Match is out of date: read the object again. |
payload-too-large | 413 | The request is larger than 27 MB. |
unsupported-media-type | 415 | Pictures must be sent as multipart/form-data. |
validation-failed | 422 | A value is invalid; errors lists every problem. |
box-incomplete | 422 | The box cannot be submitted yet; missing lists what it needs. |
idempotency-key-reused | 422 | That Idempotency-Key was already used for a different request. |
precondition-required | 428 | If-Match is missing. |
too-many-requests | 429 | Too many failed authentications from your address; wait Retry-After seconds. |
internal-error / timeout / storage-unavailable | 500 | Something went wrong on our side (timeout is 503, storage-unavailable is 502). Retry with the same Idempotency-Key. |
#Examples
Wrong or missing credentials
curl "$API/v1/me"const API = "https://api.boxlatvia.lv";
const res = await fetch(`${API}/v1/me`);
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.get(
f"{API}/v1/me",
)
print(r.status_code, r.json())401 UnauthorizedWww-Authenticate: Basic realm="BoxLatvia Supplier API", Bearer realm="BoxLatvia Supplier API"
{
"type": "https://api.boxlatvia.lv/problems/unauthorized",
"title": "Authentication required",
"status": 401,
"detail": "Send HTTP Basic credentials or a Bearer token.",
"request_id": "3f502d49-40f5-43e8-8004-dc4bb2f28a99"
}Object not found
curl "$API/v1/boxes/e8e189c3-3ac4-47d0-8ff1-584221c4e1ae" \
-u "$CLIENT_ID:$CLIENT_SECRET"const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/boxes/e8e189c3-3ac4-47d0-8ff1-584221c4e1ae`, {
headers: { Authorization: auth },
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.get(
f"{API}/v1/boxes/e8e189c3-3ac4-47d0-8ff1-584221c4e1ae",
auth=(CLIENT_ID, CLIENT_SECRET),
)
print(r.status_code, r.json())404 Not Found
{
"type": "https://api.boxlatvia.lv/problems/not-found",
"title": "Not found",
"status": 404,
"detail": "No such box.",
"request_id": "734e0d86-9a60-4107-9997-c9f0bcf77610"
}A box that is not ready
curl -X POST "$API/v1/boxes/9d7f53d3-a9cd-4ee1-b9cf-470a572f8b4e/submit" \
-u "$CLIENT_ID:$CLIENT_SECRET"const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/boxes/9d7f53d3-a9cd-4ee1-b9cf-470a572f8b4e/submit`, {
method: "POST",
headers: { Authorization: auth },
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.post(
f"{API}/v1/boxes/9d7f53d3-a9cd-4ee1-b9cf-470a572f8b4e/submit",
auth=(CLIENT_ID, CLIENT_SECRET),
)
print(r.status_code, r.json())422 Unprocessable Content
{
"type": "https://api.boxlatvia.lv/problems/box-incomplete",
"title": "Box is incomplete",
"status": 422,
"detail": "Fill in description, price, price_unit, size, features before submitting this box for review.",
"request_id": "f48c9ebd-fa4f-4b14-be21-b98154de2c1e",
"missing": [
"description",
"price",
"price_unit",
"size",
"features"
]
}Rules between fields
curl -X POST "$API/v1/boxes" \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "Box 2 m²",
"location_id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
"price": 10,
"promotional_price": 12,
"total_units": 5,
"available_units": 8,
"price_unit": "gadsimts",
"features": [
"sauna"
]
}'const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/boxes`, {
method: "POST",
headers: { Authorization: auth, "Content-Type": "application/json" },
body: JSON.stringify({
"name": "Box 2 m²",
"location_id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
"price": 10,
"promotional_price": 12,
"total_units": 5,
"available_units": 8,
"price_unit": "gadsimts",
"features": [
"sauna"
]
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.post(
f"{API}/v1/boxes",
auth=(CLIENT_ID, CLIENT_SECRET),
json={
"name": "Box 2 m²",
"location_id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
"price": 10,
"promotional_price": 12,
"total_units": 5,
"available_units": 8,
"price_unit": "gadsimts",
"features": [
"sauna",
],
},
)
print(r.status_code, r.json())422 Unprocessable Content
{
"type": "https://api.boxlatvia.lv/problems/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields are invalid.",
"request_id": "ce26822d-d546-4254-a374-08549ad6e04b",
"errors": [
{
"field": "price_unit",
"message": "is not a known price unit code"
},
{
"field": "features",
"message": "unknown or inactive feature code(s): sauna"
},
{
"field": "promotional_price",
"message": "must be lower than price"
},
{
"field": "available_units",
"message": "cannot be greater than total_units"
}
]
}#OAuth errors
The token endpoint follows the OAuth 2.0 standard instead: a JSON body with error and error_description.
Wrong client credentials
curl -X POST "$API/v1/oauth/token" \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=client_credentialsconst API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/oauth/token`, {
method: "POST",
headers: { Authorization: auth },
body: new URLSearchParams({
"grant_type": "client_credentials"
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.post(
f"{API}/v1/oauth/token",
auth=(CLIENT_ID, CLIENT_SECRET),
data={
"grant_type": "client_credentials",
},
)
print(r.status_code, r.json())401 Unauthorized
{
"error": "invalid_client",
"error_description": "Invalid client credentials."
}Note
Treat
5xx and timeouts as temporary: retry with the same Idempotency-Key and growing pauses. Do not retry other 4xx errors without changing the request (except 412, after re-reading, and 429, after waiting).