API Reference
Frank exposes a FastAPI API under /api/v1. The interactive OpenAPI UI is available at /docs when the API is running.
Local default:
http://localhost:8002/docsHealth and platform status
GET /health
GET /api/v1/status
GET /api/v1/services/health
GET /api/v1/metricsUse these for readiness checks, service health, and metrics.
Sources
POST /api/v1/sources/discover
GET /api/v1/sources/discover/status/{workflow_id}
GET /api/v1/sources
POST /api/v1/sources
GET /api/v1/sources/{source_id}
PATCH /api/v1/sources/{source_id}
DELETE /api/v1/sources/{source_id}
POST /api/v1/sources/{source_id}/sync
GET /api/v1/sources/{source_id}/sync/status
GET /api/v1/sources/{source_id}/streams
POST /api/v1/sources/{source_id}/streams
PATCH /api/v1/sources/{source_id}/streams/{stream_id}
DELETE /api/v1/sources/{source_id}/streams/{stream_id}
POST /api/v1/sources/{source_id}/streams/bulk
POST /api/v1/sources/{source_id}/streams/refresh-schema
GET /api/v1/sources/{source_id}/sync-history
GET /api/v1/sources/{source_id}/sync-history/stats
GET /api/v1/sources/{source_id}/iceberg-refs
GET /api/v1/sources/{source_id}/runs/{run_id}/logs
GET /api/v1/sources/{source_id}/runs/{run_id}/logs/download
GET /api/v1/sources/sync-runs/{sync_run_id}/streams
GET /api/v1/sources/sync-runs/{workflow_id}/details
GET /api/v1/sources/{source_id}/credentials
POST /api/v1/sources/{source_id}/credentials
PUT /api/v1/sources/{source_id}/credentials
POST /api/v1/sources/{source_id}/credentials/migrate
DELETE /api/v1/sources/{source_id}/credentials
POST /api/v1/sources/credentials/{credential_ref}/revokeDeclared credential fields are write-only in both server modes. Source readback, dry-run, export, logs, and errors never return their values.
Current mutable/base Compose uses SOURCE_CREDENTIAL_MODE=legacy_inline. Source create/update accepts credential_values, merges them into Source.source_config, and preserves stored credential fields on ordinary updates even though readback is redacted. credential_ref is unavailable. Every /credentials lifecycle endpoint listed above fails clearly in this mode; discovery and extraction continue to use the inline Source configuration.
The immutable release uses SOURCE_CREDENTIAL_MODE=vault. Source create/update accepts either credential_values plus credential_name, or an existing tenant-owned credential_ref, never both. Credential bootstrap and rotation responses contain only safe metadata: opaque reference, name, kind, declared field names, presence, exact version, lifecycle status, rotation time, and reference count. Values and Vault paths are never returned.
The migrate route writes and verifies Vault before removing declared fields from PostgreSQL. Detach never deletes or revokes Vault data. Revoke is allowed only after every Source has detached and retains Vault history for operator-managed recovery.
POST .../streams/refresh-schema accepts { "streams": [...] } as a complete discovery snapshot. Existing streams are matched by name; only schema and supported_sync_modes are refreshed. Namespace/destination routing, sync/write/cursor/enabled configuration, and runtime state are preserved. New names are created with defaults and names absent from a non-empty snapshot are removed as stale. A discovery namespace must identify a real upstream container such as a database schema or GeoServer workspace; namespace-less API streams use null, never their own stream name.
Source schedules
GET /api/v1/sources/{source_id}/schedule
PUT /api/v1/sources/{source_id}/schedule
POST /api/v1/sources/{source_id}/schedule/pause
POST /api/v1/sources/{source_id}/schedule/resume
POST /api/v1/sources/{source_id}/schedule/trigger
DELETE /api/v1/sources/{source_id}/schedule
GET /api/v1/schedulesSource patterns
GET /api/v1/patterns/discover
GET /api/v1/patterns/{pattern_id}External pattern lifecycle:
POST /api/v1/patterns/register
POST /api/v1/patterns/reconcileTransforms
GET /api/v1/transforms
GET /api/v1/transforms/{transform_id}
GET /api/v1/transforms/{transform_id}/detail
PATCH /api/v1/transforms/{transform_id}
DELETE /api/v1/transforms/{transform_id}
POST /api/v1/transforms/{transform_id}/hydrate
POST /api/v1/transforms/{transform_id}/execute
POST /api/v1/transforms/{transform_id}/materialize
GET /api/v1/transforms/{transform_id}/runs
GET /api/v1/transforms/{transform_id}/runs/{run_id}/execute is the low-level execution callback path. Product and CLI execution use the Dagster-backed materialization or schedule trigger paths.
Transform schedules
GET /api/v1/transforms/{transform_id}/schedule
PUT /api/v1/transforms/{transform_id}/schedule
POST /api/v1/transforms/{transform_id}/schedule/pause
POST /api/v1/transforms/{transform_id}/schedule/resume
POST /api/v1/transforms/{transform_id}/schedule/trigger
DELETE /api/v1/transforms/{transform_id}/schedule
GET /api/v1/transform-schedulesTransform patterns and SQL transforms
GET /api/v1/transform-patterns
GET /api/v1/transform-patterns/categories
GET /api/v1/transform-patterns/{pattern_id}
POST /api/v1/transform-patterns/{pattern_id}/validate
POST /api/v1/transform-patterns/{pattern_id}/preview
POST /api/v1/transform-patterns/syncGET /api/v1/sql-transforms
GET /api/v1/sql-transforms/categories
GET /api/v1/sql-transforms/for-type/{sql_type}
GET /api/v1/sql-transforms/{transform_id}
POST /api/v1/sql-transforms/{transform_id}/apply
POST /api/v1/sql-transforms/syncArtifacts, runs, and logs
GET /api/v1/artifacts
GET /api/v1/artifacts/{artifact_id}
GET /api/v1/artifacts/{artifact_id}/content
GET /api/v1/artifacts/{artifact_id}/downloadPOST /api/v1/runs
POST /api/v1/runs/{id}/start
POST /api/v1/runs/{id}/complete
POST /api/v1/runs/{id}/fail
POST /api/v1/runs/{id}/cancel
GET /api/v1/runs/{id}
GET /api/v1/runsGET /api/v1/transform-runs
GET /api/v1/transform-runs/{run_id}
GET /api/v1/transform-runs/{run_id}/logs
POST /api/v1/transform-runs/{run_id}/cancelPipelines
POST /api/v1/pipelines
GET /api/v1/pipelines
GET /api/v1/pipelines/{pipeline_id}
PUT /api/v1/pipelines/{pipeline_id}
PATCH /api/v1/pipelines/{pipeline_id}/steps/{step_id}
DELETE /api/v1/pipelines/{pipeline_id}
POST /api/v1/pipelines/validate-dag
POST /api/v1/pipelines/{pipeline_id}/versions
POST /api/v1/pipelines/{pipeline_id}/activate
POST /api/v1/pipelines/{pipeline_id}/pause
POST /api/v1/pipelines/{pipeline_id}/sandbox
GET /api/v1/pipelines/{pipeline_id}/sandbox/{workflow_id}/status
GET /api/v1/pipelines/{pipeline_id}/runs
GET /api/v1/pipelines/available-transforms
POST /api/v1/apply/dry-runPOST /api/v1/apply/dry-run accepts the same ordered envelope documents used by declarative apply:
{
"docs": [
{
"apiVersion": "frank.platform/v1",
"kind": "Source",
"metadata": {"name": "example"},
"spec": {"pattern_id": "rest_api", "source_config": {}}
}
],
"allow_deprecate": false,
"live_ontology": false
}The route never persists. Each result reports create, patch, noop, would-409, or error; Source results also include stream-level create/patch/noop/unmanaged actions. Set live_ontology: true to add GET-only validation of each locally valid BackingDataset against its declared ontology tenant, type, properties, relationships, keys, and carrier types. Network/authentication failures make that preflight invalid. The live check does not create or modify schema or entities.
Registered declarative routes also accept Content-Type: application/yaml. Unquoted YAML dates and datetimes are recursively converted to ISO-8601 strings before normal JSON validation. JSON-compatible scalar values retain their types. YAML-only values that cannot be represented as JSON return a sanitized HTTP 400 without echoing the submitted spec or credential-shaped values.
Datasets
GET /api/v1/datasets
GET /api/v1/datasets/{dataset_id}/preview
GET /api/v1/datasets/{dataset_id}/snapshots
GET /api/v1/datasets/{dataset_id}dataset_id is the dotted table identifier accepted by the route, for example silver.tenant_x.table_name.
AI
POST /api/v1/ai/suggest-target-schema
POST /api/v1/ai/suggest-field-mappings
POST /api/v1/ai/suggest-pattern-params
POST /api/v1/ai/review-sql
POST /api/v1/ai/generate-transform
POST /api/v1/ai/fix-ci-failure
POST /api/v1/ai/publish-transform
POST /api/v1/ai/compose-pipeline
GET /api/v1/ai/compose-pipeline/{execution_id}/statusSchema libraries and SDM registry
GET /api/v1/schema-libraries
GET /api/v1/schema-libraries/{library_id}/domains
GET /api/v1/schema-libraries/{library_id}/domains/{domain}/schemas
GET /api/v1/schema-libraries/{library_id}/schemas/{schema_id}
GET /api/v1/schema-libraries/schema/{full_id}
GET /api/v1/schema-libraries/search
POST /api/v1/schema-libraries/validate/{full_id}GET /api/v1/sdm
GET /api/v1/schemas/registry
POST /api/v1/schemas/registry/register
POST /api/v1/schemas/registry/bulk-register
POST /api/v1/schemas/registry/discover-and-register
POST /api/v1/schemas/registry/sync-catalog
POST /api/v1/schemas/registry/search
POST /api/v1/schemas/registry/validateOntology and backing datasets
GET /api/v1/ontology/status
GET /api/v1/ontology/entity-types
GET /api/v1/ontology/entity-types/domains
GET /api/v1/ontology/entity-types/{code}
POST /api/v1/ontology/entity-types
POST /api/v1/ontology/entity-types/{code}/versions
PATCH /api/v1/ontology/entity-types/{code}
DELETE /api/v1/ontology/entity-types/{code}
GET /api/v1/ontology/entity-types/{code}/versionsPOST /api/v1/backing-datasets/suggest-mappings
GET /api/v1/backing-datasets/pending-syncs
GET /api/v1/backing-datasets/capabilities
POST /api/v1/backing-datasets
GET /api/v1/backing-datasets
GET /api/v1/backing-datasets/{backing_dataset_id}
PATCH /api/v1/backing-datasets/{backing_dataset_id}
DELETE /api/v1/backing-datasets/{backing_dataset_id}
POST /api/v1/backing-datasets/{backing_dataset_id}/sync?force={boolean}
GET /api/v1/backing-datasets/{backing_dataset_id}/sync-history
GET /api/v1/backing-datasets/{backing_dataset_id}/sync-history/{run_id}
GET /api/v1/backing-datasets/{backing_dataset_id}/sync-history/{run_id}/logs
GET /api/v1/backing-datasets/{backing_dataset_id}/healthThe sync trigger returns the persisted run ID, attempted effective-SyncSpec fingerprint, and force flag. Run responses expose the replay reason and both attempted/applied fingerprints without credentials or volatile workflow data in the fingerprint itself. They also expose both the legacy numeric snapshot_id and additive decimal-string snapshot_id_exact; use the exact field whenever 64-bit Iceberg snapshot precision matters, especially in JavaScript clients. The exact-run endpoint additionally returns is_terminal, rows_synced, and bulk_jobs. Each bulk evidence item contains only job_id, operation, submitted_count, and completed_count; request rows and credentials are not persisted or returned.
GET /api/v1/backing-datasets/capabilities returns:
{
"sync_contract_version": 2,
"supports_exact_run_polling": true,
"supports_force_replay": true
}The V2 trigger fields are optional in the response schema so a newer CLI can recognize an N-1 response shape. When present together, they are the contract for polling the exact run. Clients must require the capabilities response and force_replay: true confirmation before treating a force request as accepted.
Identity policies and users
GET /api/v1/identity-policies
GET /api/v1/identity-policies/{policy_id}
GET /api/v1/identity-policies/{policy_id}/versions
GET /api/v1/identity-policies/{policy_id}/versions/{version}
POST /api/v1/identity-policies
POST /api/v1/identity-policies/{policy_id}/clone
PUT /api/v1/identity-policies/{policy_id}
DELETE /api/v1/identity-policies/{policy_id}
POST /api/v1/identity-policies/{policy_id}/dry-runGET /api/v1/users
GET /api/v1/users/{sub}Temporal
GET /api/v1/temporal/health
GET /api/v1/temporal/health/detailed
GET /api/v1/temporal/config
GET /api/v1/temporal/metrics
GET /api/v1/temporal/workers
GET /api/v1/temporal/task-queues
POST /api/v1/temporal/workflows/schema-match
POST /api/v1/temporal/workflows/transform
POST /api/v1/temporal/workflows/pipeline
GET /api/v1/temporal/workflows/{workflow_id}
POST /api/v1/temporal/workflows/{workflow_id}/cancel
POST /api/v1/temporal/workflows/{workflow_id}/wait