Errors & Responses¶
Success responses¶
There's no response envelope — endpoints return the resource itself directly, as a JSON object or array:
POST/GET(single resource) → the resource object,201on create.GET(list) → a bare JSON array. Pagination totals are in headers, not the body — see Pagination headers below.DELETE/ logout →204 No Content, empty body.
Error responses¶
Most errors — anything raised directly by a controller — come back as:
with an appropriate status code: 401 (missing/invalid/expired token), 403 (authenticated but
not permitted), 404 (resource not found), 405 (method not allowed), 409 (conflict, e.g.
duplicate email or slug), or 422 (validation failure).
404s and unhandled exceptions use a different shape, from the app's central error handler rather than a controller:
This is a real inconsistency in the current API ({ "error": ... } vs. { "status", "message" })
rather than a documentation simplification — if you're writing a client, handle both shapes rather
than assuming error is always present. In development (ENV=development), unhandled exceptions
are re-thrown instead of returning a generic 500, so you see the real PHP error and stack trace.
Common validation messages (422)¶
Non-exhaustive, but covers what you'll hit most:
name must be a non-empty string/ similar per-field required-field messagesEmail already registered(409, not 422 — included here since it's the most common signup error)password must be at least 8 characterspermissions must contain only: select, insert, update, delete, function, storage:select, storage:insert, storage:update, storage:deleteexpires_at must be a future datetimeslug must contain only letters, numbers, dashes, and underscoresFunction slug already exists in this project(409)source_code must be a PHP file starting with <?phpmethods must contain only: GET, POST, PUT, PATCH, DELETE(or similar, per allowed method list)timeout_seconds must be between 1 and 60memory_limit_mb must be between 16 and 256handler must use ClassName::method syntaxrole must be null or an alphanumeric string (max 64 chars)expression is required/expression is too long (max 10000 characters)— RLS/storage policiesexpression must be a single boolean expression: ";", "--" and "/*" are not allowedunknown placeholder $auth.foo; use one of: $auth.id, $auth.email, $auth.roleNothing to update— returned byPATCHendpoints when the request body has no recognized fields to change
Pagination headers¶
Every paginated list endpoint (tables, keys, RLS policies, end users, cron jobs, functions, storage buckets/objects/policies, and REST/Storage passthrough's own list endpoints) echoes the resolved pagination back as response headers:
| Header | Meaning |
|---|---|
X-Total-Count |
Total matching rows, ignoring limit/offset |
X-Page-Limit |
The limit actually applied (default 25 for platform list endpoints, 50 for REST passthrough; capped at 100 either way) |
X-Page-Offset |
The offset actually applied (default 0) |