Authentication
All endpoints except /signup, /login, /regions, and /errors require an API key.
Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Authentication Errors
{
"success": false,
"error": "Authorization header required"
}
Error Codes
All error responses use a standard code field. Use these codes for programmatic error handling instead of parsing error messages.
| Code | HTTP Status | Description |
| ok |
200 |
Request succeeded |
| created |
201 |
Resource was created |
| bad_request |
400 |
Invalid input or missing required fields |
| auth_required |
401 |
Authorization header missing |
| unauthorized |
401 |
Invalid API key |
| forbidden |
403 |
Tier limit reached, wrong project, or operation not allowed for isolation level |
| not_found |
404 |
Resource does not exist |
| conflict |
409 |
Resource already exists, or operation conflicts with current state |
| rate_limited |
429 |
Too many requests |
| internal_error |
500 |
Server error |
Example Error Responses
{
"success": false,
"http_status": 409,
"code": "conflict",
"error": "Tenant 'acme' is in trash. Use POST /tenants/acme/restore or DELETE /tenants/acme?hard=true"
}
{
"success": false,
"http_status": 403,
"code": "forbidden",
"error": "PITR is only available for L2 (dedicated) tenants"
}
Rate Limits
Rate limits protect shared infrastructure and ensure fair usage. Limits are applied in layers — from IP-level DDoS protection to tier-based API quotas.
IP Rate Limiting
All requests are rate-limited by IP address before authentication. This protects against abuse and DDoS. Exceeding the limit repeatedly results in a temporary ban.
| Parameter | Value | Description |
| Requests per second |
100 |
Maximum requests per second from a single IP address |
| Ban threshold |
5 violations |
After 5 rate limit violations, the IP is temporarily banned |
| Ban duration |
5 minutes |
Banned IPs receive 429 for all requests during this period |
Tier-Based Limits
After authentication, API requests are counted against your project's tier. Backup requests have a separate hourly limit. Dedicated tenants bypass the backup rate limit since backups run on their own server.
| Limit | Window | Scope | Description |
| API requests |
Per minute |
Project |
Limit varies by tier. Upgrade at tenantsdb.com/billing. |
| Backup requests |
Per hour |
Project |
Limits manual backup frequency. Dedicated tenants are exempt. |
Response
Rate-limited requests return HTTP 429 Too Many Requests with a Retry-After header indicating when to retry (1 second for rate limits, 300 seconds for bans).
Retry-After: 1
Content-Type: application/json
{
"success": false,
"error": "rate limit exceeded: max 60 requests per minute"
}
IP bans apply across both the API and database proxy connections. A ban from excessive API requests also blocks proxy connections from the same IP, and vice versa.
List available cloud regions for dedicated tenant provisioning. This endpoint is public and does not require authentication.
Shared databases are hosted in EMEA. For region selection, create or migrate tenants to dedicated isolation.
Request
curl -s https://api.tenantsdb.com/regions
Response
{
"regions": [
{
"zone": "eu-central",
"label": "Europe",
"is_default": true
},
{
"zone": "ap-southeast",
"label": "Asia Pacific"
},
{
"zone": "us-east",
"label": "US East"
},
{
"zone": "us-west",
"label": "US West"
}
]
}
Use the zone value when creating dedicated tenants or migrating to a specific region. If no region is specified, the default region is used.
List all error codes and their HTTP status mappings. Public endpoint — no authentication required. Useful for building client libraries.
Request
curl -s https://api.tenantsdb.com/errors
Response
{
"codes": {
"ok": { "status": 200, "description": "Request succeeded" },
"created": { "status": 201, "description": "Resource was created" },
"bad_request": { "status": 400, "description": "Invalid input or missing fields" },
"auth_required": { "status": 401, "description": "Authorization header missing" },
"unauthorized": { "status": 401, "description": "Invalid API key" },
"forbidden": { "status": 403, "description": "Tier limit reached or wrong project" },
"not_found": { "status": 404, "description": "Resource does not exist" },
"conflict": { "status": 409, "description": "Already exists or operation in progress" },
"rate_limited": { "status": 429, "description": "Too many requests" },
"internal_error": { "status": 500, "description": "Server error" }
}
}
Create a new account. Returns an API key for your first project.
Request Body
| Field | Type | | Description |
| email |
string |
required |
Email address |
| password |
string |
required |
Password (min 8 characters) |
| project_name |
string |
optional |
Project name (default: "My Project") |
Response
{
"success": true,
"http_status": 201,
"code": "created",
"api_key": "tenantsdb_sk_a91de156...",
"project_id": "tdb_2abf90d3"
}
Login to existing account. Returns all projects with API keys.
Request Body
| Field | Type | | Description |
| email |
string |
required |
Email address |
| password |
string |
required |
Password |
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"projects": [
{
"project_id": "tdb_2abf90d3",
"name": "Healthcare SaaS",
"api_key": "tenantsdb_sk_a91de156..."
}
]
}
Projects
Projects are the top-level organizational boundary. Each project has its own workspaces, blueprints, tenants, and API keys.
List all projects for the authenticated customer.
{
"success": true,
"http_status": 200,
"code": "ok",
"count": 2,
"projects": [
{
"project_id": "tdb_2abf90d3",
"name": "Healthcare SaaS",
"api_key_count": 2,
"created_at": "2026-01-17T20:12:06Z"
},
{
"project_id": "tdb_43cd4942",
"name": "E-commerce Platform",
"api_key_count": 1,
"created_at": "2026-01-17T20:12:24Z"
}
]
}
Create a new project. Returns a new API key.
Request Body
| Field | Type | | Description |
| name |
string |
required |
Project name |
Response
{
"success": true,
"http_status": 201,
"code": "created",
"project_id": "tdb_43cd4942",
"name": "E-commerce Platform",
"api_key": "tenantsdb_sk_42d5be1a...",
"proxy_password": "tdb_a9b55759ef905535",
"message": "Project created. Save your API key - it won't be shown again!"
}
Switch to a different project. Returns the API key for the target project. Accepts project ID or project name.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"project_id": "tdb_43cd4942",
"name": "E-commerce Platform",
"api_key": "tenantsdb_sk_42d5be1a...",
"proxy_password": "tdb_a9b55759ef905535"
}
Delete a project and all its resources (workspaces, blueprints, tenants, API keys).
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Project 'tdb_43cd4942' deleted successfully"
}
API Keys
Manage API keys for the current project.
List all API keys for the current project.
Generate a new API key. Returns HTTP 201.
Workspaces
Workspaces are development environments where you design your database schema. Each workspace operates in one of two modes:
tenant
Tenant Mode
Schema changes are captured as versioned blueprints. Deploy blueprints to create isolated tenant databases. This is the default mode.
control
Control Mode
A managed database with full DDL access. No blueprints, versioning, or tenants. Ideal for your application's control plane (users, billing, config).
List all workspaces. Each workspace includes a mode field (tenant or control).
Response
{
"workspaces": [
{
"id": "ws_abc123",
"name": "main",
"mode": "tenant",
"database": "postgresql",
"created_at": "2025-01-15T10:30:00Z",
"version": 3
},
{
"id": "ws_def456",
"name": "control-plane",
"mode": "control",
"database": "postgresql",
"created_at": "2025-01-15T11:00:00Z"
}
],
"count": 2
}
The version field is only present for tenant mode workspaces.
Create a workspace. Automatically creates a linked blueprint (tenant mode only).
Request Body
| Field | Type | | Description |
| name |
string |
required |
Workspace name. Cannot contain __ (reserved separator). |
| database |
string |
required |
PostgreSQL, MySQL, MongoDB, or Redis |
| mode |
string |
required |
tenant or control. Tenant mode uses blueprints and deployments. Control mode creates a standalone managed database. |
Response — Tenant Mode
{
"success": true,
"http_status": 201,
"code": "created",
"id": "myapp",
"mode": "tenant",
"blueprint": "myapp",
"database": "PostgreSQL",
"connection": {
"host": "pg.tenantsdb.com",
"port": 5432,
"database": "myapp_workspace",
"user": "tdb_2abf90d3",
"password": "tdb_d2bf66ed7898c448"
},
"connection_string": "postgresql://tdb_2abf90d3:[email protected]:5432/myapp_workspace?sslmode=require"
}
Response — Control Mode
Control mode workspaces omit the blueprint field. The workspace is a standalone managed database — no blueprints, versioning, or tenant deployment.
{
"success": true,
"http_status": 201,
"code": "created",
"id": "controlplane",
"mode": "control",
"database": "PostgreSQL",
"connection": {
"host": "pg.tenantsdb.com",
"port": 5432,
"database": "controlplane_workspace",
"user": "tdb_2abf90d3",
"password": "tdb_d2bf66ed7898c448"
},
"connection_string": "postgresql://tdb_2abf90d3:[email protected]:5432/controlplane_workspace?sslmode=require"
}
Connection Strings by Database
TLS is enabled for all database types. The connection string format varies:
| Database | TLS Parameter | Example |
| PostgreSQL |
?sslmode=require |
postgresql://user:pass@host:5432/db?sslmode=require |
| MySQL |
TLS required |
mysql://user:pass@host:3306/db |
| MongoDB |
?tls=true |
mongodb://user:pass@host:27017/db?authMechanism=PLAIN&directConnection=true&tls=true |
| Redis |
rediss:// scheme |
rediss://workspace:pass@host:6379/0 |
All connections are encrypted via TLS. PostgreSQL uses
sslmode=require, MySQL TLS is configured per driver (see
Connections), MongoDB uses
tls=true, and Redis uses the
rediss:// URI scheme.
Get workspace details including schema and connection info.
Response
{
"id": "ws_abc123",
"name": "main",
"mode": "tenant",
"database": "postgresql",
"schema": ["CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)"],
"schema_error": null,
"undeployed_changes": 2,
"connection": {
"host": "proxy.tenantsdb.com",
"port": 5432,
"database": "ws_abc123",
"username": "ws_abc123",
"password": "••••••••"
},
"connection_string": "postgresql://ws_abc123:••••••••@proxy.tenantsdb.com:5432/ws_abc123?sslmode=require",
"settings": {
"query_timeout_ms": 30000,
"max_rows_per_query": 1000,
"max_connections": 10
},
"version": 3
}
undeployed_changes and version are only present for tenant mode workspaces.
Delete a workspace. For tenant mode, returns 409 Conflict if tenants are deployed to its blueprint. Control mode workspaces can always be deleted.
Response — success
{
"message": "workspace deleted",
"details": {
"workspace": "main",
"mode": "tenant",
"versions_deleted": 3,
"deletion_type": "full",
"physical_db": true
}
}
Response — 409 Conflict (tenants deployed)
{
"message": "cannot delete workspace with deployed tenants",
"reason": "tenants_deployed",
"deployed_to": ["acme", "globex"],
"action_required": "Delete all tenants first or use a different workspace"
}
Run a query in the workspace dev database. DDL statements (CREATE TABLE, ALTER TABLE, etc.) are allowed and automatically tracked as blueprint versions for deployment to tenants.
Request Body
| Field | Type | | Description |
| query |
string |
required |
The SQL, MongoDB, or Redis query to execute. |
Response
{
"columns": ["id", "name", "email"],
"rows": [
[1, "Alice", "[email protected]"]
],
"row_count": 1,
"execution_time": "8ms"
}
Import schema from template, JSON, external database, or URL.
Request Body
| Field | Type | | Description |
| source |
string |
required |
json, database, template, or url |
| template |
string |
optional |
Template name: ecommerce, saas, blog, fintech |
| tables |
array |
optional |
Table definitions (for JSON source, SQL databases) |
| collections |
array |
optional |
Collection definitions (for JSON source, MongoDB) |
| connection |
object |
optional |
Database connection (for database source) |
| url |
string |
optional |
URL to JSON schema (for url source) |
From Template
{
"source": "template",
"template": "fintech"
}
From Database
{
"source": "database",
"connection": {
"type": "postgresql",
"host": "db.example.com",
"port": 5432,
"database": "mydb",
"user": "admin",
"password": "secret"
}
}
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Schema imported to workspace 'myapp'",
"source": "template",
"created": ["users", "accounts", "transactions"],
"skipped": [],
"errors": [],
"details": {
"workspace": "myapp",
"database_type": "PostgreSQL",
"statements_executed": 3,
"statements_skipped": 0,
"statements_failed": 0,
"statements_total": 3
}
}
Get the current schema of a workspace (tables, columns, indexes).
Response
{
"tables": [
{
"name": "users",
"columns": [
{ "name": "id", "type": "SERIAL", "nullable": false },
{ "name": "name", "type": "TEXT", "nullable": false }
],
"indexes": ["users_pkey"]
}
]
}
Get pending DDL changes ready for deployment.
Tenant mode only. Returns 400 Bad Request for control mode workspaces (no blueprint versioning).
Remove a DDL change from the deploy queue. Returns 404 Not Found if the DDL does not exist or has already been deployed.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "DDL 42 removed from deploy queue"
}
Revert a DDL change in the workspace by executing the reverse statement. Only works for undeployed DDLs. Supports CREATE TABLE → DROP TABLE, CREATE INDEX → DROP INDEX, ALTER TABLE ADD COLUMN → DROP COLUMN, CREATE COLLECTION → DROP COLLECTION.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Reverted: DROP TABLE IF EXISTS users;"
}
Cannot revert DDLs already deployed to tenants. Create a new migration instead.
Get current settings for a workspace. Available fields depend on the database type.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"database_type": "PostgreSQL",
"settings": {
"query_timeout_ms": 30000,
"max_rows_per_query": 10000,
"max_connections": 100
},
"available_fields": ["query_timeout_ms", "max_rows_per_query", "max_connections"]
}
PostgreSQL/MySQL/MongoDB: query_timeout_ms, max_rows_per_query, max_connections. Redis: default_ttl, max_keys, patterns.
Update workspace settings. Supports partial updates — only provided fields are changed.
Request Body (PostgreSQL / MySQL / MongoDB)
{
"query_timeout_ms": 30000,
"max_rows_per_query": 10000,
"max_connections": 100
}
Request Body (Redis)
{
"default_ttl": 3600,
"max_keys": 50000,
"patterns": {
"cache:*": { "ttl": 300 },
"session:*": { "ttl": 86400 }
}
}
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"settings": { ... },
"message": "Settings saved. Deploy to apply to tenants.",
"pending_deploy": true,
"database_type": "PostgreSQL"
}
For tenant mode, the message is "Settings saved. Deploy to apply to tenants." with pending_deploy: true. For control mode, the message is "Settings saved." with no pending deploy.
Migrating from an existing database? The data import endpoints (
import-data,
import-data/analyze,
import-full) are covered in the
Onboarding Guide →
Blueprints
Blueprints are versioned schema snapshots created from workspaces. They define what gets deployed to tenant databases.
List all blueprints.
Response
{
"blueprints": [
{
"name": "main",
"database": "postgresql",
"workspace_id": "ws_abc123",
"current_version": 3,
"tenant_count": 12
}
],
"count": 1
}
Get blueprint schema and deployment status.
Response
{
"name": "main",
"database": "postgresql",
"workspace_id": "ws_abc123",
"current_version": 3,
"schema": [
"CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)"
],
"tenant_count": 12
}
List all versions of a blueprint.
Response
{
"versions": [
{
"version": 3,
"ddl_count": 2,
"deployed_at": "2025-02-01T10:00:00Z"
},
{
"version": 2,
"ddl_count": 1,
"deployed_at": "2025-01-20T14:30:00Z"
}
],
"count": 2
}
Tenants
Tenants are your customers' isolated database instances. Each tenant gets its own physical database, created from a blueprint.
L1
Shared
Multi-tenant pool. Cost-effective, instant provisioning. Each tenant gets a separate database on a shared server.
L2
Dedicated
Own VM. Full physical isolation, dedicated resources. Zero-downtime migration via native replication.
List all tenants for the current project.
Response
{
"tenants": [
{
"tenant_id": "acme",
"status": "active",
"databases": [
{
"blueprint": "main",
"database_type": "postgresql",
"isolation_level": "L1"
}
],
"created_at": "2025-01-20T14:00:00Z"
}
],
"count": 1
}
Create a new tenant with database(s) from blueprint(s). Returns HTTP 201 Created.
Only available for tenant mode workspaces. Returns 400 Bad Request if the blueprint belongs to a control mode workspace.
L2 dedicated VMs require a paid plan. Free tier accounts receive
403 forbidden.
Upgrade →
Request Body
| Field | Type | | Description |
| tenant_id |
string |
required |
Tenant name (lowercase letters, numbers, underscores only). Cannot contain __. |
| databases |
array |
required |
Array of {blueprint, isolation_level, region}. Region is optional and applies to dedicated tenants only. |
Response — Shared (instant)
Shared tenants are created instantly. The status is ready and the connection string is available immediately.
{
"success": true,
"http_status": 201,
"code": "created",
"tenant_id": "acme",
"status": "ready",
"databases": [
{
"blueprint": "fintech",
"database_type": "PostgreSQL",
"isolation_level": 1,
"connection": {
"database": "fintech__acme",
"connection_string": "postgresql://tdb_2abf90d3:[email protected]:5432/fintech__acme?sslmode=require"
}
}
]
}
Tenant Connection Strings by Database
The connection string format in the response depends on the database type:
"mongodb://tdb_2abf90d3:[email protected]:27017/fintech__acme?authMechanism=PLAIN&directConnection=true&tls=true"
Redis uses a different auth scheme: tenant_id:api_key instead of project_id:proxy_password. The database field is always 0.
Response — Dedicated (async)
Dedicated tenants require a server to be provisioned. The response returns immediately with status: provisioning. Poll GET /tenants/{id} until the status becomes ready.
{
"success": true,
"http_status": 201,
"code": "created",
"tenant_id": "acme",
"status": "provisioning",
"databases": [
{
"blueprint": "fintech",
"database_type": "PostgreSQL",
"isolation_level": 2,
"region": "eu-central"
}
]
}
Do not attempt to connect until status is ready. Provisioning typically takes 1–2 minutes depending on region.
Get tenant details with all database connections.
Response
{
"tenant_id": "acme",
"status": "active",
"databases": [
{
"blueprint": "main",
"database_type": "postgresql",
"isolation_level": "L1",
"connection": {
"host": "proxy.tenantsdb.com",
"port": 5432,
"database": "acme",
"username": "acme",
"password": "••••••••"
},
"connection_string": "postgresql://acme:••••••••@proxy.tenantsdb.com:5432/acme?sslmode=require",
"version": 3
}
],
"recovery_undo": {
"available": true,
"original_host": "vm-pg-01",
"expires_at": "2025-02-01T14:00:00Z",
"expires_in": "23h 45m",
"command": "tdb tenants recover-undo acme"
},
"created_at": "2025-01-20T14:00:00Z"
}
recovery_undo is only present when a recent recovery can be reversed.
Soft-delete a tenant. Add ?hard=true for permanent deletion. Returns 409 Conflict if tenant is provisioning or migrating.
Restore a soft-deleted tenant. L1 tenants get databases recreated instantly. L2 tenants are restored from VM snapshots.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Tenant 'acme' restored successfully",
"tenant": {
"tenant_id": "acme",
"status": "ready"
}
}
Only tenants with status deleted can be restored. Returns 409 Conflict if tenant has a different status.
Suspend a tenant (block all queries). Only ready tenants can be suspended. Returns 409 Conflict if wrong status.
Resume a suspended tenant. Only suspended tenants can be resumed. Returns 409 Conflict if wrong status.
Migrate a tenant between shared and dedicated infrastructure, or change regions. Uses native database replication for zero-downtime migrations.
L2 dedicated VMs require a paid plan. Free tier accounts receive
403 forbidden.
Upgrade →
Request Body
| Field | Type | | Description |
| isolation_level |
int |
required |
Target level: 1 (shared) or 2 (dedicated) |
| blueprint |
string |
required |
Which database blueprint to migrate |
| region |
string |
optional |
Target region zone (e.g., eu-central, us-east). See GET /regions. |
Response — Level Change (L1 → L2)
{
"success": true,
"http_status": 200,
"code": "ok",
"tenant_id": "acme",
"blueprint": "fintech",
"status": "migrating",
"from": 1,
"to": 2,
"message": "Migration in progress for 'fintech'. Check tenant status for completion."
}
Response — Region Change (L2 → L2)
{
"success": true,
"http_status": 200,
"code": "ok",
"tenant_id": "acme",
"blueprint": "fintech",
"status": "migrating",
"from": 2,
"to": 2,
"change": "region",
"from_region": "eu-central",
"to_region": "us-east",
"message": "Migration in progress for 'fintech'. Check tenant status for completion."
}
Status Lifecycle
| Status | Queries | Description |
| syncing |
✓ Working |
Data is being replicated. Your application continues running normally on the original server. |
| migrating |
Paused |
Brief cutover (~2 seconds). Queries are held until routing switches. |
| ready |
✓ Working |
Migration complete. Tenant is live on the new server. Connection strings are unchanged. |
If replication encounters an issue, TenantsDB automatically falls back to a safe backup-and-restore approach. A safety backup is always taken before migration begins.
Trigger an on-demand backup to S3. Backs up all databases for the tenant.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Backup scheduled for tenant: acme",
"tenant_id": "acme",
"type": "manual",
"timestamp": "2026-02-15T14-30-00",
"paths": ["postgresql/manual/2026-02-15T14-30-00/tdb_2abf90d3_tenant_acme.sql.gz"]
}
List all backups for a tenant across all database types.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"tenant_id": "acme",
"count": 3,
"backups": [
{
"type": "manual",
"date": "2026-02-15T14-30-00",
"database_type": "postgresql",
"storage_path": "postgresql/manual/2026-02-15T14-30-00/tdb_2abf90d3_tenant_acme.sql.gz",
"size_bytes": 524288,
"created_at": "2026-02-14T03:00:00Z"
}
]
}
Restore a tenant from a backup using the exact storage path. Use GET /tenants/{id}/backups to list available paths. For point-in-time recovery, use POST /tenants/{id}/recover (L2 only).
Request Body
| Field | Type | | Description |
| storage_path |
string |
required |
Exact S3 path from backups list |
| storage_path |
string |
optional* |
Exact S3 path from backups list |
Use tdb tenants backups {id} to get the exact storage_path value.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Rollback scheduled for tenant: acme",
"tenant_id": "acme",
"status": "restoring",
"paths": ["postgresql/manual/2026-02-15T14-30-00/tdb_2abf90d3_tenant_acme.sql.gz"]
}
Point-in-time recovery. Creates a new VM from the target timestamp, preserving the original VM for 24 hours. L2 (dedicated) tenants only. Returns 403 Forbidden for L1 tenants.
Request Body
| Field | Type | | Description |
| timestamp |
string |
required |
ISO 8601 timestamp (e.g., "2026-02-03T17:10:59Z") |
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Recovery initiated for tenant 'acme' to 2026-02-03T17:10:59Z. Original VM preserved for 24h.",
"tenant": {
"tenant_id": "acme",
"status": "recovering",
"target_timestamp": "2026-02-03T17:10:59Z"
}
}
Undo a point-in-time recovery by swapping back to the original VM. Available within 24 hours of recovery. L2 only.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"message": "Recovery undone for tenant 'acme'. Original VM restored.",
"tenant": {
"tenant_id": "acme",
"status": "ready"
}
}
The 24-hour undo window starts when recovery is initiated. After expiry, the original VM is destroyed.
Get deployment history for a tenant. Shows which blueprint versions have been applied.
Query Parameters
| Param | Type | | Description |
| limit |
integer |
optional |
Max results (default: all) |
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"tenant_id": "acme",
"count": 3,
"deployments": [ ... ]
}
Get query execution logs.
Query Parameters
| Param | Type | | Description |
| limit |
integer |
optional |
Max results (default: 50, max: 1000) |
| offset |
integer |
optional |
Pagination offset |
| type |
string |
optional |
Filter: error, slow |
| search |
string |
optional |
Query text search |
| source |
string |
optional |
Filter by source: proxy, api |
| since |
string |
optional |
Time filter: 1h, 24h, 7d, 30d |
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"tenant_id": "acme",
"logs": [
{
"query": "SELECT * FROM users WHERE active = true",
"source": "proxy",
"success": true,
"duration_ms": 4.2,
"created_at": "2026-02-15T14:30:00Z"
}
],
"count": 50,
"has_more": true
}
Get aggregated query statistics: total queries, success/failure counts, average duration, slow query count, and breakdown by source.
Response
{
"success": true,
"http_status": 200,
"code": "ok",
"tenant_id": "acme",
"total_queries": 48230,
"successful": 47891,
"failed": 339,
"by_source": {
"proxy": 45000,
"api": 3230
},
"avg_duration_ms": 12.4,
"slow_queries": 18
}
Get performance metrics (query count, latency, success rate).
Deployments
Deploy blueprint schema changes to tenant databases. Runs DDL migrations across all or selected tenants.
List all deployment jobs.
Response
{
"deployments": [
{
"id": "dep_abc123",
"blueprint_name": "main",
"version": 3,
"status": "completed",
"tenants_total": 12,
"tenants_completed": 12,
"created_at": "2025-02-01T10:00:00Z"
}
],
"count": 1
}
Create a new deployment.
Request Body
| Field | Type | | Description |
| blueprint_name |
string |
required |
Blueprint to deploy |
| version |
string |
optional |
Version to deploy |
| deploy_all |
boolean |
optional |
Deploy to all tenants |
Get deployment status and progress.
Response
{
"id": "dep_abc123",
"blueprint_name": "main",
"version": 3,
"status": "in_progress",
"tenants_total": 12,
"tenants_completed": 8,
"tenants_failed": 0,
"results": [
{ "tenant_id": "acme", "status": "completed", "duration": "120ms" },
{ "tenant_id": "globex", "status": "pending" }
],
"created_at": "2025-02-01T10:00:00Z"
}
Admin Query
Run data queries directly on tenant databases. DDL statements are blocked. Schema changes must go through workspaces and blueprints.
Run a query directly on one or all tenant databases.
Request Body
| Field | Type | | Description |
| blueprint |
string |
required |
Blueprint name. Used to resolve database type and route to tenant databases. |
| query |
string |
required |
The SQL/MongoDB/Redis query to execute. DDL statements are blocked. |
| tenant_id |
string |
optional* |
Target a specific tenant. Provide this or all_tenants. |
| all_tenants |
boolean |
optional* |
Run query on all tenants. Provide this or tenant_id. |
Either tenant_id or all_tenants: true must be provided. Not available for control mode workspaces. Use workspace query instead.
Response — single tenant
{
"tenant_id": "acme",
"columns": ["id", "name", "email"],
"rows": [
[1, "Alice", "[email protected]"]
],
"row_count": 1,
"execution_time": "12ms"
}
Response — all tenants
{
"results": [
{
"tenant_id": "acme",
"columns": ["id", "name"],
"rows": [[1, "Alice"]],
"row_count": 1
}
],
"total_tenants": 1,
"execution_time": "45ms"
}
Response — DDL blocked
{
"success": false,
"http_status": 400,
"code": "bad_request",
"error": "DDL not allowed on tenant databases. Deploy schema through blueprints."
}