Errors

One machine-readable problem document for every failure, and what each type means for your retry logic.

Every failure — including a route that does not exist — answers with application/problem+json, the shape defined by RFC 9457. There is no path through this API that returns an HTML error page, so a parser that assumes JSON on a non-2xx response is safe.

{
  "type": "https://api.backresto.com/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The authenticated client lacks the required scope.",
  "instance": "/v1/restaurants/restaurant-1/deliveries/8f2c/images",
  "requestId": "b1c8b0a4-6c1e-4f6b-9e1c-3b2a5d7f0e91"
}

type is the stable identifier: branch on it, not on detail, which is prose and may be reworded. requestId is the value to quote in a support message — it is also returned in the X-Request-ID response header, and you can set that header yourself to correlate with your own traces.

The catalogue

type suffixStatusWhat happenedRetry?
invalid-request400A parameter is missing or malformed: an inverted or over-long delivery range, an unknown collection, or a cursor that does not match the restaurant, collection and limit you are paging with.No — fix the request.
unauthorized401No Authorization header, or a key that is malformed, unknown, revoked, expired, or left with no grants at all.No — the key needs attention.
forbidden403The key holds a grant for this restaurant but not the scope this endpoint needs.No — a key carrying that scope has to be requested.
not-found404No grant for this restaurant, or no such delivery or record. The cases are deliberately indistinguishable.No.
conflict409The request conflicts with an existing resource.No.
payload-too-large413The request body exceeds the limit.No.
rate-limit-exceeded429Your client passed its request budget.Yes, after Retry-After.
dependency-unavailable503A component the API needs is briefly unavailable.Yes, with backoff.
internal-error500An unexpected failure, already recorded on our side.Once, with backoff; then tell us the requestId.

What a client should do

Three buckets, and nothing else is worth the code:

Do not retry — 400, 401, 403, 404, 409, 413. The request will fail again identically. Log the type and the requestId, and surface it: a 401 in particular means a human at your customer's end has revoked something, and a retry loop will only hide that for a week.

Retry with backoff — 429, 503. Honour Retry-After on a 429; it is the number of seconds until your budget refills, and it is not a suggestion. For 503, exponential backoff with jitter, and give up rather than hammering.

Retry once, then escalate — 500. If it recurs on the same request, it is not transient.

Every endpoint in this API is a GET, so retrying is always safe from the API's point of view; the reason not to retry a 4xx is that it wastes your budget, not that it risks a double write.

Correlating with your own logs

Send your own identifier and it comes back:

curl "https://api.backresto.com/v1/restaurants/$RESTAURANT_ID/deliveries?from=1787846400000&to=1787932800000" \
  -H "Authorization: Bearer $BACKRESTO_PARTNER_API_KEY" \
  -H "X-Request-ID: 3f7a1c9e-2b4d-4a86-9f0c-5e1d8b6a2c40" \
  --include

The value is echoed in the response header and in the requestId of a problem document, which makes a single grep answer "what did BackResto see when my job failed at 04:12?".

Last updated 2026-09-19.