Skip to content

Compute a dry-run diff between metadata and the live database.

POST
/plan
curl --request POST \
--url https://example.com/plan \
--header 'Content-Type: application/json' \
--data '{ "destructive": false, "vault": true }'
  • None

Optional JSON body parameters for plan and apply endpoints.

Media typeapplication/json

Optional JSON body parameters for plan and apply endpoints.

object
destructive

Allow destructive operations (drop column, narrow type).

boolean
vault

Vault data before destructive operations (default: true).

boolean
default: true

Top-level result returned by plan() and apply().

Media typeapplication/json

Top-level result returned by plan() and apply().

object
changes
required

Ordered list of individual changes with risk and SQL.

Array<object>
One of:

A new table is created with the given columns.

object
risk
required

Risk level of the migration operation.

One of:

No lock escalation, instant operation.

string
Allowed value: safe
sql

DDL statements that will be (or were) executed.

Array<string>
action
required
string
Allowed value: createTable
columns
required
Array<object>

Column metadata in a plan change report.

object
generatedMode

Generated column mode ("virtual" or "stored"), if applicable.

string | null
generationExpression

SQL expression for a generated column, if applicable.

string | null
name
required

Column name (snake_case).

string
notNull

Whether the column has a NOT NULL constraint.

boolean
primaryKey

Whether this column is the table’s primary key.

boolean
type
required

Bare PostgreSQL type, never including modifiers.

Examples: "TEXT", "UUID", "BIGINT", "TIMESTAMPTZ", "VARCHAR(255)". Modifier information is carried by the dedicated boolean fields (primary_key, not_null, unique) — it never appears inline here.

string
unique

Whether the column has a UNIQUE constraint.

boolean
table
required
string
diagnostics

Non-fatal warnings emitted during compilation or diffing.

Array<object>

A diagnostic message emitted during metadata compilation.

object
message
required
string
severity
required
One of:

Informational note, does not block compilation.

string
Allowed value: info
source
required

Source location, e.g. “core_Contact.account”

string
status
required

"planned" or "applied".

string
summary
required

Aggregate change counts.

object
columnsAdded
required

Number of columns added to existing tables.

integer format: uint
columnsChanged
required

Number of columns whose definition changed (replace, generated expression).

integer format: uint
columnsDropped
required

Number of columns dropped.

integer format: uint
columnsTypeChanged
required

Number of columns whose SQL type changed.

integer format: uint
constraintsChanged
required

Number of constraint changes (foreign key, unique).

integer format: uint
indexesCreated
required

Number of new indexes created.

integer format: uint
indexesReplaced
required

Number of existing indexes replaced.

integer format: uint
tablesCreated
required

Number of new tables created.

integer format: uint
tablesDropped
required

Number of junction tables dropped (--destructive only).

integer format: uint
tablesRenamed
required

Number of junction tables renamed (OID-preserving; rows preserved).

integer format: uint
unchanged
required

Number of tables/columns that required no changes.

integer format: uint
Example
{
"changes": [
{
"risk": "safe",
"action": "createTable"
}
],
"diagnostics": [
{
"severity": "info"
}
]
}

JSON error envelope for apply/plan failures.

Named ApplyErrorResponse rather than ErrorResponse even though the shape is identical to routes::status::ErrorResponse: both are distinct local types (this file predates SPEC-DATA-0006 and was never migrated to the shared data::error::ErrorBody envelope), and two same-named, differently-scoped Rust types would otherwise collide in the generated OpenAPI document’s components/schemas map (aide auto-disambiguates with a numeric suffix, e.g. ErrorResponse2 – functionally correct but confusing to read in the published reference).

Media typeapplication/json

JSON error envelope for apply/plan failures.

Named ApplyErrorResponse rather than ErrorResponse even though the shape is identical to routes::status::ErrorResponse: both are distinct local types (this file predates SPEC-DATA-0006 and was never migrated to the shared data::error::ErrorBody envelope), and two same-named, differently-scoped Rust types would otherwise collide in the generated OpenAPI document’s components/schemas map (aide auto-disambiguates with a numeric suffix, e.g. ErrorResponse2 – functionally correct but confusing to read in the published reference).

object
error
required
string
status
required
string
Examplegenerated
{
"error": "example",
"status": "example"
}

Structured error envelope (SPEC-DATA-0006): {"errors": [{"scope", "target", "code", "message"}, ...]}.

Media typeapplication/json

The top-level response body. Wraps a non-empty list of [ErrorEntry].

object
errors
required

The error entries making up the envelope. Always non-empty.

Array<object>

One entry in the error envelope.

Carries an anchoring [ErrorScope], an optional target that disambiguates within the scope, a stable SCREAMING_SNAKE_CASE code, and a human-readable English message. See SPEC-DATA-0006 for the full envelope contract.

object
code
required

Machine-readable, stable, SCREAMING_SNAKE_CASE identifier.

string
location
Any of:

HFX source location for a [DataError::HfxCompileError] entry.

Emitted as the extra location field on the entry JSON when present, per SPEC-UI-0043. The line/column are 1-based. The frame is the offending source line extracted verbatim from the input.

object
column
required

1-based column within the line, measured in UTF-16 code units of the prefix so browser-side editors can consume it directly.

integer format: uint32
frame

The offending source line text, when available.

string | null
line
required

1-based line number within the source text.

integer format: uint32
message
required

Server-authored English message. Not part of the API contract; may change across releases without notice.

string
rule

The key of the ValidationRule that failed, when the code is RULE_FAILED. None for all other codes.

Skipped during serialization when absent so it does not appear on unrelated entries (same pattern as location).

Documented here as a plain string (#[schemars(with = "...")]) rather than a $ref to ValidationRuleKey’s own schema: that type lives in metadata-types, which does not derive JsonSchema yet (tracked by #812). ValidationRuleKey serializes transparently as its inner string (serde’s default newtype-struct behavior), so this is an accurate wire-shape description, not a placeholder.

string | null
scope
required

Anchoring category. Drives client-side rendering.

One of:

Attached to a specific request field. target is the field key.

string
Allowed value: field
target

Field key for field scope, record id for record scope, null otherwise. Always serialized, even when null.

string | null
Example
{
"errors": [
{
"scope": "field"
}
]
}