API - Errors, rate limits & conventions
A handful of things behave the same way on every endpoint. Once you know them, the rest of the API holds no surprises.
The error format
Whenever something goes wrong, the response has the same shape:
{
"error": {
"code": "validation",
"message": "…a readable explanation…",
"detail": "title must be at most 191 characters",
"field": "title",
"request_id": "…"
}
}code is a stable machine name you can switch on, detail and field tell you exactly what to put right, and request_id is the reference to give us if you ever need to ask. You'll see codes like unauthorized, forbidden, api_not_enabled, validation, image_not_found, idempotency_key_conflict, rate_limited and payload_too_large.
400 validation tells you the field and the rule it broke, a program can read that, correct itself and try again, with nobody watching.Paging
Lists take ?limit (50 by default, up to 200) and ?offset, and every list sets two response headers so you always know where you stand:
X-Has-Moreistrueorfalse.X-Next-Offsetis the?offsetto use for the next page.
Keep going while X-Has-More is true.
Rate limits
Signing in and MFA are rate limited. If you go over, you get 429 rate_limited back with a Retry-After header telling you how many seconds to wait. Wait that long before trying again.
Cheap polling
Every GET returns an ETag. Send it back as If-None-Match, and if nothing has changed you get an empty 304 Not Modified, which is easy on both ends, especially over a slow or metered connection.
Doing a lot at once
POST /v1/operations/batch runs up to 50 writes in a single request, so you can add keywords, set ratings and move images between sets all together. It hands back one summary plus a child Operation for each item, and the whole batch is checked before any of it runs, so it's all-or-nothing.
Idempotency, once more
Every write takes an Idempotency-Key. The same key with the same body gives you back the original result, safely; the same key with a different body gives you a 409. There's more in Operations.