Supabase REST API via curl. Use this skill for database CRUD operations, filtering, pagination, and real-time data management.
/plugin marketplace add vm0-ai/api0/plugin install api0@api0This skill inherits all available tools. When active, it can use any tool Claude has access to.
Use the Supabase REST API via direct curl calls to perform database CRUD operations.
Supabase auto-generates a RESTful API from your PostgreSQL database schema using PostgREST.
Official docs:
https://supabase.com/docs/guides/api
Use this skill when you need to:
export SUPABASE_URL="https://your-project-ref.supabase.co"
export SUPABASE_PUBLISHABLE_KEY="sb_publishable_..."
export SUPABASE_SECRET_KEY="sb_secret_..."
API Keys:
| Key Type | Format | Use Case |
|---|---|---|
| Publishable | sb_publishable_... | Client-side, respects Row Level Security (RLS) |
| Secret | sb_secret_... | Server-side only, bypasses RLS |
Note: Legacy
anonandservice_roleJWT keys still work but are deprecated. Use the newsb_publishable_andsb_secret_keys instead.
Important: When using
$VARin a command that pipes to another command, wrap the command containing$VARinbash -c '...'. Due to a Claude Code bug, environment variables are silently cleared when pipes are used directly.bash -c 'curl -s "https://api.example.com" -H "Authorization: Bearer $API_KEY"' | jq .
Base URL: ${SUPABASE_URL}/rest/v1
All requests require the apikey header with your API key.
Get all rows from a table:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?select=*" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Get only specific columns:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?select=id,name,email" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Filter rows using PostgREST operators.
Equal to:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?status=eq.active" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Greater than:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/products?price=gt.100" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Multiple conditions (AND):
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?age=gte.18&status=eq.active" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Available Operators:
| Operator | Meaning | Example |
|---|---|---|
eq | Equals | ?status=eq.active |
neq | Not equals | ?status=neq.deleted |
gt | Greater than | ?age=gt.18 |
gte | Greater than or equal | ?age=gte.21 |
lt | Less than | ?price=lt.100 |
lte | Less than or equal | ?price=lte.50 |
like | Pattern match (use * for %) | ?name=like.*john* |
ilike | Case-insensitive pattern | ?name=ilike.*john* |
in | In list | ?id=in.(1,2,3) |
is | Is null/true/false | ?deleted_at=is.null |
Use or for OR logic:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?or=(status.eq.active,status.eq.pending)" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Sort results.
Ascending:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?order=created_at.asc" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Descending:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?order=created_at.desc" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Multiple columns:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?order=status.asc,created_at.desc" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Use limit and offset.
First 10 rows:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?limit=10" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Page 2 (rows 11-20):
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?limit=10&offset=10" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Use Prefer: count=exact header:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?select=*" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}" -H "Prefer: count=exact" -I' | grep -i content-range
bash -c 'curl -s -X POST "${SUPABASE_URL}/rest/v1/users" -H "apikey: ${SUPABASE_SECRET_KEY}" -H "Content-Type: application/json" -H "Prefer: return=representation" -d '"'"'{"name": "John Doe", "email": "john@example.com"}'"'"'' | jq .
bash -c 'curl -s -X POST "${SUPABASE_URL}/rest/v1/users" -H "apikey: ${SUPABASE_SECRET_KEY}" -H "Content-Type: application/json" -H "Prefer: return=representation" -d '"'"'[{"name": "John", "email": "john@example.com"}, {"name": "Jane", "email": "jane@example.com"}]'"'"'' | jq .
Update rows matching a filter:
bash -c 'curl -s -X PATCH "${SUPABASE_URL}/rest/v1/users?id=eq.1" -H "apikey: ${SUPABASE_SECRET_KEY}" -H "Content-Type: application/json" -H "Prefer: return=representation" -d '"'"'{"status": "inactive"}'"'"'' | jq .
Use Prefer: resolution=merge-duplicates:
bash -c 'curl -s -X POST "${SUPABASE_URL}/rest/v1/users" -H "apikey: ${SUPABASE_SECRET_KEY}" -H "Content-Type: application/json" -H "Prefer: resolution=merge-duplicates,return=representation" -d '"'"'{"id": 1, "name": "John Updated", "email": "john@example.com"}'"'"'' | jq .
Delete rows matching a filter:
bash -c 'curl -s -X DELETE "${SUPABASE_URL}/rest/v1/users?id=eq.1" -H "apikey: ${SUPABASE_SECRET_KEY}" -H "Prefer: return=representation"' | jq .
Embed related data using foreign keys.
Get posts with their author:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/posts?select=*,author:users(*)" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Get users with their posts:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/users?select=*,posts(*)" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Search text columns:
bash -c 'curl -s "${SUPABASE_URL}/rest/v1/posts?title=fts.hello" -H "apikey: ${SUPABASE_PUBLISHABLE_KEY}"' | jq .
Call PostgreSQL functions:
bash -c 'curl -s -X POST "${SUPABASE_URL}/rest/v1/rpc/my_function" -H "apikey: ${SUPABASE_SECRET_KEY}" -H "Content-Type: application/json" -d '"'"'{"param1": "value1"}'"'"'' | jq .
| Header | Description |
|---|---|
Content-Range | Row range and total count (e.g., 0-9/100) |
Preference-Applied | Confirms applied preferences |
select to limit returned columns for better performancePrefer: return=representation to get inserted/updated rows back