REST API
Authentication, addressing and error handling for the v1 API.
Everything the dashboard does is available over HTTP. Each route is a thin wrapper over the same procedure the UI calls, so the REST API and the dashboard share one implementation, one set of validation rules and one authorization model — they cannot drift apart.
Base URL: {APP_URL}/api/v1
Authentication
Send either a session cookie (dashboard) or an API key:
x-api-key: apikee_<payload>.<signature>
x-tenant: acmeWhen both are present the API key wins, so a request can never be authorised by one credential while carrying another.
x-tenant matters for session callers: project slugs are unique per workspace, not
globally. Without the header the lookup falls back to the workspaces you belong to
and returns 400 if the address is ambiguous, rather than guessing. API-key callers
are always scoped to the team owning the key's client and never need it.
Addressing
| Placeholder | Format | Example |
|---|---|---|
project_env | <project-slug>-<env-type> | payments-api-production |
method_path | METHOD:::/path | GET:::/v1/users |
client_uuid | client id | 0b7f… |
A project slug may contain dashes. Resolution tries the whole string as a slug first, then falls back to splitting off a trailing environment type.
method_path must be URL-encoded in a path segment:
GET%3A%3A%3A%2Fv1%2Fusers.
Routes
| Clients & keys | GET POST /client · GET PUT DELETE /client/{client_uuid} · GET /client/templates |
| Key validation | POST /client/{client_uuid} |
| Endpoints | GET POST /endpoint · GET PUT DELETE /endpoint/{method_path} |
| Projects | GET POST /project · GET PUT DELETE /project/{project_env} · GET /project/{project_env}/logs |
Most routes take project_env as a query parameter.
Pagination
List routes accept page (from 1) and limit (1–100, default 10).
curl "…/api/v1/client?project_env=payments-api-production&page=2&limit=50"Errors
{ "code": "FORBIDDEN", "status": 403, "error": "Admin or owner role required" }Validation failures additionally carry fields and formErrors. Internal failures
always return a generic 500 — database and driver details are logged server-side,
never returned to the caller.
| Status | Meaning |
|---|---|
400 | Invalid input, or an ambiguous address |
401 | Missing, malformed, expired, revoked or mismatched credential |
403 | Authenticated but not permitted (role, client state, IP) |
404 | Not found, or not visible to this tenant |
409 | Conflict — duplicate slug or endpoint |
412 | Precondition failed — e.g. deleting an environment that still has clients |
429 | Rate limit exceeded; carries Retry-After |
A 404 is also what you get for an object in another workspace. Cross-tenant
identifiers are never confirmed to exist.
Limits
| Clients per bulk create | 100 |
| Keys per request | 10 |
| Active keys per client | 25 |
| Endpoints per bulk create | 200 |
| Metadata | 8 KiB, 5 levels deep |
| IP rules per client | 100 |

