Access per route
The credential and access level every route requires, generated from the route table the gateway and services share.
Every route is declared once, in chelabase-routes, with the credential it takes and an access level. The gateway and the services read the same table. The table below is generated from it and checked by a test, so it can't drift.
Access levels
| Level | Meaning |
|---|---|
| Public | No identity. Health, the API document, sign-in and accept-invite (the code is the credential). |
| Data API key | A data API key, checked by the gateway. |
| Signed in | Any verified identity (/v1/me). |
| Instance admin | Self-hosted: an active tenant admin. Platform: an active member of the operator tenant (CHELABASE_OPERATOR_TENANT_ID). |
| Tenant member | Any active member of the caller's tenant. |
| Tenant admin | An active tenant admin. |
| Project role | The caller's effective platform role on the project is at least role (Viewer, Developer, Admin). A tenant admin is Admin on every project. |
| Branch | The minimum depends on the target branch: one role for an unprotected branch, another for a protected one. For merges the target is the branch merged into. |
| Act as | At least the given platform role, and the Postgres role asked for (?role=, or the console's and SQL editor's role) must be in the caller's effective set. The owner needs Admin. Owner-level, LOGIN and reserved roles, and chains through them, are Admin-only. |
How a refusal answers:
| Case | Status | Code |
|---|---|---|
| No grant on the project (its existence isn't revealed) | 404 | not_found |
| Grant too low, or the role isn't allowed | 403 | forbidden, with error.required (the level needed, owner, role:<name>, or connect) |
| A member with no grants anywhere | 403 | no_access_yet |
| A sign-up waiting for approval | 403 | pending_approval |
| A feature not designed for platform mode | 403 | not_available_in_platform_mode |
GET /v1/me returns the caller's capabilities: tenant admin, instance admin, and per project the platform role, the Postgres roles they may act as and (projects[].databases) the databases a grant override narrows. It answers 200 for a pending sign-up too, with member.status: "pending". Studio only hides what you can't do; the API decides. See Members and invites and Roles and schema isolation.
Effective access
A member's effective access on a project combines their own grant with the grants of their teams (see Teams), then narrows it by their per-database overrides:
- Union of sources. The platform role is the best level among the own grant and the team grants. Admin from any source is Admin, holding every Postgres role.
- Per-role levels. Each Postgres role keeps the highest level among the sources that name it. An Act as route needs the platform level the route asks for and the role held at that level or above: a role held only at Viewer can't be used on
POST …/sql. - Narrowing afterwards. A database override is intersected with the union; it never widens.
- Checked on every write. Own-grant, override, team and invite writes are checked on the resulting union for each affected member and database.
- The data API's extras.
anonandauthenticatedare held only when a source names them, Admins included.
GET /v1/me reports the union per project. POST …/tables/{schema}/{table}/cell (Act as: Viewer) for a role held below Developer is read through the data API's connection, so it needs the data API on for the Postgres database (409 data_api_disabled when off).
Every route
Sorted by path. Credentials: Member token is a member access token from POST /auth/v1/token (Studio's sign-in); the data API's keys are described under Data API.
| Method | Path | Credential | Access |
|---|---|---|---|
| POST | /auth/v1/accept-invite | none | Public |
| POST | /auth/v1/app/change-email | public data key | Data API key |
| POST | /auth/v1/app/change-password | public data key | Data API key |
| GET | /auth/v1/app/jwks | none | Public |
| POST | /auth/v1/app/password-reset | public data key | Data API key |
| POST | /auth/v1/app/password-reset/confirm | public data key | Data API key |
| POST | /auth/v1/app/refresh | public data key | Data API key |
| POST | /auth/v1/app/resend-code | public data key | Data API key |
| POST | /auth/v1/app/sign-in | public data key | Data API key |
| POST | /auth/v1/app/sign-out | public data key | Data API key |
| POST | /auth/v1/app/sign-up | public data key | Data API key |
| GET | /auth/v1/app/user | public data key | Data API key |
| POST | /auth/v1/app/verify-email | public data key | Data API key |
| GET | /auth/v1/instance | none | Public |
| POST | /auth/v1/invite | none | Public |
| POST | /auth/v1/logout | none | Public |
| POST | /auth/v1/password-reset | none | Public |
| POST | /auth/v1/password-reset/confirm | none | Public |
| POST | /auth/v1/resend-code | none | Public |
| POST | /auth/v1/sign-in | none | Public |
| POST | /auth/v1/sign-up | none | Public |
| GET | /auth/v1/studio-config | none | Public |
| POST | /auth/v1/token | none | Public |
| POST | /auth/v1/verify-email | none | Public |
| POST | /data/v1/query | any data key | Data API key |
| GET | /data/v1/schema | secret data key | Data API key |
| GET | /data/v1/types | secret data key | Data API key |
| GET | /health | none | Public |
| GET | /v1/access-events | Member token | Tenant admin |
| POST | /v1/databases | Member token | Project Admin |
| DELETE | /v1/databases/\{id\} | Member token | Project Admin |
| GET | /v1/databases/\{id\} | Member token | Project Viewer |
| PATCH | /v1/databases/\{id\} | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches | Member token | Project Viewer |
| POST | /v1/databases/\{id\}/branches | Member token | Project Developer |
| DELETE | /v1/databases/\{id\}/branches/\{branch_id\} | Member token | Branch: Developer unprotected, Admin protected |
| PATCH | /v1/databases/\{id\}/branches/\{branch_id\} | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/connection | Member token | Project Admin |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/console/query | Member token | Act as: Viewer and the role in your set |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/console/schema | Member token | Act as: Viewer and the role in your set |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/data-api/schema | Member token | Project Viewer |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/data-api/types | Member token | Project Developer |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/databases | Member token | Project Viewer |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/guard-exemptions | Member token | Project Developer |
| DELETE | /v1/databases/\{id\}/branches/\{branch_id\}/guard-exemptions/\{role\} | Member token | Project Admin |
| PUT | /v1/databases/\{id\}/branches/\{branch_id\}/guard-exemptions/\{role\} | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/keys | Member token | Project Viewer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/keys | Member token | Project Developer |
| DELETE | /v1/databases/\{id\}/branches/\{branch_id\}/keys/\{key_id\} | Member token | Project Developer |
| PATCH | /v1/databases/\{id\}/branches/\{branch_id\}/keys/\{key_id\} | Member token | Project Developer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/keys/\{key_id\}/rotate | Member token | Project Developer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/merges | Member token | Branch: Developer unprotected, Admin protected |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/objects | Member token | Project Viewer |
| PATCH | /v1/databases/\{id\}/branches/\{branch_id\}/pg-databases/\{name\} | Member token | Project Admin |
| DELETE | /v1/databases/\{id\}/branches/\{branch_id\}/pg-databases/\{name\}/data-api | Member token | Project Admin |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/pg-databases/\{name\}/data-api | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/pg-databases/\{name\}/privileges | Member token | Project Viewer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/reset-password | Member token | Project Admin |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/reset-to-parent | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/restore | Member token | Branch: Developer unprotected, Admin protected |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/review | Member token | Project Developer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/review/acknowledge | Member token | Project Admin |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/review/fix | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/roles | Member token | Project Viewer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/roles | Member token | Project Admin |
| DELETE | /v1/databases/\{id\}/branches/\{branch_id\}/roles/\{role\} | Member token | Project Admin |
| PATCH | /v1/databases/\{id\}/branches/\{branch_id\}/roles/\{role\} | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/roles/\{role\}/delete-preview | Member token | Project Admin |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/roles/\{role\}/reset-password | Member token | Project Admin |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/roles/\{role\}/sessions | Member token | Project Admin |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/schema-changes | Member token | Act as, by branch: Developer unprotected, Admin protected, and the role in your set |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/sql | Member token | Act as: Developer and the role in your set |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/sql/runs/\{run_id\}/cancel | Member token | Project Developer |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/sql/schema | Member token | Act as: Developer and the role in your set |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/tables/\{schema\}/\{table\} | Member token | Project Viewer |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/tables/\{schema\}/\{table\}/cell | Member token | Act as: Viewer and the role in your set |
| POST | /v1/databases/\{id\}/branches/\{branch_id\}/tables/\{schema\}/\{table\}/rows/default | Member token | Act as: Developer and the role in your set |
| GET | /v1/databases/\{id\}/branches/\{branch_id\}/types | Member token | Project Viewer |
| GET | /v1/databases/\{id\}/connection | Member token | Project Admin |
| GET | /v1/databases/\{id\}/merges | Member token | Project Viewer |
| GET | /v1/databases/\{id\}/merges/\{merge_id\} | Member token | Project Viewer |
| PATCH | /v1/databases/\{id\}/merges/\{merge_id\} | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/abandon | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/apply | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/cancel | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/finish | Member token | Branch: Developer unprotected, Admin protected |
| GET | /v1/databases/\{id\}/merges/\{merge_id\}/plan.sql | Member token | Project Viewer |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/recompute | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/rehearse | Member token | Branch: Developer unprotected, Admin protected |
| POST | /v1/databases/\{id\}/merges/\{merge_id\}/retry | Member token | Branch: Developer unprotected, Admin protected |
| PUT | /v1/databases/\{id\}/personal-login | Member token | Project Developer |
| POST | /v1/databases/\{id\}/personal-login/reset-password | Member token | Project Developer |
| GET | /v1/databases/\{id\}/personal-logins | Member token | Project Admin |
| DELETE | /v1/databases/\{id\}/personal-logins/\{member_id\} | Member token | Tenant member |
| POST | /v1/databases/\{id\}/reset-password | Member token | Project Admin |
| GET | /v1/databases/\{id\}/sql-queries | Member token | Project Developer |
| POST | /v1/databases/\{id\}/sql-queries | Member token | Project Developer |
| DELETE | /v1/databases/\{id\}/sql-queries/\{query_id\} | Member token | Project Developer |
| GET | /v1/databases/\{id\}/sql-queries/\{query_id\} | Member token | Project Developer |
| PATCH | /v1/databases/\{id\}/sql-queries/\{query_id\} | Member token | Project Developer |
| GET | /v1/instance/settings | Member token | Instance admin |
| PATCH | /v1/instance/settings | Member token | Instance admin |
| POST | /v1/invites | Member token | Tenant admin |
| GET | /v1/invites/delivery | Member token | Tenant member |
| DELETE | /v1/invites/\{invite_id\} | Member token | Tenant admin |
| POST | /v1/invites/\{invite_id\}/resend | Member token | Tenant admin |
| GET | /v1/me | Member token | Signed in |
| GET | /v1/members | Member token | Tenant member |
| DELETE | /v1/members/\{member_id\} | Member token | Tenant admin |
| PATCH | /v1/members/\{member_id\} | Member token | Tenant admin |
| POST | /v1/members/\{member_id\}/approve | Member token | Tenant admin |
| POST | /v1/members/\{member_id\}/decline | Member token | Tenant admin |
| GET | /v1/members/\{member_id\}/personal-logins | Member token | Tenant member |
| POST | /v1/members/\{member_id\}/reinstate | Member token | Tenant admin |
| POST | /v1/members/\{member_id\}/revoke-postgres-access | Member token | Tenant admin |
| POST | /v1/members/\{member_id\}/suspend | Member token | Tenant admin |
| GET | /v1/members/\{member_id\}/teams | Member token | Tenant member |
| GET | /v1/openapi.json | none | Public |
| GET | /v1/projects | Member token | Tenant member |
| POST | /v1/projects | Member token | Tenant admin |
| DELETE | /v1/projects/\{id\} | Member token | Project Admin |
| GET | /v1/projects/\{id\} | Member token | Project Viewer |
| PATCH | /v1/projects/\{id\} | Member token | Project Admin |
| GET | /v1/projects/\{id\}/access-events | Member token | Project Admin |
| DELETE | /v1/projects/\{id\}/app-users | Member token | Project Admin |
| GET | /v1/projects/\{id\}/app-users | Member token | Project Viewer |
| PUT | /v1/projects/\{id\}/app-users | Member token | Project Admin |
| GET | /v1/projects/\{id\}/grants | Member token | Project Admin |
| DELETE | /v1/projects/\{id\}/grants/\{member_id\} | Member token | Project Admin |
| PUT | /v1/projects/\{id\}/grants/\{member_id\} | Member token | Project Admin |
| DELETE | /v1/projects/\{id\}/grants/\{member_id\}/overrides | Member token | Project Admin |
| PUT | /v1/projects/\{id\}/grants/\{member_id\}/overrides | Member token | Project Admin |
| POST | /v1/projects/\{id\}/invites | Member token | Project Admin |
| GET | /v1/projects/\{id\}/team-grants | Member token | Project Admin |
| GET | /v1/projects/\{id\}/users | Member token | Project Viewer |
| POST | /v1/projects/\{id\}/users | Member token | Project Developer |
| DELETE | /v1/projects/\{id\}/users/\{user_id\} | Member token | Project Developer |
| GET | /v1/projects/\{id\}/users/\{user_id\} | Member token | Project Viewer |
| PATCH | /v1/projects/\{id\}/users/\{user_id\} | Member token | Project Developer |
| POST | /v1/projects/\{id\}/users/\{user_id\}/deactivate | Member token | Project Developer |
| POST | /v1/projects/\{id\}/users/\{user_id\}/reactivate | Member token | Project Developer |
| DELETE | /v1/projects/\{id\}/users/\{user_id\}/sessions | Member token | Project Developer |
| GET | /v1/projects/\{id\}/users/\{user_id\}/sessions | Member token | Project Viewer |
| GET | /v1/realtime/socket | none | Public |
| POST | /v1/realtime/tickets | Member token | Signed in |
| GET | /v1/teams | Member token | Tenant member |
| POST | /v1/teams | Member token | Tenant admin |
| DELETE | /v1/teams/\{team_id\} | Member token | Tenant admin |
| GET | /v1/teams/\{team_id\} | Member token | Tenant member |
| PATCH | /v1/teams/\{team_id\} | Member token | Tenant admin |
| DELETE | /v1/teams/\{team_id\}/grants/\{project_id\} | Member token | Tenant admin |
| PUT | /v1/teams/\{team_id\}/grants/\{project_id\} | Member token | Tenant admin |
| DELETE | /v1/teams/\{team_id\}/members/\{member_id\} | Member token | Tenant admin |
| PUT | /v1/teams/\{team_id\}/members/\{member_id\} | Member token | Tenant admin |
| PATCH | /v1/tenant | Member token | Tenant admin |
The generated types for the key's schema GET
What `chelabase gen types` writes for the same secret key and options, byte for byte: the TypeScript module (`Database` and the runtime `types` map for `@chelabase/client`), or with `format=json` the runtime `types` map alone. It is built from exactly what `GET /data/v1/schema` gives the key. The `ETag` is the body's hash: send it back as `If-None-Match` for a 304 while the schema is unchanged. Not cached (`Cache-Control: no-store`): the schema follows the key.
Error codes
Every error code, its status and meaning, for the management, login and data APIs.