Skip to content
Browse docs

REST API reference

The Layerbase Cloud API lets you create, list, and query databases over HTTPS, and manage the personal API keys that authenticate every request. This page documents each public endpoint: the auth header it expects, the fields it accepts, the shape it returns, and the status codes it can send back. The Docs overview has the quickstart if you are starting from scratch.

Base URL

Every request uses HTTPS and the same base URL. The examples below store it in $LAYERBASE_API_URL.

base URL
https://cloud.layerbase.dev

Authentication

All /v1/* endpoints except GET /v1/engines require a personal API key as a Bearer token. Keys are prefixed sk_ and the full secret is shown exactly once, at creation. Create and manage keys under Personal API keys in cloud settings, or with the key endpoints below.

Authorization header
Authorization: Bearer sk_<your-key>

Keys have one of two scopes. An account key (the default) can reach every endpoint for your account. A database key is pinned to one database: it may only call /v1/databases/<that-id> and its sub-paths, and returns 403 anywhere else.

An sk_ key is the only credential the authenticated /v1/* endpoints accept (the unauthenticated ones noted above take no credential at all). In particular, the session token the CLI stores after the browser login flow, lbase login with no flags, is a browser-issued JWT that works only against the layerbase.com/api/cli/* proxy routes, and sending it here returns 401 Invalid API key. Storing a key with lbase login --api-key sk_... is a different flow and does leave the CLI holding a valid sk_ credential. If you are debugging that error while signed in to the CLI, that mismatch is the usual cause: create a key under Personal API keys and send it instead. See the CLI guide for how the two credentials divide up.

Request and response format

Requests and responses are JSON, and body fields use camelCase. Send Content-Type: application/json on any request with a body. Errors return { "error": "message" } with a relevant HTTP status; some also add a machine-readable code (for example database_limit_reached or pool_block_required).

200

Success.

201

Created (database, API key).

400

Invalid input: bad engine, name, or body field.

401

Missing, malformed, or unknown API key.

402

Account is suspended for a failed payment. Mutating calls are blocked; GET calls still work.

403

Not allowed: a database-scoped key hitting another database, an engine your plan cannot create, or an owner-only action.

404

Database or key not found (or not yours).

409

Conflict: name already taken, pool capacity exhausted, or a pool block is required.

423

Database is locked, or an operation is in progress.

429

Your plan's database limit or monthly programmatic-create limit is reached.

503

Temporarily unavailable: engine binary not ready, database waking or archived, or account migrating.

Health and engines

GET/health

Unauthenticated liveness probe. Returns { "status": "ok", "service": "layerbase-cloud" }. Returns 503 with draining or overloaded when the server is shutting down or under memory pressure.

GET/v1/engines

The public engine registry: every engine, its display name, versions, and defaults. No auth required. This is the same data the dashboard create flow reads, so you can use it to build a valid engine and version for a create call.

Databases

GET/v1/databases

Lists the databases you own plus any shared with you through a team. Returns { "databases": [ ... ] }. Each entry includes id, name, engine, version, status, host, port, connectionString, an access field of owner or member, the placement fields server / serverPool (the canonical server slug and either shared or dedicated; both null when placement is not reported), and the transient fields expiresAt / transient (see transient databases). App workloads are not databases and never appear here.

list databases
curl $LAYERBASE_API_URL/v1/databases \
  -H "Authorization: Bearer $LAYERBASE_API_KEY"
POST/v1/databases

Provisions a new database. Only engine is required; the rest have defaults.

engine

Required. e.g. postgresql, mysql, redis, valkey, mariadb, mongodb, clickhouse.

version

Optional. Defaults to the engine default from /v1/engines.

name

Optional. Lowercase letter first, then letters/numbers/hyphens/underscores, up to 63 chars. Auto-generated if omitted.

database

Optional. Initial database/schema name. Defaults per engine.

backupPolicy

Optional. 'none' (default), '7d', or '30d'.

keepAlive

Optional boolean. Always-on (skip hibernation). Paid plans only.

storageBlocks

Optional integer 0-20. Extra storage blocks.

ttlHours

Optional integer 1-72. Makes the database transient: an expires_at is stamped and the database is destroyed outright at expiry with no final backup. Ideal for CI. See Transient databases below.

teamId

Optional. Owning team. Defaults to your primary team.

Returns 201 with the new database, including its connection details and a status. Fast engines come back running; slow-start engines (MySQL, MariaDB, ClickHouse, QuestDB, libSQL) come back provisioning and finish in the background, so poll GET /v1/databases/:id until status is running. Redis and Valkey also return restUrl / restToken; MySQL and MariaDB also return psUrl / psUsername / psPassword for their HTTP drivers (see serverless and edge access).

The response also carries the placement fields server (the canonical server slug of the box hosting the database) and serverPool (shared or dedicated). Either may be null while a slow-start engine is still provisioning, or when the host does not report placement.

create a database
curl -X POST $LAYERBASE_API_URL/v1/databases \
  -H "Authorization: Bearer $LAYERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"engine": "postgresql", "name": "my-app"}'

Common failures: 400 for an invalid engine or name, 403 for an engine your plan cannot create, 409 when the name is taken or the pool is exhausted, and 429 when you hit your plan's database limit or your monthly programmatic-create limit (see programmatic-create limits).

Transient databases (TTL)

Pass ttlHours (a whole number from 1 to 72) on create to make the database transient. Layerbase stamps an expires_at deadline and a reaper destroys the database outright at expiry: there is no final backup and no archive-warning window, because you asked for a throwaway. This is the recommended primitive for a fresh, disposable database per CI run: a crashed job cannot strand a database against your quota, because it self-destructs at the deadline. Every database in the response carries two extra fields: expiresAt (an ISO timestamp, or null for a durable database) and transient (a boolean).

A transient database still counts against your plan's database quota while it is alive, and it cannot be branched. An out-of-range ttlHours returns 400 with { "code": "invalid_ttl" } (the value is never silently clamped), and branching a transient database returns 400 with { "code": "branch_on_transient_forbidden" }.

create a 2-hour transient database
curl -X POST $LAYERBASE_API_URL/v1/databases \
  -H "Authorization: Bearer $LAYERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"engine": "postgresql", "ttlHours": 2}'
GET/v1/databases/:id

Returns one database with the same fields as the list entry plus teamName and stopped_at. Returns 404 if the database does not exist or is not yours. Poll this after a create to watch status settle.

POST/v1/databases/:id/query

Runs a query over HTTP against the database, no driver or open socket required, which makes it the easiest path from serverless and edge runtimes. Send { "query": "SELECT 1" } for SQL engines; the query is capped at 10 KB. A hibernated database wakes automatically (you may get a 503 with retry_after while it does); an archived one returns 503 with a restore path, and a locked one returns 423. The full request shapes for non-SQL engines and edge examples are in serverless and edge access.

query over HTTP
curl -X POST $LAYERBASE_API_URL/v1/databases/<id>/query \
  -H "Authorization: Bearer $LAYERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT 1"}'

Identity and usage

GET/v1/me

Returns who the key belongs to and your current programmatic-create usage, with no side effects. Use it for a whoami check or to let an agent report your standing before it provisions anything.

GET /v1/me response
{
  "user": { "id": "...", "email": "you@example.com", "plan": "pro" },
  "usage": {
    "programmaticCreates": {
      "used": 12,
      "limit": 500,
      "resetsAt": "2026-08-01T00:00:00.000Z"
    }
  }
}

limit is null when your plan is unmetered (a Custom plan on your own servers), and resetsAt is the first instant of next month in UTC.

Programmatic-create limits

Every database create authenticated by an API key counts toward a monthly programmatic-create quota, tracked per calendar month in UTC. This is separate from your plan's database-count quota: it caps how many databases automation may spin up over a month (transient or durable), so a CI loop cannot exhaust shared capacity. Creates you make in the dashboard do not count. The per-plan limits are:

Free5 / month
Solo30 / month
Pro500 / month
Team1,000 / month
Custom (dedicated servers)Unmetered

When you exceed the limit, the create returns 429 before any provisioning work, with a machine-readable body so a script or agent can back off gracefully:

429 over the monthly limit
{
  "code": "programmatic_create_limit_reached",
  "error": "Programmatic create limit reached (5/5 this month). Upgrade your plan for a higher limit: https://layerbase.com/pricing",
  "used": 5,
  "limit": 5,
  "resetsAt": "2026-08-01T00:00:00.000Z"
}

API keys

Manage the personal keys that authenticate the API. The raw secret is returned exactly once, on create and rotate; store it immediately.

GET/v1/api-keys

Lists your active keys. Returns { "keys": [ ... ] } with each key's id, name, prefix, scopeType, createdAt, and lastUsedAt. The secret is never included.

POST/v1/api-keys

Creates a key. Body is optional: name (defaults to default, max 80 chars), scopeType (account or database), and scopeId (required when scopeType is database, naming a database you own). Returns 201 with { "key": { ..., "secret": "sk_..." } }. The secret appears only in this response.

create an API key
curl -X POST $LAYERBASE_API_URL/v1/api-keys \
  -H "Authorization: Bearer $LAYERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "ci"}'
POST/v1/api-keys/:id/rotate

Mints a replacement key with the same name and scope and revokes the old one after a 24-hour grace window, so long-running callers can pick up the new secret without an outage. Returns 201 with the new key and its one-time secret. Returns 404 if the key is not yours and 410 if it is already revoked.

DELETE/v1/api-keys/:id

Revokes a key immediately. Returns { "ok": true } and is idempotent (revoking an already-revoked key still returns 200). Any request using that key fails 401 afterward.

The dashboard exposes many more per-database operations (stop, start, backup, restore, branch, firewall, client certificates) over the same /v1/databases/:id/* surface. Those are covered in their own guides, linked below.