Projects API
API endpoints for project management.
Manage Supabase projects through the REST API.
Endpoints Overview
| Method | Endpoint | Description |
|---|---|---|
| GET | /projects | List all projects |
| POST | /projects | Create project |
| POST | /projects/create | Create with streaming |
| GET | /projects/:id | Get project |
| DELETE | /projects/:id | Delete project |
| GET | /projects/:id/status | Get status |
| POST | /projects/:id/start | Start project |
| POST | /projects/:id/stop | Stop project |
| GET | /projects/:id/logs | Get logs |
| GET | /projects/:id/containers | Get containers |
| GET | /projects/:id/services | Get services |
| PUT | /projects/:id/services | Update services |
| GET | /projects/:id/domain | Get domain |
| POST | /projects/:id/domain | Set domain |
| DELETE | /projects/:id/domain | Remove domain |
| GET | /projects/:id/settings | Get settings |
| PUT | /projects/:id/settings | Update settings |
| GET | /projects/:id/auth-providers | Get auth providers |
| PUT | /projects/:id/auth-providers | Update auth providers |
| GET | /projects/:id/functions | List Edge Functions |
| POST | /projects/:id/functions | Create Edge Function |
| GET | /projects/:id/functions/:name | Get Edge Function files |
| PUT | /projects/:id/functions/:name | Write / delete Edge Function files |
| DELETE | /projects/:id/functions/:name | Delete Edge Function |
List Projects
GET /api/v1/projects
Permission: projects:read
Response:
[
{
"id": "my-project",
"name": "My Project",
"description": "Development environment",
"directory": "/var/supascale/projects/my-project",
"status": "running",
"ports": {
"api": 8000,
"db": 5432,
"studio": 3001
},
"domain": "api.example.com",
"createdAt": "2026-01-19T10:00:00Z",
"updatedAt": "2026-01-19T12:00:00Z"
}
]
Create Project
POST /api/v1/projects
Permission: projects:write
Request:
{
"id": "my-project",
"name": "My Project",
"description": "Development environment",
"postgresVersion": "15"
}
Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique project identifier (lowercase, alphanumeric, hyphens, underscores) |
name | string | Yes | Display name for the project |
description | string | No | Optional description |
postgresVersion | string | No | PostgreSQL version: "15", "16", or "17" (default: "15") |
Response:
{
"id": "my-project",
"name": "My Project",
"directory": "/var/supascale/projects/my-project",
"ports": { "api": 8000, "db": 5432, "studio": 3001 },
"postgresVersion": "15",
"externalDbAccess": false,
"status": "running",
"createdAt": "2026-01-19T12:00:00Z"
}
Create Project (Streaming)
POST /api/v1/projects/create
Returns Server-Sent Events with progress updates.
Request:
{
"id": "my-project",
"name": "My Project",
"services": ["realtime", "storage"],
"postgresVersion": "17"
}
Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique project identifier |
name | string | Yes | Display name for the project |
description | string | No | Optional description |
services | array | No | Optional services to enable (e.g., ["realtime", "storage", "inbucket"]) |
postgresVersion | string | No | PostgreSQL version: "15", "16", or "17" (default: "15") |
Response (SSE):
event: progress
data: {"step": 1, "total": 7, "status": "running", "message": "Validating..."}
event: progress
data: {"step": 2, "total": 7, "status": "running", "message": "Generating config..."}
event: progress
data: {"step": 6, "total": 7, "status": "completed", "detail": "7 services configured (PostgreSQL 17)"}
event: complete
data: {"project": {...}}
Get Project
GET /api/v1/projects/:id
Query Parameters:
credentials=true- Include decrypted credentials
Response:
{
"id": "my-project",
"name": "My Project",
"description": "Development environment",
"directory": "/var/supascale/projects/my-project",
"status": "running",
"ports": { "api": 8000, "db": 5432, "studio": 3001 },
"domain": null,
"enabledServices": ["db", "rest", "auth", "kong", "studio", "meta", "realtime"],
"postgresVersion": "15",
"externalDbAccess": false,
"autoStart": true,
"createdAt": "2026-01-19T10:00:00Z"
}
With credentials=true:
{
"...": "...",
"credentials": {
"dbPassword": "secure-password",
"jwtSecret": "jwt-secret-key",
"anonKey": "eyJhbGciOiJIUzI1NiIs...",
"serviceRoleKey": "eyJhbGciOiJIUzI1NiIs..."
}
}
Delete Project
DELETE /api/v1/projects/:id
Query Parameters:
removeFiles=true- Delete project files
Response:
{
"success": true,
"message": "Project deleted"
}
Get Project Status
GET /api/v1/projects/:id/status
Response:
{
"status": "running",
"lastChecked": "2026-01-19T12:00:00Z",
"containers": {
"total": 8,
"running": 8,
"stopped": 0
}
}
Start Project
POST /api/v1/projects/:id/start
Returns SSE with startup logs.
Response:
event: log
data: {"message": "Starting containers..."}
event: log
data: {"message": "Container db started"}
event: complete
data: {"success": true}
Stop Project
POST /api/v1/projects/:id/stop
Returns SSE with shutdown logs.
Get Project Logs
GET /api/v1/projects/:id/logs
Query Parameters:
service- Filter by service nametail- Number of lines (default: 200)
Response:
{
"logs": [
{
"timestamp": "2026-01-19T12:00:00Z",
"service": "db",
"level": "info",
"message": "database system is ready"
}
]
}
Get Containers
GET /api/v1/projects/:id/containers
Query Parameters:
stats=true- Include CPU/memory stats
Response:
{
"containers": [
{
"name": "my-project-db",
"service": "db",
"status": "running",
"state": "Up 2 hours"
}
]
}
With stats=true:
{
"containers": [
{
"name": "my-project-db",
"service": "db",
"status": "running",
"stats": {
"cpu": "2.5%",
"memory": "256MB / 1GB"
}
}
]
}
Get/Update Services
GET /api/v1/projects/:id/services PUT /api/v1/projects/:id/services
GET Response:
{
"services": ["db", "rest", "auth", "kong", "studio", "meta", "realtime"],
"enabledServices": {
"db": true,
"rest": true,
"auth": true,
"kong": true,
"studio": true,
"meta": true,
"realtime": true,
"storage": false,
"functions": false,
"inbucket": false
}
}
PUT Request:
{
"services": ["db", "rest", "auth", "kong", "studio", "meta", "realtime", "storage"]
}
Domain Configuration
GET /api/v1/projects/:id/domain POST /api/v1/projects/:id/domain DELETE /api/v1/projects/:id/domain
POST Request:
{
"name": "api.example.com",
"sslEnabled": true,
"webServer": "nginx"
}
POST Response:
{
"success": true,
"data": {
"name": "api.example.com",
"sslEnabled": true,
"webServer": "nginx"
},
"message": "Domain configured successfully. nginx configuration generated. Restart the project for Studio to use the new domain.",
"requiresRestart": true
}
When a domain is configured, the project's API_EXTERNAL_URL is automatically updated. You must restart the project for Supabase Studio to use the new domain for API calls.
Project Settings
GET /api/v1/projects/:id/settings PUT /api/v1/projects/:id/settings
GET Query Parameters:
category- storage, smtp, auth, pooler, api, database
Categories:
| Category | Description |
|---|---|
storage | File storage backend settings (local/S3) |
smtp | Email/SMTP server settings |
auth | Authentication settings (signup, JWT, etc.) |
pooler | Connection pooler (Supavisor) settings |
api | PostgREST API settings |
database | PostgreSQL version and external access settings |
inbucket | Email testing (Inbucket) settings |
SMTP Settings Example
PUT Request:
{
"category": "smtp",
"settings": {
"host": "smtp.example.com",
"port": 587,
"user": "apikey",
"password": "your-api-key"
}
}
Database Settings
Configure which network interface the PostgreSQL ports listen on. The address applies to both the direct port (port) and the Supavisor pooler port (poolerPort).
GET Response:
{
"success": true,
"data": {
"externalAccess": false,
"bindAddress": "127.0.0.1",
"postgresVersion": "15",
"port": 54322,
"poolerPort": 54329,
"interfaces": [
{ "address": "203.0.113.5", "interfaceName": "eth0" }
],
"firewall": {
"type": "ufw",
"active": true,
"portsOpen": true,
"portDetails": [
{ "port": 54322, "protocol": "tcp", "allowed": true },
{ "port": 54329, "protocol": "tcp", "allowed": true }
]
}
}
}
PUT Request - Bind to an Address:
{
"category": "database",
"settings": {
"bindAddress": "0.0.0.0"
}
}
bindAddress must be 127.0.0.1, 0.0.0.0, or an address from the GET response's interfaces list; anything else is rejected with 400. The legacy "externalAccess": true / false form is still accepted and maps to 0.0.0.0 / 127.0.0.1.
Response:
{
"success": true,
"message": "Database settings updated. PostgreSQL published on 0.0.0.0: direct port 54322, pooler port 54329. Firewall ports opened. Restart the project for changes to take effect.",
"requiresRestart": true
}
External PostgreSQL Access: Any address other than 127.0.0.1 exposes your PostgreSQL ports to that network. Ensure your firewall is properly configured and use strong database passwords.
PostgreSQL Version: postgresVersion is fixed when the project is created. Sending a different value returns 400; create a new project and migrate your data to change major versions.
Inbucket Settings
Inbucket is a local email testing server that captures all outgoing emails for development and testing.
GET Response:
{
"success": true,
"data": {
"enabled": true,
"externalAccess": false
}
}
PUT Request - Enable Inbucket:
{
"category": "inbucket",
"settings": {
"enabled": true
}
}
PUT Request - Enable External Access:
{
"category": "inbucket",
"settings": {
"externalAccess": true
}
}
Response:
{
"success": true,
"message": "Inbucket settings updated. External access enabled on port 54324. Restart the project for changes to take effect.",
"requiresRestart": true
}
About Inbucket: When Inbucket is enabled, Supabase Auth is automatically configured to send emails to the local Inbucket SMTP server instead of external providers. This allows you to test email flows (signup confirmations, password resets, magic links) without sending real emails.
External Access: Enabling external access allows anyone on your network to view captured emails. This is safe for development but should not be enabled in production environments.
Auth Providers
GET /api/v1/projects/:id/auth-providers PUT /api/v1/projects/:id/auth-providers
PUT Request:
{
"providers": [
{
"provider": "google",
"enabled": true,
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
}
]
}
Edge Functions
GET /api/v1/projects/:id/functions POST /api/v1/projects/:id/functions GET /api/v1/projects/:id/functions/:name PUT /api/v1/projects/:id/functions/:name DELETE /api/v1/projects/:id/functions/:name
Permission: projects:read for GET, projects:write for POST / PUT / DELETE
Functions live in supabase/docker/volumes/functions/<name>/ inside the project directory and are served by the functions container at /functions/v1/<name> through the API gateway. Changes take effect on the next request — no restart. The main directory is the runtime's router and is never listed or writable through this API.
Function names use lowercase letters, digits, - and _ (1–63 characters, starting with a letter or digit).
List — GET Response:
{
"success": true,
"data": {
"serviceEnabled": true,
"functions": [
{
"name": "hello",
"hasEntrypoint": true,
"fileCount": 1,
"sizeBytes": 412,
"modifiedAt": "2026-08-28T14:02:11.000Z"
}
]
}
}
Create — POST Request:
{
"name": "send-welcome-email",
"content": "Deno.serve(() => new Response('ok'))"
}
content is the index.ts entrypoint; omit it to start from the built-in template. Returns 201, or 409 if the name is taken.
Get — GET Response:
{
"success": true,
"data": {
"name": "send-welcome-email",
"files": [
{ "path": "index.ts", "sizeBytes": 412, "content": "Deno.serve(...)" },
{ "path": "lib/template.ts", "sizeBytes": 88, "content": "export const html = ..." },
{ "path": "assets/logo.png", "sizeBytes": 20480 }
]
}
}
content is included for text files up to 1 MB. Binary or larger files are listed without it.
Update — PUT Request:
{
"files": [
{ "path": "index.ts", "content": "Deno.serve(...)" },
{ "path": "lib/template.ts", "content": "..." }
],
"deletePaths": ["old-helper.ts"]
}
Paths are relative to the function directory; anything that would resolve outside it is rejected with 400. Parent directories are created as needed. The response carries the updated file list.
Delete — DELETE Response:
{
"success": true,
"message": "Function \"send-welcome-email\" deleted."
}
Invoke a function:
curl "http://your-server:54321/functions/v1/send-welcome-email" \
-H "Authorization: Bearer <anon or service_role key>" \
-H "Content-Type: application/json" \
-d '{"name": "Ada"}'
Bulk upload: to bring in a whole supabase/functions directory at once, use Import Edge Functions with a .tar.gz or .zip archive.