Skip to content

Data-Plane API

The data plane (/v1/*) is what your applications and end users talk to. It’s addressed per project and authenticated with per-project API keys or a user JWT — not management credentials.

Base URL & auth

https://<host>/v1

Send your project key in apikey, and (for a signed-in user) the JWT in Authorization:

apikey: anvilbase_anon_<slug>_…
Authorization: Bearer <user-jwt> # optional
ScopeCredentialRLS
anonanon keyenforced (public rows)
authenticatedanon key + user JWTenforced (user’s rows)
service_roleservice_role keybypassed

With the Supabase SDK, the base URL is https://<host>/v1/<project_id>.

REST (REST→SQL engine)

/v1/rest/<project_id>/<table>
MethodAction
GETread rows (Reading Data)
POSTinsert (Modifying Data)
PATCHupdate (filter required)
DELETEdelete (filter required)
POST /rpc/<fn>call a function (RPC)

Query syntax (filters, select, order, limit, offset) is in REST Query Syntax. Headers: Prefer: return=representation, Prefer: count=exact, Accept: application/vnd.pgrst.object+json.

Raw SQL: POST /v1/rest/<id>/rpc/exec_sql (service_role only) — see SQL Editor.

Auth

/v1/auth/<project_id>/*
MethodPathPurpose
POSTsign-up{email, password}
POSTsign-in{email, password}access_token (JWT)
POSTsign-outend session
GETsessioncurrent session
POSTmagic-link{email}
GEToauth/<provider>OAuth redirect

See Auth.

Storage

/v1/storage/<project_id>/*
MethodPathPurpose
PUTobject/<bucket>/<path>upload
GETobject/<bucket>/<path>download
DELETEobject/<bucket>/<path>delete
POSTobject/list/<bucket>list
POSTobject/sign/<bucket>/<path>signed URL ({expires_in})

See Storage.

Queues (PGMQ)

A server-side queue surface over PGMQ — service_role only (anon / authenticated keys get 403). Native shape /v1/queue/<project_id>/...; the SDK alias (client.queues) is /v1/<project_id>/queue/v1/....

MethodPathPurpose
POST / GETqueue/<project_id>/queuescreate ({name}) / list
DELETEqueue/<project_id>/queues/<name>drop a queue
POSTqueue/<project_id>/queues/<name>/sendenqueue one ({message, delay?})
POSTqueue/<project_id>/queues/<name>/send_batchenqueue many ({messages: [...]})
POSTqueue/<project_id>/queues/<name>/readread with a visibility timeout ({vt, qty?})
POSTqueue/<project_id>/queues/<name>/popread + delete one atomically
POSTqueue/<project_id>/queues/<name>/ackdelete a message ({msg_id})
POSTqueue/<project_id>/queues/<name>/archivemove a message to the archive ({msg_id})
GETqueue/<project_id>/queues/<name>/archivedlist archived (DLQ-equivalent)
POSTqueue/<project_id>/queues/<name>/replayre-send an archived message ({msg_id})
GETqueue/<project_id>/queues/<name>/metricsqueue length + message ages

PGMQ has no separate dead-letter queue — archive is the DLQ-equivalent. See Queues.

Cache (Valkey)

A server-side KV surface over Valkey — service_role only. Every op runs as the project’s per-project ACL user, physically confined to the <project_id>:* keyspace. Native shape /v1/cache/<project_id>/...; the SDK alias (client.cache) is /v1/<project_id>/cache/v1/....

MethodPathPurpose
GETcache/<project_id>/get/<key>get a string
POSTcache/<project_id>/setset ({key, value, ex?, px?, nx?, xx?}ex wins over px)
POSTcache/<project_id>/deldelete keys ({keys: [...]})
POSTcache/<project_id>/incrincrement ({key, by?})
POSTcache/<project_id>/decrdecrement ({key, by?})
POSTcache/<project_id>/expireset TTL ({key, seconds})
GETcache/<project_id>/ttl/<key>remaining TTL
GETcache/<project_id>/exists/<key>existence check
POSTcache/<project_id>/mgetmulti-get ({keys: [...]})
POSTcache/<project_id>/msetmulti-set ({pairs: {k: v}})
GETcache/<project_id>/scaniterate keys (?cursor=, ?match=, ?count=)

Keys are bare in requests/responses — the <project_id>: prefix is added for you. See Cache.

Cron (pg_cron)

A server-side scheduled-jobs surface over pg_cron — service_role only. Each job runs inside the project’s database and is namespaced + tenant-isolated. Native shape /v1/cron/<project_id>/jobs...; the SDK alias (client.cron) is /v1/<project_id>/cron/v1/jobs.... (The console reads jobs via the admin Management API.)

MethodPathPurpose
POST / GETcron/<project_id>/jobsschedule ({name, schedule, command}) / list
DELETEcron/<project_id>/jobs/<name>unschedule a job
GETcron/<project_id>/jobs/<name>/runsrecent run history, newest-first (?limit= ≤ 100)

schedule is a 5-field cron expression or a pg_cron interval (e.g. 5 seconds); command is SQL run in the project DB on that schedule. See Cron & Scheduling.

Edge functions

POST /v1/functions/<project_id>/<name>

Invokes a deployed function. verify_jwt: true (default) requires a token. The runtime receives injected X-AnvilBase-* context headers. See Edge Functions.

Realtime

ws(s)://<host>/v1/realtime/<project_id>/socket/websocket?token=<jwt>&vsn=2.0.0

Phoenix Channels — postgres changes, broadcast, presence. Auth via the token query param. See Realtime.

eIDAS (optional)

/v1/eidas/<project_id>/*
MethodPathPurpose
POSTverifystart an OpenID4VP verification
POSTverify/callbacksubmit the wallet’s VP token
POSTissuecreate a credential offer (OpenID4VCI)
GET.well-known/openid4vpverifier metadata
GET.well-known/openid-credential-issuerissuer metadata

See eIDAS.

Rate limits

Per project, per scope:

ScopeLimit / 60s
anon100
authenticated1,000
service_role5,000

Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and (on 429) Retry-After. Per-project DB pool exhaustion also returns 429 with Retry-After: 1.

Errors

{ "error": "invalid query", "statusCode": 400, "hint": "...", "details": "..." }

See Error Codes. Management endpoints (/api/v1) are documented separately in Management API.