Schema engine endpoints
18 endpoints at https://api.vaif.studio, generated from the API's OpenAPI document. The REST API page covers authentication, and All endpoints lists every group.
POST /schema-engine/analyze/{projectId}
Analyze SQL statements without executing them
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string | No |
projectId | path | string (uuid) | Yes |
Request body (application/json, required)
{
sql: string;
}Response 200 (application/json)
{
readOnly: boolean;
destructive: boolean;
ddl: boolean;
statements: {
sql: string;
kind: string;
readOnly: boolean;
destructive: boolean;
ddl: boolean;
temporaryTable?: boolean;
}[];
}Errors: 400, 401, 403, 404, with the error body.
POST /schema-engine/preview
Preview schema migration changes
Request body (application/json, required)
{
projectId: string (uuid);
envId?: string (uuid);
definition: {
schemaVersion: "1.0";
tables: {
name: string;
columns: {
name: string;
type: "uuid" | "text" | "varchar" | "string" | "int" | "integer" | "bigint" | "boolean" | "bool" | "jsonb" | "json" | "timestamptz" | "timestamp" | "date" | "numeric" | "decimal" | "float" | "double" | "text[]" | "integer[]";
primaryKey?: boolean;
unique?: boolean;
nullable?: boolean;
default?: string | number | boolean;
references?: {
table: string;
column?: string;
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
};
}[];
indexes?: {
name: string;
columns: string[];
unique?: boolean;
}[];
unique?: {
name: string;
columns: string[];
}[];
publicRead?: boolean;
ownerColumn?: string;
}[];
rawSql?: any;
};
allowDestructive?: boolean;
allowProduction?: boolean;
allowEmpty?: boolean;
}Response 200 (application/json)
{
ok: true;
projectSchema: string;
plan: any[];
upSql: string;
downSql?: string | null;
warnings?: any[];
destructive?: boolean[];
hasDestructive?: boolean;
planHash?: string;
}Errors: 400, 401, 403, 404, 409, 500, with the error body.
POST /schema-engine/apply
Apply schema migration
Request body (application/json, required)
{
projectId: string (uuid);
envId?: string (uuid);
definition: {
schemaVersion: "1.0";
tables: {
name: string;
columns: {
name: string;
type: "uuid" | "text" | "varchar" | "string" | "int" | "integer" | "bigint" | "boolean" | "bool" | "jsonb" | "json" | "timestamptz" | "timestamp" | "date" | "numeric" | "decimal" | "float" | "double" | "text[]" | "integer[]";
primaryKey?: boolean;
unique?: boolean;
nullable?: boolean;
default?: string | number | boolean;
references?: {
table: string;
column?: string;
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
};
}[];
indexes?: {
name: string;
columns: string[];
unique?: boolean;
}[];
unique?: {
name: string;
columns: string[];
}[];
publicRead?: boolean;
ownerColumn?: string;
}[];
rawSql?: any;
};
migrationName?: string;
allowDestructive?: boolean;
allowProduction?: boolean;
allowEmpty?: boolean;
expectedPlanHash?: string;
fromAiWorkspace?: boolean;
}Response 200 (application/json)
{
ok: true;
projectSchema: string;
migration: {
id: string;
name: string;
status: string;
appliedAt: string | string (date-time);
};
appliedSteps: number;
snapshotId?: string;
}Errors: 400, 401, 403, 404, 409, 500, with the error body.
GET /schema-engine/introspect/{projectId}
Introspect current database schema for a project
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string | No |
projectId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
schemaExists: boolean;
schemaName?: string;
supportedColumnTypes: ("uuid" | "text" | "varchar" | "string" | "int" | "integer" | "bigint" | "boolean" | "bool" | "jsonb" | "json" | "timestamptz" | "timestamp" | "date" | "numeric" | "decimal" | "float" | "double" | "text[]" | "integer[]")[];
tables: {
name: string;
columns: {
name: string;
type: string;
primaryKey: boolean;
nullable: boolean;
unique: boolean;
default: string | null;
udtName?: string;
enumValues?: string[];
comment?: string | null;
formattedType?: string;
references?: {
table: string;
column: string;
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
};
}[];
indexes: string[];
indexDetails: {
name: string;
columns: string[];
unique: boolean;
method?: string;
where?: string | null;
expression?: boolean;
valid?: boolean;
}[];
primaryKey: string[];
foreignKeys: {
constraintName: string;
columnName: string;
refTable: string;
refColumn: string;
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
}[];
uniqueConstraints: {
constraintName: string;
columns: string[];
}[];
rlsEnabled: boolean;
policies: {
name: string;
command: string;
permissive: boolean;
roles: string[];
using?: string;
withCheck?: string;
}[];
triggers: {
name: string;
table: string;
definition?: string;
enabled: string;
}[];
estimatedRows?: number;
comment?: string | null;
}[];
enums?: {
name: string;
values: string[];
}[];
views?: {
name: string;
definition?: string;
materialized: boolean;
columns: {
name: string;
type: string;
primaryKey: boolean;
nullable: boolean;
unique: boolean;
default: string | null;
udtName?: string;
enumValues?: string[];
comment?: string | null;
formattedType?: string;
references?: {
table: string;
column: string;
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL" | "SET DEFAULT" | "NO ACTION";
};
}[];
}[];
functions?: {
name: string;
arguments: string;
resultType: string;
language: string;
definition?: string;
}[];
definitionsHidden?: boolean;
triggers?: {
name: string;
table: string;
definition?: string;
enabled: string;
}[];
compositeTypes?: {
name: string;
attributes: {
name: string;
type: string;
}[];
}[];
}Errors: 400, 401, 403, 404, 500, with the error body.
GET /schema-engine/migrations/project/{projectId}
List migrations for a project
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string | No |
limit | query | number | No |
offset | query | number | No |
projectId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
migrations: any[];
}Errors: 400, 401, 403, 404, with the error body.
GET /schema-engine/{projectId}/changes
Get schema change history for a project
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
limit | query | string | No |
Response 200 (application/json)
{
ok: true;
data: any[];
}Errors: 400, 401, 403, with the error body.
POST /schema-engine/query/{projectId}
Execute SQL query against project database (single OR multi-statement)
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string | No |
projectId | path | string (uuid) | Yes |
Request body (application/json, required)
{
sql: string;
editorSessionToken?: string;
timeoutMs?: number;
rowLimit?: number;
params?: any[];
allowProduction?: boolean;
readOnly?: boolean;
}Response 200 (application/json)
{
ok: true;
executionTimeMs: number;
rows?: any[];
rowValues?: any[][];
rowCount?: number | null;
command?: string;
fields?: {
name: string;
dataTypeID: number;
}[];
truncated?: boolean;
rowLimit?: number;
results?: {
rows: any[];
rowValues?: any[][];
rowCount: number | null;
command?: string;
truncated?: boolean;
rowLimit?: number;
executionTimeMs?: number;
fields?: {
name: string;
dataTypeID: number;
}[];
}[];
statementCount?: number;
}Errors: 400, 401, 403, 404, 500, with the error body.
GET /schema-engine/migrations/{projectId}/{migrationId}/diff
Get diff between pre-migration snapshot and current schema
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string | No |
projectId | path | string (uuid) | Yes |
migrationId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
migrationId: string;
snapshotId: string | null;
diff: {
entries: {
table: string;
column?: string;
kind: string;
destructive: boolean;
detail?: string;
}[];
destructiveCount: number;
};
rollbackHasDestructive?: boolean;
rollbackPlan?: any[];
rollbackSql?: string;
rollbackPlanHash?: string;
}Errors: 400, 401, 403, 404, 500, with the error body.
POST /schema-engine/migrations/{projectId}/{migrationId}/rollback
Roll back a migration using its pre-apply snapshot
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
migrationId | path | string (uuid) | Yes |
Request body (application/json, required)
any | {
envId?: string (uuid);
allowDestructive?: boolean;
allowProduction?: boolean;
expectedPlanHash?: string;
} | nullResponse 200 (application/json)
{
ok: true;
migrationId: string;
snapshotId: string;
appliedSteps: number;
warning?: string;
}Errors: 400, 401, 403, 404, 409, 500, with the error body.
GET /schema-engine/snapshots/project/{projectId}
List migration snapshots for a project
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
limit | query | string | No |
Response 200 (application/json)
{
ok: true;
snapshots: any[];
}Errors: 400, 401, 403, with the error body.
GET /schema-engine/editor-sessions/{projectId}/capabilities
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
Response 200 (application/json)
{
enabled: boolean;
idleTimeoutMs: 600000;
maxPerUser: 2;
maxPerProject: 4;
}Errors: 400, 401, 403, 404, 429, 503, with the error body.
POST /schema-engine/editor-sessions/{projectId}
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string (uuid) | No |
projectId | path | string (uuid) | Yes |
Response 200 (application/json)
{
token: string;
envId: string (uuid);
idleTimeoutMs: 600000;
}Errors: 400, 401, 403, 404, 429, 503, with the error body.
POST /schema-engine/editor-sessions/{projectId}/close
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string (uuid) | No |
projectId | path | string (uuid) | Yes |
Request body (application/json, required)
{
token: string;
}Response 200 (application/json)
{
ok: true;
}Errors: 400, 401, 403, 404, 429, 503, with the error body.
POST /schema-engine/push/{projectId}
Apply a SQL migration file through the schema engine (vaif db push)
| Parameter | In | Type | Required |
|---|---|---|---|
envId | query | string | No |
projectId | path | string (uuid) | Yes |
Request body (application/json, required)
{
sql: string;
name?: string;
dryRun?: boolean;
allowProduction?: boolean;
force?: boolean;
pushRunId?: string (uuid);
before?: string[];
}Response 200 (application/json)
{
ok: true;
status: "applied" | "no-changes" | "dry-run" | "already-applied";
projectSchema: string;
plan: any[];
}Errors: 400, 401, 403, 404, 409, 429, 500, 503, with the error body.
GET /schema-engine/snippets/{projectId}
List the caller's SQL snippets and the project's shared ones
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
Response 200 (application/json)
{
snippets: {
id: string (uuid);
name: string;
folder: string;
sql: string;
shared: boolean;
owner: {
id: string (uuid);
name: string | null;
};
mine: boolean;
canEdit: boolean;
createdAt: string;
updatedAt: string;
}[];
}Errors: 401, 403, 404, with the error body.
POST /schema-engine/snippets/{projectId}
Save a SQL snippet (private unless shared with project members)
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
Request body (application/json, required)
{
name: string;
folder?: string;
sql: string;
shared?: boolean;
}Response 201 (application/json)
{
snippet: {
id: string (uuid);
name: string;
folder: string;
sql: string;
shared: boolean;
owner: {
id: string (uuid);
name: string | null;
};
mine: boolean;
canEdit: boolean;
createdAt: string;
updatedAt: string;
};
}Errors: 400, 401, 403, 404, 409, with the error body.
PATCH /schema-engine/snippets/{projectId}/{snippetId}
Rename, move, edit, share or unshare a SQL snippet
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
snippetId | path | string (uuid) | Yes |
Request body (application/json, required)
{
name?: string;
folder?: string;
sql?: string;
shared?: boolean;
}Response 200 (application/json)
{
snippet: {
id: string (uuid);
name: string;
folder: string;
sql: string;
shared: boolean;
owner: {
id: string (uuid);
name: string | null;
};
mine: boolean;
canEdit: boolean;
createdAt: string;
updatedAt: string;
};
}Errors: 400, 401, 403, 404, with the error body.
DELETE /schema-engine/snippets/{projectId}/{snippetId}
Delete a SQL snippet
| Parameter | In | Type | Required |
|---|---|---|---|
projectId | path | string (uuid) | Yes |
snippetId | path | string (uuid) | Yes |
Response 200 (application/json)
{
ok: true;
}Errors: 401, 403, 404, with the error body.