Every error uses the same envelope as successful responses — only success is false and the error object is populated:
{
  "success": false,
  "data": null,
  "meta": {
    "request_id": "b3f1c2e4-...",
    "took_ms": 2.9
  },
  "error": {
    "code": "MISSING_PARAMS",
    "message": "At least one criterion required: q, color_name, color_hex, orientation, source, license_type, photographer or after_date.",
    "request_id": "b3f1c2e4-..."
  }
}
Always branch on error.code (stable, machine-readable) rather than parsing error.message (human-readable, may change). Quote meta.request_id when contacting support.

HTTP status codes

StatusMeaning
200 / 201Success.
400Bad request — a parameter is missing or invalid.
401Authentication failed — missing or invalid x-api-key.
403Forbidden — your plan or account is not allowed to perform this action.
404The resource (photo, collection, photographer) or route does not exist.
409Conflict — the action clashes with the current state (e.g. duplicate).
422Validation error — a parameter failed validation (type, range, required).
429Too many requests — you hit a rate limit. Slow down and retry.
500Internal error — something went wrong on our side.
504The search backend timed out — retry shortly.

Error codes

error.codeStatusWhen it happens
MISSING_PARAMS400A search was sent with no query and no filter.
INVALID_PARAMS400Conflicting parameters (e.g. color_name and color_hex together).
INVALID_ID400photo_id is not a valid UUID.
VALIDATION_ERROR422A parameter failed validation (out of range, wrong type, required). The error.fields array lists each offending parameter.
MISSING_IMAGE422Image search was called without an image file.
INVALID_IMAGE422The uploaded file is not a supported image (JPEG, PNG, WebP, AVIF) or is too large.
UNAUTHORIZED401The x-api-key header is missing or invalid.
FORBIDDEN403Your account/plan cannot perform this action.
PLAN_RESTRICTION403The requested field or feature is not in your plan.
COLLECTIONS_LIMIT_REACHED403You reached the maximum number of collections for your plan.
PHOTO_NOT_FOUND404No photo matches the given photo_id.
NOT_FOUND404The collection, photographer or route does not exist.
PHOTO_ALREADY_IN_COLLECTION409The photo is already in that collection.
RATE_LIMITED429You exceeded the request rate limit.
SEARCH_TIMEOUT504The search backend did not respond in time — retry.
INTERNAL_ERROR500Unexpected server error — retry, then contact support with the request_id.
VALIDATION_ERROR responses include an extra error.fields array — one entry per invalid parameter with its field, message and type — so you can show precise form errors.