Skip to content

REST API Reference

Base URL: http://localhost:3000 (or your server address)

Authentication: Authorization: Bearer <token> (API token or OIDC JWT), unless noted otherwise.

All responses include the x-dbward-version header.


Most error responses follow this structure:

{"error": "subject_id is required", "code": "validation.failed", "hint": "subject_id is required"}

code and hint may be absent in some edge cases (e.g. 405, 501 responses).

HTTP StatusMeaning
400Validation error
401Not authenticated
402Plan limit exceeded
403Not authorized
404Resource not found
405Method not allowed (config-managed resource)
409Conflict (idempotency key race)
410Gone (expired or TTL’d resource)
413Payload too large
500Internal server error
503Service unavailable (draining)

Create a new SQL execution or migration request.

Permission: request.dml | request.query | request.ddl | request.break_glass_query (emergency SELECT) | request.break_glass_dml (emergency writes) — scoped by database/environment. DDL operations (DROP TABLE/VIEW/INDEX/SEQUENCE, TRUNCATE, CREATE SEQUENCE) require request.ddl. allow_ddl=true additionally requires request.break_glass_ddl.

FieldTypeRequiredDescription
databasestringTarget database name
environmentstringTarget environment
operationstringOperation type (default: execute_select). migrate_repair requires emergency=true.
detailstringSQL statement or migration detail
reasonstringReason for the request. Required when emergency=true.
idempotency_keystringIdempotency key to prevent duplicates
metadataobjectArbitrary JSON metadata
emergencyboolBreak-glass mode (default: false)
allow_ddlboolAllow DDL in execute operations (default: false)
no_result_storeboolSkip persisting result to storage (default: false)
share_withstring[]Subject IDs to share the result with

List requests with optional filtering. Non-admins see only: own requests, requests where they are a designated approver, and requests matching their share_with selectors.

Permission: request.view (when pending_for_me=true, accessible to designated approvers)

ParamDefaultDescription
limit50Max results (max: 100)
offset0Pagination offset
statusFilter by request status
userFilter by requester subject ID
pending_for_meOnly show requests where the caller matches an approver selector in the current step

Get full request details. Supports long-polling with ?wait=<seconds> (max 120s). Accessible by: the requester, admins, or designated approvers of the current step (approvers can only view pending requests).

Permission: request.view (scoped)

ParamDefaultDescription
waitLong-poll timeout in seconds (max 120)

Approve a pending request. The caller must match an approver selector in the current workflow step. If matching multiple groups, the selector parameter is required (400 if ambiguous). Self-approval is blocked unless allow_self_approve is enabled. Duplicate approval returns 409. Expired requests return 410.

Permission: Current workflow step approver (scoped)

FieldTypeRequiredDescription
commentstringApproval comment
selectorstringApprover group selector (required when matching multiple groups)

Reject a pending request. The requester can always reject their own request (self-reject). Other users must match an approver selector in the current workflow step. Expired requests return 410.

Permission: Requester (self-reject) or current workflow step approver

FieldTypeRequiredDescription
commentstringRejection reason

Cancel a request. Only the requester or admins can cancel.

Permission: request.cancel (scoped; requester or admin)

FieldTypeRequiredDescription
reasonstringCancellation reason

Resume an approved request, triggering agent dispatch. Only the requester or admins can resume.

Permission: request.resume (scoped; requester or admin)

Long-poll for execution result (timeout: 300s). Returns the result envelope on completion, or 204 No Content on timeout.

Permission: result.view (scoped)

Get the stored execution result as a JSON envelope containing success, result_data, rows_affected, truncated, and error_message.

Permission: result.view (scoped)

ParamDefaultDescription
execution_idSpecific execution ID (defaults to latest)

List execution history for a request.

Permission: request.view (scoped)

ParamDefaultDescription
limit20Max results (max: 100)

Analyze a SQL statement without creating a request. Returns risk level, review findings, policy simulation, and optional EXPLAIN plan. Safe to call repeatedly while iterating on SQL.

Permission: request.preflight (scoped). EXPLAIN requires request.preflight_explain — if denied, silently skipped.

FieldTypeRequiredDescription
databasestringTarget database name
environmentstringTarget environment
sqlstringSQL to analyze
include_explainboolRun EXPLAIN via agent (default: true)
explain_timeout_msu64Max EXPLAIN wait in ms (default: 5000)

Response includes status (requestable/blocked/warning), risk, classification, review, risk_assessment, policy, impact, fix_hints, retryable, next_actions, and requires_ddl_permission (boolean — true when the SQL contains DestructiveDdl statements requiring request.ddl permission).

Status codes: 200 (success), 400 (validation), 401 (auth), 403 (forbidden), 429 (rate limit).


List stored results accessible to the current user (filtered by result policy).

Permission: result.view

ParamDefaultDescription
limit50Max results (max: 100)

Get the agent-collected schema snapshot for a database.

Permission: request.view (scoped)

ParamDefaultDescription
summarytrueTable names and row counts only
tableFilter to a single table (supports schema.table)
environmentExplicit environment (auto-resolved if omitted)

Get the current user’s profile, resolved roles, and group memberships.

Permission: Any authenticated user


Create a new user and generate an initial API token. The raw token is returned only once — store it securely.

Permission: user.write

FieldTypeRequiredDescription
idstringUser identifier (1–128 chars, ASCII alphanumeric + -_@.)
rolesstring[]Roles to assign
groupsstring[]Groups to assign

Response (201) includes id, token, token_prefix, roles, groups.

List all registered users.

Permission: user.read

Get a single user’s details including roles, groups, and status.

Permission: user.read

Update a user’s roles, groups, or profile fields. All fields are optional but at least one must be provided.

Permission: user.write

FieldTypeDescription
rolesstring[]Replace all roles
add_rolesstring[]Add roles
rm_rolesstring[]Remove roles
add_groupsstring[]Add to groups
rm_groupsstring[]Remove from groups
slack_user_idstring | nullSet or clear Slack user ID

Suspend a user. Revokes all active tokens and cancels pending requests.

Permission: user.write

Reactivate a previously suspended user.

Permission: user.write

Soft-delete a user. The user record is retained for audit purposes but can no longer authenticate.

Permission: user.write


List all groups defined in config.

Permission: user.read

Get a group’s current members.

Permission: user.read


Create a new API token. The raw token value is returned only once — store it securely.

Permission: token.create (self user) or token.create_agent (agent)

FieldTypeRequiredDescription
subject_idstringSubject the token authenticates as
subject_typestringuser or agent
namestringHuman-readable label
scope_ceilingobjectMax effective roles: {"roles": ["requester"]}
expires_atDateTimeExpiration time (ISO 8601)

Notes:

  • scope_ceiling is required for user tokens. Specifies which roles the token is limited to. If the ceiling roles have no intersection with the user’s resolved roles at request time, authentication fails (fail-closed).
  • Agent tokens may omit scope_ceiling (unrestricted).
  • Effective permissions = resolved roles ∩ scope_ceiling.
  • Creating tokens for other users is not allowed. Use POST /api/users/{id}/reissue-initial-token instead.

List all tokens with metadata and status.

Permission: token.list

Revoke a token immediately.

Permission: token.list or token.revoke (for own tokens)

Show the token’s effective roles and permissions after ceiling application.

Permission: Token owner or token.list

POST /api/users/{id}/reissue-initial-token

Section titled “POST /api/users/{id}/reissue-initial-token”

Reissue a user’s initial token. Revokes the existing initial token (if any), creates a new one, and attempts Slack DM delivery.

Permission: token.reissue


Config-managed resource. Define webhooks in [[webhooks]] in server.toml. Mutation endpoints return 405.

List all registered webhooks.

Permission: workflow.read

Get a webhook’s configuration and delivery statistics.

Permission: workflow.read

List webhook delivery attempts.

Permission: metrics.view

ParamDefaultDescription
statusFilter: pending, in_progress, delivered, dead, cancelled
limit50Max results (max: 100)
offset0Pagination offset

Config-managed resource. Define roles in [[auth.roles]] in server.toml. Mutation endpoints return 405.

List all roles (built-in and custom) with their permissions.

Permission: workflow.read


Config-managed resources. Define in server.toml ([[workflows]], [[execution_policies]], [[result_policies]], [[notification_policies]], [[sql_review]]). Mutation endpoints return 405.

List all configured workflows.

Permission: workflow.read

List all execution policies.

Permission: workflow.read

List all result policies.

Permission: workflow.read

Get a specific result policy.

Permission: workflow.read

List all notification policies.

Permission: workflow.read

Get a specific notification policy.

Permission: workflow.read

List all active SQL review policies.

Permission: workflow.read

Resolve the effective policy for a database/environment combination.

Permission: request.view (scoped)

ParamRequiredDescription
databaseDatabase name
environmentEnvironment name
operationSpecific operation (omit for all)

Search audit log events.

Permission: audit.read

ParamDefaultDescription
actor_idFilter by user
event_typeFilter by event type
event_categoryFilter by category
outcomeFilter by outcome
databaseFilter by database
environmentFilter by environment
sinceStart time (ISO 8601)
untilEnd time (ISO 8601)
limit50Max results (max: 200)
offset0Pagination offset

Verify the audit log hash chain integrity.

Permission: audit.read


Agent reports capabilities and polls for pending jobs.

Permission: agent.operate (agent token required)

FieldTypeRequiredDescription
capabilitiesobject{scopes: [{database: string, environment: string}], operations?: string[]}
limitu32Max jobs to return (default: 10, max: 20)
statusobjectAgent status report (in_flight, max_concurrent, draining, etc.)
agent_versionstringAgent binary version

Agent claims a specific job for execution.

Permission: agent.operate (agent token required)

Agent extends its lease on a running job.

Permission: agent.operate (agent token required)

Agent submits execution result.

Permission: agent.operate (agent token required)

FieldTypeRequiredDescription
successboolWhether execution succeeded
result_datastringQuery result data
error_messagestringError message on failure
rows_affectedu64Number of rows affected
duration_msu64Execution duration

List connected agents with status and capabilities.

Permission: metrics.view

Agent reports a database schema snapshot.

Permission: agent.operate (agent token required)

Body limit: 10 MB

FieldTypeRequiredDescription
databasestringDatabase name
environmentstringEnvironment name
dialectstringDatabase dialect
statusstringSync status
snapshotobjectSchema snapshot JSON
error_messagestringError on failure

Agent claims a dry-run job for EXPLAIN execution.

Permission: agent.operate (agent token required)

Agent submits EXPLAIN output.

Permission: agent.operate (agent token required)

FieldTypeRequiredDescription
claim_tokenstringClaim token from claim response
resultobjectEXPLAIN output
errorstringError message

Agent submits preflight EXPLAIN result. Exactly one of result or error must be provided.

Permission: agent.operate (agent token required)

FieldTypeRequiredDescription
job_idstringPreflight job ID
claim_tokenstringClaim token from poll response
resultobjectEXPLAIN plan (max 256KB)
errorstringError message (max 4KB)

Status codes: 200 (accepted), 400 (validation), 410 (expired/stale job), 413 (payload too large).


List all registered databases and their environments.

Permission: request.view


JSON-RPC over HTTP with SSE streaming. Each tool invocation checks its own permission.

Send a JSON-RPC message (initialize, tool call, etc.).

Permission: Any authenticated user (tool-level checks apply)

Headers: Content-Type: application/json, Accept: application/json, text/event-stream

Resume or replay SSE stream for an existing session.

Headers: Accept: text/event-stream, Mcp-Session-Id (required), Last-Event-Id (required)

Terminate an MCP session.

Headers: Mcp-Session-Id (required)


Health check. Always returns 200 if the server is running.

Readiness check. Returns 200 when all subsystems are operational, 503 otherwise.

Slack interaction payloads (button clicks, modal submissions). Verified by Slack signing secret — no Bearer token required.

Slack slash command payloads. Verified by Slack signing secret — no Bearer token required.


Prometheus metrics in text format.

Permission: metrics.view

Ed25519 public key for execution token verification.

Permission: Agent token required