API Reference
Base URL: http://localhost:8787/api/v1 (local). For deployed apps, run teeny status and append /api/v1 to the exact URL it prints.
Auth header: Authorization: Bearer <token>
Admin API auth: Authorization: Bearer <ADMIN_SERVICE_TOKEN>
Legacy note: a raw Authorization: <ADMIN_SERVICE_TOKEN> header is still accepted for admin access, but Bearer is the documented format. X-Service-Token is not supported.
CRUD
Insert
POST /table/{table}/insert{
"values": { "title": "Hello", "body": "World" },
"returning": "*"
}Select
GET /table/{table}/select?where=published==true&order=-created&limit=10&select=id,titleOr POST to the same endpoint with JSON body:
{
"where": "published == true",
"order": "-created",
"limit": 10,
"select": "id,title"
}where uses teenybase expression syntax, not raw SQL. Use operators like ==, !=, =, ~, !~, <, <=, >, >=, &, |, !, in, ||, ->, and ->>.
Examples:
content~'%note%'published == true & author == auth.uidrole in ['editor','admin']
Do not send raw SQL fragments like content LIKE '%note%' or a = 1 AND b = 2. Use ~ instead of LIKE, and & / | instead of AND / OR.
List (with total count)
GET /table/{table}/list?where=...&limit=10The same endpoint also accepts POST with the same JSON body shape as select. Returns { "items": [...], "total": 42 }.
View
GET /table/{table}/view/{id}Update
POST /table/{table}/update{
"where": "id == 'post-123'",
"setValues": { "published": 1 },
"returning": "*"
}If you omit returning, the response is an empty array [].
Edit (single record shorthand)
POST /table/{table}/edit/{id}{ "title": "Updated Title" }Returns the updated record (defaults to returning the uid field, or * if no uid mapping).
Delete
POST /table/{table}/delete{
"where": "id == 'post-123'",
"returning": "*"
}If you omit returning, the response is an empty array [].
Auth
All auth endpoints are under /table/{table}/auth/.
Sign up
POST /table/{table}/auth/sign-up{ "username": "alice", "email": "alice@test.com", "password": "secret123", "name": "Alice" }Returns { "token", "refresh_token", "record", "verified" }.
Body fields must match your auth table schema. If you use the scaffolded authFields, name is required.
If your auth extension sets passwordConfirmSuffix (the default scaffold uses 'Confirm'), also send the matching confirm field, for example passwordConfirm.
Login
POST /table/{table}/auth/login-password{ "identity": "alice@test.com", "password": "secret123" }identity can be email or username.
Refresh token
POST /table/{table}/auth/refresh-token{ "refresh_token": "..." }Send the current access token in Authorization: Bearer <token> as well.
Password reset
POST /table/{table}/auth/request-password-reset
{ "email": "alice@test.com" }
POST /table/{table}/auth/confirm-password-reset
{ "token": "from-email", "password": "newpassword" }Use the user's email address in the email field.
If your auth extension sets passwordConfirmSuffix, include the confirm field here too.
Email verification
POST /table/{table}/auth/request-verification
Authorization: Bearer <token>
POST /table/{table}/auth/confirm-verification
{ "token": "from-email" }OAuth
GET /table/{table}/auth/oauth/{provider} # Start redirect flow
GET /table/{table}/auth/oauth/{provider}/callback # Callback (register in provider dashboard)
POST /table/{table}/auth/google-login # Google One Tap form POST
POST /table/{table}/auth/login-token # Bearer token login
POST /table/{table}/auth/logout # Invalidate current session
POST /auth/logout # Clear auth cookie only/auth/google-login expects application/x-www-form-urlencoded with credential and g_csrf_token.
Files
GET /files/{table}/{record_id}/{path} # Download file by stored file name/pathpath is the stored file value from the record, not the field name.
Upload via multipart form data on insert/update:
curl -X POST http://localhost:8787/api/v1/table/posts/insert \
-H 'Authorization: Bearer YOUR_TOKEN' \
-F '@filePayload=@photo.jpg' \
-F '@jsonPayload={"values":{"title":"My Post","cover_image":"@filePayload.0"}}'Other
GET /health # Health check
GET /doc # OpenAPI 3.1.0 spec (JSON)
GET /doc/ui # Swagger UIActions
POST /action/{name}{ "post_id": "abc-123" }Params defined in the action config.