Projects
Projects are the top-level unit of organisation in AxiomDB. Each project maps to one application in one environment, owns one or more database branches, and carries its own network policy, audit log, and provisioning jobs.
Overview
A project is identified by two required fields:
| Field | Description | Example |
|---|---|---|
name | Human-readable label | "Servers API" |
app_key | Slug-style app identifier | "servers" |
env | Environment identifier | "prod" |
The slug is derived automatically as {app_key}-{env} (e.g. servers-prod) and is unique across your organization. Once created, only name can be updated — changing app_key or env requires creating a new project.
Creating a project
Projects are created asynchronously via a Redis-backed job queue. The gateway immediately returns a 202 Accepted with a job_id. Poll /api/v1/jobs/:job_id or watch the console for the status to change from queued → running → succeeded.
POST /api/v1/projects
Authorization: Bearer <paseto-v4-token>
Content-Type: application/json
{
"name": "Servers API",
"app_key": "servers",
"env": "prod"
}Response (202 Accepted):
{
"job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "queued",
"name": "Servers API",
"app_key": "servers",
"env": "prod",
"slug": "servers-prod"
}Role requirement: Only owner, admin, and operator roles can create projects. viewer tokens will receive 403 Forbidden.
Validation rules
app_keymust be lowercase alphanumeric with hyphens/underscores, max 48 characters.envmust be lowercase alphanumeric with hyphens/underscores, max 24 characters.- The
slug({app_key}-{env}) must be unique within your tenant. Attempting to recreate an existing active project returns the existing project's data instead of failing.
Listing projects
GET /api/v1/projects
Authorization: Bearer <paseto-v4-token>Response:
{
"projects": [
{
"id": "...",
"slug": "servers-prod",
"name": "Servers API",
"app_key": "servers",
"env": "prod",
"status": "active",
"created_by": "...",
"tenant_id": "...",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
]
}owner and admin roles see all projects in the tenant. operator and viewer roles see only projects they created.
Looking up a project by name
GET /api/v1/projects/lookup?name=servers-prod
Authorization: Bearer <paseto-v4-token>Matches on name, app_key, slug, or {app_key}-{env} (case-insensitive).
Response:
{
"matches": [...],
"is_duplicate": false
}Getting a single project
GET /api/v1/projects/:project_id
Authorization: Bearer <paseto-v4-token>Project credentials
The main branch credentials for Prisma:
GET /api/v1/projects/:project_id/credentials
Authorization: Bearer <paseto-v4-token>Response:
{
"project_id": "...",
"database": "sq_servers_prod",
"database_url": "postgresql://servers_prod_rw:...@db.squareexp.com:6432/sq_servers_prod?sslmode=require",
"direct_url": "postgresql://servers_prod_owner:...@db.squareexp.com:5432/sq_servers_prod?sslmode=require",
"runtime_key": "DATABASE_URL_SERVERS_PROD",
"direct_key": "DIRECT_URL_SERVERS_PROD"
}Every credential fetch is written to audit_events with action project.credentials.viewed. This creates an immutable record of who accessed the connection strings and when.
Project usage
Track storage consumption across all branches:
GET /api/v1/projects/:project_id/usage
Authorization: Bearer <paseto-v4-token>Response:
{
"project_id": "...",
"storage_used_bytes": 52428800,
"storage_limit_bytes": 10737418240,
"branch_count": 3
}When storage_used_bytes >= storage_limit_bytes, new branch creation is blocked until you extend storage or delete old branches.
Deleting a project
DELETE /api/v1/projects/:project_id
Authorization: Bearer <paseto-v4-token>Project deletion is permanent and irreversible. All branches, network rules, provisioning jobs, and audit events are cascade-deleted from the control plane. The underlying PostgreSQL databases are deprovisioned via square-dbctl deprovision. Requires owner or admin role.
Project statuses
| Status | Description |
|---|---|
active | Healthy, connectable project |
archived | Read-only, no new branches can be created |
failed | Provisioning failed; inspect provisioning_jobs for the error |
Data model
CREATE TABLE projects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
slug TEXT UNIQUE NOT NULL, -- "{app_key}-{env}"
name TEXT NOT NULL,
app_key TEXT NOT NULL,
env TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
created_by UUID NOT NULL REFERENCES users(id),
tenant_id TEXT NOT NULL, -- from Square IdP ctx.tenant_id
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(app_key, env)
);Provisioning internals
When you call POST /api/v1/projects, the gateway:
- Validates
app_key,env, andsluguniqueness. - Publishes a command to the Redis stream
axiomdb:project_commands(consumer groupgateway_project_workers). - A background Tokio task (started at server boot) reads from the stream, calls
square-dbctl provision --app {app_key} --env {env}. square-dbctlcreates the PostgreSQL database, three roles, and writes secret keys to/home/opsdc/.creds/zone.env.- The gateway records the
project,project_databases, and initialmainbranch in the control-plane DB. - The provisioning job status is updated to
succeededorfailed.
How is this guide?
