Confluye
Endpoints

Databases

Manage tables and rows, import data, and run SQL queries via the API.

Endpoints for databases under /api/v1/databases.

Endpoints

MethodPathDescription
GET/api/v1/databasesList tables
POST/api/v1/databasesCreate a table
PATCH/api/v1/databases/{tableId}Update a table
GET/api/v1/databases/{tableId}/rowsList rows
POST/api/v1/databases/{tableId}/rowsInsert rows
PATCH/api/v1/databases/{tableId}/rowsUpdate rows
DELETE/api/v1/databases/{tableId}/rowsDelete rows
GET/api/v1/databases/{tableId}/exportExport a table
GET/api/v1/databases/{tableId}/managed-rowsRead managed rows
PUT/api/v1/databases/{tableId}/managed-rowsCreate or update one managed row
POST/api/v1/databases/importImport data (CSV)
POST/api/v1/databases/queryRun a SQL query
GET/api/v1/configuration/catalogList configuration catalog
GET/api/v1/configuration/historyRead configuration history
POST/api/v1/configuration/{operation}Export, validate, preview, prepare, apply, or declare configuration

Tables and rows

GET /api/v1/databases returns { databases[], tables[] } for the workspace.

POST /api/v1/databases creates a database (when only databaseName is given) or a table:

FieldTypeNotes
databaseNamestringTarget database (required)
tableNamestringIf present, creates a table in that database
columnsarrayColumn definitions; type ∈ text | number | status | date | json
rowsarrayOptional initial rows; scalar columns keep their documented scalar values, while a json column accepts any JSON value, including arrays, objects, booleans, and null

GET /api/v1/databases/{tableId}/rows supports limit and offset and returns { table, rows[], pagination: { limit, offset, returned, total } }. POST inserts one row ({ values }), PATCH updates by { rowIndex, values }, and DELETE removes by { rowIndex }. PATCH /api/v1/databases/{tableId} trashes a table ({ trashed }) or adds a column ({ column, defaultValue }).

Each row's values object must name only declared columns. Scalar columns accept strings or finite numbers; values supplied as JavaScript numbers (not strings) must be finite. A partial PATCH updates only the supplied keys and leaves every other cell untouched, including cells stored as absent or JSON null. Structured values are valid only in columns declared as json. Invalid table creation, inserts, or updates return 400 (BAD_REQUEST in tRPC); they are never surfaced as an internal-server error. JSON exports preserve the original structure, while CSV exports serialize each JSON cell as compact JSON text.

Import CSV

POST /api/v1/databases/import is multipart/form-data only:

FieldNotes
fileRequired, .csv / CSV mime; max 5 MB (413), non-CSV → 415
databaseId / databaseNameTarget database
tableNameDefaults to a cleaned-up filename
hasHeadertrue/1/yes, default true
delimiterOptional delimiter override (auto-detected otherwise)
columnsJSON array of { name, type } type overrides

Returns 201 with { table, stats, rowsUrl }. Malformed CSV returns 422 { error, code }.

Run a SQL query

POST /api/v1/databases/query runs a read-only query against one database's tables:

{ "databaseId": "db_...", "sql": "SELECT * FROM \"orders\" WHERE total > 100 LIMIT 100" }

Both fields are required. Queries are SELECT-only and run in a sandbox over the database's tables (never against Postgres). Success returns { columns, rows, truncated, durationMs }. A missing database returns 404; a slow query returns 408 { error, code, availableTables }; other SQL errors return 400. See Databases & SQL for the constraints.

Export

GET /api/v1/databases/{tableId}/export?format=csv|json (default json) returns the table as a downloadable file with a Content-Disposition: attachment header.

Managed configuration

Managed configuration applies only to tables explicitly declared as non-sensitive configuration by an Admin or Owner. The declaration fixes the textual key and lifecycle columns (active and retired), the allowed column types, and any local table references. Ordinary tables retain their existing API behavior. Declared tables reject legacy CSV append and workflow writes; use the stable managed key and expected revision instead.

Declaration is permanent: it cannot be undone, and ordinary writers cannot be restored. Recognized secrets in either lifecycle value are rejected before declaration, including for empty tables. A column with tableReference: false is equivalent to one that omits the flag.

All managed configuration requests are scoped to the workspace of the authenticated API key. A client that has organization access must still name the destination workspace with the workspaceId query parameter when targeting it; the key's effective access is checked against that workspace. A key or organization principal cannot use this parameter to cross the authorized workspace boundary.

The dynamic configuration route has this method split:

MethodPathOperation
GET/api/v1/configuration/catalogList declared tables, contracts, databases, and affected writers
GET/api/v1/configuration/historyRead workspace-scoped application receipts
POST/api/v1/configuration/exportExport selected declared tables
POST/api/v1/configuration/validateValidate a package without reading or writing destination rows
POST/api/v1/configuration/previewCalculate actions and blockers
POST/api/v1/configuration/preparePersist a proposal and return a panel URL for human review
POST/api/v1/configuration/applyApply a currently confirmed plan when application is enabled
POST/api/v1/configuration/declareDeclare one existing table as managed configuration

Using the wrong method for a listed operation returns HTTP 405 with an Allow header naming the supported method. Unknown operation names and internal row-handler names return HTTP 404 for either method; use the dedicated managed-rows route for row access.

The catalog also returns applyEnabled and applyDisabledReason. The reason is null when deployment settings enable writes, or writes_disabled when the feature flag is off. These fields describe deployment availability; the caller still needs Admin or Owner authority to write. Without durable storage, the catalog returns HTTP 503 with applyEnabled: false and applyDisabledReason: "storage_unavailable", without table or database metadata.

There is no API confirm operation. prepare returns a proposal link; the authenticated human session in the Tables panel performs the confirmation before apply. Agents and API clients can prepare a proposal but cannot issue that confirmation themselves. GET and PUT /api/v1/databases/{tableId}/managed-rows read or write one declared table by stable key. The PUT body is { "key", "expectedRevision", "values" }; the key is immutable and a stale revision is a conflict.

For row writes, a declared table-reference cell contains the ID of a managed table in the same workspace. A table owned by an applied package can reference only another table in that deployment. Portable exports replace these IDs with logical $table keys. An export reference conflict returns bounded details.blockers with logical tableKey, row key, and reason; preview returns the same identifiers in its blockers. Error details retain the full row key, up to 256 characters, so keys with a shared prefix remain distinguishable. Existing rows remain readable so an authorized editor can correct a legacy invalid reference.

Configuration packages use fluxus.configuration-artifact.v1 and are capped at 20 tables, 500 rows per table, 1,000 rows total, and 1 MiB. Before loading row values, export checks the selected stored JSON text in PostgreSQL and rejects more than 32 MiB. This is a separate read budget, not an increase to the portable package limit. Packages contain only explicitly selected non-sensitive configuration. Source IDs are not portable, and references use logical $table keys within the package. Export reads all selected tables from one consistent database snapshot, including when concurrent writers commit changes. Every destination must be mapped explicitly to an existing declared table or to a named table in a selected database.

Preview and apply compare the package, the observed destination, and the last successful baseline. A row already equal to the desired package is unchanged, even if its prior baseline differs; that is convergence. Differences unexplained by the desired package or baseline are drift. Schema, ownership, classification, missing, unexpected, or changed-row drift blocks apply; no SQL override, delete operation, or ignore-drift flag exists. A successful apply writes all package tables, its baseline, and its receipt atomically. Repeating a request with the same requestId and input returns the existing receipt after authorization checks; using that identity for different input is a conflict, which makes a lost response safe to retry. An authorized retry can recover a committed receipt even after the write flag is disabled; a request without a committed receipt still returns 503 while writes are disabled.

GET /api/v1/configuration/history returns up to the latest 50 workspace-scoped receipts. Each receipt identifies the actor (actorId), package key, action identifiers, status: "applied", and creation time; it does not include managed row values. In the Tables panel, an existing row draft retains the revision it originally read even if background data refreshes. A failed new-row save leaves its entered values available for correction. Reload rows and discard edits clears local drafts and fetches current rows when you want to recover from a stale revision.

Apply, declaration, and managed-row writes require Admin or Owner authority, durable PostgreSQL, and MANAGED_CONFIGURATION_APPLY_ENABLED=true. Until deployment certification enables the flag, apply remains unavailable while ordinary tables continue to work. A deployment without DATABASE_URL does not advertise apply availability. Errors use 400 for validation, 403 for authorization, 404 for an unknown or cross-workspace resource, 409 for drift or ownership conflict, 412 for expired confirmation/proposal state, and 503 when durable storage or apply is unavailable.

Next steps