Skip to content

Data API

Once tables exist in your schema, these endpoints are automatically available.

MethodPathPurpose
GET/v1/{app_id}/{table}List rows
GET/v1/{app_id}/{table}/{id}Read single row
POST/v1/{app_id}/{table}Create a row
PATCH/v1/{app_id}/{table}/{id}Update a row
DELETE/v1/{app_id}/{table}/{id}Delete a row

Format: column=operator.value

OperatorExampleSQL
eqstatus=eq.published= 'published'
neqstatus=neq.draft!= 'draft'
gtage=gt.18> 18
gteage=gte.18>= 18
ltprice=lt.100< 100
lteprice=lte.100<= 100
liketitle=like.%hello%LIKE '%hello%'
iliketitle=ilike.%hello%ILIKE '%hello%'
isdeleted_at=is.nullIS NULL
inid=in.(1,2,3)IN (1,2,3)
ftstitle=fts.helloFull-text search
?order=created_at.desc
?order=name.asc,created_at.desc
?limit=20&offset=40
?select=id,title,created_at
Auth methodRoleAccess
Nonebutterbase_anonPublic data only
End-user JWTbutterbase_userUser-scoped data (RLS)
API key (bb_sk_...)butterbase_serviceAll data (bypasses RLS)
Terminal window
POST /v1/{app_id}/posts
Content-Type: application/json
Authorization: Bearer {token}
{
"title": "Hello World",
"body": "My first post",
"published": true
}

If the table has a user isolation policy with auto-populate trigger, the user_id column is filled automatically.

Terminal window
PATCH /v1/{app_id}/posts/{id}
Content-Type: application/json
Authorization: Bearer {token}
{
"published": false
}

Only send columns you want to change.

Terminal window
DELETE /v1/{app_id}/posts/{id}
Authorization: Bearer {token}
MethodPathPurpose
GET/v1/{app_id}/schemaRead current schema
POST/v1/{app_id}/schema/applyApply schema update (dry_run: true to preview)
GET/v1/{app_id}/migrationsList applied migrations
MethodPathPurpose
GET/appsList your apps
POST/initCreate a new app. Body: {"name": "my-app"}
DELETE/apps/{app_id}Delete an app permanently