HTTP API
Everything the CLI can do is also available over HTTP, served under the /api prefix by civex serve (paths below omit that prefix — see Server & web UI for how to start the server). This page is rendered from the same OpenAPI spec the running server exposes at /openapi.json, so it stays in sync with the code automatically.
The raw spec is also published alongside this page: openapi.json. Paste it into Swagger Editor, Postman, or an SDK generator if you'd rather work from the machine-readable version than this rendered page.
This reference doesn't include a "try it out" console — it's a static page with no server behind it, so there's nothing to call. Use civex serve and the live /docs Swagger UI for that.
civex 2.0.0rc4.post3
civex is a local-first research data management system: schemas, records, files, and workflow automation in one place, running on your own machine against your own database.
Every endpoint below is served under the /api prefix (e.g. GET /api/schemas); paths in this reference omit that prefix for brevity.
Errors
Errors share one envelope shape across the API. Domain errors (not found, already exists, validation, misconfiguration) return a 4xx/5xx status with a JSON body of {"detail": "<message>"}. Request body/query validation failures return 422 with {"detail": "Request validation failed", "errors": [...]}, one entry per invalid field. Anything unexpected returns a generic 500 with {"detail": "Internal server error", "request_id": "<id>"} — the same id echoed on the x-request-id response header, for correlating with server logs.
See the getting started guide for installing the CLI and standing up your first project.
ai
POST /api/ai/chat
Chat
Request body
Schema of the request body
{
"properties": {
"messages": {
"items": {
"discriminator": {
"mapping": {
"assistant": "#/components/schemas/AssistantMessage",
"tool_call": "#/components/schemas/ToolCallMessage",
"user": "#/components/schemas/UserMessage"
},
"propertyName": "role"
},
"oneOf": [
{
"$ref": "#/components/schemas/UserMessage"
},
{
"$ref": "#/components/schemas/AssistantMessage"
},
{
"$ref": "#/components/schemas/ToolCallMessage"
}
]
},
"title": "Messages",
"type": "array"
}
},
"required": [
"messages"
],
"title": "ChatRequest",
"type": "object"
}
Responses
GET /api/ai/config
Get Ai Config
Responses
{
"base_url": null,
"configured": true,
"key_hint": null,
"model": "string",
"provider": "string",
"source": "string"
}
Schema of the response body
{
"properties": {
"base_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Base Url"
},
"configured": {
"title": "Configured",
"type": "boolean"
},
"key_hint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Key Hint"
},
"model": {
"title": "Model",
"type": "string"
},
"provider": {
"title": "Provider",
"type": "string"
},
"source": {
"title": "Source",
"type": "string"
}
},
"required": [
"configured",
"source",
"model",
"provider",
"base_url",
"key_hint"
],
"title": "AiConfigResponse",
"type": "object"
}
PATCH /api/ai/config
Update Ai Config
Request body
Schema of the request body
{
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Api Key"
},
"base_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Base Url"
},
"model": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Model"
},
"provider": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Provider"
}
},
"title": "AiConfigUpdate",
"type": "object"
}
Responses
{
"base_url": null,
"configured": true,
"key_hint": null,
"model": "string",
"provider": "string",
"source": "string"
}
Schema of the response body
{
"properties": {
"base_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Base Url"
},
"configured": {
"title": "Configured",
"type": "boolean"
},
"key_hint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Key Hint"
},
"model": {
"title": "Model",
"type": "string"
},
"provider": {
"title": "Provider",
"type": "string"
},
"source": {
"title": "Source",
"type": "string"
}
},
"required": [
"configured",
"source",
"model",
"provider",
"base_url",
"key_hint"
],
"title": "AiConfigResponse",
"type": "object"
}
GET /api/ai/ollama/models
Ollama Models
Description
List models installed in a running Ollama instance.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
base_url |
query | string | http://localhost:11434/v1 | No |
Responses
GET /api/ai/openrouter/auth-url
Openrouter Auth Url
Description
Return the OAuth URL for the OpenRouter login flow.
Responses
GET /api/ai/openrouter/callback
Openrouter Callback
Description
Receive OAuth code from OpenRouter, exchange for key, save to config.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
code |
query | string | No |
Responses
GET /api/ai/openrouter/limits
Openrouter Limits
Description
Proxy GET https://openrouter.ai/api/v1/key to expose usage/rate-limit info.
Responses
GET /api/ai/usage
Get Ai Usage
Description
All-time token usage, regardless of provider/model -- backs both the
AI panel's usage display and civex ai usage.
Responses
{
"by_model": [
{
"input_tokens": 0,
"model": "string",
"output_tokens": 0,
"provider": "string",
"requests": 0,
"total_tokens": 0
}
],
"total": {
"input_tokens": 0,
"output_tokens": 0,
"requests": 0,
"total_tokens": 0
}
}
Schema of the response body
analytics
GET /api/analytics/ai/usage
Ai Token Usage
Description
AI provider token usage over time, broken out by provider and model.
Applies start, end, bucket, plus this endpoint's own provider
and model params -- not part of the shared filter contract since no
other endpoint has a use for them.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
model |
query | No | AI model to scope to, e.g. 'claude-sonnet-5'. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
provider |
query | No | AI provider to scope to, e.g. 'anthropic'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
GET /api/analytics/audit/events
Audit Event Counts
Description
Audit log entry counts over time, broken out by action and
entity_type. Applies start, end, bucket, entity_type, action.
AuditLog carries no actor/user field, so this endpoint has no
per-user breakdown.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
GET /api/analytics/jobs/by-trigger
Job Trigger Breakdown
Description
Job counts grouped by trigger type (record_created, record_updated,
manual) -- a snapshot over the filtered range, not a time series.
Applies start, end, workflow_id, status, trigger.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
GET /api/analytics/jobs/duration
Job Duration Stats
Description
Step execution duration distribution: summary stats (count, avg,
min, max, p50, p90, p99, in seconds), a histogram of counts by
duration bucket, and which bucket each percentile falls in. Applies
start, end, plugin_id, status (matched against the step's own
status, not the parent job's).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
{
"avg_seconds": null,
"bins": [
{
"count": 0,
"label": "string"
}
],
"count": 0,
"max_seconds": null,
"min_seconds": null,
"p50_seconds": null,
"p90_seconds": null,
"p99_seconds": null,
"percentile_markers": [
{
"bin_label": "string",
"label": "string"
}
]
}
Schema of the response body
{
"properties": {
"avg_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Avg Seconds"
},
"bins": {
"description": "Duration distribution, bucketed into fixed-width ranges.",
"items": {
"$ref": "#/components/schemas/DurationHistogramBinResponse"
},
"title": "Bins",
"type": "array"
},
"count": {
"description": "Number of step executions the stats are over.",
"title": "Count",
"type": "integer"
},
"max_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Max Seconds"
},
"min_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Min Seconds"
},
"p50_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "P50 Seconds"
},
"p90_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "P90 Seconds"
},
"p99_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "P99 Seconds"
},
"percentile_markers": {
"description": "Which bucket each of p50/p90/p99 falls in, for a chart to draw as reference lines over `bins`.",
"items": {
"$ref": "#/components/schemas/DurationPercentileMarkerResponse"
},
"title": "Percentile Markers",
"type": "array"
}
},
"required": [
"count",
"avg_seconds",
"min_seconds",
"max_seconds",
"p50_seconds",
"p90_seconds",
"p99_seconds",
"bins",
"percentile_markers"
],
"title": "JobDurationStatsResponse",
"type": "object"
}
GET /api/analytics/jobs/failures-by-plugin
Plugin Failure Counts
Description
Failed step-execution counts over time, broken out by plugin --
generalizes the aggregate civex worker stats uses with a date range
and bucket size. Applies start, end, bucket, plugin_id.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
Schema of the response body
GET /api/analytics/jobs/status
Job Status Counts
Description
Workflow job counts over time, broken out by status. Applies start,
end, bucket, workflow_id, trigger, status.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
Schema of the response body
GET /api/analytics/records/counts
Record Counts
Description
Current record totals by dataset and schema -- a snapshot, not a time
series. Applies the dataset and schema filters; the rest of the
shared filter contract is ignored here.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
GET /api/analytics/records/growth
Record Growth
Description
Record creation counts over time, broken out by dataset and schema.
Applies start, end, bucket, dataset, schema.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Audit action to scope to: create, update, delete, or purge. | ||
bucket |
query | string | day | No | Time-bucket size for time-series endpoints. Ignored by current-state endpoints (e.g. record counts). |
dataset |
query | No | Dataset name to scope to. | ||
end |
query | No | Exclusive upper bound (UTC). | ||
entity_type |
query | No | Audit entity type to scope to: record, schema, field, or dataset. | ||
plugin_id |
query | No | Plugin id to scope to, e.g. 'civex.load_file'. | ||
schema |
query | No | Schema name to scope to. | ||
start |
query | No | Inclusive lower bound (UTC) on the endpoint's primary timestamp column. | ||
status |
query | No | Job or step status to scope to. | ||
trigger |
query | No | Workflow trigger to scope to: record_created, record_updated, or manual. | ||
workflow_id |
query | No | Workflow name to scope to -- workflows are identified by name, not a separate id. |
Responses
{
"bucket": "string",
"items": [
{
"bucket": "string",
"count": 0,
"dataset": "string",
"schema_name": "string"
}
]
}
Schema of the response body
{
"properties": {
"bucket": {
"description": "Bucket size applied: day, week, or month.",
"title": "Bucket",
"type": "string"
},
"items": {
"items": {
"$ref": "#/components/schemas/RecordGrowthPointResponse"
},
"title": "Items",
"type": "array"
}
},
"required": [
"bucket",
"items"
],
"title": "RecordGrowthResponse",
"type": "object"
}
audit
GET /api/audit
List Audit
Description
General-purpose audit search, filterable by entity type and/or id.
Prefer /records/{id}/audit or /schemas/{name}/audit when scoping to a
single known resource — this endpoint is for cross-entity queries.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Only entries of this action (create, update, ...). | ||
entity_id |
query | No | Filter to a single entity's audit trail. | ||
entity_type |
query | No | Filter to one entity type: record, schema, field, dataset, view. | ||
limit |
query | integer | 50 | No | |
offset |
query | integer | 0 | No | |
since |
query | No | Only entries at or after this time (ISO 8601; a time with no zone is read as UTC). | ||
sort |
query | No | 'timestamp' or 'action', optionally ':asc' / ':desc'. Newest first by default. |
Responses
{
"items": [
{
"action": "string",
"actor": null,
"changes": [
{
"after": null,
"before": null,
"deleted": null,
"dtype": null,
"field": "string",
"label": null
}
],
"device": null,
"entity_id": "string",
"entity_type": "string",
"id": "string",
"new_data": null,
"now": null,
"old_data": null,
"sync": [
{}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/AuditLogResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedAuditLogResponse",
"type": "object"
}
POST /api/audit/batches
Open Audit Batch
Description
Start a batch for work done over many requests, such as an import. Send
its id in an X-Civex-Batch header on each of them and what they change is
one event in history.
Request body
Schema of the request body
{
"properties": {
"kind": {
"const": "import",
"default": "import",
"description": "What the batch is. Only an import is opened by a client; the server opens its own for deletes, restores and workflow runs.",
"title": "Kind",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "E.g. the file imported.",
"title": "Label"
}
},
"title": "OpenBatchRequest",
"type": "object"
}
Responses
{
"created_at": "2022-04-13T15:42:05.901Z",
"id": "string",
"kind": "string",
"label": null,
"ref": null
}
Schema of the response body
{
"properties": {
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"description": "import, delete, restore, purge or workflow.",
"title": "Kind",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A workflow's name or an import's file.",
"title": "Label"
},
"ref": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What started it, e.g. a workflow run's id.",
"title": "Ref"
}
},
"required": [
"id",
"kind",
"created_at"
],
"title": "AuditBatchResponse",
"type": "object"
}
GET /api/audit/batches/{batch_id}
Get Audit Batch
Description
One batch as an event, with everything in it counted by kind and action.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
batch_id |
path | string | No |
Responses
{
"actor": null,
"batch": null,
"count": 0,
"device": null,
"entry": null,
"id": "string",
"kind": "string",
"parts": [
{
"action": "string",
"count": 0,
"entity_type": "string"
}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
Schema of the response body
{
"properties": {
"actor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Who made it, as reported by the machine that made it; for a batch, who made its changes. Null when it was not recorded.",
"title": "Actor"
},
"batch": {
"anyOf": [
{
"$ref": "#/components/schemas/AuditBatchResponse"
},
{
"type": "null"
}
],
"description": "What the batch was, for kind=batch."
},
"count": {
"description": "Changes in it that match the filters.",
"title": "Count",
"type": "integer"
},
"device": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a synced change, the device it came through (verified by the authority).",
"title": "Device"
},
"entry": {
"anyOf": [
{
"$ref": "#/components/schemas/AuditLogResponse"
},
{
"type": "null"
}
],
"description": "The change itself, for kind=entry."
},
"id": {
"description": "The entry's id, or the batch's.",
"title": "Id",
"type": "string"
},
"kind": {
"description": "entry (a single change) or batch.",
"title": "Kind",
"type": "string"
},
"parts": {
"description": "For a batch, what it holds by kind of thing and action. Its entries are listed at /audit/batches/{id}/entries.",
"items": {
"$ref": "#/components/schemas/AuditPart"
},
"title": "Parts",
"type": "array"
},
"timestamp": {
"description": "The latest change in it.",
"format": "date-time",
"title": "Timestamp",
"type": "string"
}
},
"required": [
"id",
"kind",
"timestamp",
"count"
],
"title": "AuditEventResponse",
"type": "object"
}
GET /api/audit/batches/{batch_id}/entries
List Audit Batch Entries
Description
The changes in one batch, with their field-level changes.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Only entries of this action (create, update, ...). | ||
batch_id |
path | string | No | ||
limit |
query | integer | 50 | No | |
offset |
query | integer | 0 | No | |
since |
query | No | Only entries at or after this time (ISO 8601; a time with no zone is read as UTC). | ||
sort |
query | No | 'timestamp' or 'action', optionally ':asc' / ':desc'. Newest first by default. |
Responses
{
"items": [
{
"action": "string",
"actor": null,
"changes": [
{
"after": null,
"before": null,
"deleted": null,
"dtype": null,
"field": "string",
"label": null
}
],
"device": null,
"entity_id": "string",
"entity_type": "string",
"id": "string",
"new_data": null,
"now": null,
"old_data": null,
"sync": [
{}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/AuditLogResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedAuditLogResponse",
"type": "object"
}
GET /api/audit/events
List Audit Events
Description
The whole project's history as events, newest first. A batch (an import,
a delete that took a tree with it, a workflow run) is one event however
many changes it holds, with a count of what it did; any other change is an
event of its own, with its field-level changes and where the record is
now. The filter and q match changes; an event is listed when any of its
changes match, with how many did.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
filter |
query | No | A filter tree as JSON (`{"and": [{"field": "kind", "op": "eq", "value": "record"}]}`), the same kind records and runs take. Fields come from GET /audit/filter-fields. | ||
limit |
query | integer | 25 | No | |
offset |
query | integer | 0 | No | |
q |
query | No | Text to find in what a change stored (a value, a file's name) or in a batch's label (a workflow's name, an imported file). | ||
sort |
query | No | `timestamp:asc` for oldest first; newest first by default. |
Responses
{
"items": [
{
"actor": null,
"batch": null,
"count": 0,
"device": null,
"entry": null,
"id": "string",
"kind": "string",
"parts": [
{
"action": "string",
"count": 0,
"entity_type": "string"
}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/AuditEventResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedAuditEventsResponse",
"type": "object"
}
GET /api/audit/filter-fields
Audit Filter Fields
Description
The fields a history filter may test, with their types and operators.
Responses
GET /api/audit/restore-all
Plan Restore All
Description
What restoring everything deleted that this filter matches would do, without doing it: how many collections, schemas, fields and records, how many records come back in all, and how many are blocked because something above them is deleted and not in the set.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
batch |
query | No | Only what this batch deleted: the id of a bulk delete's event in `/audit/events`, to undo it whole. | ||
filter |
query | No | The history filter, as for `/audit/events`. | ||
q |
query | No |
Responses
{
"blocked": 0,
"collections": 0,
"fields": 0,
"records": 0,
"restores": 0,
"schemas": 0,
"things": 0,
"truncated": true
}
Schema of the response body
{
"properties": {
"blocked": {
"description": "Matched, but under something deleted that is not in the set (for a field, also one whose name has since been taken).",
"title": "Blocked",
"type": "integer"
},
"collections": {
"description": "Deleted collections matched.",
"title": "Collections",
"type": "integer"
},
"fields": {
"default": 0,
"description": "Deleted fields matched.",
"title": "Fields",
"type": "integer"
},
"records": {
"description": "Deleted records matched.",
"title": "Records",
"type": "integer"
},
"restores": {
"description": "Records that would be live afterwards, counting what came back with each, once.",
"title": "Restores",
"type": "integer"
},
"schemas": {
"description": "Deleted schemas matched.",
"title": "Schemas",
"type": "integer"
},
"things": {
"description": "All of the above.",
"title": "Things",
"type": "integer"
},
"truncated": {
"description": "More matched than were looked at.",
"title": "Truncated",
"type": "boolean"
}
},
"required": [
"collections",
"schemas",
"records",
"things",
"restores",
"blocked",
"truncated"
],
"title": "RestoreAllPlanResponse",
"type": "object"
}
POST /api/audit/restore-all
Restore All
Description
Restore everything deleted that the filter matches, as one event in history: collections and schemas first, then records parent-first. A record left under something deleted that is not in the set stays deleted and is counted as blocked.
Request body
Schema of the request body
{
"properties": {
"batch": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only what this batch deleted: the id of a bulk delete (a record and everything beneath it) from `/audit/events`.",
"title": "Batch"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "The history filter tree whose matches are restored (the one `GET /audit/events` takes), or null for everything deleted.",
"title": "Filter"
},
"q": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Text the changes must contain.",
"title": "Q"
}
},
"title": "RestoreAllRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"blocked": {
"description": "Left deleted: a parent is deleted and not in the set, or a field's name has been taken.",
"title": "Blocked",
"type": "integer"
},
"records": {
"description": "Records that came back in all.",
"title": "Records",
"type": "integer"
},
"restored": {
"description": "Things brought back.",
"title": "Restored",
"type": "integer"
}
},
"required": [
"restored",
"records",
"blocked"
],
"title": "RestoreAllResultResponse",
"type": "object"
}
GET /api/audit/storage
History Storage
Description
How history is stored: edits still to convert to what-changed form, how far the background conversion has got, and the room a reclaim would give back.
Responses
{
"converting": true,
"done": null,
"free_bytes": null,
"size_bytes": null,
"total": null,
"whole_entries": 0
}
Schema of the response body
{
"properties": {
"converting": {
"description": "The conversion is running now.",
"title": "Converting",
"type": "boolean"
},
"done": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Entries looked at since the conversion began.",
"title": "Done"
},
"free_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Room inside the file no longer used: what reclaiming gives back. Reclaiming needs about `size_bytes` of free disk while it runs.",
"title": "Free Bytes"
},
"size_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "The database file's size (SQLite; null where the database manages its own space).",
"title": "Size Bytes"
},
"total": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "What was left when the conversion began.",
"title": "Total"
},
"whole_entries": {
"description": "Edits still stored as two whole copies (written before history stored only what changed); converted in the background.",
"title": "Whole Entries",
"type": "integer"
}
},
"required": [
"whole_entries",
"converting"
],
"title": "HistoryStorageResponse",
"type": "object"
}
POST /api/audit/storage/reclaim
Reclaim History Storage
Description
Give unused room in the database file back to the disk (SQLite VACUUM). Refused while history is being converted. It needs about the file's size in free disk while it runs, and the project waits for it.
Responses
{
"converting": true,
"done": null,
"free_bytes": null,
"size_bytes": null,
"total": null,
"whole_entries": 0
}
Schema of the response body
{
"properties": {
"converting": {
"description": "The conversion is running now.",
"title": "Converting",
"type": "boolean"
},
"done": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Entries looked at since the conversion began.",
"title": "Done"
},
"free_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Room inside the file no longer used: what reclaiming gives back. Reclaiming needs about `size_bytes` of free disk while it runs.",
"title": "Free Bytes"
},
"size_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "The database file's size (SQLite; null where the database manages its own space).",
"title": "Size Bytes"
},
"total": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "What was left when the conversion began.",
"title": "Total"
},
"whole_entries": {
"description": "Edits still stored as two whole copies (written before history stored only what changed); converted in the background.",
"title": "Whole Entries",
"type": "integer"
}
},
"required": [
"whole_entries",
"converting"
],
"title": "HistoryStorageResponse",
"type": "object"
}
GET /api/audit/{audit_id}
Get Audit Entry
Description
One history entry, with the changes it made worked out field by field.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
audit_id |
path | string | No |
Responses
{
"action": "string",
"actor": null,
"changes": [
{
"after": null,
"before": null,
"deleted": null,
"dtype": null,
"field": "string",
"label": null
}
],
"device": null,
"entity_id": "string",
"entity_type": "string",
"id": "string",
"new_data": null,
"now": null,
"old_data": null,
"sync": [
{}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
Schema of the response body
{
"properties": {
"action": {
"description": "One of: create, update, delete, restore, purge.",
"title": "Action",
"type": "string"
},
"actor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Who made the change, as reported by the machine that made it (the name chosen in the project, else the operating-system user). Not verified. Null for entries from before this was recorded.",
"title": "Actor"
},
"changes": {
"description": "What the entry changed, field by field, in schema order. A delete or purge lists the values that were lost; a restore lists nothing.",
"items": {
"$ref": "#/components/schemas/AuditChange"
},
"title": "Changes",
"type": "array"
},
"device": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a synced change, the device it came through, as the authority stamped it from that device's token (verified). Null for a change made on the authority, not synced yet, or synced before this was kept.",
"title": "Device"
},
"entity_id": {
"title": "Entity Id",
"type": "string"
},
"entity_type": {
"description": "One of: record, schema, field, dataset, view.",
"title": "Entity Type",
"type": "string"
},
"id": {
"title": "Id",
"type": "string"
},
"new_data": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "The thing after the change: whole for a create, identity and the changed values for an edit or restore (see `old_data`). Null on delete.",
"title": "New Data"
},
"now": {
"anyOf": [
{
"$ref": "#/components/schemas/AuditNow"
},
{
"type": "null"
}
],
"description": "Where the record this entry is about is now, so a lost one can be told from one that was edited, deleted or purged."
},
"old_data": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "The thing before the change. A delete has it whole; an edit or restore, which is stored as only what changed, has the thing's identity (id, name, label, where it sits) and the values it changed, so anything absent was not changed. A record's values are keyed by field id, so an entry survives a rename; `changes` has them by current name. Null on create.",
"title": "Old Data"
},
"sync": {
"description": "What became of this change when it was sent to the authority, if it did not go in as made: one row per clash, refusal or edit against a delete (kind, field_label, yours, theirs, base, theirs_actor, status, resolution, message, attempted, changes; the same rows as `/remote/conflicts`), open or settled. Empty for a change that went in as made, and when the project follows no authority.",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Sync",
"type": "array"
},
"timestamp": {
"format": "date-time",
"title": "Timestamp",
"type": "string"
}
},
"required": [
"id",
"action",
"entity_type",
"entity_id",
"timestamp"
],
"title": "AuditLogResponse",
"type": "object"
}
GET /api/audit/{audit_id}/revert
Plan Revert
Description
Preview undoing a history entry without changing anything: which fields
would be put back, which were edited since (conflicts), and which cannot be
put back. blocked says why when nothing can be undone at all.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
audit_id |
path | string | No | ||
fields |
query | No | Only plan these fields (repeat the parameter). |
Responses
{
"audit_id": "string",
"blocked": null,
"blocker": null,
"can_apply": true,
"entity_id": "string",
"entity_type": "string",
"fields": [
{
"current": null,
"dtype": null,
"field": "string",
"label": null,
"reason": null,
"status": "string",
"target": null
}
],
"has_conflicts": true,
"kind": null
}
Schema of the response body
{
"properties": {
"audit_id": {
"title": "Audit Id",
"type": "string"
},
"blocked": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the entry can't be reverted at all.",
"title": "Blocked"
},
"blocker": {
"anyOf": [
{
"$ref": "#/components/schemas/BlockerResponse"
},
{
"type": "null"
}
],
"description": "When a deleted record can't come back yet, what to restore first."
},
"can_apply": {
"title": "Can Apply",
"type": "boolean"
},
"entity_id": {
"title": "Entity Id",
"type": "string"
},
"entity_type": {
"title": "Entity Type",
"type": "string"
},
"fields": {
"description": "Per-field plan, for an update.",
"items": {
"$ref": "#/components/schemas/RevertFieldResponse"
},
"title": "Fields",
"type": "array"
},
"has_conflicts": {
"title": "Has Conflicts",
"type": "boolean"
},
"kind": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "update (put fields back), restore (undo a delete) or delete (undo a create). Null when nothing can be reverted.",
"title": "Kind"
}
},
"required": [
"audit_id",
"entity_type",
"entity_id",
"can_apply",
"has_conflicts"
],
"title": "RevertPlanResponse",
"type": "object"
}
POST /api/audit/{audit_id}/revert
Revert Audit Entry
Description
Undo a history entry on a record: an update puts the changed fields back,
a delete restores the record, a create deletes it. Goes through the normal
record update, so the same rules apply and the revert is itself recorded
(and can be reverted). Fields edited since the entry are left alone unless
force is set.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
audit_id |
path | string | No |
Request body
Responses
Schema of the response body
{
"properties": {
"applied": {
"description": "Names of the fields that were put back (an update only).",
"items": {
"type": "string"
},
"title": "Applied",
"type": "array"
},
"audit_id": {
"title": "Audit Id",
"type": "string"
},
"entity_id": {
"title": "Entity Id",
"type": "string"
},
"kind": {
"title": "Kind",
"type": "string"
}
},
"required": [
"audit_id",
"entity_id",
"kind",
"applied"
],
"title": "RevertResultResponse",
"type": "object"
}
GET /api/records/{record_id}/audit
List Record Audit
Description
Audit entries for a single record — every create/update/delete recorded against it, most recent first.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Only entries of this action (create, update, ...). | ||
limit |
query | integer | 50 | No | |
offset |
query | integer | 0 | No | |
record_id |
path | string | No | ||
since |
query | No | Only entries at or after this time (ISO 8601; a time with no zone is read as UTC). | ||
sort |
query | No | 'timestamp' or 'action', optionally ':asc' / ':desc'. Newest first by default. |
Responses
{
"items": [
{
"action": "string",
"actor": null,
"changes": [
{
"after": null,
"before": null,
"deleted": null,
"dtype": null,
"field": "string",
"label": null
}
],
"device": null,
"entity_id": "string",
"entity_type": "string",
"id": "string",
"new_data": null,
"now": null,
"old_data": null,
"sync": [
{}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/AuditLogResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedAuditLogResponse",
"type": "object"
}
GET /api/schemas/{name}/audit
List Schema Audit
Description
Audit entries for a schema and its own fields (not inherited ones), most recent first — schema/field renames, field additions and removals, restriction changes, and so on.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Only entries of this action (create, update, ...). | ||
limit |
query | integer | 50 | No | |
name |
path | string | No | ||
offset |
query | integer | 0 | No | |
since |
query | No | Only entries at or after this time (ISO 8601; a time with no zone is read as UTC). | ||
sort |
query | No | 'timestamp' or 'action', optionally ':asc' / ':desc'. Newest first by default. |
Responses
{
"items": [
{
"action": "string",
"actor": null,
"changes": [
{
"after": null,
"before": null,
"deleted": null,
"dtype": null,
"field": "string",
"label": null
}
],
"device": null,
"entity_id": "string",
"entity_type": "string",
"id": "string",
"new_data": null,
"now": null,
"old_data": null,
"sync": [
{}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/AuditLogResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedAuditLogResponse",
"type": "object"
}
jobs
GET /api/automation
Automation Status
Description
Whether automation is paused, and how many runs are waiting or running.
Responses
Schema of the response body
{
"properties": {
"batch": {
"anyOf": [
{
"$ref": "#/components/schemas/BatchResponse"
},
{
"type": "null"
}
],
"description": "The current stretch of work with how many have succeeded and failed so far; null when nothing is waiting or running."
},
"cancelled": {
"default": 0,
"description": "How many runs the call just cancelled (stop only).",
"title": "Cancelled",
"type": "integer"
},
"paused": {
"description": "True while automation is paused: triggers start nothing, waiting runs are not picked up, and manual runs are refused.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Runs waiting to start.",
"title": "Pending",
"type": "integer"
},
"running": {
"description": "Runs in progress.",
"title": "Running",
"type": "integer"
}
},
"required": [
"paused",
"pending",
"running"
],
"title": "AutomationStatusResponse",
"type": "object"
}
POST /api/automation/resume
Resume Automation
Description
Lift a pause. Triggers fire and queued runs are picked up again.
Responses
Schema of the response body
{
"properties": {
"batch": {
"anyOf": [
{
"$ref": "#/components/schemas/BatchResponse"
},
{
"type": "null"
}
],
"description": "The current stretch of work with how many have succeeded and failed so far; null when nothing is waiting or running."
},
"cancelled": {
"default": 0,
"description": "How many runs the call just cancelled (stop only).",
"title": "Cancelled",
"type": "integer"
},
"paused": {
"description": "True while automation is paused: triggers start nothing, waiting runs are not picked up, and manual runs are refused.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Runs waiting to start.",
"title": "Pending",
"type": "integer"
},
"running": {
"description": "Runs in progress.",
"title": "Running",
"type": "integer"
}
},
"required": [
"paused",
"pending",
"running"
],
"title": "AutomationStatusResponse",
"type": "object"
}
POST /api/automation/stop
Stop Automation
Description
Stop all automation, for example a workflow that keeps triggering itself.
Pauses automation (nothing new is triggered or started, and manual runs are
refused), cancels every waiting run, and stops every running one before its
next step. A step already in progress finishes or times out first. Call
POST /automation/resume to start again.
Responses
Schema of the response body
{
"properties": {
"batch": {
"anyOf": [
{
"$ref": "#/components/schemas/BatchResponse"
},
{
"type": "null"
}
],
"description": "The current stretch of work with how many have succeeded and failed so far; null when nothing is waiting or running."
},
"cancelled": {
"default": 0,
"description": "How many runs the call just cancelled (stop only).",
"title": "Cancelled",
"type": "integer"
},
"paused": {
"description": "True while automation is paused: triggers start nothing, waiting runs are not picked up, and manual runs are refused.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Runs waiting to start.",
"title": "Pending",
"type": "integer"
},
"running": {
"description": "Runs in progress.",
"title": "Running",
"type": "integer"
}
},
"required": [
"paused",
"pending",
"running"
],
"title": "AutomationStatusResponse",
"type": "object"
}
GET /api/jobs
List Jobs
Description
record_id filters to runs triggered by that record; affected_record_id
filters to runs that created or updated that record -- the two directions of
the run/record audit trail (a record can be both for different runs).
affected_schema filters to runs that wrote to that schema (indexed).
Results are paginated: limit defaults to 50 and is capped at 500.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
affected_record_id |
query | No | |||
affected_schema |
query | No | |||
filter |
query | No | A filter tree as JSON (`{"and": [{"field": "status", "op": "eq", "value": "failed"}]}`), the same shape as the records filter. Fields come from GET /jobs/filter-fields. | ||
limit |
query | integer | 50 | No | |
offset |
query | integer | 0 | No | |
record_id |
query | No | |||
search |
query | No | Match on workflow name or error text. | ||
sort |
query | No | 'column[:asc|desc]' over workflow_name, status, trigger, schema_name, created_at. Newest first otherwise. | ||
status |
query | No | |||
trigger |
query | No | |||
workflow |
query | No | Only runs of the workflow with exactly this name. |
Responses
[
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
]
GET /api/jobs/count
Count Jobs
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
affected_record_id |
query | No | |||
affected_schema |
query | No | |||
filter |
query | No | A filter tree as JSON (`{"and": [{"field": "status", "op": "eq", "value": "failed"}]}`), the same shape as the records filter. Fields come from GET /jobs/filter-fields. | ||
record_id |
query | No | |||
search |
query | No | |||
status |
query | No | |||
trigger |
query | No | |||
workflow |
query | No |
Responses
POST /api/jobs/delete
Delete Jobs
Description
Delete runs, whatever their state. A waiting run never starts; a running one stops before its next step; a finished one is removed with its step log. What a run already changed in records stays (and is in their history).
Request body
Schema of the request body
{
"properties": {
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Instead of ids: delete every run this filter matches (the same filter tree as GET /jobs, at most 1000 runs).",
"title": "Filter"
},
"ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 1000,
"minItems": 1,
"type": "array"
},
{
"type": "null"
}
],
"description": "Ids of the runs to delete.",
"title": "Ids"
}
},
"title": "DeleteJobsRequest",
"type": "object"
}
Responses
POST /api/jobs/drain
Drain Jobs
Description
Kick off the worker to process all pending jobs.
Responses
GET /api/jobs/failure-groups
Failure Groups
Description
Failed runs grouped by workflow and what went wrong, most first, so a
thousand failures read as the few causes they are. filter narrows which
runs are counted (only failed ones ever are).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
filter |
query | No | A filter tree as JSON (`{"and": [{"field": "status", "op": "eq", "value": "failed"}]}`), the same shape as the records filter. Fields come from GET /jobs/filter-fields. |
Responses
GET /api/jobs/filter-fields
Run Filter Fields
Description
The fields a run filter may test, with their types and operators.
Responses
POST /api/jobs/rerun
Rerun Jobs
Description
Repeat several runs at once: each is queued as a new run of the same
workflow on the same record, with the same input. One request, one commit and
one pass of the worker, however many. A run that cannot be repeated (a bad id,
an unknown run, a record that has since been deleted) is listed under
skipped with the reason, and the rest are still queued. Refused (422) while
automation is paused.
Request body
Schema of the request body
{
"properties": {
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Instead of ids: repeat every run this filter matches (the same filter tree as GET /jobs, at most 1000 runs).",
"title": "Filter"
},
"ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 200,
"minItems": 1,
"type": "array"
},
{
"type": "null"
}
],
"description": "Ids of the runs to repeat. Each is queued as a new run.",
"title": "Ids"
}
},
"title": "RerunJobsRequest",
"type": "object"
}
Responses
{
"skipped": [
{
"id": "string",
"reason": "string"
}
],
"started": [
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
]
}
Schema of the response body
{
"properties": {
"skipped": {
"description": "Runs that could not be repeated, such as one whose record has since been deleted.",
"items": {
"$ref": "#/components/schemas/SkippedJob"
},
"title": "Skipped",
"type": "array"
},
"started": {
"description": "The new runs that were queued, in the order asked.",
"items": {
"$ref": "#/components/schemas/WorkflowJobResponse"
},
"title": "Started",
"type": "array"
}
},
"required": [
"started",
"skipped"
],
"title": "RerunJobsResponse",
"type": "object"
}
DELETE /api/jobs/{job_id}
Delete Job
Description
Delete one run, whatever its state (see POST /jobs/delete).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
job_id |
path | string | No |
Responses
GET /api/jobs/{job_id}
Get Job
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
job_id |
path | string | No |
Responses
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
Schema of the response body
{
"properties": {
"affected_records": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Affected Records"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"depth": {
"default": 0,
"description": "How many workflow-triggered-by-workflow hops deep this run is: 0 for a run started by a person or an ordinary edit, 1 for a run started by another run's save, and so on.",
"title": "Depth",
"type": "integer"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"error_details": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Error Details"
},
"finished_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"id": {
"title": "Id",
"type": "string"
},
"log": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Log"
},
"record_id": {
"title": "Record Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"started_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"title": "Status",
"type": "string"
},
"step_executions": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Step Executions"
},
"trigger": {
"title": "Trigger",
"type": "string"
},
"trigger_detail": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "What caused the run. `changes` lists each field that changed, with a short `before` and `after` and whether the workflow was `watched` for it. `caused_by` is {job_id, workflow} when another run's own save started this one, else null. Null for a run started by hand.",
"title": "Trigger Detail"
},
"workflow_name": {
"title": "Workflow Name",
"type": "string"
}
},
"required": [
"id",
"workflow_name",
"record_id",
"schema_name",
"trigger",
"status",
"error",
"error_details",
"log",
"step_executions",
"affected_records",
"created_at",
"started_at",
"finished_at"
],
"title": "WorkflowJobResponse",
"type": "object"
}
POST /api/jobs/{job_id}/cancel
Cancel Job
Description
Cancel one run. A waiting run never starts; a running one stops before its next step (a step already in progress finishes or times out first). A run that has already finished is returned unchanged.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
job_id |
path | string | No |
Responses
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
Schema of the response body
{
"properties": {
"affected_records": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Affected Records"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"depth": {
"default": 0,
"description": "How many workflow-triggered-by-workflow hops deep this run is: 0 for a run started by a person or an ordinary edit, 1 for a run started by another run's save, and so on.",
"title": "Depth",
"type": "integer"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"error_details": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Error Details"
},
"finished_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"id": {
"title": "Id",
"type": "string"
},
"log": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Log"
},
"record_id": {
"title": "Record Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"started_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"title": "Status",
"type": "string"
},
"step_executions": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Step Executions"
},
"trigger": {
"title": "Trigger",
"type": "string"
},
"trigger_detail": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "What caused the run. `changes` lists each field that changed, with a short `before` and `after` and whether the workflow was `watched` for it. `caused_by` is {job_id, workflow} when another run's own save started this one, else null. Null for a run started by hand.",
"title": "Trigger Detail"
},
"workflow_name": {
"title": "Workflow Name",
"type": "string"
}
},
"required": [
"id",
"workflow_name",
"record_id",
"schema_name",
"trigger",
"status",
"error",
"error_details",
"log",
"step_executions",
"affected_records",
"created_at",
"started_at",
"finished_at"
],
"title": "WorkflowJobResponse",
"type": "object"
}
POST /api/jobs/{job_id}/rerun
Rerun Job
Description
Enqueue a new job using the same workflow and record as an existing job.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
job_id |
path | string | No |
Responses
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
Schema of the response body
{
"properties": {
"affected_records": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Affected Records"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"depth": {
"default": 0,
"description": "How many workflow-triggered-by-workflow hops deep this run is: 0 for a run started by a person or an ordinary edit, 1 for a run started by another run's save, and so on.",
"title": "Depth",
"type": "integer"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"error_details": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Error Details"
},
"finished_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"id": {
"title": "Id",
"type": "string"
},
"log": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Log"
},
"record_id": {
"title": "Record Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"started_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"title": "Status",
"type": "string"
},
"step_executions": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Step Executions"
},
"trigger": {
"title": "Trigger",
"type": "string"
},
"trigger_detail": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "What caused the run. `changes` lists each field that changed, with a short `before` and `after` and whether the workflow was `watched` for it. `caused_by` is {job_id, workflow} when another run's own save started this one, else null. Null for a run started by hand.",
"title": "Trigger Detail"
},
"workflow_name": {
"title": "Workflow Name",
"type": "string"
}
},
"required": [
"id",
"workflow_name",
"record_id",
"schema_name",
"trigger",
"status",
"error",
"error_details",
"log",
"step_executions",
"affected_records",
"created_at",
"started_at",
"finished_at"
],
"title": "WorkflowJobResponse",
"type": "object"
}
collections
GET /api/collections
List Datasets
Responses
POST /api/collections
Create Dataset
Request body
{
"description": null,
"name": "string",
"schemas": [
"string"
],
"scope": "string",
"timezone": null
}
Schema of the request body
{
"properties": {
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"name": {
"title": "Name",
"type": "string"
},
"schemas": {
"description": "Names of the schemas the collection is for. A child schema's parent schema must be listed too.",
"items": {
"type": "string"
},
"title": "Schemas",
"type": "array"
},
"scope": {
"default": "local",
"description": "'local' (default) or 'global' -- see the collection's `scope`.",
"title": "Scope",
"type": "string"
},
"timezone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "IANA timezone for datetime values in this collection. Omit or null to leave unset.",
"title": "Timezone"
}
},
"required": [
"name"
],
"title": "CreateDatasetRequest",
"type": "object"
}
Responses
{
"deleted_at": null,
"description": null,
"id": "string",
"name": "string",
"record_count": 0,
"schemas": [
"string"
],
"scope": "string",
"timezone": null
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this collection was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"record_count": {
"title": "Record Count",
"type": "integer"
},
"schemas": {
"description": "Names of the schemas this collection is for. Records in it can only be of these schemas.",
"items": {
"type": "string"
},
"title": "Schemas",
"type": "array"
},
"scope": {
"default": "local",
"description": "Who may reference this collection's records: 'local' (only records in this collection) or 'global' (records in any collection).",
"title": "Scope",
"type": "string"
},
"timezone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "IANA timezone (e.g. 'America/Chicago') that datetime values in this collection are read and shown in. Null means unset: offset-less input is read as UTC and the UI uses the viewer's own zone. A datetime field's own `timezone` restriction overrides this.",
"title": "Timezone"
}
},
"required": [
"id",
"name",
"description",
"record_count"
],
"title": "DatasetResponse",
"type": "object"
}
GET /api/collections/deleted
List Deleted Datasets
Description
Collections currently in Recently Deleted, most recently deleted first.
Responses
GET /api/collections/{name_or_id}
Get Dataset
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name_or_id |
path | string | No |
Responses
{
"deleted_at": null,
"description": null,
"id": "string",
"name": "string",
"record_count": 0,
"schemas": [
"string"
],
"scope": "string",
"timezone": null
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this collection was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"record_count": {
"title": "Record Count",
"type": "integer"
},
"schemas": {
"description": "Names of the schemas this collection is for. Records in it can only be of these schemas.",
"items": {
"type": "string"
},
"title": "Schemas",
"type": "array"
},
"scope": {
"default": "local",
"description": "Who may reference this collection's records: 'local' (only records in this collection) or 'global' (records in any collection).",
"title": "Scope",
"type": "string"
},
"timezone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "IANA timezone (e.g. 'America/Chicago') that datetime values in this collection are read and shown in. Null means unset: offset-less input is read as UTC and the UI uses the viewer's own zone. A datetime field's own `timezone` restriction overrides this.",
"title": "Timezone"
}
},
"required": [
"id",
"name",
"description",
"record_count"
],
"title": "DatasetResponse",
"type": "object"
}
PATCH /api/collections/{name_or_id}
Update Dataset
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name_or_id |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"rename": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Rename"
},
"schemas": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Replace the collection's schema list. Omit or null to leave unchanged. A schema with records in the collection can't be removed.",
"title": "Schemas"
},
"scope": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "'local' or 'global'. Omit or null to leave unchanged. A global collection that other collections reference can't become local.",
"title": "Scope"
},
"timezone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "IANA timezone for datetime values in this collection. Omit or null to leave unchanged; an empty string clears it back to unset.",
"title": "Timezone"
}
},
"title": "UpdateDatasetRequest",
"type": "object"
}
Responses
{
"deleted_at": null,
"description": null,
"id": "string",
"name": "string",
"record_count": 0,
"schemas": [
"string"
],
"scope": "string",
"timezone": null
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this collection was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"record_count": {
"title": "Record Count",
"type": "integer"
},
"schemas": {
"description": "Names of the schemas this collection is for. Records in it can only be of these schemas.",
"items": {
"type": "string"
},
"title": "Schemas",
"type": "array"
},
"scope": {
"default": "local",
"description": "Who may reference this collection's records: 'local' (only records in this collection) or 'global' (records in any collection).",
"title": "Scope",
"type": "string"
},
"timezone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "IANA timezone (e.g. 'America/Chicago') that datetime values in this collection are read and shown in. Null means unset: offset-less input is read as UTC and the UI uses the viewer's own zone. A datetime field's own `timezone` restriction overrides this.",
"title": "Timezone"
}
},
"required": [
"id",
"name",
"description",
"record_count"
],
"title": "DatasetResponse",
"type": "object"
}
GET /api/collections/{name_or_id}/audit
List Dataset Audit
Description
Audit entries for a collection — renames, description changes, delete/restore/purge — most recent first.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
action |
query | No | Only entries of this action (create, update, ...). | ||
limit |
query | integer | 50 | No | |
name_or_id |
path | string | No | ||
offset |
query | integer | 0 | No | |
since |
query | No | Only entries at or after this time (ISO 8601; a time with no zone is read as UTC). | ||
sort |
query | No | 'timestamp' or 'action', optionally ':asc' / ':desc'. Newest first by default. |
Responses
{
"items": [
{
"action": "string",
"actor": null,
"changes": [
{
"after": null,
"before": null,
"deleted": null,
"dtype": null,
"field": "string",
"label": null
}
],
"device": null,
"entity_id": "string",
"entity_type": "string",
"id": "string",
"new_data": null,
"now": null,
"old_data": null,
"sync": [
{}
],
"timestamp": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/AuditLogResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedAuditLogResponse",
"type": "object"
}
GET /api/collections/{name_or_id}/record-counts
Record Counts
Description
Record counts grouped by schema name — single SQL GROUP BY, no record loading. Takes the list endpoint's filters (except 'schema', which is the grouping), so e.g. 'within' counts what sits under one record.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
filter |
query | No | JSON-encoded filter tree, AND/OR groups of field conditions. Leaf: {"field": " |
||
name_or_id |
path | string | No | ||
parent_record_id |
query | No | Record id (or prefix): direct children only, of any schema. | ||
schema |
query | No | Only records of this schema. | ||
search |
query | No | Full-text search across all field values | ||
sort |
query | array | [] | No | Repeatable '[schema.]field[:asc|desc]'. Nulls sort last either way. Needs 'schema'; 'schema.' names an ancestor whose field to sort by. |
where |
query | array | [] | No | Simple equality filter, repeatable: 'field=value'. AND-combined with each other and with 'filter'. Kept for backwards compatibility -- prefer 'filter' for anything beyond plain equality. |
within |
query | No | Record id (or prefix): only records of 'schema' that descend from it, at any depth -- an encounter's selections, not just its recordings. Requires 'schema'. |
Responses
DELETE /api/collections/{name}
Delete Dataset
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
DELETE /api/collections/{name}/purge
Purge Dataset
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
POST /api/collections/{name}/restore
Restore Dataset
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"deleted_at": null,
"description": null,
"id": "string",
"name": "string",
"record_count": 0,
"schemas": [
"string"
],
"scope": "string",
"timezone": null
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this collection was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"record_count": {
"title": "Record Count",
"type": "integer"
},
"schemas": {
"description": "Names of the schemas this collection is for. Records in it can only be of these schemas.",
"items": {
"type": "string"
},
"title": "Schemas",
"type": "array"
},
"scope": {
"default": "local",
"description": "Who may reference this collection's records: 'local' (only records in this collection) or 'global' (records in any collection).",
"title": "Scope",
"type": "string"
},
"timezone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "IANA timezone (e.g. 'America/Chicago') that datetime values in this collection are read and shown in. Null means unset: offset-less input is read as UTC and the UI uses the viewer's own zone. A datetime field's own `timezone` restriction overrides this.",
"title": "Timezone"
}
},
"required": [
"id",
"name",
"description",
"record_count"
],
"title": "DatasetResponse",
"type": "object"
}
GET /api/collections/{name}/restore-plan
Restore Dataset Plan
Description
What restoring a deleted collection would bring back: it and the records deleted with it, not records deleted on their own earlier.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"blocked": null,
"blocked_by": null,
"can_restore": true,
"collection": null,
"collection_id": null,
"conflict": null,
"deleted_at": null,
"id": "string",
"kind": "string",
"name": "string",
"parents_needed": null,
"records": 0,
"schema_name": null
}
Schema of the response body
{
"properties": {
"blocked": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it can't be restored yet, in plain words. Null when it can.",
"title": "Blocked"
},
"blocked_by": {
"anyOf": [
{
"$ref": "#/components/schemas/BlockerResponse"
},
{
"type": "null"
}
],
"description": "The deleted collection, schema or record that must be restored first. Null when it can be restored now."
},
"can_restore": {
"title": "Can Restore",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a record: the collection it will be in.",
"title": "Collection"
},
"collection_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Collection Id"
},
"conflict": {
"anyOf": [
{
"$ref": "#/components/schemas/RestoreConflictResponse"
},
{
"type": "null"
}
],
"description": "Set when another record has taken the values of a uniqueness key while this one was deleted: restoring is refused until that record is changed or deleted."
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When it was deleted.",
"title": "Deleted At"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"description": "record, collection, schema or field.",
"title": "Kind",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"parents_needed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "For a record held back only by deleted records above it: how many of them. `POST .../restore?with_parents=true` brings each back by itself (not what was deleted alongside it), so just this record (`&only_this=true`) comes back as `parents_needed + 1` records and its deleted siblings stay deleted. Null otherwise.",
"title": "Parents Needed"
},
"records": {
"description": "How many records come back: those deleted together with this, the record itself included when it is one. Never something deleted on its own earlier.",
"title": "Records",
"type": "integer"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a field: the schema it belongs to.",
"title": "Schema Name"
}
},
"required": [
"kind",
"id",
"name",
"records",
"can_restore"
],
"title": "RestorePlanResponse",
"type": "object"
}
records
GET /api/collections/{collection_name}/export.csv
Export Records Csv
Description
Export records in a collection as a CSV file, honoring the same
filters as the record list endpoint. One table for everything listed; to
choose the columns and format, or to take the files too, use
POST /file-access/zip with a table.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection_name |
path | string | No | ||
filter |
query | No | JSON-encoded filter tree, AND/OR groups of field conditions. Leaf: {"field": " |
||
parent_record_id |
query | No | Record id (or prefix): direct children only, of any schema. | ||
schema |
query | No | Only records of this schema. | ||
search |
query | No | Full-text search across all field values | ||
sort |
query | array | [] | No | Repeatable '[schema.]field[:asc|desc]'. Nulls sort last either way. Needs 'schema'; 'schema.' names an ancestor whose field to sort by. |
where |
query | array | [] | No | Simple equality filter, repeatable: 'field=value'. AND-combined with each other and with 'filter'. Kept for backwards compatibility -- prefer 'filter' for anything beyond plain equality. |
within |
query | No | Record id (or prefix): only records of 'schema' that descend from it, at any depth -- an encounter's selections, not just its recordings. Requires 'schema'. |
Responses
DELETE /api/collections/{dataset_name}/records
Delete All Records
Description
Delete every record the query matches -- with no filters, all of the collection's records (of 'schema', if given). The same filters as the list endpoint, so "delete all N matching" deletes exactly what a list with those filters shows.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
dataset_name |
path | string | No | ||
filter |
query | No | JSON-encoded filter tree, AND/OR groups of field conditions. Leaf: {"field": " |
||
force |
query | boolean | False | No | |
parent_record_id |
query | No | Record id (or prefix): direct children only, of any schema. | ||
schema |
query | No | Only records of this schema. | ||
search |
query | No | Full-text search across all field values | ||
sort |
query | array | [] | No | Repeatable '[schema.]field[:asc|desc]'. Nulls sort last either way. Needs 'schema'; 'schema.' names an ancestor whose field to sort by. |
where |
query | array | [] | No | Simple equality filter, repeatable: 'field=value'. AND-combined with each other and with 'filter'. Kept for backwards compatibility -- prefer 'filter' for anything beyond plain equality. |
within |
query | No | Record id (or prefix): only records of 'schema' that descend from it, at any depth -- an encounter's selections, not just its recordings. Requires 'schema'. |
Responses
GET /api/collections/{dataset_name}/records
List Records
Description
List records in a collection, paginated, filtered and sorted.
'where' and 'filter' can be combined -- the equality checks from 'where' are AND-combined with the 'filter' tree, if both are given.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
child_counts |
query | boolean | False | No | Attach each record's live child count per child schema. |
columns |
query | array | [] | No | Repeatable column names whose values aren't in a record's own 'data' -- inherited fields and 'ref_field.target_field' joins -- returned under each record's 'derived'. |
dataset_name |
path | string | No | ||
filter |
query | No | JSON-encoded filter tree, AND/OR groups of field conditions. Leaf: {"field": " |
||
limit |
query | integer | 50 | No | |
offset |
query | integer | 0 | No | |
parent_record_id |
query | No | Record id (or prefix): direct children only, of any schema. | ||
schema |
query | No | Only records of this schema. | ||
search |
query | No | Full-text search across all field values | ||
sort |
query | array | [] | No | Repeatable '[schema.]field[:asc|desc]'. Nulls sort last either way. Needs 'schema'; 'schema.' names an ancestor whose field to sort by. |
where |
query | array | [] | No | Simple equality filter, repeatable: 'field=value'. AND-combined with each other and with 'filter'. Kept for backwards compatibility -- prefer 'filter' for anything beyond plain equality. |
within |
query | No | Record id (or prefix): only records of 'schema' that descend from it, at any depth -- an encounter's selections, not just its recordings. Requires 'schema'. |
Responses
{
"items": [
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/RecordResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedRecordResponse",
"type": "object"
}
POST /api/collections/{dataset_name}/records
Create Record
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
dataset_name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"data": {
"additionalProperties": true,
"default": {},
"title": "Data",
"type": "object"
},
"parent_record_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Record Id"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
}
},
"required": [
"schema_name"
],
"title": "CreateRecordRequest",
"type": "object"
}
Responses
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
Schema of the response body
{
"properties": {
"ancestors": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch: the parent chain, root first, for breadcrumbs.",
"title": "Ancestors"
},
"child_counts": {
"anyOf": [
{
"additionalProperties": {
"type": "integer"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when requested ('child_counts=true'): how many live child records this record has, per child schema name.",
"title": "Child Counts"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Name of the collection this record lives in.",
"title": "Collection"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"data": {
"additionalProperties": true,
"title": "Data",
"type": "object"
},
"dataset_id": {
"title": "Dataset Id",
"type": "string"
},
"deleted_above": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch of a live record: the deleted records directly above it, topmost first. Not empty means it is out of sight (nothing above it lists it); POST /records/{id}/restore-above brings them back.",
"title": "Deleted Above"
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this record was soft-deleted. Null means live.",
"title": "Deleted At"
},
"deleted_fields": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/DeletedFieldValue"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Values this record still holds for fields that have been deleted from its schema. Nothing is lost: restoring the field (`POST /schemas/{schema_name}/fields/{id}/restore`) puts each back in `data`. Null when there are none.",
"title": "Deleted Fields"
},
"derived": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when 'columns' were requested: the requested columns this record's own 'data' can't answer -- fields inherited from an ancestor record, and 'ref_field.target_field' joins -- keyed by column.",
"title": "Derived"
},
"id": {
"title": "Id",
"type": "string"
},
"natural_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Natural Name"
},
"parent_record_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Record Id"
},
"reference_collections": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For reference/reference_list targets that live in a different collection (a global one), the target's id mapped to that collection's name. Targets in the record's own collection are left out.",
"title": "Reference Collections"
},
"reference_labels": {
"anyOf": [
{
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For every reference/reference_list value on this record, the target record's id mapped to its natural_name (null if the target has none). Lets clients render a reference as a link with a readable label without a lookup per value.",
"title": "Reference Labels"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"updated_at": {
"format": "date-time",
"title": "Updated At",
"type": "string"
}
},
"required": [
"id",
"dataset_id",
"schema_name",
"parent_record_id",
"data",
"natural_name",
"created_at",
"updated_at"
],
"title": "RecordResponse",
"type": "object"
}
GET /api/records
Search Records Global
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
limit |
query | integer | 20 | No | |
reachable_from |
query | No | Collection name: only records a record in that collection may reference -- its own collection's and those of global collections. What a reference picker should pass. | ||
schema |
query | string | No | Schema name to search within | |
search |
query | No |
Responses
[
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
]
POST /api/records/bulk-delete
Bulk Delete Records
Request body
Responses
GET /api/records/deleted
List Deleted Records
Description
Records currently in Recently Deleted, most recently deleted first.
Paginated: limit defaults to 200 and is capped at 1000.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
dataset |
query | No | Limit to records from this collection | ||
limit |
query | integer | 200 | No | |
offset |
query | integer | 0 | No |
Responses
[
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
]
POST /api/records/labels
Record Labels
Description
Names for a batch of record ids, as they are now.
Anywhere that kept only a record's id (a workflow run's records, a pinned record, a link) asks here for its name instead of keeping a copy that would go stale when the record or its schema's name template changes. One call resolves any number of ids (up to 200); ids that aren't records, or whose record no longer exists, are omitted. Read-only: it is a POST only so the ids travel in the body rather than a long address.
Request body
Responses
GET /api/records/orphans
List Orphans
Description
Live records that sit under a deleted record, so nothing above them lists them: each with what it sits under. Restore that with POST /records/{id}/restore-above, or delete the record.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
limit |
query | integer | 200 | No |
Responses
{
"items": [
{
"above": [
{
"id": "string",
"natural_name": null,
"schema_name": "string"
}
],
"collection": null,
"record": null
}
],
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"description": "Up to `limit` of them.",
"items": {
"$ref": "#/components/schemas/OrphanResponse"
},
"title": "Items",
"type": "array"
},
"total": {
"description": "How many live records sit under a deleted one.",
"title": "Total",
"type": "integer"
}
},
"required": [
"total",
"items"
],
"title": "OrphansResponse",
"type": "object"
}
POST /api/records/restore-selected
Restore Selected Records
Description
Restore exactly these deleted records, not what was deleted alongside
them: for taking back three of the sixty records one delete took. The
deleted records above a chosen one come back too (each by itself) unless
with_parents is false, in which case such a record is left.
Request body
Schema of the request body
{
"properties": {
"ids": {
"description": "The deleted records to restore.",
"items": {
"type": "string"
},
"maxItems": 5000,
"title": "Ids",
"type": "array"
},
"with_parents": {
"default": true,
"description": "Also restore the deleted records above a chosen one, each by itself. Without it, a record under a deleted record is left.",
"title": "With Parents",
"type": "boolean"
}
},
"required": [
"ids"
],
"title": "RestoreSelectedRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"came_back": {
"description": "Records live again in all, counting the parents brought back.",
"title": "Came Back",
"type": "integer"
},
"left": {
"description": "Chosen records still deleted, and why not.",
"title": "Left",
"type": "integer"
},
"restored": {
"description": "Chosen records that came back.",
"title": "Restored",
"type": "integer"
}
},
"required": [
"restored",
"came_back",
"left"
],
"title": "RestoreSelectedResponse",
"type": "object"
}
GET /api/records/search
Search Records
Description
Search records of every schema in one query, best match first -- what
the web UI's jump-to box uses. Each result's collection says where it
lives. Records that are deleted, or in a deleted collection or schema,
are never returned.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection |
query | No | Collection name: only search records in it. Omitted, every collection is searched. | ||
limit |
query | integer | 20 | No | |
q |
query | string | No | Text to find in a record's values, or the start of its id. |
Responses
[
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
]
DELETE /api/records/{record_id}
Delete Record
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
force |
query | boolean | False | No | |
record_id |
path | string | No |
Responses
GET /api/records/{record_id}
Get Record
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record_id |
path | string | No |
Responses
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
Schema of the response body
{
"properties": {
"ancestors": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch: the parent chain, root first, for breadcrumbs.",
"title": "Ancestors"
},
"child_counts": {
"anyOf": [
{
"additionalProperties": {
"type": "integer"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when requested ('child_counts=true'): how many live child records this record has, per child schema name.",
"title": "Child Counts"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Name of the collection this record lives in.",
"title": "Collection"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"data": {
"additionalProperties": true,
"title": "Data",
"type": "object"
},
"dataset_id": {
"title": "Dataset Id",
"type": "string"
},
"deleted_above": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch of a live record: the deleted records directly above it, topmost first. Not empty means it is out of sight (nothing above it lists it); POST /records/{id}/restore-above brings them back.",
"title": "Deleted Above"
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this record was soft-deleted. Null means live.",
"title": "Deleted At"
},
"deleted_fields": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/DeletedFieldValue"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Values this record still holds for fields that have been deleted from its schema. Nothing is lost: restoring the field (`POST /schemas/{schema_name}/fields/{id}/restore`) puts each back in `data`. Null when there are none.",
"title": "Deleted Fields"
},
"derived": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when 'columns' were requested: the requested columns this record's own 'data' can't answer -- fields inherited from an ancestor record, and 'ref_field.target_field' joins -- keyed by column.",
"title": "Derived"
},
"id": {
"title": "Id",
"type": "string"
},
"natural_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Natural Name"
},
"parent_record_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Record Id"
},
"reference_collections": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For reference/reference_list targets that live in a different collection (a global one), the target's id mapped to that collection's name. Targets in the record's own collection are left out.",
"title": "Reference Collections"
},
"reference_labels": {
"anyOf": [
{
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For every reference/reference_list value on this record, the target record's id mapped to its natural_name (null if the target has none). Lets clients render a reference as a link with a readable label without a lookup per value.",
"title": "Reference Labels"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"updated_at": {
"format": "date-time",
"title": "Updated At",
"type": "string"
}
},
"required": [
"id",
"dataset_id",
"schema_name",
"parent_record_id",
"data",
"natural_name",
"created_at",
"updated_at"
],
"title": "RecordResponse",
"type": "object"
}
PATCH /api/records/{record_id}
Update Record
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record_id |
path | string | No |
Request body
Responses
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
Schema of the response body
{
"properties": {
"ancestors": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch: the parent chain, root first, for breadcrumbs.",
"title": "Ancestors"
},
"child_counts": {
"anyOf": [
{
"additionalProperties": {
"type": "integer"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when requested ('child_counts=true'): how many live child records this record has, per child schema name.",
"title": "Child Counts"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Name of the collection this record lives in.",
"title": "Collection"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"data": {
"additionalProperties": true,
"title": "Data",
"type": "object"
},
"dataset_id": {
"title": "Dataset Id",
"type": "string"
},
"deleted_above": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch of a live record: the deleted records directly above it, topmost first. Not empty means it is out of sight (nothing above it lists it); POST /records/{id}/restore-above brings them back.",
"title": "Deleted Above"
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this record was soft-deleted. Null means live.",
"title": "Deleted At"
},
"deleted_fields": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/DeletedFieldValue"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Values this record still holds for fields that have been deleted from its schema. Nothing is lost: restoring the field (`POST /schemas/{schema_name}/fields/{id}/restore`) puts each back in `data`. Null when there are none.",
"title": "Deleted Fields"
},
"derived": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when 'columns' were requested: the requested columns this record's own 'data' can't answer -- fields inherited from an ancestor record, and 'ref_field.target_field' joins -- keyed by column.",
"title": "Derived"
},
"id": {
"title": "Id",
"type": "string"
},
"natural_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Natural Name"
},
"parent_record_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Record Id"
},
"reference_collections": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For reference/reference_list targets that live in a different collection (a global one), the target's id mapped to that collection's name. Targets in the record's own collection are left out.",
"title": "Reference Collections"
},
"reference_labels": {
"anyOf": [
{
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For every reference/reference_list value on this record, the target record's id mapped to its natural_name (null if the target has none). Lets clients render a reference as a link with a readable label without a lookup per value.",
"title": "Reference Labels"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"updated_at": {
"format": "date-time",
"title": "Updated At",
"type": "string"
}
},
"required": [
"id",
"dataset_id",
"schema_name",
"parent_record_id",
"data",
"natural_name",
"created_at",
"updated_at"
],
"title": "RecordResponse",
"type": "object"
}
GET /api/records/{record_id}/files.zip
Export Record Files Zip
Description
Bundle a record's files into a zip, one entry per file, named with the
same resolved_filename used for single-file download. Entries that
would collide (e.g. two files resolving to the same template output) get
a numeric suffix rather than overwriting each other in the archive.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
field |
query | No | Limit the export to a single file/file_list field; omit for every file on the record | ||
record_id |
path | string | No |
Responses
DELETE /api/records/{record_id}/purge
Purge Record
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record_id |
path | string | No |
Responses
GET /api/records/{record_id}/referrers
Get Record Referrers
Description
What points at this record: live records referencing it through a
reference or reference_list field, counted per (collection, schema,
field) -- the reverse of the record's own reference values.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record_id |
path | string | No |
Responses
POST /api/records/{record_id}/restore
Restore Record
Description
Restore a deleted record with what was deleted alongside it. Refused while
its collection or schema is deleted, or a record above it is (unless
with_parents).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
only_this |
query | boolean | False | No | Restore just this record, not what was deleted alongside it (its children). |
record_id |
path | string | No | ||
with_parents |
query | boolean | False | No | When only deleted records above this one hold it back, restore them too, each by itself, so its deleted siblings stay deleted. |
Responses
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
Schema of the response body
{
"properties": {
"ancestors": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch: the parent chain, root first, for breadcrumbs.",
"title": "Ancestors"
},
"child_counts": {
"anyOf": [
{
"additionalProperties": {
"type": "integer"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when requested ('child_counts=true'): how many live child records this record has, per child schema name.",
"title": "Child Counts"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Name of the collection this record lives in.",
"title": "Collection"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"data": {
"additionalProperties": true,
"title": "Data",
"type": "object"
},
"dataset_id": {
"title": "Dataset Id",
"type": "string"
},
"deleted_above": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/RecordRef"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only on a single-record fetch of a live record: the deleted records directly above it, topmost first. Not empty means it is out of sight (nothing above it lists it); POST /records/{id}/restore-above brings them back.",
"title": "Deleted Above"
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this record was soft-deleted. Null means live.",
"title": "Deleted At"
},
"deleted_fields": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/DeletedFieldValue"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Values this record still holds for fields that have been deleted from its schema. Nothing is lost: restoring the field (`POST /schemas/{schema_name}/fields/{id}/restore`) puts each back in `data`. Null when there are none.",
"title": "Deleted Fields"
},
"derived": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Only when 'columns' were requested: the requested columns this record's own 'data' can't answer -- fields inherited from an ancestor record, and 'ref_field.target_field' joins -- keyed by column.",
"title": "Derived"
},
"id": {
"title": "Id",
"type": "string"
},
"natural_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Natural Name"
},
"parent_record_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Record Id"
},
"reference_collections": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For reference/reference_list targets that live in a different collection (a global one), the target's id mapped to that collection's name. Targets in the record's own collection are left out.",
"title": "Reference Collections"
},
"reference_labels": {
"anyOf": [
{
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"type": "object"
},
{
"type": "null"
}
],
"description": "For every reference/reference_list value on this record, the target record's id mapped to its natural_name (null if the target has none). Lets clients render a reference as a link with a readable label without a lookup per value.",
"title": "Reference Labels"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"updated_at": {
"format": "date-time",
"title": "Updated At",
"type": "string"
}
},
"required": [
"id",
"dataset_id",
"schema_name",
"parent_record_id",
"data",
"natural_name",
"created_at",
"updated_at"
],
"title": "RecordResponse",
"type": "object"
}
POST /api/records/{record_id}/restore-above
Restore Above
Description
Bring back what a live record sits under that is deleted: each deleted record directly above it, by itself, so their other children stay deleted. Refused (422) while the collection or schema of the topmost is deleted, or when one would clash with a live record's unique key.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record_id |
path | string | No |
Responses
[
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
]
GET /api/records/{record_id}/restore-plan
Restore Record Plan
Description
What restoring a deleted record would do, without doing it: how many
records come back with it (those deleted together with it), the collection
it will be in, and blocked_by when its collection, schema or a parent
record is still deleted and must be restored first.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record_id |
path | string | No |
Responses
{
"blocked": null,
"blocked_by": null,
"can_restore": true,
"collection": null,
"collection_id": null,
"conflict": null,
"deleted_at": null,
"id": "string",
"kind": "string",
"name": "string",
"parents_needed": null,
"records": 0,
"schema_name": null
}
Schema of the response body
{
"properties": {
"blocked": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it can't be restored yet, in plain words. Null when it can.",
"title": "Blocked"
},
"blocked_by": {
"anyOf": [
{
"$ref": "#/components/schemas/BlockerResponse"
},
{
"type": "null"
}
],
"description": "The deleted collection, schema or record that must be restored first. Null when it can be restored now."
},
"can_restore": {
"title": "Can Restore",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a record: the collection it will be in.",
"title": "Collection"
},
"collection_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Collection Id"
},
"conflict": {
"anyOf": [
{
"$ref": "#/components/schemas/RestoreConflictResponse"
},
{
"type": "null"
}
],
"description": "Set when another record has taken the values of a uniqueness key while this one was deleted: restoring is refused until that record is changed or deleted."
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When it was deleted.",
"title": "Deleted At"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"description": "record, collection, schema or field.",
"title": "Kind",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"parents_needed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "For a record held back only by deleted records above it: how many of them. `POST .../restore?with_parents=true` brings each back by itself (not what was deleted alongside it), so just this record (`&only_this=true`) comes back as `parents_needed + 1` records and its deleted siblings stay deleted. Null otherwise.",
"title": "Parents Needed"
},
"records": {
"description": "How many records come back: those deleted together with this, the record itself included when it is one. Never something deleted on its own earlier.",
"title": "Records",
"type": "integer"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a field: the schema it belongs to.",
"title": "Schema Name"
}
},
"required": [
"kind",
"id",
"name",
"records",
"can_restore"
],
"title": "RestorePlanResponse",
"type": "object"
}
GET /api/schemas/{schema_name}/records
List Schema Records
Description
List a schema's records across every collection -- the same query as a collection's list, just not scoped to one collection (what a saved view browses).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
child_counts |
query | boolean | False | No | Attach each record's live child count per child schema. |
columns |
query | array | [] | No | Repeatable column names whose values aren't in a record's own 'data' -- inherited fields and 'ref_field.target_field' joins -- returned under each record's 'derived'. |
filter |
query | No | JSON-encoded filter tree, AND/OR groups of field conditions. Leaf: {"field": " |
||
limit |
query | integer | 50 | No | |
offset |
query | integer | 0 | No | |
parent_record_id |
query | No | Record id (or prefix): direct children only, of any schema. | ||
schema |
query | No | Only records of this schema. | ||
schema_name |
path | string | No | ||
search |
query | No | Full-text search across all field values | ||
sort |
query | array | [] | No | Repeatable '[schema.]field[:asc|desc]'. Nulls sort last either way. Needs 'schema'; 'schema.' names an ancestor whose field to sort by. |
where |
query | array | [] | No | Simple equality filter, repeatable: 'field=value'. AND-combined with each other and with 'filter'. Kept for backwards compatibility -- prefer 'filter' for anything beyond plain equality. |
within |
query | No | Record id (or prefix): only records of 'schema' that descend from it, at any depth -- an encounter's selections, not just its recordings. Requires 'schema'. |
Responses
{
"items": [
{
"ancestors": null,
"child_counts": null,
"collection": null,
"created_at": "2022-04-13T15:42:05.901Z",
"data": {},
"dataset_id": "string",
"deleted_above": null,
"deleted_at": null,
"deleted_fields": null,
"derived": null,
"id": "string",
"natural_name": null,
"parent_record_id": null,
"reference_collections": null,
"reference_labels": null,
"schema_name": "string",
"updated_at": "2022-04-13T15:42:05.901Z"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/RecordResponse"
},
"title": "Items",
"type": "array"
},
"limit": {
"title": "Limit",
"type": "integer"
},
"offset": {
"title": "Offset",
"type": "integer"
},
"total": {
"title": "Total",
"type": "integer"
}
},
"required": [
"items",
"total",
"offset",
"limit"
],
"title": "PaginatedRecordResponse",
"type": "object"
}
db
PATCH /api/db/config
Set Url
Request body
Responses
{
"dialect": "string",
"docker": null,
"docker_managed": true,
"migration": {
"current_revision": null,
"error": null,
"head_revision": null,
"up_to_date": true
},
"url": "string"
}
Schema of the response body
{
"properties": {
"dialect": {
"title": "Dialect",
"type": "string"
},
"docker": {
"anyOf": [
{
"$ref": "#/components/schemas/DockerStatusResponse"
},
{
"type": "null"
}
]
},
"docker_managed": {
"title": "Docker Managed",
"type": "boolean"
},
"migration": {
"$ref": "#/components/schemas/MigrationStatusResponse"
},
"url": {
"title": "Url",
"type": "string"
}
},
"required": [
"url",
"dialect",
"docker_managed",
"migration",
"docker"
],
"title": "DbStatusResponse",
"type": "object"
}
POST /api/db/docker/setup
Docker Setup
Responses
{
"dialect": "string",
"docker": null,
"docker_managed": true,
"migration": {
"current_revision": null,
"error": null,
"head_revision": null,
"up_to_date": true
},
"url": "string"
}
Schema of the response body
{
"properties": {
"dialect": {
"title": "Dialect",
"type": "string"
},
"docker": {
"anyOf": [
{
"$ref": "#/components/schemas/DockerStatusResponse"
},
{
"type": "null"
}
]
},
"docker_managed": {
"title": "Docker Managed",
"type": "boolean"
},
"migration": {
"$ref": "#/components/schemas/MigrationStatusResponse"
},
"url": {
"title": "Url",
"type": "string"
}
},
"required": [
"url",
"dialect",
"docker_managed",
"migration",
"docker"
],
"title": "DbStatusResponse",
"type": "object"
}
POST /api/db/docker/teardown
Docker Teardown
Description
Removes the Docker container and its data volume, but leaves
config.toml pointed at it — mirrors civex db teardown's own warning
that a subsequent setup-docker/--sqlite is needed to keep using this
project. Returns the (now-broken) status so the UI can show what
happened rather than a bare 204.
Responses
{
"dialect": "string",
"docker": null,
"docker_managed": true,
"migration": {
"current_revision": null,
"error": null,
"head_revision": null,
"up_to_date": true
},
"url": "string"
}
Schema of the response body
{
"properties": {
"dialect": {
"title": "Dialect",
"type": "string"
},
"docker": {
"anyOf": [
{
"$ref": "#/components/schemas/DockerStatusResponse"
},
{
"type": "null"
}
]
},
"docker_managed": {
"title": "Docker Managed",
"type": "boolean"
},
"migration": {
"$ref": "#/components/schemas/MigrationStatusResponse"
},
"url": {
"title": "Url",
"type": "string"
}
},
"required": [
"url",
"dialect",
"docker_managed",
"migration",
"docker"
],
"title": "DbStatusResponse",
"type": "object"
}
POST /api/db/migrate
Migrate
Responses
{
"dialect": "string",
"docker": null,
"docker_managed": true,
"migration": {
"current_revision": null,
"error": null,
"head_revision": null,
"up_to_date": true
},
"url": "string"
}
Schema of the response body
{
"properties": {
"dialect": {
"title": "Dialect",
"type": "string"
},
"docker": {
"anyOf": [
{
"$ref": "#/components/schemas/DockerStatusResponse"
},
{
"type": "null"
}
]
},
"docker_managed": {
"title": "Docker Managed",
"type": "boolean"
},
"migration": {
"$ref": "#/components/schemas/MigrationStatusResponse"
},
"url": {
"title": "Url",
"type": "string"
}
},
"required": [
"url",
"dialect",
"docker_managed",
"migration",
"docker"
],
"title": "DbStatusResponse",
"type": "object"
}
POST /api/db/move
Start Move
Description
Start copying the project's data into the destination, in the
background; poll GET /db/move/{id}. Only when the copy has been verified
does the project switch to the new database, and the old one is never
modified, so a move can always be undone.
Request body
{
"database": null,
"host": null,
"kind": "sqlite",
"password": null,
"path": null,
"port": 0,
"url": null,
"user": null
}
Schema of the request body
{
"properties": {
"database": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Database name, for kind 'postgres'.",
"title": "Database"
},
"host": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Server host, for kind 'postgres'.",
"title": "Host"
},
"kind": {
"description": "Where to move to: 'sqlite' (a new file in the project), 'docker' (this project's Civex-managed PostgreSQL container) or 'postgres' (a PostgreSQL server you run).",
"enum": [
"sqlite",
"docker",
"postgres"
],
"title": "Kind",
"type": "string"
},
"password": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Password, for kind 'postgres'.",
"title": "Password"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "File to create, for kind 'sqlite'. Defaults to a new file in _civex/.",
"title": "Path"
},
"port": {
"default": 5432,
"description": "Server port, for kind 'postgres'.",
"title": "Port",
"type": "integer"
},
"url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full connection URL, for kind 'postgres' (instead of the fields below).",
"title": "Url"
},
"user": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "User name, for kind 'postgres'.",
"title": "User"
}
},
"required": [
"kind"
],
"title": "MoveTargetRequest",
"type": "object"
}
Responses
{
"error": null,
"id": "string",
"progress": {
"message": "string",
"phase": "string",
"rows_done": 0,
"rows_total": 0,
"table": null,
"tables_done": 0,
"tables_total": 0
},
"record": null,
"status": "running"
}
Schema of the response body
{
"properties": {
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it failed or was cancelled.",
"title": "Error"
},
"id": {
"description": "Job id to poll.",
"title": "Id",
"type": "string"
},
"progress": {
"$ref": "#/components/schemas/MoveProgressResponse",
"description": "Latest progress."
},
"record": {
"anyOf": [
{
"$ref": "#/components/schemas/MoveRecordResponse"
},
{
"type": "null"
}
],
"description": "The history entry, once the move has ended."
},
"status": {
"description": "State of the move.",
"enum": [
"running",
"done",
"failed",
"cancelled"
],
"title": "Status",
"type": "string"
}
},
"required": [
"id",
"status",
"progress"
],
"title": "MoveJobResponse",
"type": "object"
}
POST /api/db/move/preflight
Move Preflight
Description
What moving to this destination would do, and whether it can -- with no side effects: nothing is created, started or written.
Request body
{
"database": null,
"host": null,
"kind": "sqlite",
"password": null,
"path": null,
"port": 0,
"url": null,
"user": null
}
Schema of the request body
{
"properties": {
"database": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Database name, for kind 'postgres'.",
"title": "Database"
},
"host": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Server host, for kind 'postgres'.",
"title": "Host"
},
"kind": {
"description": "Where to move to: 'sqlite' (a new file in the project), 'docker' (this project's Civex-managed PostgreSQL container) or 'postgres' (a PostgreSQL server you run).",
"enum": [
"sqlite",
"docker",
"postgres"
],
"title": "Kind",
"type": "string"
},
"password": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Password, for kind 'postgres'.",
"title": "Password"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "File to create, for kind 'sqlite'. Defaults to a new file in _civex/.",
"title": "Path"
},
"port": {
"default": 5432,
"description": "Server port, for kind 'postgres'.",
"title": "Port",
"type": "integer"
},
"url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full connection URL, for kind 'postgres' (instead of the fields below).",
"title": "Url"
},
"user": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "User name, for kind 'postgres'.",
"title": "User"
}
},
"required": [
"kind"
],
"title": "MoveTargetRequest",
"type": "object"
}
Responses
{
"can_proceed": true,
"estimate_seconds": 0,
"problems": [
"string"
],
"source": {
"dialect": "string",
"error": null,
"label": "string",
"location": "string",
"reachable": true,
"records": 0,
"rows": 0,
"size_bytes": null
},
"target": null,
"target_label": "string",
"warnings": [
"string"
]
}
Schema of the response body
{
"properties": {
"can_proceed": {
"description": "False when `problems` is not empty.",
"title": "Can Proceed",
"type": "boolean"
},
"estimate_seconds": {
"description": "Rough time the copy will take.",
"title": "Estimate Seconds",
"type": "integer"
},
"problems": {
"description": "Reasons the move can't go ahead.",
"items": {
"type": "string"
},
"title": "Problems",
"type": "array"
},
"source": {
"$ref": "#/components/schemas/DatabaseSummaryResponse",
"description": "The database now in use."
},
"target": {
"$ref": "#/components/schemas/DatabaseSummaryResponse",
"description": "The destination."
},
"target_label": {
"description": "Kind of destination, for display.",
"title": "Target Label",
"type": "string"
},
"warnings": {
"description": "Things worth knowing that don't block it.",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
}
},
"required": [
"source",
"target",
"target_label",
"can_proceed",
"problems",
"warnings",
"estimate_seconds"
],
"title": "MovePreflightResponse",
"type": "object"
}
GET /api/db/move/{job_id}
Get Move
Description
Progress and outcome of a move started with POST /db/move.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
job_id |
path | string | No |
Responses
{
"error": null,
"id": "string",
"progress": {
"message": "string",
"phase": "string",
"rows_done": 0,
"rows_total": 0,
"table": null,
"tables_done": 0,
"tables_total": 0
},
"record": null,
"status": "running"
}
Schema of the response body
{
"properties": {
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it failed or was cancelled.",
"title": "Error"
},
"id": {
"description": "Job id to poll.",
"title": "Id",
"type": "string"
},
"progress": {
"$ref": "#/components/schemas/MoveProgressResponse",
"description": "Latest progress."
},
"record": {
"anyOf": [
{
"$ref": "#/components/schemas/MoveRecordResponse"
},
{
"type": "null"
}
],
"description": "The history entry, once the move has ended."
},
"status": {
"description": "State of the move.",
"enum": [
"running",
"done",
"failed",
"cancelled"
],
"title": "Status",
"type": "string"
}
},
"required": [
"id",
"status",
"progress"
],
"title": "MoveJobResponse",
"type": "object"
}
POST /api/db/move/{job_id}/cancel
Cancel Move
Description
Ask a running move to stop. Nothing is changed: the copy is one transaction, and the project keeps using its current database.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
job_id |
path | string | No |
Responses
{
"error": null,
"id": "string",
"progress": {
"message": "string",
"phase": "string",
"rows_done": 0,
"rows_total": 0,
"table": null,
"tables_done": 0,
"tables_total": 0
},
"record": null,
"status": "running"
}
Schema of the response body
{
"properties": {
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it failed or was cancelled.",
"title": "Error"
},
"id": {
"description": "Job id to poll.",
"title": "Id",
"type": "string"
},
"progress": {
"$ref": "#/components/schemas/MoveProgressResponse",
"description": "Latest progress."
},
"record": {
"anyOf": [
{
"$ref": "#/components/schemas/MoveRecordResponse"
},
{
"type": "null"
}
],
"description": "The history entry, once the move has ended."
},
"status": {
"description": "State of the move.",
"enum": [
"running",
"done",
"failed",
"cancelled"
],
"title": "Status",
"type": "string"
}
},
"required": [
"id",
"status",
"progress"
],
"title": "MoveJobResponse",
"type": "object"
}
GET /api/db/moves
List Moves
Description
Past database moves, newest first.
Responses
[
{
"counts": {},
"error": null,
"finished_at": null,
"id": "string",
"problems": [
"string"
],
"reverted_at": null,
"seconds": null,
"source_label": "string",
"source_location": "string",
"started_at": "string",
"status": "running",
"target_label": "string",
"target_location": "string"
}
]
POST /api/db/moves/{move_id}/revert
Revert Move
Description
Point the project back at the database a move came from. Nothing is copied: anything written to the new database since stays there.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
move_id |
path | string | No |
Responses
{
"dialect": "string",
"docker": null,
"docker_managed": true,
"migration": {
"current_revision": null,
"error": null,
"head_revision": null,
"up_to_date": true
},
"url": "string"
}
Schema of the response body
{
"properties": {
"dialect": {
"title": "Dialect",
"type": "string"
},
"docker": {
"anyOf": [
{
"$ref": "#/components/schemas/DockerStatusResponse"
},
{
"type": "null"
}
]
},
"docker_managed": {
"title": "Docker Managed",
"type": "boolean"
},
"migration": {
"$ref": "#/components/schemas/MigrationStatusResponse"
},
"url": {
"title": "Url",
"type": "string"
}
},
"required": [
"url",
"dialect",
"docker_managed",
"migration",
"docker"
],
"title": "DbStatusResponse",
"type": "object"
}
GET /api/db/status
Get Status
Responses
{
"dialect": "string",
"docker": null,
"docker_managed": true,
"migration": {
"current_revision": null,
"error": null,
"head_revision": null,
"up_to_date": true
},
"url": "string"
}
Schema of the response body
{
"properties": {
"dialect": {
"title": "Dialect",
"type": "string"
},
"docker": {
"anyOf": [
{
"$ref": "#/components/schemas/DockerStatusResponse"
},
{
"type": "null"
}
]
},
"docker_managed": {
"title": "Docker Managed",
"type": "boolean"
},
"migration": {
"$ref": "#/components/schemas/MigrationStatusResponse"
},
"url": {
"title": "Url",
"type": "string"
}
},
"required": [
"url",
"dialect",
"docker_managed",
"migration",
"docker"
],
"title": "DbStatusResponse",
"type": "object"
}
GET /api/db/summary
Get Summary
Description
What is in the database now in use: its kind, location, size and record count.
Responses
{
"dialect": "string",
"error": null,
"label": "string",
"location": "string",
"reachable": true,
"records": 0,
"rows": 0,
"size_bytes": null
}
Schema of the response body
{
"properties": {
"dialect": {
"description": "'sqlite' or 'postgresql'.",
"title": "Dialect",
"type": "string"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why not, when unreachable.",
"title": "Error"
},
"label": {
"description": "'SQLite file', 'Docker PostgreSQL' or 'PostgreSQL server'.",
"title": "Label",
"type": "string"
},
"location": {
"description": "Where it is, with any password hidden.",
"title": "Location",
"type": "string"
},
"reachable": {
"description": "Whether it could be read.",
"title": "Reachable",
"type": "boolean"
},
"records": {
"description": "Number of records.",
"title": "Records",
"type": "integer"
},
"rows": {
"description": "Rows across every table.",
"title": "Rows",
"type": "integer"
},
"size_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "On-disk size, when known.",
"title": "Size Bytes"
}
},
"required": [
"label",
"dialect",
"location",
"reachable",
"records",
"rows"
],
"title": "DatabaseSummaryResponse",
"type": "object"
}
POST /api/db/test-connection
Test Connection
Description
Check a PostgreSQL server's details connect, and say in plain words what is wrong if they don't.
Request body
{
"database": null,
"host": null,
"kind": "sqlite",
"password": null,
"path": null,
"port": 0,
"url": null,
"user": null
}
Schema of the request body
{
"properties": {
"database": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Database name, for kind 'postgres'.",
"title": "Database"
},
"host": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Server host, for kind 'postgres'.",
"title": "Host"
},
"kind": {
"description": "Where to move to: 'sqlite' (a new file in the project), 'docker' (this project's Civex-managed PostgreSQL container) or 'postgres' (a PostgreSQL server you run).",
"enum": [
"sqlite",
"docker",
"postgres"
],
"title": "Kind",
"type": "string"
},
"password": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Password, for kind 'postgres'.",
"title": "Password"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "File to create, for kind 'sqlite'. Defaults to a new file in _civex/.",
"title": "Path"
},
"port": {
"default": 5432,
"description": "Server port, for kind 'postgres'.",
"title": "Port",
"type": "integer"
},
"url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full connection URL, for kind 'postgres' (instead of the fields below).",
"title": "Url"
},
"user": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "User name, for kind 'postgres'.",
"title": "User"
}
},
"required": [
"kind"
],
"title": "MoveTargetRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why not, in plain words, when ok is false.",
"title": "Error"
},
"ok": {
"description": "Whether a connection was made.",
"title": "Ok",
"type": "boolean"
}
},
"required": [
"ok"
],
"title": "ConnectionCheckResponse",
"type": "object"
}
dump
GET /api/dump
Export Dump
Description
Export all schemas, datasets, records, and workflows as a YAML file download.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
no_data |
query | boolean | False | No |
Responses
POST /api/restore
Import Dump
Description
Restore schemas, datasets, records, and workflows from an uploaded YAML dump.
Request body
Responses
{
"datasets": 0,
"plugins": 0,
"records_restored": 0,
"records_total": 0,
"schemas": 0,
"workflows": 0
}
Schema of the response body
{
"properties": {
"datasets": {
"title": "Datasets",
"type": "integer"
},
"plugins": {
"title": "Plugins",
"type": "integer"
},
"records_restored": {
"title": "Records Restored",
"type": "integer"
},
"records_total": {
"title": "Records Total",
"type": "integer"
},
"schemas": {
"title": "Schemas",
"type": "integer"
},
"workflows": {
"title": "Workflows",
"type": "integer"
}
},
"required": [
"schemas",
"datasets",
"records_restored",
"records_total",
"workflows",
"plugins"
],
"title": "RestoreResult",
"type": "object"
}
files
GET /api/file-access/definitions
Available Definitions
Description
The saved exports to offer where the person is: on a record of schema
(those saved with it or a schema above it whose files are at or beneath it),
or on a collection (those saved with any schema it is for). Give neither for
every saved export. Run one with export as schema/name and collection
and/or within.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection |
query | No | A collection name: the exports saved with its schemas. | ||
schema |
query | No | A schema name: the exports that can run within a record of it. |
Responses
[
{
"fields": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"holder": null,
"id": "string",
"include_files": true,
"name": "string",
"schema_id": "string",
"schema_name": "string",
"tables": [
{
"columns": null,
"format": "csv",
"kind": null,
"name": null,
"shape": "rows",
"skip_empty": true,
"where": null
}
]
}
]
POST /api/file-access/download
Download Files
Description
Download the picked files that are only on the server to this computer (onto their collection's drive). Answers when they have arrived: how many came and which the server hasn't got yet.
Request body
{
"base": null,
"below": true,
"collection": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"kinds": null,
"layout": "tree",
"name": null,
"place": null,
"record_ids": null,
"schema_name": null,
"search": null,
"shas": null,
"sort": null,
"tables": null,
"used_by": null,
"view": null,
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files whose name, or whose record's name, contains this.",
"title": "Name"
},
"place": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't).",
"title": "Place"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"shas": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 100000,
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked.",
"title": "Shas"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"used_by": {
"anyOf": [
{
"items": {
"type": "integer"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only files used by exactly one of these numbers of live records (anywhere, not only in the selection).",
"title": "Used By"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"title": "FilePickRequest",
"type": "object"
}
Responses
POST /api/file-access/export
Export Files
Description
Build the selection as a folder tree on the server's machine.
link makes hard links in a folder on the drive that holds the files;
copy makes copies on the drive named by volume. Answers 409, building
nothing, when files are out of reach (files_unavailable, unless
allow_partial), when they are on several drives and a link was asked for
(files_scattered), or when the drive can't hold links
(links_not_possible). Building again into the same folder updates it.
Request body
{
"allow_partial": true,
"base": null,
"below": true,
"collection": null,
"dest": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"kinds": null,
"layout": "tree",
"mode": "link",
"name": null,
"open": true,
"record_ids": null,
"schema_name": null,
"search": null,
"sort": null,
"tables": null,
"view": null,
"volume": null,
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"allow_partial": {
"default": false,
"description": "Go ahead without files that can't be reached. Without it, a selection with unreachable files answers 409 and builds nothing.",
"title": "Allow Partial",
"type": "boolean"
},
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"dest": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Advanced: a folder to build in, empty or an earlier export, instead of civex's own exports folder. Overrides 'name' and 'volume'. For 'link' it must be on the drive holding the files.",
"title": "Dest"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"mode": {
"default": "link",
"description": "'link' makes hard links in a folder on the drive that holds the files: no copying, no extra space, and refused (409 'files_scattered') when the files are on more than one drive. 'copy' makes real copies on one drive ('volume'), wherever the files are.",
"enum": [
"link",
"copy"
],
"title": "Mode",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Names the folder: <where>/exports/<name>. The same name reuses the same folder.",
"title": "Name"
},
"open": {
"default": false,
"description": "Show the folder in the file manager, if the request came from the server's own machine.",
"title": "Open",
"type": "boolean"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"volume": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For 'copy': the drive to copy onto (a volume name); the project folder if omitted. Ignored for 'link', which goes where the files are.",
"title": "Volume"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"title": "FileExportRequest",
"type": "object"
}
Responses
GET /api/file-access/exports
List Exports
Description
The export folders civex made, newest first, in the project and on each connected drive: where they are, how many files, and how much space they take (links take none; copies do). Exports on a drive that isn't connected can't be listed.
Responses
POST /api/file-access/exports/remove
Remove Exports
Description
Delete export folders: the links or copies the export made, then the
folder. A link is removed without touching the stored file it points at.
Files in the folder that the export didn't make are left, with the folder.
A path that isn't an export folder is refused (listed under errors).
Request body
Responses
POST /api/file-access/files
List Files
Description
A page of a selection's files, one row per file as stored (a file
several records use is one row: uses lists those records, each with the
names of the records above it, trail; others counts the records
outside the selection that use it too), each with where it is (place: a
drive's name, server or missing; place_kind: drive, unreachable,
server or missing), narrowed by place, name (the file's, or any record's
it sits under) and the selection's own filter; and summary, where all
of the selection's files are, by place. Counts are of files.
Request body
{
"base": null,
"below": true,
"collection": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"kinds": null,
"layout": "tree",
"limit": 0,
"name": null,
"offset": 0,
"order": "string",
"place": null,
"record_ids": null,
"schema_name": null,
"search": null,
"shas": null,
"sort": null,
"tables": null,
"used_by": null,
"view": null,
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"limit": {
"default": 100,
"maximum": 1000.0,
"minimum": 1.0,
"title": "Limit",
"type": "integer"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files whose name, or whose record's name, contains this.",
"title": "Name"
},
"offset": {
"default": 0,
"minimum": 0.0,
"title": "Offset",
"type": "integer"
},
"order": {
"default": "path",
"description": "path, name, size, record or place; a leading '-' reverses it.",
"title": "Order",
"type": "string"
},
"place": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't).",
"title": "Place"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"shas": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 100000,
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked.",
"title": "Shas"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"used_by": {
"anyOf": [
{
"items": {
"type": "integer"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only files used by exactly one of these numbers of live records (anywhere, not only in the selection).",
"title": "Used By"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"title": "FileListRequest",
"type": "object"
}
Responses
POST /api/file-access/free-up
Free Up Files
Description
Remove this computer's copies of the picked files to free space; each
comes back when opened or exported. Only files the server confirms it
holds, and never one a collection kept on this computer uses (switch that
collection to fetch when opened first). Counts unless dry_run=false.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
dry_run |
query | boolean | True | No | Only count (the default). |
Request body
{
"base": null,
"below": true,
"collection": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"kinds": null,
"layout": "tree",
"name": null,
"place": null,
"record_ids": null,
"schema_name": null,
"search": null,
"shas": null,
"sort": null,
"tables": null,
"used_by": null,
"view": null,
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files whose name, or whose record's name, contains this.",
"title": "Name"
},
"place": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't).",
"title": "Place"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"shas": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 100000,
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked.",
"title": "Shas"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"used_by": {
"anyOf": [
{
"items": {
"type": "integer"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only files used by exactly one of these numbers of live records (anywhere, not only in the selection).",
"title": "Used By"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"title": "FilePickRequest",
"type": "object"
}
Responses
POST /api/file-access/gather
Gather Files
Description
Move the picked files onto one drive: a selection's files, narrowed by
place, name or ticked files (shas). Only those move; the rest of their
collections stay where they are. Files only on the server are downloaded
first; files on a drive that can't be reached, or missing, are left out. It
runs like any other move (one at a time, safe to pause, cancel or lose
power; see /store/transfers). Files downloaded straight onto the drive need
no move: when nothing else has to move, transfer_id is null and
downloaded says how many came. Files that records not picked also use
stay where they are unless include_shared (shared_left says how
many). With dry_run, only plan is answered and nothing is done. 422
when they are all already there.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
dry_run |
query | boolean | False | No | Only say what the move would do. |
Request body
{
"base": null,
"below": true,
"collection": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"include_shared": true,
"kinds": null,
"layout": "tree",
"name": null,
"place": null,
"record_ids": null,
"schema_name": null,
"search": null,
"shas": null,
"sort": null,
"tables": null,
"used_by": null,
"view": null,
"volume": "string",
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"include_shared": {
"default": false,
"description": "Also move files that records not picked use (they move for those records too). By default those stay where they are.",
"title": "Include Shared",
"type": "boolean"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files whose name, or whose record's name, contains this.",
"title": "Name"
},
"place": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't).",
"title": "Place"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"shas": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 100000,
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked.",
"title": "Shas"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"used_by": {
"anyOf": [
{
"items": {
"type": "integer"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only files used by exactly one of these numbers of live records (anywhere, not only in the selection).",
"title": "Used By"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"volume": {
"description": "The drive (volume name) to gather the selection's files onto. Only the files in the selection move, not the rest of their collections.",
"title": "Volume",
"type": "string"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"required": [
"volume"
],
"title": "FileGatherRequest",
"type": "object"
}
Responses
POST /api/file-access/plan
Plan Files
Description
What a selection holds, each file named by its place in the record hierarchy, and what can be reached right now. Makes nothing: this is what to show a person before they are pointed at a folder.
Request body
{
"base": null,
"below": true,
"collection": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"include_items": true,
"kinds": null,
"layout": "tree",
"limit": null,
"offset": 0,
"record_ids": null,
"schema_name": null,
"search": null,
"sort": null,
"tables": null,
"view": null,
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"include_items": {
"default": true,
"description": "Send the files too, not just the totals.",
"title": "Include Items",
"type": "boolean"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"limit": {
"anyOf": [
{
"maximum": 5000.0,
"minimum": 1.0,
"type": "integer"
},
{
"type": "null"
}
],
"description": "How many files to send.",
"title": "Limit"
},
"offset": {
"default": 0,
"description": "First file to send.",
"minimum": 0.0,
"title": "Offset",
"type": "integer"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"title": "FilePlanRequest",
"type": "object"
}
Responses
GET /api/file-access/progress/{progress_id}
Get Progress
Description
How far a request tagged with this id has got: the stage it is in, how many steps it has done of how many (0 when that isn't known yet), and whether it has finished. 404 until the request has begun, and again a little after it ends.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
progress_id |
path | string | No |
Responses
POST /api/file-access/zip
Zip Files
Description
The selection as something to download, with the same paths and tables as
an export -- for someone who can't see the server's disk: a zip of the files
and their tables, or, when the selection is a single table and nothing else,
that table itself. Unreachable files answer 409 unless allow_partial is
set, and are then listed in MISSING.txt.
Request body
{
"allow_partial": true,
"base": null,
"below": true,
"collection": null,
"export": null,
"fields": null,
"files": true,
"filter": null,
"kinds": null,
"layout": "tree",
"name": null,
"record_ids": null,
"schema_name": null,
"search": null,
"sort": null,
"tables": null,
"view": null,
"where": [
"string"
],
"with_within": true,
"within": null
}
Schema of the request body
{
"properties": {
"allow_partial": {
"default": false,
"description": "Zip what can be reached; the archive then holds MISSING.txt.",
"title": "Allow Partial",
"type": "boolean"
},
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix) that paths start below; defaults to 'within'.",
"title": "Base"
},
"below": {
"default": false,
"description": "Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files.",
"title": "Below",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this collection.",
"title": "Collection"
},
"export": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has.",
"title": "Export"
},
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these file fields; omit for every one.",
"title": "Fields"
},
"files": {
"default": true,
"description": "False takes the tables alone, with no files (needs 'tables').",
"title": "Files",
"type": "boolean"
},
"filter": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter tree, as for listing records.",
"title": "Filter"
},
"kinds": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree.",
"title": "Kinds"
},
"layout": {
"default": "tree",
"description": "'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Layout",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Names the download: <name>.zip. Defaults to 'files'.",
"title": "Name"
},
"record_ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Exactly these records (the rows ticked in a list); the other selectors are then ignored.",
"title": "Record Ids"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only records of this schema.",
"title": "Schema Name"
},
"search": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Full-text search.",
"title": "Search"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...].",
"title": "Sort"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them.",
"title": "Tables"
},
"view": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it).",
"title": "View"
},
"where": {
"description": "'field=value' terms.",
"items": {
"type": "string"
},
"title": "Where",
"type": "array"
},
"with_within": {
"default": false,
"description": "With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too).",
"title": "With Within",
"type": "boolean"
},
"within": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it.",
"title": "Within"
}
},
"title": "FileZipRequest",
"type": "object"
}
Responses
POST /api/files
Upload File
Description
Upload a multipart file. Starlette has already spooled the body to a temp file by the time this runs; it is hashed and copied into the object store 1 MiB at a time, so memory use is independent of file size.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection |
query | No | Id of the collection the file is for. It only steers which volume receives *new* content (the collection's home volume, if it has one); a file whose content is already stored is reused where it lives, never copied again. |
Request body
Responses
Schema of the response body
{
"properties": {
"filename": {
"title": "Filename",
"type": "string"
},
"sha256": {
"title": "Sha256",
"type": "string"
},
"size": {
"title": "Size",
"type": "integer"
},
"volume": {
"default": "default",
"title": "Volume",
"type": "string"
}
},
"required": [
"sha256",
"filename",
"size"
],
"title": "FileRefResponse",
"type": "object"
}
PUT /api/files/stream
Upload File Stream
Description
Upload a raw (non-multipart) request body, streamed straight to the object store instead of buffered in memory first. A multipart body sent via POST / has to be fully spooled to a temp file by Starlette's form parser before this code ever runs -- reading it back into memory here would mean the bytes touch disk twice for no reason. Sending the raw body instead lets us read it directly off the wire in chunks, and (unlike multipart, where per-part sizes aren't available upfront) a raw body carries an accurate Content-Length the object store can use to pick a volume with enough room before writing a single byte.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection |
query | No | Id of the collection the file is for. It only steers which volume receives *new* content (the collection's home volume, if it has one); a file whose content is already stored is reused where it lives, never copied again. | ||
filename |
query | string | upload | No |
Responses
Schema of the response body
{
"properties": {
"filename": {
"title": "Filename",
"type": "string"
},
"sha256": {
"title": "Sha256",
"type": "string"
},
"size": {
"title": "Size",
"type": "integer"
},
"volume": {
"default": "default",
"title": "Volume",
"type": "string"
}
},
"required": [
"sha256",
"filename",
"size"
],
"title": "FileRefResponse",
"type": "object"
}
GET /api/files/{sha256}
Download File
Description
Fetch raw file bytes by content hash.
This endpoint is content-addressed only — it has no notion of which
record/field a download is "for", so it can't apply a filename_template
resolution itself. Callers that want a resolved Content-Disposition
filename (e.g. scripted access) should read resolved_filename off the
record via the records API and pass it as ?filename=; the record-UI
download link does this implicitly via the download attribute.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
filename |
query | string | No | ||
sha256 |
path | string | No |
Responses
GET /api/files/{sha256}/info
File Info
Description
Where a file's content is stored and what uses it.
Lists every place the content is, or is recorded to be (each volume, its state, and the object's path on it, including a volume that is unplugged right now), the size, and the records, collections and workflow runs that use it. A file used by several records is stored once, so this is how to see everything that shares it.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
sha256 |
path | string | No |
Responses
{
"collections": [
{
"id": "string",
"name": null,
"records": 0
}
],
"copies": [
{
"network": true,
"path": "string",
"present": null,
"state": "string",
"volume": "string"
}
],
"deleted_records": 0,
"jobs": 0,
"records": 0,
"sha256": "string",
"size": null,
"uses": [
{
"collection": null,
"id": "string",
"name": "string",
"trail": [
"string"
]
}
]
}
Schema of the response body
{
"properties": {
"collections": {
"items": {
"$ref": "#/components/schemas/CollectionUseResponse"
},
"title": "Collections",
"type": "array"
},
"copies": {
"description": "Every place the content is, or is recorded to be.",
"items": {
"$ref": "#/components/schemas/FileCopyResponse"
},
"title": "Copies",
"type": "array"
},
"deleted_records": {
"default": 0,
"description": "Deleted records that still reference it: they keep it while they can be restored, but don't count as using it.",
"title": "Deleted Records",
"type": "integer"
},
"jobs": {
"description": "Workflow runs that took it as an input.",
"title": "Jobs",
"type": "integer"
},
"records": {
"description": "Live records that use this file, across all collections.",
"title": "Records",
"type": "integer"
},
"sha256": {
"title": "Sha256",
"type": "string"
},
"size": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Size in bytes, if known.",
"title": "Size"
},
"uses": {
"description": "The live records that use it, named, with the records above each (at most 200; `records` is the full count).",
"items": {
"$ref": "#/components/schemas/RecordUseResponse"
},
"title": "Uses",
"type": "array"
}
},
"required": [
"sha256",
"size",
"copies",
"records",
"jobs",
"collections"
],
"title": "FileInfoResponse",
"type": "object"
}
legal
GET /api/legal/license
Get License
Description
The software's own license text -- independent of any project, so this doesn't go through Depends(get_ctx).
Responses
GET /api/legal/policies
List Policies
Description
Org-authored data/governance policy documents from _civex/policies/.
Responses
GET /api/legal/policies/{stem}
Get Policy
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
stem |
path | string | No |
Responses
plugins
GET /api/plugins
List Plugins
Description
List all registered plugins (built-ins + user plugins from _civex/plugins/).
Responses
[
{
"builtin": true,
"capabilities": [
"string"
],
"category": "string",
"config_schema": {},
"description": "string",
"filename": null,
"id": "string",
"inputs": null,
"name": "string",
"outputs": null
}
]
POST /api/plugins
Save Plugin Json
Description
Save a plugin from JSON source (used by the AI confirmation UI and the Tier 1 plugin editor). Writes the file, then re-registers it -- which describes it in the same request, so a broken contract surfaces immediately as an error response rather than only on next use.
Request body
Responses
GET /api/plugins/containers
List Container Plugins
Description
List Tier 2 (container) plugin directories under _civex/plugins/.
Responses
GET /api/plugins/containers/{name}
Get Container Plugin
Description
Full file tree (Dockerfile + source) of a container plugin.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
PUT /api/plugins/containers/{name}
Save Container Plugin File
Description
Save one file in the plugin's directory, then rebuild its Docker image immediately -- the multi-file equivalent of Tier 1's save-triggers- describe round-trip.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Responses
GET /api/plugins/errors
List Plugin Load Errors
Description
List user plugin files that failed discovery -- these have no plugin id and so never appear in GET /plugins, but the frontend plugin panel still needs to show why they're missing.
Responses
POST /api/plugins/upload
Upload Plugin
Description
Upload a .py plugin file into _civex/plugins/ and register it immediately.
Request body
Responses
DELETE /api/plugins/{filename}
Delete Plugin
Description
Delete a user plugin file. Refuses to delete built-ins (they have no
file to delete, and 404) and any plugin still referenced by a workflow
step (409), unless force is set.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
filename |
path | string | No | ||
force |
query | boolean | False | No |
Responses
GET /api/plugins/{filename}/source
Get Plugin Source
Description
Read a single user plugin's raw source, e.g. to populate the editor.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
filename |
path | string | No |
Responses
sync
GET /api/remote
Status
Description
How this project stands with its authority.
Responses
{
"configured": true,
"connect_error": null,
"connecting": true,
"download_files": "string",
"files_to_fetch": 0,
"interval_seconds": 0,
"last_error": null,
"last_error_at": null,
"last_result": null,
"last_synced_at": null,
"open_conflicts": 0,
"paused": true,
"pending": 0,
"progress": null,
"project_id": "string",
"remote": null,
"running": true,
"serving": true
}
Schema of the response body
{
"properties": {
"configured": {
"description": "Whether this project follows an authority.",
"title": "Configured",
"type": "boolean"
},
"connect_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last connect started here failed.",
"title": "Connect Error"
},
"connecting": {
"default": false,
"description": "A connect started here is still running.",
"title": "Connecting",
"type": "boolean"
},
"download_files": {
"description": "Which files this device keeps a copy of: all, or opened.",
"title": "Download Files",
"type": "string"
},
"files_to_fetch": {
"description": "Files records here cite that aren't on this computer yet.",
"title": "Files To Fetch",
"type": "integer"
},
"interval_seconds": {
"description": "How often it looks for changes; 0 means only when asked.",
"title": "Interval Seconds",
"type": "integer"
},
"last_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last attempt failed, if it did.",
"title": "Last Error"
},
"last_error_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Error At"
},
"last_result": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncResultResponse"
},
{
"type": "null"
}
],
"description": "What the last sync run by this server did; null after a restart or before the first one."
},
"last_synced_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Synced At"
},
"open_conflicts": {
"description": "Values that did not go in as made.",
"title": "Open Conflicts",
"type": "integer"
},
"paused": {
"description": "The schedule is stopped; Sync now still works.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Changes made here that have not been sent.",
"title": "Pending",
"type": "integer"
},
"progress": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncProgressResponse"
},
{
"type": "null"
}
],
"description": "How far a long step has got while one runs here: copying the project from the authority, filling an empty one, or fetching the history from before joining."
},
"project_id": {
"title": "Project Id",
"type": "string"
},
"remote": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The authority's address.",
"title": "Remote"
},
"running": {
"description": "A sync is in progress right now.",
"title": "Running",
"type": "boolean"
},
"serving": {
"description": "This project is itself an authority.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"configured",
"remote",
"project_id",
"paused",
"interval_seconds",
"serving",
"pending",
"open_conflicts",
"last_synced_at",
"last_error",
"last_error_at",
"running",
"download_files",
"files_to_fetch"
],
"title": "RemoteStatusResponse",
"type": "object"
}
PATCH /api/remote
Update
Description
Pause or resume the schedule, change how often it looks, or choose which files this device keeps a copy of.
Request body
Schema of the request body
{
"properties": {
"download_files": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Keep a copy of every file (all), or only of files opened or exported (opened).",
"title": "Download Files"
},
"interval_seconds": {
"anyOf": [
{
"minimum": 0.0,
"type": "integer"
},
{
"type": "null"
}
],
"description": "Seconds between looks for changes; 0 = never (only when asked).",
"title": "Interval Seconds"
},
"paused": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Stop or start the schedule.",
"title": "Paused"
}
},
"title": "RemoteUpdateRequest",
"type": "object"
}
Responses
{
"configured": true,
"connect_error": null,
"connecting": true,
"download_files": "string",
"files_to_fetch": 0,
"interval_seconds": 0,
"last_error": null,
"last_error_at": null,
"last_result": null,
"last_synced_at": null,
"open_conflicts": 0,
"paused": true,
"pending": 0,
"progress": null,
"project_id": "string",
"remote": null,
"running": true,
"serving": true
}
Schema of the response body
{
"properties": {
"configured": {
"description": "Whether this project follows an authority.",
"title": "Configured",
"type": "boolean"
},
"connect_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last connect started here failed.",
"title": "Connect Error"
},
"connecting": {
"default": false,
"description": "A connect started here is still running.",
"title": "Connecting",
"type": "boolean"
},
"download_files": {
"description": "Which files this device keeps a copy of: all, or opened.",
"title": "Download Files",
"type": "string"
},
"files_to_fetch": {
"description": "Files records here cite that aren't on this computer yet.",
"title": "Files To Fetch",
"type": "integer"
},
"interval_seconds": {
"description": "How often it looks for changes; 0 means only when asked.",
"title": "Interval Seconds",
"type": "integer"
},
"last_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last attempt failed, if it did.",
"title": "Last Error"
},
"last_error_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Error At"
},
"last_result": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncResultResponse"
},
{
"type": "null"
}
],
"description": "What the last sync run by this server did; null after a restart or before the first one."
},
"last_synced_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Synced At"
},
"open_conflicts": {
"description": "Values that did not go in as made.",
"title": "Open Conflicts",
"type": "integer"
},
"paused": {
"description": "The schedule is stopped; Sync now still works.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Changes made here that have not been sent.",
"title": "Pending",
"type": "integer"
},
"progress": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncProgressResponse"
},
{
"type": "null"
}
],
"description": "How far a long step has got while one runs here: copying the project from the authority, filling an empty one, or fetching the history from before joining."
},
"project_id": {
"title": "Project Id",
"type": "string"
},
"remote": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The authority's address.",
"title": "Remote"
},
"running": {
"description": "A sync is in progress right now.",
"title": "Running",
"type": "boolean"
},
"serving": {
"description": "This project is itself an authority.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"configured",
"remote",
"project_id",
"paused",
"interval_seconds",
"serving",
"pending",
"open_conflicts",
"last_synced_at",
"last_error",
"last_error_at",
"running",
"download_files",
"files_to_fetch"
],
"title": "RemoteStatusResponse",
"type": "object"
}
GET /api/remote/authority
Authority
Description
Whether this project accepts devices, the devices that joined, and the invites waiting.
Responses
{
"devices": [
{
"created_at": "string",
"fingerprint": "string",
"last_seen_at": null,
"may_publish": true,
"name": "string",
"revoked": true
}
],
"fingerprint": null,
"invites": [
{
"created_at": "string",
"expires_at": "string",
"name": "string"
}
],
"library": "string",
"serving": true
}
Schema of the response body
{
"properties": {
"devices": {
"description": "The devices that joined.",
"items": {
"$ref": "#/components/schemas/DeviceResponse"
},
"title": "Devices",
"type": "array"
},
"fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "This authority's key's short code; null until it first invites.",
"title": "Fingerprint"
},
"invites": {
"description": "Invites not used yet and not expired.",
"items": {
"$ref": "#/components/schemas/InviteResponse"
},
"title": "Invites",
"type": "array"
},
"library": {
"default": "workflows",
"description": "What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code).",
"title": "Library",
"type": "string"
},
"serving": {
"description": "This project accepts devices.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"serving",
"fingerprint",
"devices",
"invites"
],
"title": "AuthorityResponse",
"type": "object"
}
PATCH /api/remote/authority
Update Authority
Description
Start or stop accepting devices (the devices stay on record), and say what the library takes from them.
Request body
Schema of the request body
{
"properties": {
"library": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "off, workflows or all: what the library takes.",
"title": "Library"
},
"serving": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Accept devices, or stop accepting them.",
"title": "Serving"
}
},
"title": "AuthorityUpdateRequest",
"type": "object"
}
Responses
{
"devices": [
{
"created_at": "string",
"fingerprint": "string",
"last_seen_at": null,
"may_publish": true,
"name": "string",
"revoked": true
}
],
"fingerprint": null,
"invites": [
{
"created_at": "string",
"expires_at": "string",
"name": "string"
}
],
"library": "string",
"serving": true
}
Schema of the response body
{
"properties": {
"devices": {
"description": "The devices that joined.",
"items": {
"$ref": "#/components/schemas/DeviceResponse"
},
"title": "Devices",
"type": "array"
},
"fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "This authority's key's short code; null until it first invites.",
"title": "Fingerprint"
},
"invites": {
"description": "Invites not used yet and not expired.",
"items": {
"$ref": "#/components/schemas/InviteResponse"
},
"title": "Invites",
"type": "array"
},
"library": {
"default": "workflows",
"description": "What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code).",
"title": "Library",
"type": "string"
},
"serving": {
"description": "This project accepts devices.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"serving",
"fingerprint",
"devices",
"invites"
],
"title": "AuthorityResponse",
"type": "object"
}
POST /api/remote/authority/devices/{name}/publish
Allow Publish
Description
Let a device publish to the library, or stop it.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Responses
{
"devices": [
{
"created_at": "string",
"fingerprint": "string",
"last_seen_at": null,
"may_publish": true,
"name": "string",
"revoked": true
}
],
"fingerprint": null,
"invites": [
{
"created_at": "string",
"expires_at": "string",
"name": "string"
}
],
"library": "string",
"serving": true
}
Schema of the response body
{
"properties": {
"devices": {
"description": "The devices that joined.",
"items": {
"$ref": "#/components/schemas/DeviceResponse"
},
"title": "Devices",
"type": "array"
},
"fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "This authority's key's short code; null until it first invites.",
"title": "Fingerprint"
},
"invites": {
"description": "Invites not used yet and not expired.",
"items": {
"$ref": "#/components/schemas/InviteResponse"
},
"title": "Invites",
"type": "array"
},
"library": {
"default": "workflows",
"description": "What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code).",
"title": "Library",
"type": "string"
},
"serving": {
"description": "This project accepts devices.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"serving",
"fingerprint",
"devices",
"invites"
],
"title": "AuthorityResponse",
"type": "object"
}
POST /api/remote/authority/devices/{name}/revoke
Revoke Device
Description
Stop a device syncing, at once: its session is refused from now on.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"devices": [
{
"created_at": "string",
"fingerprint": "string",
"last_seen_at": null,
"may_publish": true,
"name": "string",
"revoked": true
}
],
"fingerprint": null,
"invites": [
{
"created_at": "string",
"expires_at": "string",
"name": "string"
}
],
"library": "string",
"serving": true
}
Schema of the response body
{
"properties": {
"devices": {
"description": "The devices that joined.",
"items": {
"$ref": "#/components/schemas/DeviceResponse"
},
"title": "Devices",
"type": "array"
},
"fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "This authority's key's short code; null until it first invites.",
"title": "Fingerprint"
},
"invites": {
"description": "Invites not used yet and not expired.",
"items": {
"$ref": "#/components/schemas/InviteResponse"
},
"title": "Invites",
"type": "array"
},
"library": {
"default": "workflows",
"description": "What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code).",
"title": "Library",
"type": "string"
},
"serving": {
"description": "This project accepts devices.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"serving",
"fingerprint",
"devices",
"invites"
],
"title": "AuthorityResponse",
"type": "object"
}
POST /api/remote/authority/invites
Invite Device
Description
Invite a device. The answer is the only time the invite is shown.
Request body
Schema of the request body
Responses
{
"devices": [
{
"created_at": "string",
"fingerprint": "string",
"last_seen_at": null,
"may_publish": true,
"name": "string",
"revoked": true
}
],
"fingerprint": null,
"invite": "string",
"invites": [
{
"created_at": "string",
"expires_at": "string",
"name": "string"
}
],
"library": "string",
"serving": true
}
Schema of the response body
{
"properties": {
"devices": {
"description": "The devices that joined.",
"items": {
"$ref": "#/components/schemas/DeviceResponse"
},
"title": "Devices",
"type": "array"
},
"fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "This authority's key's short code; null until it first invites.",
"title": "Fingerprint"
},
"invite": {
"description": "The invite, for the device to connect with. Shown once: only its hash is kept. It works once.",
"title": "Invite",
"type": "string"
},
"invites": {
"description": "Invites not used yet and not expired.",
"items": {
"$ref": "#/components/schemas/InviteResponse"
},
"title": "Invites",
"type": "array"
},
"library": {
"default": "workflows",
"description": "What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code).",
"title": "Library",
"type": "string"
},
"serving": {
"description": "This project accepts devices.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"serving",
"fingerprint",
"devices",
"invites",
"invite"
],
"title": "InvitedResponse",
"type": "object"
}
POST /api/remote/authority/invites/{name}/cancel
Cancel Invite
Description
Cancel a device's invite before it is used.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"devices": [
{
"created_at": "string",
"fingerprint": "string",
"last_seen_at": null,
"may_publish": true,
"name": "string",
"revoked": true
}
],
"fingerprint": null,
"invites": [
{
"created_at": "string",
"expires_at": "string",
"name": "string"
}
],
"library": "string",
"serving": true
}
Schema of the response body
{
"properties": {
"devices": {
"description": "The devices that joined.",
"items": {
"$ref": "#/components/schemas/DeviceResponse"
},
"title": "Devices",
"type": "array"
},
"fingerprint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "This authority's key's short code; null until it first invites.",
"title": "Fingerprint"
},
"invites": {
"description": "Invites not used yet and not expired.",
"items": {
"$ref": "#/components/schemas/InviteResponse"
},
"title": "Invites",
"type": "array"
},
"library": {
"default": "workflows",
"description": "What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code).",
"title": "Library",
"type": "string"
},
"serving": {
"description": "This project accepts devices.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"serving",
"fingerprint",
"devices",
"invites"
],
"title": "AuthorityResponse",
"type": "object"
}
GET /api/remote/conflicts
Conflicts
Description
Values that did not go in as made, with both sides.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
record |
query | No | Only conflicts about this record or thing. | ||
status |
query | open | No | open, resolved, or all. |
Responses
[
{
"also_saved": [
{}
],
"attempted": null,
"base": null,
"changes": [
{}
],
"created_at": "string",
"current": null,
"dataset_name": null,
"device_name": null,
"dtype": null,
"entity_id": "string",
"entity_type": "string",
"field": null,
"field_label": null,
"id": "string",
"kind": "string",
"message": null,
"record_deleted": true,
"record_name": null,
"resolution": null,
"resolved_at": null,
"schema_name": null,
"sits_under": [
{}
],
"stale": true,
"status": "string",
"takes": [
"string"
],
"theirs": null,
"theirs_actor": null,
"theirs_at": null,
"theirs_device": null,
"yours": null
}
]
POST /api/remote/conflicts/reopen
Reopen
Description
Open conflicts again that were settled with theirs (an undo: that choice
changed nothing). Others are ignored; undo those from Activity.
Request body
Responses
Schema of the response body
POST /api/remote/conflicts/resolve-many
Resolve Many
Description
Settle every open conflict that matches (the given ids, kind and record; all
of them if none is given) the same way, in one request. Conflicts that don't
offer that way, or fail their checks, stay open and are counted or listed: the
rest are still settled. dry_run only counts.
Request body
Schema of the request body
{
"properties": {
"dry_run": {
"default": false,
"description": "Only count what would be settled; change nothing.",
"title": "Dry Run",
"type": "boolean"
},
"force": {
"default": false,
"description": "For `mine`: put values back even where the record's value changed since.",
"title": "Force",
"type": "boolean"
},
"ids": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Only these conflicts. Omit for all that match.",
"title": "Ids"
},
"kind": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only this kind: conflict, rejected or edit_vs_delete.",
"title": "Kind"
},
"record_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only conflicts about this record.",
"title": "Record Id"
},
"take": {
"description": "How to settle each one: `theirs`, `mine`, `delete` or `retry` (see the single resolve). `value` is not offered: it needs a value each.",
"title": "Take",
"type": "string"
}
},
"required": [
"take"
],
"title": "ResolveManyRequest",
"type": "object"
}
Responses
{
"done": 0,
"failed": [
{
"id": "string",
"message": "string"
}
],
"not_offered": 0,
"settled_ids": [
"string"
]
}
Schema of the response body
{
"properties": {
"done": {
"description": "Settled (with `dry_run`, how many would be).",
"title": "Done",
"type": "integer"
},
"failed": {
"description": "Left open because they failed their checks; the rest were settled.",
"items": {
"$ref": "#/components/schemas/ResolveFailure"
},
"title": "Failed",
"type": "array"
},
"not_offered": {
"description": "Left open because they don't offer that way of settling.",
"title": "Not Offered",
"type": "integer"
},
"settled_ids": {
"description": "Which were settled (empty for `dry_run`); `reopen` takes them back if the way was `theirs`.",
"items": {
"type": "string"
},
"title": "Settled Ids",
"type": "array"
}
},
"required": [
"done",
"settled_ids",
"not_offered",
"failed"
],
"title": "ResolveManyResponse",
"type": "object"
}
POST /api/remote/conflicts/{conflict_id}/resolve
Resolve
Description
Settle a conflict. Putting a value back is an ordinary edit (checked, in the
history, synced); it answers 409 with what is there now when the record's value
changed since the conflict was recorded, unless force.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
conflict_id |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"force": {
"default": false,
"description": "Put the value back even though the record's value changed since the conflict was recorded.",
"title": "Force",
"type": "boolean"
},
"take": {
"description": "`theirs` keeps what the authority has (or lets a refused change go); `mine` puts your value back as a new edit; `value` puts the one in `value`; `delete` deletes a record that was deleted there; `retry` sends a refused change again from the record as it is now; `restore_above` brings back the deleted records a refused record sits under, then sends it again; `edited` closes a clash because the field was just set by hand on the record.",
"title": "Take",
"type": "string"
},
"value": {
"description": "The value, for `take: value`.",
"title": "Value"
}
},
"required": [
"take"
],
"title": "ResolveRequest",
"type": "object"
}
Responses
{
"configured": true,
"connect_error": null,
"connecting": true,
"download_files": "string",
"files_to_fetch": 0,
"interval_seconds": 0,
"last_error": null,
"last_error_at": null,
"last_result": null,
"last_synced_at": null,
"open_conflicts": 0,
"paused": true,
"pending": 0,
"progress": null,
"project_id": "string",
"remote": null,
"running": true,
"serving": true
}
Schema of the response body
{
"properties": {
"configured": {
"description": "Whether this project follows an authority.",
"title": "Configured",
"type": "boolean"
},
"connect_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last connect started here failed.",
"title": "Connect Error"
},
"connecting": {
"default": false,
"description": "A connect started here is still running.",
"title": "Connecting",
"type": "boolean"
},
"download_files": {
"description": "Which files this device keeps a copy of: all, or opened.",
"title": "Download Files",
"type": "string"
},
"files_to_fetch": {
"description": "Files records here cite that aren't on this computer yet.",
"title": "Files To Fetch",
"type": "integer"
},
"interval_seconds": {
"description": "How often it looks for changes; 0 means only when asked.",
"title": "Interval Seconds",
"type": "integer"
},
"last_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last attempt failed, if it did.",
"title": "Last Error"
},
"last_error_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Error At"
},
"last_result": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncResultResponse"
},
{
"type": "null"
}
],
"description": "What the last sync run by this server did; null after a restart or before the first one."
},
"last_synced_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Synced At"
},
"open_conflicts": {
"description": "Values that did not go in as made.",
"title": "Open Conflicts",
"type": "integer"
},
"paused": {
"description": "The schedule is stopped; Sync now still works.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Changes made here that have not been sent.",
"title": "Pending",
"type": "integer"
},
"progress": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncProgressResponse"
},
{
"type": "null"
}
],
"description": "How far a long step has got while one runs here: copying the project from the authority, filling an empty one, or fetching the history from before joining."
},
"project_id": {
"title": "Project Id",
"type": "string"
},
"remote": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The authority's address.",
"title": "Remote"
},
"running": {
"description": "A sync is in progress right now.",
"title": "Running",
"type": "boolean"
},
"serving": {
"description": "This project is itself an authority.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"configured",
"remote",
"project_id",
"paused",
"interval_seconds",
"serving",
"pending",
"open_conflicts",
"last_synced_at",
"last_error",
"last_error_at",
"running",
"download_files",
"files_to_fetch"
],
"title": "RemoteStatusResponse",
"type": "object"
}
POST /api/remote/connect
Connect
Description
Point this project at an authority. An empty project becomes a copy of it; a project with data fills an empty authority; two with data are refused.
The address, the invite and who holds data are checked before this answers
(an invite is used up here: this computer joins the authority), so a
mistake is said at once. Copying can take a long time, so it then runs in
the background: GET /remote says how far it has got (progress), and why
it stopped if it did (connect_error).
Request body
Schema of the request body
{
"properties": {
"invite": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The invite the authority's admin gave. Leave out when this computer has joined that address before (trying a connect again).",
"title": "Invite"
},
"url": {
"description": "The authority's address.",
"title": "Url",
"type": "string"
}
},
"required": [
"url"
],
"title": "RemoteConnectRequest",
"type": "object"
}
Responses
Schema of the response body
POST /api/remote/disconnect
Disconnect
Description
Stop following the authority. The data here stays.
Responses
{
"configured": true,
"connect_error": null,
"connecting": true,
"download_files": "string",
"files_to_fetch": 0,
"interval_seconds": 0,
"last_error": null,
"last_error_at": null,
"last_result": null,
"last_synced_at": null,
"open_conflicts": 0,
"paused": true,
"pending": 0,
"progress": null,
"project_id": "string",
"remote": null,
"running": true,
"serving": true
}
Schema of the response body
{
"properties": {
"configured": {
"description": "Whether this project follows an authority.",
"title": "Configured",
"type": "boolean"
},
"connect_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last connect started here failed.",
"title": "Connect Error"
},
"connecting": {
"default": false,
"description": "A connect started here is still running.",
"title": "Connecting",
"type": "boolean"
},
"download_files": {
"description": "Which files this device keeps a copy of: all, or opened.",
"title": "Download Files",
"type": "string"
},
"files_to_fetch": {
"description": "Files records here cite that aren't on this computer yet.",
"title": "Files To Fetch",
"type": "integer"
},
"interval_seconds": {
"description": "How often it looks for changes; 0 means only when asked.",
"title": "Interval Seconds",
"type": "integer"
},
"last_error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the last attempt failed, if it did.",
"title": "Last Error"
},
"last_error_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Error At"
},
"last_result": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncResultResponse"
},
{
"type": "null"
}
],
"description": "What the last sync run by this server did; null after a restart or before the first one."
},
"last_synced_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Last Synced At"
},
"open_conflicts": {
"description": "Values that did not go in as made.",
"title": "Open Conflicts",
"type": "integer"
},
"paused": {
"description": "The schedule is stopped; Sync now still works.",
"title": "Paused",
"type": "boolean"
},
"pending": {
"description": "Changes made here that have not been sent.",
"title": "Pending",
"type": "integer"
},
"progress": {
"anyOf": [
{
"$ref": "#/components/schemas/SyncProgressResponse"
},
{
"type": "null"
}
],
"description": "How far a long step has got while one runs here: copying the project from the authority, filling an empty one, or fetching the history from before joining."
},
"project_id": {
"title": "Project Id",
"type": "string"
},
"remote": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The authority's address.",
"title": "Remote"
},
"running": {
"description": "A sync is in progress right now.",
"title": "Running",
"type": "boolean"
},
"serving": {
"description": "This project is itself an authority.",
"title": "Serving",
"type": "boolean"
}
},
"required": [
"configured",
"remote",
"project_id",
"paused",
"interval_seconds",
"serving",
"pending",
"open_conflicts",
"last_synced_at",
"last_error",
"last_error_at",
"running",
"download_files",
"files_to_fetch"
],
"title": "RemoteStatusResponse",
"type": "object"
}
GET /api/remote/files
Collection Files
Description
Each collection's files on this computer: how many are here and their size, how many are only on the server, and whether it keeps a copy here.
Responses
PATCH /api/remote/files/{collection}
Set Collection Mode
Description
Keep a collection's files on this computer, fetch them only when opened, or follow the project's setting. Keeping starts the background download of what is missing.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection |
path | string | No |
Request body
Responses
POST /api/remote/files/{collection}/free-up
Free Up
Description
Remove this computer's copies of a collection's files to free space;
they are fetched again when opened. Only files the server confirms it
holds, and never one a collection kept here also uses. Counts first unless
dry_run=false, which also sets the collection to fetch when opened.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection |
path | string | No | ||
dry_run |
query | boolean | True | No | Only count (the default). |
Responses
Schema of the response body
{
"properties": {
"bytes": {
"description": "The space that frees.",
"title": "Bytes",
"type": "integer"
},
"done": {
"description": "False when only counted.",
"title": "Done",
"type": "boolean"
},
"files": {
"description": "Copies removed (or that would be, counting).",
"title": "Files",
"type": "integer"
},
"kept_shared": {
"description": "Kept: also used by a collection kept on this computer.",
"title": "Kept Shared",
"type": "integer"
},
"not_on_server": {
"description": "Kept: the server hasn't got them yet (never sent).",
"title": "Not On Server",
"type": "integer"
}
},
"required": [
"files",
"bytes",
"kept_shared",
"not_on_server",
"done"
],
"title": "FreeUpResponse",
"type": "object"
}
GET /api/remote/library
Library
Description
The workflows and plugins shared through the authority (the newest version of each, with its history), and where each stands here. Empty when this project shares with no server.
Responses
[
{
"content": null,
"description": null,
"filename": "string",
"here": null,
"history": [
{
"pins": {},
"published_at": null,
"published_by": null,
"sha256": "string",
"version": 0
}
],
"kind": "string",
"local_version": null,
"missing": [
"string"
],
"name": "string",
"needs": [
"string"
],
"pins": {},
"provides": null,
"published_at": null,
"published_by": null,
"sha256": "string",
"size": 0,
"title": null,
"triggers": [
"string"
],
"version": 0
}
]
POST /api/remote/library/publish
Publish To Library
Description
Publish a workflow (with the plugins it uses, which it is pinned to) or a plugin from this project to the library. New text is the next version.
Request body
Schema of the request body
{
"properties": {
"kind": {
"description": "workflow or plugin.",
"title": "Kind",
"type": "string"
},
"name": {
"description": "The workflow's or plugin file's name here.",
"title": "Name",
"type": "string"
},
"with_plugins": {
"default": true,
"description": "A workflow: send the plugins its steps use too.",
"title": "With Plugins",
"type": "boolean"
}
},
"required": [
"kind",
"name"
],
"title": "LibraryPublishRequest",
"type": "object"
}
Responses
{
"items": [
{
"content": null,
"description": null,
"filename": "string",
"here": null,
"history": [
{
"pins": {},
"published_at": null,
"published_by": null,
"sha256": "string",
"version": 0
}
],
"kind": "string",
"local_version": null,
"missing": [
"string"
],
"name": "string",
"needs": [
"string"
],
"pins": {},
"provides": null,
"published_at": null,
"published_by": null,
"sha256": "string",
"size": 0,
"title": null,
"triggers": [
"string"
],
"version": 0
}
],
"warnings": [
"string"
]
}
Schema of the response body
{
"properties": {
"items": {
"description": "The versions stored.",
"items": {
"$ref": "#/components/schemas/LibraryItemResponse"
},
"title": "Items",
"type": "array"
},
"warnings": {
"description": "Shared workflows still on an older version of a plugin that the new version would break.",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
}
},
"required": [
"items"
],
"title": "LibraryPublishResponse",
"type": "object"
}
DELETE /api/remote/library/{kind}/{name}
Unpublish
Description
Take something out of the library. Copies already installed stay.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
force |
query | boolean | False | No | Even if shared workflows are pinned to it. |
kind |
path | string | No | ||
name |
path | string | No | ||
version |
query | No | One version; omit to remove every version. |
Responses
GET /api/remote/library/{kind}/{name}
Library Item
Description
One version of a shared workflow or plugin with its text, to read first.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
kind |
path | string | No | ||
name |
path | string | No | ||
version |
query | No | Omit for the newest. |
Responses
{
"content": null,
"description": null,
"filename": "string",
"here": null,
"history": [
{
"pins": {},
"published_at": null,
"published_by": null,
"sha256": "string",
"version": 0
}
],
"kind": "string",
"local_version": null,
"missing": [
"string"
],
"name": "string",
"needs": [
"string"
],
"pins": {},
"provides": null,
"published_at": null,
"published_by": null,
"sha256": "string",
"size": 0,
"title": null,
"triggers": [
"string"
],
"version": 0
}
Schema of the response body
{
"properties": {
"content": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Its text, when asked for one.",
"title": "Content"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"filename": {
"title": "Filename",
"type": "string"
},
"here": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "On this computer, against this version: absent, same, older (an earlier version from the library) or different (changed here).",
"title": "Here"
},
"history": {
"description": "Every version, newest first.",
"items": {
"$ref": "#/components/schemas/LibraryVersionResponse"
},
"title": "History",
"type": "array"
},
"kind": {
"description": "workflow or plugin.",
"title": "Kind",
"type": "string"
},
"local_version": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "The library version this computer has, if any.",
"title": "Local Version"
},
"missing": {
"description": "Plugins it needs that are neither here nor in the library.",
"items": {
"type": "string"
},
"title": "Missing",
"type": "array"
},
"name": {
"title": "Name",
"type": "string"
},
"needs": {
"description": "A workflow: the plugins its steps use.",
"items": {
"type": "string"
},
"title": "Needs",
"type": "array"
},
"pins": {
"additionalProperties": {
"type": "integer"
},
"description": "A workflow: the version of each plugin it was published with.",
"title": "Pins",
"type": "object"
},
"provides": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A plugin: the plugin id it registers as.",
"title": "Provides"
},
"published_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Published At"
},
"published_by": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Published By"
},
"sha256": {
"title": "Sha256",
"type": "string"
},
"size": {
"title": "Size",
"type": "integer"
},
"title": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A workflow's own name.",
"title": "Title"
},
"triggers": {
"description": "A workflow: what starts it by itself.",
"items": {
"type": "string"
},
"title": "Triggers",
"type": "array"
},
"version": {
"description": "This version's number (the newest in a list).",
"title": "Version",
"type": "integer"
}
},
"required": [
"kind",
"name",
"filename",
"sha256",
"size",
"version"
],
"title": "LibraryItemResponse",
"type": "object"
}
GET /api/remote/library/{kind}/{name}/install
Install Plan
Description
What installing (a version) would write here, what it would break among the workflows here, and what stops it. Writes and runs nothing.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
force |
query | boolean | False | No | |
kind |
path | string | No | ||
name |
path | string | No | ||
replace |
query | boolean | False | No | |
version |
query | No | |||
with_plugins |
query | boolean | True | No |
Responses
{
"blocked": [
"string"
],
"breaks": [
"string"
],
"runs_code": true,
"steps": [
{
"here": "string",
"item": {
"content": null,
"description": null,
"filename": "string",
"here": null,
"history": [
{
"pins": {},
"published_at": null,
"published_by": null,
"sha256": "string",
"version": 0
}
],
"kind": "string",
"local_version": null,
"missing": [
"string"
],
"name": "string",
"needs": [
"string"
],
"pins": {},
"provides": null,
"published_at": null,
"published_by": null,
"sha256": "string",
"size": 0,
"title": null,
"triggers": [
"string"
],
"version": 0
},
"local_version": null,
"path": "string"
}
],
"warnings": [
"string"
]
}
Schema of the response body
{
"properties": {
"blocked": {
"description": "Why it can't be installed as asked.",
"items": {
"type": "string"
},
"title": "Blocked",
"type": "array"
},
"breaks": {
"description": "What the new plugin versions would break among the workflows here.",
"items": {
"type": "string"
},
"title": "Breaks",
"type": "array"
},
"runs_code": {
"description": "It writes a plugin, which is code this computer will run.",
"title": "Runs Code",
"type": "boolean"
},
"steps": {
"items": {
"$ref": "#/components/schemas/InstallStepResponse"
},
"title": "Steps",
"type": "array"
},
"warnings": {
"description": "What to know first (what starts a workflow by itself).",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
}
},
"required": [
"steps",
"blocked",
"warnings",
"runs_code"
],
"title": "InstallPlanResponse",
"type": "object"
}
POST /api/remote/library/{kind}/{name}/install
Install
Description
Install (a version) from the library into this project. A plugin is code: it is described before anything is written, and runs on this computer from now on.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
kind |
path | string | No | ||
name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"force": {
"default": false,
"description": "Install even though it would break workflows here.",
"title": "Force",
"type": "boolean"
},
"replace": {
"default": false,
"description": "Replace files here that were changed here.",
"title": "Replace",
"type": "boolean"
},
"version": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Omit for the newest.",
"title": "Version"
},
"with_plugins": {
"default": true,
"description": "A workflow: install the plugin versions it is pinned to too.",
"title": "With Plugins",
"type": "boolean"
}
},
"title": "LibraryInstallRequest",
"type": "object"
}
Responses
{
"blocked": [
"string"
],
"breaks": [
"string"
],
"runs_code": true,
"steps": [
{
"here": "string",
"item": {
"content": null,
"description": null,
"filename": "string",
"here": null,
"history": [
{
"pins": {},
"published_at": null,
"published_by": null,
"sha256": "string",
"version": 0
}
],
"kind": "string",
"local_version": null,
"missing": [
"string"
],
"name": "string",
"needs": [
"string"
],
"pins": {},
"provides": null,
"published_at": null,
"published_by": null,
"sha256": "string",
"size": 0,
"title": null,
"triggers": [
"string"
],
"version": 0
},
"local_version": null,
"path": "string"
}
],
"warnings": [
"string"
]
}
Schema of the response body
{
"properties": {
"blocked": {
"description": "Why it can't be installed as asked.",
"items": {
"type": "string"
},
"title": "Blocked",
"type": "array"
},
"breaks": {
"description": "What the new plugin versions would break among the workflows here.",
"items": {
"type": "string"
},
"title": "Breaks",
"type": "array"
},
"runs_code": {
"description": "It writes a plugin, which is code this computer will run.",
"title": "Runs Code",
"type": "boolean"
},
"steps": {
"items": {
"$ref": "#/components/schemas/InstallStepResponse"
},
"title": "Steps",
"type": "array"
},
"warnings": {
"description": "What to know first (what starts a workflow by itself).",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
}
},
"required": [
"steps",
"blocked",
"warnings",
"runs_code"
],
"title": "InstallPlanResponse",
"type": "object"
}
POST /api/remote/sync
Sync Now
Description
Ask for a sync now. It runs in the background; GET /remote shows how it went.
Responses
GET /api/sync/v1/feed
Feed
Description
Everyone's changes past after, in the order the authority numbered them.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
after |
query | integer | 0 | No | The last number the device has. |
limit |
query | integer | 200 | No |
Responses
Schema of the response body
{
"properties": {
"entries": {
"description": "Changes past `after`, in the authority's order, each with its `hub_seq` and whether it was `superseded` by a later settled state.",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Entries",
"type": "array"
},
"head_seq": {
"title": "Head Seq",
"type": "integer"
},
"more": {
"description": "There are more past this page.",
"title": "More",
"type": "boolean"
}
},
"required": [
"entries",
"head_seq",
"more"
],
"title": "SyncFeedResponse",
"type": "object"
}
POST /api/sync/v1/files/missing
Files Missing
Description
Which of these files the authority does not have: what a device uploads before the changes that cite them.
Request body
Responses
GET /api/sync/v1/files/{sha256}
Download File
Description
The bytes of a file the authority holds, for a device that was sent only the record that cites it.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
sha256 |
path | string | No |
Responses
PUT /api/sync/v1/files/{sha256}
Upload File
Description
Store a file under its content hash. The bytes are hashed as they arrive;
ones that don't match sha256 are refused.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
sha256 |
path | string | No |
Responses
GET /api/sync/v1/hello
Hello
Description
Say who this server is: its project, its latest number, whether it holds data. A device asks first, to decide whether to join, fill it, or stop.
Responses
{
"capabilities": [
"string"
],
"counts": {},
"device_name": "string",
"empty": true,
"feed_floor": 0,
"head_seq": 0,
"project_id": "string",
"protocol_max": 0,
"protocol_min": 0,
"protocol_version": 0,
"seeded_by": null,
"server_version": null
}
Schema of the response body
{
"properties": {
"capabilities": {
"description": "Optional features it has, by name. Adding one is not a protocol change.",
"items": {
"type": "string"
},
"title": "Capabilities",
"type": "array"
},
"counts": {
"additionalProperties": {
"type": "integer"
},
"description": "How many of each kind it holds, deleted ones included, so a device copying it can show how far along it is.",
"title": "Counts",
"type": "object"
},
"device_name": {
"description": "What the token used is called here.",
"title": "Device Name",
"type": "string"
},
"empty": {
"description": "True when it holds none of the project's things yet (an empty authority can be filled from a project that has data).",
"title": "Empty",
"type": "boolean"
},
"feed_floor": {
"default": 0,
"description": "The highest number the feed no longer holds (history pruned here). A device whose cursor is below it copies the project again.",
"title": "Feed Floor",
"type": "integer"
},
"head_seq": {
"description": "The latest number the authority has handed out.",
"title": "Head Seq",
"type": "integer"
},
"project_id": {
"description": "The project's id, shared by every copy.",
"title": "Project Id",
"type": "string"
},
"protocol_max": {
"description": "The newest sync protocol it speaks.",
"title": "Protocol Max",
"type": "integer"
},
"protocol_min": {
"description": "The oldest sync protocol it speaks.",
"title": "Protocol Min",
"type": "integer"
},
"protocol_version": {
"description": "The sync protocol this server and the calling device agreed on.",
"title": "Protocol Version",
"type": "integer"
},
"seeded_by": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The device that put the first data in, if any.",
"title": "Seeded By"
},
"server_version": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The civex release it runs.",
"title": "Server Version"
}
},
"required": [
"protocol_version",
"project_id",
"head_seq",
"empty",
"device_name",
"protocol_min",
"protocol_max"
],
"title": "SyncHelloResponse",
"type": "object"
}
POST /api/sync/v1/join
Join
Description
Join with an invite: the device's public key is kept, the invite is used up, and the answer carries the authority's key.
Request body
Schema of the request body
{
"properties": {
"device_id": {
"description": "This device's id (a UUID).",
"title": "Device Id",
"type": "string"
},
"invite": {
"description": "The invite code the authority's admin gave.",
"title": "Invite",
"type": "string"
},
"public_key": {
"description": "This device's Ed25519 public key, base64 of its 32 bytes.",
"title": "Public Key",
"type": "string"
}
},
"required": [
"invite",
"device_id",
"public_key"
],
"title": "SyncJoinRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"authority_key": {
"description": "The authority's public key: it signs its answers to sign-ins.",
"title": "Authority Key",
"type": "string"
},
"device_name": {
"description": "What the device was invited as.",
"title": "Device Name",
"type": "string"
},
"project_id": {
"description": "The project's id, shared by every copy.",
"title": "Project Id",
"type": "string"
}
},
"required": [
"project_id",
"authority_key",
"device_name"
],
"title": "SyncJoinResponse",
"type": "object"
}
GET /api/sync/v1/library
Library
Description
The workflows and plugins shared through this server: the newest version of each, with its history, without its text.
Responses
Schema of the response body
{
"properties": {
"items": {
"description": "The newest version of each item, without its text: kind, name, sha256, size, version, title, description, provides, needs, triggers, pins, contract, published_by, published_at, and its history (every version).",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Items",
"type": "array"
}
},
"required": [
"items"
],
"title": "LibraryListResponse",
"type": "object"
}
POST /api/sync/v1/library
Publish
Description
Publish to the library. Refused (403) unless the admin allowed this device, and for plugins unless the server takes them; checked without being run, and taken whole or not at all. A workflow is pinned to the plugin versions it is published with.
Request body
{
"items": [
{
"content": "string",
"contract": null,
"kind": "string",
"name": "string",
"provides": null,
"sha256": "string",
"size": 0
}
]
}
Schema of the request body
{
"properties": {
"items": {
"description": "A workflow and the plugins it uses, or a plugin. Taken whole or not at all; new text becomes the next version.",
"items": {
"$ref": "#/components/schemas/LibraryItemBody"
},
"maxItems": 50,
"title": "Items",
"type": "array"
}
},
"required": [
"items"
],
"title": "LibraryPublishRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"items": {
"description": "The newest version of each item, without its text: kind, name, sha256, size, version, title, description, provides, needs, triggers, pins, contract, published_by, published_at, and its history (every version).",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Items",
"type": "array"
},
"warnings": {
"description": "What to know: shared workflows still on an older version of a plugin that the new version would break.",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
}
},
"required": [
"items"
],
"title": "LibraryPublishResponse",
"type": "object"
}
DELETE /api/sync/v1/library/{kind}/{name}
Unpublish
Description
Take something out of the library. Copies already installed stay.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
force |
query | boolean | False | No | Remove a plugin version even if shared workflows are pinned to it. |
kind |
path | string | No | ||
name |
path | string | No | ||
version |
query | No | One version; omit to remove every version. |
Responses
GET /api/sync/v1/library/{kind}/{name}
Library Item
Description
One version of a shared workflow or plugin, with its text.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
kind |
path | string | No | ||
name |
path | string | No | ||
version |
query | No | Omit for the newest. |
Responses
POST /api/sync/v1/push
Push
Description
Settle the changes a device made. Each is merged with what the authority holds, numbered, and answered; the answer is remembered, so a repeat (the device never heard) is answered the same way and nothing is done twice.
Request body
Schema of the request body
{
"properties": {
"entries": {
"description": "Changes made on the device, oldest first: history entries with their snapshots. Each is identified by its id, so sending one twice is harmless.",
"items": {
"additionalProperties": true,
"type": "object"
},
"maxItems": 500,
"title": "Entries",
"type": "array"
}
},
"required": [
"entries"
],
"title": "SyncPushRequest",
"type": "object"
}
Responses
{
"head_seq": 0,
"results": [
{
"conflicts": [
{}
],
"hub_seq": null,
"message": null,
"op_id": "string",
"status": "string"
}
]
}
Schema of the response body
{
"properties": {
"head_seq": {
"title": "Head Seq",
"type": "integer"
},
"results": {
"description": "One answer per change, in order. Fewer than were sent means the rest were held back behind one that has to wait.",
"items": {
"$ref": "#/components/schemas/SyncOpResponse"
},
"title": "Results",
"type": "array"
}
},
"required": [
"results",
"head_seq"
],
"title": "SyncPushResponse",
"type": "object"
}
POST /api/sync/v1/session
Session
Description
Sign in: a request signed with the device's key, for a token that expires in minutes.
Request body
Schema of the request body
{
"properties": {
"at": {
"description": "Now, in unix seconds, as the device's clock says.",
"title": "At",
"type": "integer"
},
"device_id": {
"description": "The device signing in.",
"title": "Device Id",
"type": "string"
},
"signature": {
"description": "The device's signature over the session request (the authority's key, the device id and `at`).",
"title": "Signature",
"type": "string"
}
},
"required": [
"device_id",
"at",
"signature"
],
"title": "SyncSessionRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"expires_at": {
"description": "When the token stops working, unix seconds.",
"title": "Expires At",
"type": "integer"
},
"signature": {
"description": "The authority's signature over its answer to this request.",
"title": "Signature",
"type": "string"
},
"token": {
"description": "Send as `Authorization: Bearer` until it expires.",
"title": "Token",
"type": "string"
}
},
"required": [
"token",
"expires_at",
"signature"
],
"title": "SyncSessionResponse",
"type": "object"
}
GET /api/sync/v1/snapshot/{kind}
Snapshot
Description
One kind of thing as it is now, a page at a time, for a device joining the project: schema, field, dataset, view, record (in that order).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
after |
query | No | The previous page's `next`; omit for the first. | ||
kind |
path | string | No | ||
limit |
query | integer | 200 | No |
Responses
Schema of the response body
{
"properties": {
"head_seq": {
"description": "Taken before reading: what changes meanwhile is in the feed past it.",
"title": "Head Seq",
"type": "integer"
},
"items": {
"description": "Things of this kind as they are now, in the shape a history entry stores them.",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Items",
"type": "array"
},
"kind": {
"title": "Kind",
"type": "string"
},
"more": {
"title": "More",
"type": "boolean"
},
"next": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Pass as `after` for the next page; null on the last page.",
"title": "Next"
}
},
"required": [
"kind",
"items",
"more",
"head_seq"
],
"title": "SyncSnapshotResponse",
"type": "object"
}
retention
POST /api/retention/purged-history
Forget Purged
Description
Delete the history of records that were permanently deleted before
permanent deletes removed it themselves: every entry about a record that no
longer exists. Cannot be undone. With dry_run (the default) it only
counts.
Request body
Responses
Schema of the response body
POST /api/retention/run
Run Retention
Description
Clean up by age: permanently delete items deleted before a date, remove
change history before a date, and remove finished workflow runs (with their
step logs) before a date. from_settings applies the retention settings;
a date given outright wins over the setting for that kind. With dry_run
(the default) nothing is removed and the response says what would be.
History about something that can still be restored is never removed. Files nothing
refers to afterwards are the file clean-up's job (/store/gc).
Request body
{
"audit_before": null,
"deleted_before": null,
"dry_run": true,
"from_settings": true,
"runs_before": null
}
Schema of the request body
{
"properties": {
"audit_before": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "Remove change history before this (not about anything that can still be restored, and with a remote, not yet pushed).",
"title": "Audit Before"
},
"deleted_before": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "Permanently delete everything deleted before this.",
"title": "Deleted Before"
},
"dry_run": {
"default": true,
"description": "Only count what would be removed.",
"title": "Dry Run",
"type": "boolean"
},
"from_settings": {
"default": false,
"description": "Apply the retention settings (each kind left at keep-forever is left alone).",
"title": "From Settings",
"type": "boolean"
},
"runs_before": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "Remove finished workflow runs, with their step logs, before this.",
"title": "Runs Before"
}
},
"title": "RetentionRunRequest",
"type": "object"
}
Responses
{
"anything": true,
"audit_batches": 0,
"audit_entries": 0,
"audit_kept_first_and_last": 0,
"audit_kept_restorable": 0,
"audit_kept_unsynced": 0,
"deleted_collections": 0,
"deleted_records": 0,
"deleted_schemas": 0,
"dry_run": true,
"run_steps": 0,
"runs": 0,
"skipped": [
"string"
]
}
Schema of the response body
{
"properties": {
"anything": {
"title": "Anything",
"type": "boolean"
},
"audit_batches": {
"title": "Audit Batches",
"type": "integer"
},
"audit_entries": {
"title": "Audit Entries",
"type": "integer"
},
"audit_kept_first_and_last": {
"default": 0,
"description": "Older history kept because it is a thing's creation or its latest entry, which are kept however old.",
"title": "Audit Kept First And Last",
"type": "integer"
},
"audit_kept_restorable": {
"description": "Older history kept because it is about something that can still be restored.",
"title": "Audit Kept Restorable",
"type": "integer"
},
"audit_kept_unsynced": {
"description": "Older history kept because it has not been synced yet.",
"title": "Audit Kept Unsynced",
"type": "integer"
},
"deleted_collections": {
"title": "Deleted Collections",
"type": "integer"
},
"deleted_records": {
"title": "Deleted Records",
"type": "integer"
},
"deleted_schemas": {
"title": "Deleted Schemas",
"type": "integer"
},
"dry_run": {
"title": "Dry Run",
"type": "boolean"
},
"run_steps": {
"title": "Run Steps",
"type": "integer"
},
"runs": {
"title": "Runs",
"type": "integer"
},
"skipped": {
"description": "Deleted things that could not be removed, with why.",
"items": {
"type": "string"
},
"title": "Skipped",
"type": "array"
}
},
"required": [
"dry_run",
"deleted_records",
"deleted_collections",
"deleted_schemas",
"skipped",
"audit_entries",
"audit_batches",
"audit_kept_restorable",
"audit_kept_unsynced",
"runs",
"run_steps",
"anything"
],
"title": "RetentionReportResponse",
"type": "object"
}
schemas
GET /api/schemas
List Schemas
Responses
[
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
]
POST /api/schemas
Create Schema
Request body
Schema of the request body
{
"properties": {
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"fields": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/AddFieldRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Fields"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Optional human-facing display name; free text.",
"title": "Label"
},
"name": {
"description": "Machine key: lowercase letters, digits and underscores, not starting with a digit.",
"title": "Name",
"type": "string"
},
"parent": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent"
}
},
"required": [
"name"
],
"title": "CreateSchemaRequest",
"type": "object"
}
Responses
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this schema was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used.",
"title": "Display Template"
},
"fields": {
"items": {
"$ref": "#/components/schemas/FieldResponse"
},
"title": "Fields",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"parent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Id"
},
"unique_keys": {
"description": "Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record).",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Unique Keys",
"type": "array"
}
},
"required": [
"id",
"name",
"description",
"parent_id",
"fields"
],
"title": "SchemaResponse",
"type": "object"
}
GET /api/schemas/deleted
List Deleted Schemas
Description
Schemas currently in Recently Deleted, most recently deleted first.
Responses
[
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
]
GET /api/schemas/field-types
Field Types
Description
Every field type, the rules each can carry and how to present them, plus the field-kind picker. The web UI builds its field editor and its record-form guidance from this, so a new type or rule appears there without a frontend change.
Responses
{
"kinds": [
{
"description": "string",
"focus": null,
"key": "string",
"label": "string",
"type": "string"
}
],
"types": [
{
"description": "string",
"entry_hint": "string",
"example": "string",
"label": "string",
"restrictions": [
{
"control": "string",
"help": "string",
"key": "string",
"label": "string"
}
],
"stored_as": "string",
"supports_default": true,
"type": "string"
}
]
}
Schema of the response body
{
"properties": {
"kinds": {
"description": "The 'what kind of data is this?' picker, in display order.",
"items": {
"$ref": "#/components/schemas/FieldKindResponse"
},
"title": "Kinds",
"type": "array"
},
"types": {
"description": "Every field type, with the rules each can carry.",
"items": {
"$ref": "#/components/schemas/FieldTypeDescriptorResponse"
},
"title": "Types",
"type": "array"
}
},
"required": [
"types",
"kinds"
],
"title": "FieldTypesResponse",
"type": "object"
}
GET /api/schemas/lint
Lint Schema Names
Description
Schema and field names that predate slug validation -- the same
report civex schema lint prints, exposed for the analytics
naming-health widget. Nothing is broken; these names still resolve.
Responses
GET /api/schemas/{name_or_id}
Get Schema
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name_or_id |
path | string | No |
Responses
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this schema was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used.",
"title": "Display Template"
},
"fields": {
"items": {
"$ref": "#/components/schemas/FieldResponse"
},
"title": "Fields",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"parent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Id"
},
"unique_keys": {
"description": "Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record).",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Unique Keys",
"type": "array"
}
},
"required": [
"id",
"name",
"description",
"parent_id",
"fields"
],
"title": "SchemaResponse",
"type": "object"
}
DELETE /api/schemas/{name}
Delete Schema
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
PATCH /api/schemas/{name}
Update Schema
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names the schema's records. Send an empty string to clear it; omit the key to leave it unchanged.",
"title": "Display Template"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "New display name. Send an empty string to clear it and fall back to the derived label; omit the key to leave it unchanged.",
"title": "Label"
},
"rename": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Rename"
}
},
"title": "UpdateSchemaRequest",
"type": "object"
}
Responses
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this schema was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used.",
"title": "Display Template"
},
"fields": {
"items": {
"$ref": "#/components/schemas/FieldResponse"
},
"title": "Fields",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"parent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Id"
},
"unique_keys": {
"description": "Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record).",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Unique Keys",
"type": "array"
}
},
"required": [
"id",
"name",
"description",
"parent_id",
"fields"
],
"title": "SchemaResponse",
"type": "object"
}
GET /api/schemas/{name}/delete-impact
Get Schema Delete Impact
Description
What deleting this schema would take with it, so the caller can warn before the delete happens rather than after it fails or silently loses data.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
Schema of the response body
{
"properties": {
"child_schema_count": {
"description": "Schemas that inherit from this one, directly or transitively — informational only, they are not deleted along with it, but their presence blocks a later purge.",
"title": "Child Schema Count",
"type": "integer"
},
"record_count": {
"description": "Records typed by this schema itself, across every collection — deleted along with it.",
"title": "Record Count",
"type": "integer"
}
},
"required": [
"child_schema_count",
"record_count"
],
"title": "SchemaDeleteImpactResponse",
"type": "object"
}
POST /api/schemas/{name}/fields
Add Field
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
{
"default": null,
"label": null,
"name": "string",
"required": true,
"restrictions": null,
"type": "string"
}
Schema of the request body
{
"properties": {
"default": {
"anyOf": [
{},
{
"type": "null"
}
],
"title": "Default"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Optional human-facing display name; free text.",
"title": "Label"
},
"name": {
"description": "Machine key: lowercase letters, digits and underscores, not starting with a digit. This is what workflows and CSV headers reference.",
"title": "Name",
"type": "string"
},
"required": {
"default": false,
"title": "Required",
"type": "boolean"
},
"restrictions": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Restrictions"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"name",
"type"
],
"title": "AddFieldRequest",
"type": "object"
}
Responses
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
Schema of the response body
{
"properties": {
"default": {
"anyOf": [
{},
{
"type": "null"
}
],
"title": "Default"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"required": {
"title": "Required",
"type": "boolean"
},
"restrictions": {
"additionalProperties": true,
"default": {},
"title": "Restrictions",
"type": "object"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"required"
],
"title": "FieldResponse",
"type": "object"
}
PUT /api/schemas/{name}/fields/reorder
Reorder Fields
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Responses
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this schema was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used.",
"title": "Display Template"
},
"fields": {
"items": {
"$ref": "#/components/schemas/FieldResponse"
},
"title": "Fields",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"parent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Id"
},
"unique_keys": {
"description": "Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record).",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Unique Keys",
"type": "array"
}
},
"required": [
"id",
"name",
"description",
"parent_id",
"fields"
],
"title": "SchemaResponse",
"type": "object"
}
POST /api/schemas/{name}/fields/{field_id}/restore
Restore Field
Description
Bring a deleted field back, with every value records still hold for it.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
field_id |
path | string | No | ||
name |
path | string | No |
Responses
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
Schema of the response body
{
"properties": {
"default": {
"anyOf": [
{},
{
"type": "null"
}
],
"title": "Default"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"required": {
"title": "Required",
"type": "boolean"
},
"restrictions": {
"additionalProperties": true,
"default": {},
"title": "Restrictions",
"type": "object"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"required"
],
"title": "FieldResponse",
"type": "object"
}
GET /api/schemas/{name}/fields/{field_id}/restore-plan
Restore Field Plan
Description
What restoring a deleted field would do: it returns to the schema with the values records still hold for it. Blocked while the schema is deleted, or when a live field has since taken its name.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
field_id |
path | string | No | ||
name |
path | string | No |
Responses
{
"blocked": null,
"blocked_by": null,
"can_restore": true,
"collection": null,
"collection_id": null,
"conflict": null,
"deleted_at": null,
"id": "string",
"kind": "string",
"name": "string",
"parents_needed": null,
"records": 0,
"schema_name": null
}
Schema of the response body
{
"properties": {
"blocked": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it can't be restored yet, in plain words. Null when it can.",
"title": "Blocked"
},
"blocked_by": {
"anyOf": [
{
"$ref": "#/components/schemas/BlockerResponse"
},
{
"type": "null"
}
],
"description": "The deleted collection, schema or record that must be restored first. Null when it can be restored now."
},
"can_restore": {
"title": "Can Restore",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a record: the collection it will be in.",
"title": "Collection"
},
"collection_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Collection Id"
},
"conflict": {
"anyOf": [
{
"$ref": "#/components/schemas/RestoreConflictResponse"
},
{
"type": "null"
}
],
"description": "Set when another record has taken the values of a uniqueness key while this one was deleted: restoring is refused until that record is changed or deleted."
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When it was deleted.",
"title": "Deleted At"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"description": "record, collection, schema or field.",
"title": "Kind",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"parents_needed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "For a record held back only by deleted records above it: how many of them. `POST .../restore?with_parents=true` brings each back by itself (not what was deleted alongside it), so just this record (`&only_this=true`) comes back as `parents_needed + 1` records and its deleted siblings stay deleted. Null otherwise.",
"title": "Parents Needed"
},
"records": {
"description": "How many records come back: those deleted together with this, the record itself included when it is one. Never something deleted on its own earlier.",
"title": "Records",
"type": "integer"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a field: the schema it belongs to.",
"title": "Schema Name"
}
},
"required": [
"kind",
"id",
"name",
"records",
"can_restore"
],
"title": "RestorePlanResponse",
"type": "object"
}
DELETE /api/schemas/{name}/fields/{field_name}
Delete Field
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
field_name |
path | string | No | ||
name |
path | string | No |
Responses
PATCH /api/schemas/{name}/fields/{field_name}
Update Field
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
field_name |
path | string | No | ||
name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"default": {
"anyOf": [
{},
{
"type": "null"
}
],
"title": "Default"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "New display name. Send an empty string to clear it and fall back to the derived label; omit the key to leave it unchanged.",
"title": "Label"
},
"rename": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Rename"
},
"required": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Required"
},
"restrictions": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Restrictions"
}
},
"title": "UpdateFieldRequest",
"type": "object"
}
Responses
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
Schema of the response body
{
"properties": {
"default": {
"anyOf": [
{},
{
"type": "null"
}
],
"title": "Default"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"required": {
"title": "Required",
"type": "boolean"
},
"restrictions": {
"additionalProperties": true,
"default": {},
"title": "Restrictions",
"type": "object"
},
"type": {
"title": "Type",
"type": "string"
}
},
"required": [
"id",
"name",
"type",
"required"
],
"title": "FieldResponse",
"type": "object"
}
POST /api/schemas/{name}/preview-name
Preview Name
Description
Render a name template against sample values without saving it. An
invalid template is answered with error set, not an HTTP error, so an
editor can show the problem as the person types.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"kind": {
"default": "record",
"description": "'record' renders a record's name; 'file' renders a download name, where `{ext}` is available and a blank value makes the result null.",
"enum": [
"record",
"file"
],
"title": "Kind",
"type": "string"
},
"template": {
"description": "The template to try, e.g. '{site}-{taken_on:YYYY-MM}'.",
"title": "Template",
"type": "string"
},
"values": {
"additionalProperties": true,
"description": "Field values (keyed by field name) of the sample record to render against.",
"title": "Values",
"type": "object"
}
},
"required": [
"template"
],
"title": "PreviewNameRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the template is not valid, if it is not.",
"title": "Error"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The rendered text, or null when the template renders to nothing.",
"title": "Name"
}
},
"required": [
"name"
],
"title": "PreviewNameResponse",
"type": "object"
}
DELETE /api/schemas/{name}/purge
Purge Schema
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
POST /api/schemas/{name}/restore
Restore Schema
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this schema was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used.",
"title": "Display Template"
},
"fields": {
"items": {
"$ref": "#/components/schemas/FieldResponse"
},
"title": "Fields",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"parent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Id"
},
"unique_keys": {
"description": "Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record).",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Unique Keys",
"type": "array"
}
},
"required": [
"id",
"name",
"description",
"parent_id",
"fields"
],
"title": "SchemaResponse",
"type": "object"
}
GET /api/schemas/{name}/restore-plan
Restore Schema Plan
Description
What restoring a deleted schema would bring back: it and the records deleted with it, not records deleted on their own earlier.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"blocked": null,
"blocked_by": null,
"can_restore": true,
"collection": null,
"collection_id": null,
"conflict": null,
"deleted_at": null,
"id": "string",
"kind": "string",
"name": "string",
"parents_needed": null,
"records": 0,
"schema_name": null
}
Schema of the response body
{
"properties": {
"blocked": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why it can't be restored yet, in plain words. Null when it can.",
"title": "Blocked"
},
"blocked_by": {
"anyOf": [
{
"$ref": "#/components/schemas/BlockerResponse"
},
{
"type": "null"
}
],
"description": "The deleted collection, schema or record that must be restored first. Null when it can be restored now."
},
"can_restore": {
"title": "Can Restore",
"type": "boolean"
},
"collection": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a record: the collection it will be in.",
"title": "Collection"
},
"collection_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Collection Id"
},
"conflict": {
"anyOf": [
{
"$ref": "#/components/schemas/RestoreConflictResponse"
},
{
"type": "null"
}
],
"description": "Set when another record has taken the values of a uniqueness key while this one was deleted: restoring is refused until that record is changed or deleted."
},
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When it was deleted.",
"title": "Deleted At"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"description": "record, collection, schema or field.",
"title": "Kind",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"parents_needed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "For a record held back only by deleted records above it: how many of them. `POST .../restore?with_parents=true` brings each back by itself (not what was deleted alongside it), so just this record (`&only_this=true`) comes back as `parents_needed + 1` records and its deleted siblings stay deleted. Null otherwise.",
"title": "Parents Needed"
},
"records": {
"description": "How many records come back: those deleted together with this, the record itself included when it is one. Never something deleted on its own earlier.",
"title": "Records",
"type": "integer"
},
"schema_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "For a field: the schema it belongs to.",
"title": "Schema Name"
}
},
"required": [
"kind",
"id",
"name",
"records",
"can_restore"
],
"title": "RestorePlanResponse",
"type": "object"
}
PUT /api/schemas/{name}/unique-keys
Set Unique Keys
Description
Replace a schema's uniqueness policies.
Each key is a set of the schema's own fields that no two records may share the values of, within the same parent record (top-level records: the same collection). Refused with 422 when existing records already break a key being added. Records with a blank in a key's fields are not constrained by it.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"keys": {
"description": "The schema's complete list of uniqueness keys, replacing the current one; each key is a list of the schema's own field names. An empty list removes every policy.",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Keys",
"type": "array"
}
},
"required": [
"keys"
],
"title": "SetUniqueKeysRequest",
"type": "object"
}
Responses
{
"deleted_at": null,
"description": null,
"display_template": null,
"fields": [
{
"default": null,
"id": "string",
"label": null,
"name": "string",
"required": true,
"restrictions": {},
"type": "string"
}
],
"id": "string",
"label": null,
"name": "string",
"parent_id": null,
"unique_keys": [
[
"string"
]
]
}
Schema of the response body
{
"properties": {
"deleted_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"description": "When this schema was soft-deleted. Null means live.",
"title": "Deleted At"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"display_template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used.",
"title": "Display Template"
},
"fields": {
"items": {
"$ref": "#/components/schemas/FieldResponse"
},
"title": "Fields",
"type": "array"
},
"id": {
"title": "Id",
"type": "string"
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-facing display name. Null means none was set — render the name title-cased instead.",
"title": "Label"
},
"name": {
"title": "Name",
"type": "string"
},
"parent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Parent Id"
},
"unique_keys": {
"description": "Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record).",
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"title": "Unique Keys",
"type": "array"
}
},
"required": [
"id",
"name",
"description",
"parent_id",
"fields"
],
"title": "SchemaResponse",
"type": "object"
}
exports
GET /api/schemas/{schema_name}/exports
List Exports
Description
The exports saved with a schema.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No |
Responses
[
{
"fields": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"holder": null,
"id": "string",
"include_files": true,
"name": "string",
"schema_id": "string",
"schema_name": "string",
"tables": [
{
"columns": null,
"format": "csv",
"kind": null,
"name": null,
"shape": "rows",
"skip_empty": true,
"where": null
}
]
}
]
POST /api/schemas/{schema_name}/exports
Create Export
Description
Save an export with a schema: the kind of record that holds the files, which file fields, an optional filter, and a layout. It is then offered on collections that use the schema and on records of it and of the schemas below it, down to the kind that holds the files. Checked as a whole: the holder must be the schema or beneath it, and the fields must be file fields it has.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No |
Request body
{
"fields": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"holder": null,
"include_files": true,
"name": "string",
"tables": [
{
"columns": null,
"format": "csv",
"kind": null,
"name": null,
"shape": "rows",
"skip_empty": true,
"where": null
}
]
}
Schema of the request body
{
"properties": {
"fields": {
"description": "File fields to export; empty means every file field.",
"items": {
"type": "string"
},
"title": "Fields",
"type": "array"
},
"files_layout": {
"default": "tree",
"description": "'tree': a folder per record above each file; 'grouped': the records that hold the files share one folder named for their kind (Encounter/Recording/Selections/...); 'flat': every file in one folder.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter on the records that hold the files; needs 'holder'.",
"title": "Filter Tree"
},
"holder": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The kind of record that holds the files: the schema itself or a kind beneath it. Omit for any kind beneath.",
"title": "Holder"
},
"include_files": {
"default": true,
"description": "False makes the export tables alone.",
"title": "Include Files",
"type": "boolean"
},
"name": {
"description": "What the export is called, in your own words.",
"title": "Name",
"type": "string"
},
"tables": {
"description": "Also make these tables.",
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"title": "Tables",
"type": "array"
}
},
"required": [
"name"
],
"title": "CreateExportDefinitionRequest",
"type": "object"
}
Responses
{
"fields": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"holder": null,
"id": "string",
"include_files": true,
"name": "string",
"schema_id": "string",
"schema_name": "string",
"tables": [
{
"columns": null,
"format": "csv",
"kind": null,
"name": null,
"shape": "rows",
"skip_empty": true,
"where": null
}
]
}
Schema of the response body
{
"properties": {
"fields": {
"description": "The file fields exported; empty means every file field.",
"items": {
"type": "string"
},
"title": "Fields",
"type": "array"
},
"files_layout": {
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter on the records that hold the files (same shape as the records 'filter' parameter).",
"title": "Filter Tree"
},
"holder": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The kind of record that holds the files; null means any kind beneath the schema.",
"title": "Holder"
},
"id": {
"title": "Id",
"type": "string"
},
"include_files": {
"default": true,
"description": "False: the export is tables alone.",
"title": "Include Files",
"type": "boolean"
},
"name": {
"title": "Name",
"type": "string"
},
"schema_id": {
"title": "Schema Id",
"type": "string"
},
"schema_name": {
"description": "The schema the export is saved with.",
"title": "Schema Name",
"type": "string"
},
"tables": {
"description": "The tables made beside the files.",
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"title": "Tables",
"type": "array"
}
},
"required": [
"id",
"schema_id",
"schema_name",
"name",
"fields",
"files_layout"
],
"title": "ExportDefinitionResponse",
"type": "object"
}
DELETE /api/schemas/{schema_name}/exports/{export_name}
Delete Export
Description
Delete a saved export. Folders it already made are left (they are listed under /file-access/exports).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
export_name |
path | string | No | ||
schema_name |
path | string | No |
Responses
GET /api/schemas/{schema_name}/exports/{export_name}
Get Export
Description
One saved export.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
export_name |
path | string | No | ||
schema_name |
path | string | No |
Responses
{
"fields": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"holder": null,
"id": "string",
"include_files": true,
"name": "string",
"schema_id": "string",
"schema_name": "string",
"tables": [
{
"columns": null,
"format": "csv",
"kind": null,
"name": null,
"shape": "rows",
"skip_empty": true,
"where": null
}
]
}
Schema of the response body
{
"properties": {
"fields": {
"description": "The file fields exported; empty means every file field.",
"items": {
"type": "string"
},
"title": "Fields",
"type": "array"
},
"files_layout": {
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter on the records that hold the files (same shape as the records 'filter' parameter).",
"title": "Filter Tree"
},
"holder": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The kind of record that holds the files; null means any kind beneath the schema.",
"title": "Holder"
},
"id": {
"title": "Id",
"type": "string"
},
"include_files": {
"default": true,
"description": "False: the export is tables alone.",
"title": "Include Files",
"type": "boolean"
},
"name": {
"title": "Name",
"type": "string"
},
"schema_id": {
"title": "Schema Id",
"type": "string"
},
"schema_name": {
"description": "The schema the export is saved with.",
"title": "Schema Name",
"type": "string"
},
"tables": {
"description": "The tables made beside the files.",
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"title": "Tables",
"type": "array"
}
},
"required": [
"id",
"schema_id",
"schema_name",
"name",
"fields",
"files_layout"
],
"title": "ExportDefinitionResponse",
"type": "object"
}
PATCH /api/schemas/{schema_name}/exports/{export_name}
Update Export
Description
Change a saved export. A key left out is left alone; holder and
filter_tree may be sent as null to clear them. The result is checked as a
whole.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
export_name |
path | string | No | ||
schema_name |
path | string | No |
Request body
{
"fields": null,
"files_layout": null,
"filter_tree": null,
"holder": null,
"include_files": null,
"rename": null,
"tables": null
}
Schema of the request body
{
"properties": {
"fields": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Replace the file fields; omit to leave as is.",
"title": "Fields"
},
"files_layout": {
"anyOf": [
{
"enum": [
"tree",
"grouped",
"flat"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Change the layout; omit to leave as is.",
"title": "Files Layout"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Replace the filter; send null to clear it.",
"title": "Filter Tree"
},
"holder": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Change the kind; send null for 'any beneath'.",
"title": "Holder"
},
"include_files": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Take the files or not; omit to leave as is.",
"title": "Include Files"
},
"rename": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "New name.",
"title": "Rename"
},
"tables": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Replace the tables; send an empty list to remove them.",
"title": "Tables"
}
},
"title": "UpdateExportDefinitionRequest",
"type": "object"
}
Responses
{
"fields": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"holder": null,
"id": "string",
"include_files": true,
"name": "string",
"schema_id": "string",
"schema_name": "string",
"tables": [
{
"columns": null,
"format": "csv",
"kind": null,
"name": null,
"shape": "rows",
"skip_empty": true,
"where": null
}
]
}
Schema of the response body
{
"properties": {
"fields": {
"description": "The file fields exported; empty means every file field.",
"items": {
"type": "string"
},
"title": "Fields",
"type": "array"
},
"files_layout": {
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "A filter on the records that hold the files (same shape as the records 'filter' parameter).",
"title": "Filter Tree"
},
"holder": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The kind of record that holds the files; null means any kind beneath the schema.",
"title": "Holder"
},
"id": {
"title": "Id",
"type": "string"
},
"include_files": {
"default": true,
"description": "False: the export is tables alone.",
"title": "Include Files",
"type": "boolean"
},
"name": {
"title": "Name",
"type": "string"
},
"schema_id": {
"title": "Schema Id",
"type": "string"
},
"schema_name": {
"description": "The schema the export is saved with.",
"title": "Schema Name",
"type": "string"
},
"tables": {
"description": "The tables made beside the files.",
"items": {
"$ref": "#/components/schemas/TableRequest"
},
"title": "Tables",
"type": "array"
}
},
"required": [
"id",
"schema_id",
"schema_name",
"name",
"fields",
"files_layout"
],
"title": "ExportDefinitionResponse",
"type": "object"
}
views
GET /api/schemas/{schema_name}/views
List Views
Description
Saved views for a single schema.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No |
Responses
[
{
"columns": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"id": "string",
"name": "string",
"schema_id": "string",
"schema_name": "string",
"sort": [
{}
]
}
]
POST /api/schemas/{schema_name}/views
Create View
Description
Create a saved column/filter/sort view against a schema's own fields,
with columns optionally joining one hop through a reference field.
files_layout says how its files are arranged when it is exported as a
folder or zip.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"columns": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Base schema field names to show, in order. May also include single-hop reference-field joins as 'ref_field.target_field'.",
"title": "Columns"
},
"files_layout": {
"default": "tree",
"description": "How the view's files are arranged when exported: 'tree' (a folder per record above each file) or 'flat' (all in one folder).",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "AND/OR filter tree, same shape as the records 'filter' query parameter (conditions may name an ancestor or descendant schema).",
"title": "Filter Tree"
},
"name": {
"description": "What the view is called, in your own words -- spaces, capitals and punctuation are fine. Only '/', '\\' and control characters are refused. Unique per schema.",
"title": "Name",
"type": "string"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Ordered list of {field, direction} entries; direction is 'asc' or 'desc'.",
"title": "Sort"
}
},
"required": [
"name"
],
"title": "CreateViewRequest",
"type": "object"
}
Responses
{
"columns": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"id": "string",
"name": "string",
"schema_id": "string",
"schema_name": "string",
"sort": [
{}
]
}
Schema of the response body
{
"properties": {
"columns": {
"description": "Base schema field names to show, in order (own or inherited). May also include single-hop reference-field joins as 'ref_field.target_field' (e.g. 'customer.email').",
"items": {
"type": "string"
},
"title": "Columns",
"type": "array"
},
"files_layout": {
"default": "tree",
"description": "How the view's files are arranged when exported as a folder or zip: 'tree' puts each file in a folder per record above it (Encounter/Recording/Selection/...), 'grouped' keeps the folders above the records that hold the files but gathers those records' files into one folder named for their kind (Encounter/Recording/Selections/...), 'flat' puts every file in one folder.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "AND/OR filter tree, same shape as the records 'filter' query parameter (conditions may name an ancestor or descendant schema).",
"title": "Filter Tree"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"schema_id": {
"title": "Schema Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"sort": {
"description": "Ordered list of {field, direction} entries; direction is 'asc' or 'desc'.",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Sort",
"type": "array"
}
},
"required": [
"id",
"schema_id",
"schema_name",
"name",
"columns",
"sort"
],
"title": "ViewResponse",
"type": "object"
}
POST /api/schemas/{schema_name}/views/preview
Preview View
Description
Rows + total count for a column/filter/sort selection without saving it as a view -- backs the view builder's live preview.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"columns": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Same shape as a view's 'columns' -- base schema field names and/or single-hop reference-field joins. Validated the same way, but not persisted.",
"title": "Columns"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Same shape as a view's 'filter_tree'.",
"title": "Filter Tree"
},
"limit": {
"default": 50,
"maximum": 1000.0,
"minimum": 1.0,
"title": "Limit",
"type": "integer"
},
"offset": {
"default": 0,
"minimum": 0.0,
"title": "Offset",
"type": "integer"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Same shape as a view's 'sort': the schema's own or an inherited field, each ascending or descending.",
"title": "Sort"
}
},
"title": "PreviewViewRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"rows": {
"description": "One dict per matching record, keyed by column (joined columns use the 'ref_field.target_field' key).",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Rows",
"type": "array"
},
"total": {
"description": "Total matching records regardless of 'limit'/'offset'.",
"title": "Total",
"type": "integer"
}
},
"required": [
"rows",
"total"
],
"title": "PreviewViewResponse",
"type": "object"
}
DELETE /api/schemas/{schema_name}/views/{view_name}
Delete View
Description
Delete a saved view. Does not affect the underlying records.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No | ||
view_name |
path | string | No |
Responses
GET /api/schemas/{schema_name}/views/{view_name}
Get View
Description
A single saved view by name.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No | ||
view_name |
path | string | No |
Responses
{
"columns": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"id": "string",
"name": "string",
"schema_id": "string",
"schema_name": "string",
"sort": [
{}
]
}
Schema of the response body
{
"properties": {
"columns": {
"description": "Base schema field names to show, in order (own or inherited). May also include single-hop reference-field joins as 'ref_field.target_field' (e.g. 'customer.email').",
"items": {
"type": "string"
},
"title": "Columns",
"type": "array"
},
"files_layout": {
"default": "tree",
"description": "How the view's files are arranged when exported as a folder or zip: 'tree' puts each file in a folder per record above it (Encounter/Recording/Selection/...), 'grouped' keeps the folders above the records that hold the files but gathers those records' files into one folder named for their kind (Encounter/Recording/Selections/...), 'flat' puts every file in one folder.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "AND/OR filter tree, same shape as the records 'filter' query parameter (conditions may name an ancestor or descendant schema).",
"title": "Filter Tree"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"schema_id": {
"title": "Schema Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"sort": {
"description": "Ordered list of {field, direction} entries; direction is 'asc' or 'desc'.",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Sort",
"type": "array"
}
},
"required": [
"id",
"schema_id",
"schema_name",
"name",
"columns",
"sort"
],
"title": "ViewResponse",
"type": "object"
}
PATCH /api/schemas/{schema_name}/views/{view_name}
Update View
Description
Rename a view and/or replace its columns/filter_tree/sort/files_layout.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
schema_name |
path | string | No | ||
view_name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"columns": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Replace the column list; omit the key to leave it unchanged.",
"title": "Columns"
},
"files_layout": {
"anyOf": [
{
"enum": [
"tree",
"grouped",
"flat"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Change how the view's files are arranged when exported; omit the key to leave it unchanged.",
"title": "Files Layout"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "Replace the filter tree; send null to clear it, omit the key to leave it unchanged.",
"title": "Filter Tree"
},
"rename": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "New name; same rules as when creating.",
"title": "Rename"
},
"sort": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Replace the sort order; omit the key to leave it unchanged.",
"title": "Sort"
}
},
"title": "UpdateViewRequest",
"type": "object"
}
Responses
{
"columns": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"id": "string",
"name": "string",
"schema_id": "string",
"schema_name": "string",
"sort": [
{}
]
}
Schema of the response body
{
"properties": {
"columns": {
"description": "Base schema field names to show, in order (own or inherited). May also include single-hop reference-field joins as 'ref_field.target_field' (e.g. 'customer.email').",
"items": {
"type": "string"
},
"title": "Columns",
"type": "array"
},
"files_layout": {
"default": "tree",
"description": "How the view's files are arranged when exported as a folder or zip: 'tree' puts each file in a folder per record above it (Encounter/Recording/Selection/...), 'grouped' keeps the folders above the records that hold the files but gathers those records' files into one folder named for their kind (Encounter/Recording/Selections/...), 'flat' puts every file in one folder.",
"enum": [
"tree",
"grouped",
"flat"
],
"title": "Files Layout",
"type": "string"
},
"filter_tree": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "AND/OR filter tree, same shape as the records 'filter' query parameter (conditions may name an ancestor or descendant schema).",
"title": "Filter Tree"
},
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"schema_id": {
"title": "Schema Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"sort": {
"description": "Ordered list of {field, direction} entries; direction is 'asc' or 'desc'.",
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Sort",
"type": "array"
}
},
"required": [
"id",
"schema_id",
"schema_name",
"name",
"columns",
"sort"
],
"title": "ViewResponse",
"type": "object"
}
GET /api/schemas/{schema_name}/views/{view_name}/export
Export View
Description
Export a view's rows as csv, tsv, xlsx, json or jsonl, honoring its saved
filter and sort and flattening columns (joined columns are dotted headers
"ref_field.target_field" in the text formats; json nests them). Any
file/file_list column gets bundled into a zip alongside the table, laid out as
the view's files_layout says -- the same paths as the Files menu -- and each
file cell holds that path. Files that can't be reached (a drive that isn't
connected) are left out and listed in MISSING.txt. This is the same export as
POST /file-access/zip with view, which also takes a collection or record to
run it in.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
format |
query | string | csv | No | |
schema_name |
path | string | No | ||
view_name |
path | string | No |
Responses
GET /api/views
List All Views
Description
Every saved view across every schema, sorted by schema then view name -- backs the top-level Views index page.
Responses
[
{
"columns": [
"string"
],
"files_layout": "tree",
"filter_tree": null,
"id": "string",
"name": "string",
"schema_id": "string",
"schema_name": "string",
"sort": [
{}
]
}
]
settings
DELETE /api/settings/command-line
Remove Command Line
Description
Take the desktop app's civex off PATH again (only ever its own entry
or link).
Responses
Schema of the response body
{
"properties": {
"available": {
"description": "Whether this is the desktop app's civex, the only one this applies to (a uv, pipx or pip install is already a command).",
"title": "Available",
"type": "boolean"
},
"note": {
"description": "What is still to do, or why it can't be done; blank if nothing.",
"title": "Note",
"type": "string"
},
"on_path": {
"description": "Whether a new terminal finds this civex as `civex`.",
"title": "On Path",
"type": "boolean"
},
"shadowed_by": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Another civex a terminal would find first, if there is one.",
"title": "Shadowed By"
},
"where": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The folder put on PATH (Windows) or the link made (macOS, Linux).",
"title": "Where"
}
},
"required": [
"available",
"on_path",
"where",
"shadowed_by",
"note"
],
"title": "CommandLineResponse",
"type": "object"
}
GET /api/settings/command-line
Get Command Line
Description
Whether the desktop app's civex can be typed in a terminal.
Responses
Schema of the response body
{
"properties": {
"available": {
"description": "Whether this is the desktop app's civex, the only one this applies to (a uv, pipx or pip install is already a command).",
"title": "Available",
"type": "boolean"
},
"note": {
"description": "What is still to do, or why it can't be done; blank if nothing.",
"title": "Note",
"type": "string"
},
"on_path": {
"description": "Whether a new terminal finds this civex as `civex`.",
"title": "On Path",
"type": "boolean"
},
"shadowed_by": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Another civex a terminal would find first, if there is one.",
"title": "Shadowed By"
},
"where": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The folder put on PATH (Windows) or the link made (macOS, Linux).",
"title": "Where"
}
},
"required": [
"available",
"on_path",
"where",
"shadowed_by",
"note"
],
"title": "CommandLineResponse",
"type": "object"
}
POST /api/settings/command-line
Add Command Line
Description
Put the desktop app's civex on PATH: the user PATH on Windows (no
administrator), a link in ~/.local/bin on macOS and Linux. 409 when this
isn't the desktop app's civex, or the link's place is taken.
Responses
Schema of the response body
{
"properties": {
"available": {
"description": "Whether this is the desktop app's civex, the only one this applies to (a uv, pipx or pip install is already a command).",
"title": "Available",
"type": "boolean"
},
"note": {
"description": "What is still to do, or why it can't be done; blank if nothing.",
"title": "Note",
"type": "string"
},
"on_path": {
"description": "Whether a new terminal finds this civex as `civex`.",
"title": "On Path",
"type": "boolean"
},
"shadowed_by": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Another civex a terminal would find first, if there is one.",
"title": "Shadowed By"
},
"where": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The folder put on PATH (Windows) or the link made (macOS, Linux).",
"title": "Where"
}
},
"required": [
"available",
"on_path",
"where",
"shadowed_by",
"note"
],
"title": "CommandLineResponse",
"type": "object"
}
GET /api/settings/identity
Get Identity
Description
Who changes made in this project are recorded as.
Responses
Schema of the response body
{
"properties": {
"chosen": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The name chosen for this project, or null when none is.",
"title": "Chosen"
},
"default": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What is used when none is chosen: the operating-system user.",
"title": "Default"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What changes made here are recorded as.",
"title": "Name"
}
},
"required": [
"name",
"chosen",
"default"
],
"title": "IdentityResponse",
"type": "object"
}
PATCH /api/settings/identity
Update Identity
Description
Choose the name recorded on changes made in this project. It is saved in this project's config.toml.
Request body
Schema of the request body
{
"properties": {
"name": {
"anyOf": [
{
"maxLength": 100,
"type": "string"
},
{
"type": "null"
}
],
"description": "The name to record on changes made in this project; blank or null goes back to the default (the operating-system user). Saved in the project's config.toml.",
"title": "Name"
}
},
"title": "UpdateIdentityRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"chosen": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The name chosen for this project, or null when none is.",
"title": "Chosen"
},
"default": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What is used when none is chosen: the operating-system user.",
"title": "Default"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "What changes made here are recorded as.",
"title": "Name"
}
},
"required": [
"name",
"chosen",
"default"
],
"title": "IdentityResponse",
"type": "object"
}
GET /api/settings/map
Get Map Settings
Description
Where the location editor gets street-level map tiles, if anywhere.
Responses
Schema of the response body
{
"properties": {
"attribution": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Credit shown on the map for the tile provider, as plain text.",
"title": "Attribution"
},
"tile_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "XYZ tile URL for the location editor's street-level map, with {z}, {x} and {y} placeholders. Null means the editor uses only its bundled coastlines.",
"title": "Tile Url"
}
},
"required": [
"tile_url",
"attribution"
],
"title": "MapSettingsResponse",
"type": "object"
}
PATCH /api/settings/map
Update Map Settings
Description
Set (or clear, with null) the map tile URL. It must be an http(s) XYZ URL containing {z}, {x} and {y}. The provider's terms of use apply.
Request body
Schema of the request body
{
"properties": {
"attribution": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Plain-text credit for the provider, or null.",
"title": "Attribution"
},
"tile_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "XYZ tile URL (http or https, with {z}, {x}, {y}), or null to clear.",
"title": "Tile Url"
}
},
"required": [
"tile_url"
],
"title": "UpdateMapSettingsRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"attribution": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Credit shown on the map for the tile provider, as plain text.",
"title": "Attribution"
},
"tile_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "XYZ tile URL for the location editor's street-level map, with {z}, {x} and {y} placeholders. Null means the editor uses only its bundled coastlines.",
"title": "Tile Url"
}
},
"required": [
"tile_url",
"attribution"
],
"title": "MapSettingsResponse",
"type": "object"
}
GET /api/settings/retention
Get Retention Settings
Description
Return how long this project keeps deleted items, change history and workflow runs. Nothing is removed by itself: a clean-up applies these.
Responses
Schema of the response body
{
"properties": {
"audit_days": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Change history older than this many days is removed by a clean-up. Null keeps it forever.",
"title": "Audit Days"
},
"auto_purge_deleted": {
"description": "Whether a clean-up permanently deletes items deleted more than `purge_after_days` ago.",
"title": "Auto Purge Deleted",
"type": "boolean"
},
"purge_after_days": {
"description": "Deleted items can be restored for this many days. A clean-up only deletes them permanently after that when `auto_purge_deleted` is on.",
"title": "Purge After Days",
"type": "integer"
},
"run_days": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Finished workflow runs, with their step logs, older than this many days are removed by a clean-up. Null keeps them forever.",
"title": "Run Days"
}
},
"required": [
"purge_after_days",
"auto_purge_deleted",
"audit_days",
"run_days"
],
"title": "RetentionSettingsResponse",
"type": "object"
}
PATCH /api/settings/retention
Update Retention Settings
Description
Change the retention settings. Only the fields sent change; a null
audit_days or run_days means keep that kind forever.
Request body
Schema of the request body
{
"description": "Only the fields sent are changed; send null for `audit_days` or\n`run_days` to keep that kind forever.",
"properties": {
"audit_days": {
"anyOf": [
{
"minimum": 1.0,
"type": "integer"
},
{
"type": "null"
}
],
"title": "Audit Days"
},
"auto_purge_deleted": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Auto Purge Deleted"
},
"purge_after_days": {
"anyOf": [
{
"minimum": 1.0,
"type": "integer"
},
{
"type": "null"
}
],
"title": "Purge After Days"
},
"run_days": {
"anyOf": [
{
"minimum": 1.0,
"type": "integer"
},
{
"type": "null"
}
],
"title": "Run Days"
}
},
"title": "UpdateRetentionSettingsRequest",
"type": "object"
}
Responses
Schema of the response body
{
"properties": {
"audit_days": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Change history older than this many days is removed by a clean-up. Null keeps it forever.",
"title": "Audit Days"
},
"auto_purge_deleted": {
"description": "Whether a clean-up permanently deletes items deleted more than `purge_after_days` ago.",
"title": "Auto Purge Deleted",
"type": "boolean"
},
"purge_after_days": {
"description": "Deleted items can be restored for this many days. A clean-up only deletes them permanently after that when `auto_purge_deleted` is on.",
"title": "Purge After Days",
"type": "integer"
},
"run_days": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"description": "Finished workflow runs, with their step logs, older than this many days are removed by a clean-up. Null keeps them forever.",
"title": "Run Days"
}
},
"required": [
"purge_after_days",
"auto_purge_deleted",
"audit_days",
"run_days"
],
"title": "RetentionSettingsResponse",
"type": "object"
}
GET /api/settings/shortcut
Get Shortcut
Description
Whether this project has a Desktop shortcut that starts civex.
Responses
Schema of the response body
{
"properties": {
"exists": {
"description": "Whether the Desktop shortcut for this project is there.",
"title": "Exists",
"type": "boolean"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Where it is (or would be), when there is a Desktop.",
"title": "Path"
}
},
"required": [
"exists"
],
"title": "ShortcutResponse",
"type": "object"
}
POST /api/settings/shortcut
Create Shortcut
Description
Put a Desktop shortcut that starts civex for this project and opens it in the browser. Runs on the machine civex runs on.
Responses
Schema of the response body
{
"properties": {
"exists": {
"description": "Whether the Desktop shortcut for this project is there.",
"title": "Exists",
"type": "boolean"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Where it is (or would be), when there is a Desktop.",
"title": "Path"
}
},
"required": [
"exists"
],
"title": "ShortcutResponse",
"type": "object"
}
GET /api/settings/ui
Get Ui Settings
Description
Return this project's UI preferences.
Responses
PATCH /api/settings/ui
Update Ui Settings
Description
Update this project's UI preferences.
Request body
Responses
status
GET /api/status/db
Db Status
Description
Tests the database connection with a live round-trip. A bare Depends(get_ctx) isn't enough on its own — SQLAlchemy Sessions connect lazily, so building the context doesn't prove a query would actually succeed. A failure here is caught by get_ctx() the same as any other route's query (auto-recovers a docker-managed container when possible).
Responses
store
GET /api/store/browse
Browse Directory
Description
List the folders inside a directory on the machine running Civex, for choosing where a volume lives.
Folders only, never files. Starts at the home folder when path is omitted,
and also returns places to start from: the project, home and mounted drives
(network drives marked as such). A location that doesn't answer in a few
seconds is reported as not responding rather than waited on.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
path |
query | No | |||
show_hidden |
query | boolean | False | No |
Responses
{
"entries": [
{
"name": "string",
"path": "string"
}
],
"hint": null,
"locations": [
{
"free_bytes": null,
"kind": "string",
"label": "string",
"network": true,
"path": "string",
"source": null,
"total_bytes": null
}
],
"parent": null,
"path": "string",
"truncated": true
}
Schema of the response body
{
"properties": {
"entries": {
"description": "The folders directly inside it (never files).",
"items": {
"$ref": "#/components/schemas/DirectoryEntryResponse"
},
"title": "Entries",
"type": "array"
},
"hint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why a drive might be missing from `locations`, where the platform has a known reason (for example a Windows drive not yet mounted under WSL).",
"title": "Hint"
},
"locations": {
"description": "Places to start browsing from: the project, home and mounted drives.",
"items": {
"$ref": "#/components/schemas/StorageLocationResponse"
},
"title": "Locations",
"type": "array"
},
"parent": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Its parent folder; null at the top.",
"title": "Parent"
},
"path": {
"description": "The folder that was listed, as an absolute path.",
"title": "Path",
"type": "string"
},
"truncated": {
"description": "True if there were more folders than are shown.",
"title": "Truncated",
"type": "boolean"
}
},
"required": [
"path",
"parent",
"entries",
"truncated",
"locations"
],
"title": "DirectoryListingResponse",
"type": "object"
}
POST /api/store/browse/folder
Create Folder
Description
Create a folder while choosing a volume location.
Request body
Schema of the request body
{
"properties": {
"name": {
"description": "Name of the new folder (no slashes).",
"title": "Name",
"type": "string"
},
"parent": {
"description": "Absolute path of the folder to create it in.",
"title": "Parent",
"type": "string"
}
},
"required": [
"parent",
"name"
],
"title": "CreateFolderRequest",
"type": "object"
}
Responses
GET /api/store/collections
All Collection Storage
Description
Where every collection's files are stored, in one call.
The same answer as GET /store/collections/{id} for each collection that
has files, for pages that show them side by side. Collections with no files
are left out.
Responses
[
{
"bytes": 0,
"collection_id": "string",
"files": 0,
"unlocated_files": 0,
"unlocated_place": "string",
"volumes": [
{
"available": true,
"bytes": 0,
"files": 0,
"shared_files": 0,
"state": "string",
"volume": "string"
}
]
}
]
GET /api/store/collections/{collection_id}
Collection Storage
Description
Where a collection's files are stored.
Lists each volume that holds some of the collection's files, with how many files and bytes, how many of those another collection also uses, and whether the volume can be read now. Answered from the catalog, so it is quick however many files there are.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection_id |
path | string | No |
Responses
{
"bytes": 0,
"collection_id": "string",
"files": 0,
"unlocated_files": 0,
"unlocated_place": "string",
"volumes": [
{
"available": true,
"bytes": 0,
"files": 0,
"shared_files": 0,
"state": "string",
"volume": "string"
}
]
}
Schema of the response body
{
"properties": {
"bytes": {
"description": "Total size of the files the catalog knows.",
"title": "Bytes",
"type": "integer"
},
"collection_id": {
"title": "Collection Id",
"type": "string"
},
"files": {
"description": "Distinct files the collection's records use.",
"title": "Files",
"type": "integer"
},
"unlocated_files": {
"description": "Files records use that the catalog doesn't place on any volume.",
"title": "Unlocated Files",
"type": "integer"
},
"unlocated_place": {
"default": "missing",
"description": "Where those are: `server` (this project follows one, so they are only there) or `missing`.",
"title": "Unlocated Place",
"type": "string"
},
"volumes": {
"description": "Each volume that holds some of them, largest first.",
"items": {
"$ref": "#/components/schemas/CollectionVolumeShareResponse"
},
"title": "Volumes",
"type": "array"
}
},
"required": [
"collection_id",
"files",
"bytes",
"volumes",
"unlocated_files"
],
"title": "CollectionStorageResponse",
"type": "object"
}
POST /api/store/gc
Run Gc
Description
Reclaim object-store blobs no longer referenced by any live record or
workflow job. Defaults to a dry run (apply=false) that only reports
what's collectible; pass apply=true to actually delete. Objects
referenced only by audit history or job step logs are not protected --
both retain FileRef snapshots indefinitely, so an old audit diff may
reference a hash GC has since removed. Pass volume to clean up one
volume only (404 if there is no such volume).
Request body
Schema of the request body
{
"properties": {
"apply": {
"default": false,
"description": "Actually delete collectible objects. False (default) only reports what would be deleted.",
"title": "Apply",
"type": "boolean"
},
"grace_days": {
"default": 14,
"description": "Skip unreferenced objects written more recently than this many days.",
"minimum": 0.0,
"title": "Grace Days",
"type": "integer"
},
"rebuild_refs": {
"default": false,
"description": "Recompute the file-reference table from every record and job before collecting. Normally unnecessary; use if the table may have drifted.",
"title": "Rebuild Refs",
"type": "boolean"
},
"volume": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Only collect objects stored on this volume. Omit to clean up every volume.",
"title": "Volume"
}
},
"title": "GCRequest",
"type": "object"
}
Responses
{
"deleted": [
{
"mtime": 10.12,
"sha256": "string",
"size": 0,
"volume": "string"
}
],
"deleted_bytes": 0,
"deleted_count": 0,
"dry_run": true,
"grace_days": 0,
"protected_by_grace": 0,
"referenced": 0,
"scanned": 0,
"stale_scratch_removed": 0,
"volume": null
}
Schema of the response body
{
"properties": {
"deleted": {
"items": {
"$ref": "#/components/schemas/StoredObjectResponse"
},
"title": "Deleted",
"type": "array"
},
"deleted_bytes": {
"title": "Deleted Bytes",
"type": "integer"
},
"deleted_count": {
"description": "Objects deleted (or, if dry_run, collectible).",
"title": "Deleted Count",
"type": "integer"
},
"dry_run": {
"description": "True if no objects were actually deleted.",
"title": "Dry Run",
"type": "boolean"
},
"grace_days": {
"title": "Grace Days",
"type": "integer"
},
"protected_by_grace": {
"description": "Unreferenced objects skipped for being younger than the grace period.",
"title": "Protected By Grace",
"type": "integer"
},
"referenced": {
"description": "Distinct content hashes reachable from a live record or workflow job.",
"title": "Referenced",
"type": "integer"
},
"scanned": {
"description": "Total objects found in the store.",
"title": "Scanned",
"type": "integer"
},
"stale_scratch_removed": {
"description": "Abandoned upload scratch files (from an interrupted streamed upload) removed, or if dry_run, collectible.",
"title": "Stale Scratch Removed",
"type": "integer"
},
"volume": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The volume this pass was limited to, or null for every volume.",
"title": "Volume"
}
},
"required": [
"dry_run",
"grace_days",
"scanned",
"referenced",
"protected_by_grace",
"deleted_count",
"deleted_bytes",
"deleted",
"stale_scratch_removed"
],
"title": "GCReportResponse",
"type": "object"
}
GET /api/store/inspect
Inspect Path
Description
What adding a folder as a volume would involve, before doing it.
Reports whether it exists or would be created, whether Civex can write to
it, free space, whether it is on a network drive or on the same disk as the
project, and whether it is already a volume or carries another volume's
identity. problems are reasons adding it would be refused; warnings are
things worth knowing. Adding a volume enforces exactly these rules.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
path |
query | string | No |
Responses
{
"existing_volume": null,
"exists": true,
"free_bytes": null,
"has_civex_data": true,
"inside_project": true,
"is_dir": true,
"is_network": true,
"marker_volume": null,
"path": "string",
"problems": [
"string"
],
"same_disk_as_project": null,
"total_bytes": null,
"warnings": [
"string"
],
"will_create": true,
"writable": true
}
Schema of the response body
{
"properties": {
"existing_volume": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The configured volume already at this path, if any.",
"title": "Existing Volume"
},
"exists": {
"title": "Exists",
"type": "boolean"
},
"free_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Free Bytes"
},
"has_civex_data": {
"title": "Has Civex Data",
"type": "boolean"
},
"inside_project": {
"title": "Inside Project",
"type": "boolean"
},
"is_dir": {
"title": "Is Dir",
"type": "boolean"
},
"is_network": {
"description": "The folder is on a network filesystem.",
"title": "Is Network",
"type": "boolean"
},
"marker_volume": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The configured volume whose drive this is, if any.",
"title": "Marker Volume"
},
"path": {
"title": "Path",
"type": "string"
},
"problems": {
"description": "Reasons it can't be added as a volume.",
"items": {
"type": "string"
},
"title": "Problems",
"type": "array"
},
"same_disk_as_project": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Same Disk As Project"
},
"total_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Total Bytes"
},
"warnings": {
"description": "Things to know; they don't block adding it.",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
},
"will_create": {
"description": "The folder doesn't exist and would be created.",
"title": "Will Create",
"type": "boolean"
},
"writable": {
"title": "Writable",
"type": "boolean"
}
},
"required": [
"path",
"exists",
"is_dir",
"writable",
"will_create",
"inside_project",
"same_disk_as_project",
"free_bytes",
"total_bytes",
"existing_volume",
"marker_volume",
"has_civex_data",
"is_network",
"problems",
"warnings"
],
"title": "PathInspectionResponse",
"type": "object"
}
GET /api/store/placement
List Placements
Description
Every collection that has a home volume.
A placement only steers where a collection's new files are written. A file whose content already exists on any volume is reused where it lives and is never copied again.
Responses
DELETE /api/store/placement/{collection_id}
Clear Placement
Description
Send a collection's new files back to the general write queue.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection_id |
path | string | No |
Responses
PUT /api/store/placement/{collection_id}
Set Placement
Description
Make a volume the home of a collection's new files.
The collection is identified by id, so renaming it changes nothing here. The home need not be in the general write queue.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
collection_id |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"on_unavailable": {
"default": "spill",
"description": "spill (default) or fail.",
"title": "On Unavailable",
"type": "string"
},
"volume": {
"description": "Name of the volume that becomes the home.",
"title": "Volume",
"type": "string"
}
},
"required": [
"volume"
],
"title": "SetPlacementRequest",
"type": "object"
}
Responses
{
"collection_id": "string",
"collection_name": null,
"on_unavailable": "string",
"volume": "string"
}
Schema of the response body
{
"properties": {
"collection_id": {
"description": "Id of the collection this placement is for.",
"title": "Collection Id",
"type": "string"
},
"collection_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The collection's name, or null if it no longer exists.",
"title": "Collection Name"
},
"on_unavailable": {
"description": "spill: use the general write queue when the home volume can't take a file. fail: refuse the upload instead.",
"title": "On Unavailable",
"type": "string"
},
"volume": {
"description": "The collection's home volume.",
"title": "Volume",
"type": "string"
}
},
"required": [
"collection_id",
"collection_name",
"volume",
"on_unavailable"
],
"title": "PlacementResponse",
"type": "object"
}
PUT /api/store/queue
Set Queue
Request body
Responses
GET /api/store/transfers
List Transfers
Description
Past and running transfers, newest first.
Responses
[
{
"auto_resume": true,
"control": null,
"created_at": null,
"error": null,
"failures": [
{
"reason": "string",
"sha256": "string",
"volume": "string"
}
],
"failures_total": 0,
"finished_at": null,
"frozen": {},
"id": "string",
"kind": "string",
"live": true,
"pause_reason": null,
"plan": null,
"progress": {
"bytes_done": 0,
"bytes_total": 0,
"current": null,
"current_bytes": 0,
"current_total": 0,
"eta_seconds": null,
"files_done": 0,
"files_failed": 0,
"files_skipped": 0,
"files_total": 0,
"message": "string",
"rate_bytes_per_second": 10.12
},
"spec": {
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
},
"started_at": null,
"status": "string",
"updated_at": null
}
]
POST /api/store/transfers
Start Transfer
Description
Queue a move of files between volumes. Moves run one at a time, in the
order they were queued, so asking for a second while one is running is fine:
it waits its turn (status is queued).
Poll GET /store/transfers/{id} for progress. A file is only removed from
its source after the copy has been checked and recorded, so a transfer can
be paused, cancelled, interrupted or lose power at any moment without losing
anything. Refused (422) with every reason if it can't start.
Request body
{
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
}
Schema of the request body
{
"properties": {
"collection_ids": {
"description": "consolidate: ids of the collections to move.",
"items": {
"type": "string"
},
"title": "Collection Ids",
"type": "array"
},
"freeze_sources": {
"default": true,
"description": "drain: make the sources read-only while it runs, so new uploads don't keep landing on them, and put them back afterwards.",
"title": "Freeze Sources",
"type": "boolean"
},
"kind": {
"description": "drain: move everything off the `sources` volumes. consolidate: move the files of the `collection_ids` collections.",
"title": "Kind",
"type": "string"
},
"sources": {
"description": "drain: the volumes to empty.",
"items": {
"type": "string"
},
"title": "Sources",
"type": "array"
},
"targets": {
"description": "Volumes to put the files on, in order of preference: a file goes to the first that is usable and has room.",
"items": {
"type": "string"
},
"title": "Targets",
"type": "array"
},
"verify": {
"default": "copy",
"description": "copy: each file is hashed as it is copied and must match its recorded hash. full: the copy is also read back and hashed (about twice the reading).",
"title": "Verify",
"type": "string"
}
},
"required": [
"kind",
"targets"
],
"title": "TransferRequest",
"type": "object"
}
Responses
{
"auto_resume": true,
"control": null,
"created_at": null,
"error": null,
"failures": [
{
"reason": "string",
"sha256": "string",
"volume": "string"
}
],
"failures_total": 0,
"finished_at": null,
"frozen": {},
"id": "string",
"kind": "string",
"live": true,
"pause_reason": null,
"plan": null,
"progress": {
"bytes_done": 0,
"bytes_total": 0,
"current": null,
"current_bytes": 0,
"current_total": 0,
"eta_seconds": null,
"files_done": 0,
"files_failed": 0,
"files_skipped": 0,
"files_total": 0,
"message": "string",
"rate_bytes_per_second": 10.12
},
"spec": {
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
},
"started_at": null,
"status": "string",
"updated_at": null
}
Schema of the response body
{
"properties": {
"auto_resume": {
"description": "Paused only because a volume stopped answering, and will carry on by itself when it does.",
"title": "Auto Resume",
"type": "boolean"
},
"control": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A pause or cancel asked for and not yet acted on.",
"title": "Control"
},
"created_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Created At"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"failures": {
"description": "Files that couldn't be moved (the first few hundred).",
"items": {
"$ref": "#/components/schemas/TransferFailureResponse"
},
"title": "Failures",
"type": "array"
},
"failures_total": {
"title": "Failures Total",
"type": "integer"
},
"finished_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"frozen": {
"additionalProperties": {
"type": "string"
},
"description": "Volumes made read-only for the duration, and what each was before.",
"title": "Frozen",
"type": "object"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"title": "Kind",
"type": "string"
},
"live": {
"description": "Running on a thread of this server right now.",
"title": "Live",
"type": "boolean"
},
"pause_reason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Pause Reason"
},
"plan": {
"anyOf": [
{
"$ref": "#/components/schemas/TransferPlanResponse"
},
{
"type": "null"
}
]
},
"progress": {
"$ref": "#/components/schemas/TransferProgressResponse"
},
"spec": {
"$ref": "#/components/schemas/TransferRequest"
},
"started_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"description": "running, paused, completed, failed, cancelled or interrupted (the process died; resumable).",
"title": "Status",
"type": "string"
},
"updated_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Updated At"
}
},
"required": [
"id",
"kind",
"status",
"spec",
"plan",
"progress",
"failures",
"failures_total",
"pause_reason",
"auto_resume",
"error",
"control",
"frozen",
"live",
"created_at",
"started_at",
"finished_at",
"updated_at"
],
"title": "TransferResponse",
"type": "object"
}
POST /api/store/transfers/preview
Preview Transfer
Description
What a transfer would do, without doing anything.
Reports how many files and bytes would move and where each target would put
them, and lists problems that would stop it (a volume that is offline or
read-only, not enough room) and warnings that
are worth knowing. The sizes come from the catalog, so they are close, not
exact.
Request body
{
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
}
Schema of the request body
{
"properties": {
"collection_ids": {
"description": "consolidate: ids of the collections to move.",
"items": {
"type": "string"
},
"title": "Collection Ids",
"type": "array"
},
"freeze_sources": {
"default": true,
"description": "drain: make the sources read-only while it runs, so new uploads don't keep landing on them, and put them back afterwards.",
"title": "Freeze Sources",
"type": "boolean"
},
"kind": {
"description": "drain: move everything off the `sources` volumes. consolidate: move the files of the `collection_ids` collections.",
"title": "Kind",
"type": "string"
},
"sources": {
"description": "drain: the volumes to empty.",
"items": {
"type": "string"
},
"title": "Sources",
"type": "array"
},
"targets": {
"description": "Volumes to put the files on, in order of preference: a file goes to the first that is usable and has room.",
"items": {
"type": "string"
},
"title": "Targets",
"type": "array"
},
"verify": {
"default": "copy",
"description": "copy: each file is hashed as it is copied and must match its recorded hash. full: the copy is also read back and hashed (about twice the reading).",
"title": "Verify",
"type": "string"
}
},
"required": [
"kind",
"targets"
],
"title": "TransferRequest",
"type": "object"
}
Responses
{
"already_there": 0,
"bytes": 0,
"can_proceed": true,
"copied": 0,
"copied_bytes": 0,
"files": 0,
"problems": [
"string"
],
"targets": [
{
"bytes": 0,
"files": 0,
"free_bytes": null,
"volume": "string"
}
],
"warnings": [
"string"
]
}
Schema of the response body
{
"properties": {
"already_there": {
"description": "Files already on a target, left alone.",
"title": "Already There",
"type": "integer"
},
"bytes": {
"title": "Bytes",
"type": "integer"
},
"can_proceed": {
"title": "Can Proceed",
"type": "boolean"
},
"copied": {
"description": "Of `files`, those copied rather than moved: the drive they come from is the home of another collection that uses them, and keeps its copy.",
"title": "Copied",
"type": "integer"
},
"copied_bytes": {
"title": "Copied Bytes",
"type": "integer"
},
"files": {
"description": "Files that would be moved (from the catalog, so close, not exact).",
"title": "Files",
"type": "integer"
},
"problems": {
"description": "Reasons the transfer can't start.",
"items": {
"type": "string"
},
"title": "Problems",
"type": "array"
},
"targets": {
"items": {
"$ref": "#/components/schemas/TargetShareResponse"
},
"title": "Targets",
"type": "array"
},
"warnings": {
"description": "Things worth knowing; they don't stop it.",
"items": {
"type": "string"
},
"title": "Warnings",
"type": "array"
}
},
"required": [
"files",
"bytes",
"already_there",
"copied",
"copied_bytes",
"targets",
"problems",
"warnings",
"can_proceed"
],
"title": "TransferPlanResponse",
"type": "object"
}
GET /api/store/transfers/{transfer_id}
Get Transfer
Description
A transfer's progress and outcome: files and bytes done, speed and time
remaining, the file being copied, anything that couldn't be moved, and why
it is paused if it is. A running transfer that has stopped saving progress
(its process died) is reported as interrupted.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
transfer_id |
path | string | No |
Responses
{
"auto_resume": true,
"control": null,
"created_at": null,
"error": null,
"failures": [
{
"reason": "string",
"sha256": "string",
"volume": "string"
}
],
"failures_total": 0,
"finished_at": null,
"frozen": {},
"id": "string",
"kind": "string",
"live": true,
"pause_reason": null,
"plan": null,
"progress": {
"bytes_done": 0,
"bytes_total": 0,
"current": null,
"current_bytes": 0,
"current_total": 0,
"eta_seconds": null,
"files_done": 0,
"files_failed": 0,
"files_skipped": 0,
"files_total": 0,
"message": "string",
"rate_bytes_per_second": 10.12
},
"spec": {
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
},
"started_at": null,
"status": "string",
"updated_at": null
}
Schema of the response body
{
"properties": {
"auto_resume": {
"description": "Paused only because a volume stopped answering, and will carry on by itself when it does.",
"title": "Auto Resume",
"type": "boolean"
},
"control": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A pause or cancel asked for and not yet acted on.",
"title": "Control"
},
"created_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Created At"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"failures": {
"description": "Files that couldn't be moved (the first few hundred).",
"items": {
"$ref": "#/components/schemas/TransferFailureResponse"
},
"title": "Failures",
"type": "array"
},
"failures_total": {
"title": "Failures Total",
"type": "integer"
},
"finished_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"frozen": {
"additionalProperties": {
"type": "string"
},
"description": "Volumes made read-only for the duration, and what each was before.",
"title": "Frozen",
"type": "object"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"title": "Kind",
"type": "string"
},
"live": {
"description": "Running on a thread of this server right now.",
"title": "Live",
"type": "boolean"
},
"pause_reason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Pause Reason"
},
"plan": {
"anyOf": [
{
"$ref": "#/components/schemas/TransferPlanResponse"
},
{
"type": "null"
}
]
},
"progress": {
"$ref": "#/components/schemas/TransferProgressResponse"
},
"spec": {
"$ref": "#/components/schemas/TransferRequest"
},
"started_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"description": "running, paused, completed, failed, cancelled or interrupted (the process died; resumable).",
"title": "Status",
"type": "string"
},
"updated_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Updated At"
}
},
"required": [
"id",
"kind",
"status",
"spec",
"plan",
"progress",
"failures",
"failures_total",
"pause_reason",
"auto_resume",
"error",
"control",
"frozen",
"live",
"created_at",
"started_at",
"finished_at",
"updated_at"
],
"title": "TransferResponse",
"type": "object"
}
POST /api/store/transfers/{transfer_id}/cancel
Cancel Transfer
Description
Stop a transfer for good. Nothing already moved is moved back and no file is lost; volumes it made read-only are restored.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
transfer_id |
path | string | No |
Responses
{
"auto_resume": true,
"control": null,
"created_at": null,
"error": null,
"failures": [
{
"reason": "string",
"sha256": "string",
"volume": "string"
}
],
"failures_total": 0,
"finished_at": null,
"frozen": {},
"id": "string",
"kind": "string",
"live": true,
"pause_reason": null,
"plan": null,
"progress": {
"bytes_done": 0,
"bytes_total": 0,
"current": null,
"current_bytes": 0,
"current_total": 0,
"eta_seconds": null,
"files_done": 0,
"files_failed": 0,
"files_skipped": 0,
"files_total": 0,
"message": "string",
"rate_bytes_per_second": 10.12
},
"spec": {
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
},
"started_at": null,
"status": "string",
"updated_at": null
}
Schema of the response body
{
"properties": {
"auto_resume": {
"description": "Paused only because a volume stopped answering, and will carry on by itself when it does.",
"title": "Auto Resume",
"type": "boolean"
},
"control": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A pause or cancel asked for and not yet acted on.",
"title": "Control"
},
"created_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Created At"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"failures": {
"description": "Files that couldn't be moved (the first few hundred).",
"items": {
"$ref": "#/components/schemas/TransferFailureResponse"
},
"title": "Failures",
"type": "array"
},
"failures_total": {
"title": "Failures Total",
"type": "integer"
},
"finished_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"frozen": {
"additionalProperties": {
"type": "string"
},
"description": "Volumes made read-only for the duration, and what each was before.",
"title": "Frozen",
"type": "object"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"title": "Kind",
"type": "string"
},
"live": {
"description": "Running on a thread of this server right now.",
"title": "Live",
"type": "boolean"
},
"pause_reason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Pause Reason"
},
"plan": {
"anyOf": [
{
"$ref": "#/components/schemas/TransferPlanResponse"
},
{
"type": "null"
}
]
},
"progress": {
"$ref": "#/components/schemas/TransferProgressResponse"
},
"spec": {
"$ref": "#/components/schemas/TransferRequest"
},
"started_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"description": "running, paused, completed, failed, cancelled or interrupted (the process died; resumable).",
"title": "Status",
"type": "string"
},
"updated_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Updated At"
}
},
"required": [
"id",
"kind",
"status",
"spec",
"plan",
"progress",
"failures",
"failures_total",
"pause_reason",
"auto_resume",
"error",
"control",
"frozen",
"live",
"created_at",
"started_at",
"finished_at",
"updated_at"
],
"title": "TransferResponse",
"type": "object"
}
POST /api/store/transfers/{transfer_id}/pause
Pause Transfer
Description
Ask a transfer to pause. A running one stops within a moment, discarding any half-copied file, and keeps everything already moved; a queued one is taken out of the queue. Works for a transfer started from the command line as well as one running here.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
transfer_id |
path | string | No |
Responses
{
"auto_resume": true,
"control": null,
"created_at": null,
"error": null,
"failures": [
{
"reason": "string",
"sha256": "string",
"volume": "string"
}
],
"failures_total": 0,
"finished_at": null,
"frozen": {},
"id": "string",
"kind": "string",
"live": true,
"pause_reason": null,
"plan": null,
"progress": {
"bytes_done": 0,
"bytes_total": 0,
"current": null,
"current_bytes": 0,
"current_total": 0,
"eta_seconds": null,
"files_done": 0,
"files_failed": 0,
"files_skipped": 0,
"files_total": 0,
"message": "string",
"rate_bytes_per_second": 10.12
},
"spec": {
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
},
"started_at": null,
"status": "string",
"updated_at": null
}
Schema of the response body
{
"properties": {
"auto_resume": {
"description": "Paused only because a volume stopped answering, and will carry on by itself when it does.",
"title": "Auto Resume",
"type": "boolean"
},
"control": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A pause or cancel asked for and not yet acted on.",
"title": "Control"
},
"created_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Created At"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"failures": {
"description": "Files that couldn't be moved (the first few hundred).",
"items": {
"$ref": "#/components/schemas/TransferFailureResponse"
},
"title": "Failures",
"type": "array"
},
"failures_total": {
"title": "Failures Total",
"type": "integer"
},
"finished_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"frozen": {
"additionalProperties": {
"type": "string"
},
"description": "Volumes made read-only for the duration, and what each was before.",
"title": "Frozen",
"type": "object"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"title": "Kind",
"type": "string"
},
"live": {
"description": "Running on a thread of this server right now.",
"title": "Live",
"type": "boolean"
},
"pause_reason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Pause Reason"
},
"plan": {
"anyOf": [
{
"$ref": "#/components/schemas/TransferPlanResponse"
},
{
"type": "null"
}
]
},
"progress": {
"$ref": "#/components/schemas/TransferProgressResponse"
},
"spec": {
"$ref": "#/components/schemas/TransferRequest"
},
"started_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"description": "running, paused, completed, failed, cancelled or interrupted (the process died; resumable).",
"title": "Status",
"type": "string"
},
"updated_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Updated At"
}
},
"required": [
"id",
"kind",
"status",
"spec",
"plan",
"progress",
"failures",
"failures_total",
"pause_reason",
"auto_resume",
"error",
"control",
"frozen",
"live",
"created_at",
"started_at",
"finished_at",
"updated_at"
],
"title": "TransferResponse",
"type": "object"
}
POST /api/store/transfers/{transfer_id}/resume
Resume Transfer
Description
Put a paused, failed or interrupted transfer back in the queue; it carries on where it left off when its turn comes. What is already moved is not moved again.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
transfer_id |
path | string | No |
Responses
{
"auto_resume": true,
"control": null,
"created_at": null,
"error": null,
"failures": [
{
"reason": "string",
"sha256": "string",
"volume": "string"
}
],
"failures_total": 0,
"finished_at": null,
"frozen": {},
"id": "string",
"kind": "string",
"live": true,
"pause_reason": null,
"plan": null,
"progress": {
"bytes_done": 0,
"bytes_total": 0,
"current": null,
"current_bytes": 0,
"current_total": 0,
"eta_seconds": null,
"files_done": 0,
"files_failed": 0,
"files_skipped": 0,
"files_total": 0,
"message": "string",
"rate_bytes_per_second": 10.12
},
"spec": {
"collection_ids": [
"string"
],
"freeze_sources": true,
"kind": "string",
"sources": [
"string"
],
"targets": [
"string"
],
"verify": "string"
},
"started_at": null,
"status": "string",
"updated_at": null
}
Schema of the response body
{
"properties": {
"auto_resume": {
"description": "Paused only because a volume stopped answering, and will carry on by itself when it does.",
"title": "Auto Resume",
"type": "boolean"
},
"control": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A pause or cancel asked for and not yet acted on.",
"title": "Control"
},
"created_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Created At"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"failures": {
"description": "Files that couldn't be moved (the first few hundred).",
"items": {
"$ref": "#/components/schemas/TransferFailureResponse"
},
"title": "Failures",
"type": "array"
},
"failures_total": {
"title": "Failures Total",
"type": "integer"
},
"finished_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"frozen": {
"additionalProperties": {
"type": "string"
},
"description": "Volumes made read-only for the duration, and what each was before.",
"title": "Frozen",
"type": "object"
},
"id": {
"title": "Id",
"type": "string"
},
"kind": {
"title": "Kind",
"type": "string"
},
"live": {
"description": "Running on a thread of this server right now.",
"title": "Live",
"type": "boolean"
},
"pause_reason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Pause Reason"
},
"plan": {
"anyOf": [
{
"$ref": "#/components/schemas/TransferPlanResponse"
},
{
"type": "null"
}
]
},
"progress": {
"$ref": "#/components/schemas/TransferProgressResponse"
},
"spec": {
"$ref": "#/components/schemas/TransferRequest"
},
"started_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"description": "running, paused, completed, failed, cancelled or interrupted (the process died; resumable).",
"title": "Status",
"type": "string"
},
"updated_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Updated At"
}
},
"required": [
"id",
"kind",
"status",
"spec",
"plan",
"progress",
"failures",
"failures_total",
"pause_reason",
"auto_resume",
"error",
"control",
"frozen",
"live",
"created_at",
"started_at",
"finished_at",
"updated_at"
],
"title": "TransferResponse",
"type": "object"
}
GET /api/store/volumes
List Volumes
Description
Every volume with its state and usage, including how much of what it
holds no collection uses (unused_*, which garbage collection can reclaim,
and history_*, kept only for workflow run history).
Responses
[
{
"allocated_gb": null,
"available": true,
"civex_used_bytes": null,
"disk_free_bytes": null,
"disk_total_bytes": null,
"fix": "string",
"history_bytes": 0,
"history_files": 0,
"in_queue": true,
"name": "string",
"network": true,
"path": "string",
"reason": "string",
"state": "string",
"unused_bytes": 0,
"unused_files": 0,
"warning": true
}
]
POST /api/store/volumes
Add Volume
Request body
Schema of the request body
{
"properties": {
"add_to_queue": {
"default": false,
"description": "Also put the volume in the general write queue. Leave false for a volume that only homes particular collections.",
"title": "Add To Queue",
"type": "boolean"
},
"allocated_gb": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Allocated Gb"
},
"name": {
"title": "Name",
"type": "string"
},
"path": {
"title": "Path",
"type": "string"
}
},
"required": [
"name",
"path"
],
"title": "AddVolumeRequest",
"type": "object"
}
Responses
{
"allocated_gb": null,
"available": true,
"civex_used_bytes": null,
"disk_free_bytes": null,
"disk_total_bytes": null,
"fix": "string",
"history_bytes": 0,
"history_files": 0,
"in_queue": true,
"name": "string",
"network": true,
"path": "string",
"reason": "string",
"state": "string",
"unused_bytes": 0,
"unused_files": 0,
"warning": true
}
Schema of the response body
{
"properties": {
"allocated_gb": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Allocated Gb"
},
"available": {
"description": "True if the volume's files can be read right now (online, read-only or retired).",
"title": "Available",
"type": "boolean"
},
"civex_used_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Civex Used Bytes"
},
"disk_free_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Disk Free Bytes"
},
"disk_total_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Disk Total Bytes"
},
"fix": {
"description": "A plain-language next step for an offline or wrong-drive volume; empty otherwise.",
"title": "Fix",
"type": "string"
},
"history_bytes": {
"default": 0,
"title": "History Bytes",
"type": "integer"
},
"history_files": {
"default": 0,
"description": "Files kept only because a workflow run took them as an input.",
"title": "History Files",
"type": "integer"
},
"in_queue": {
"title": "In Queue",
"type": "boolean"
},
"name": {
"title": "Name",
"type": "string"
},
"network": {
"default": false,
"description": "The volume's folder is on a network drive.",
"title": "Network",
"type": "boolean"
},
"path": {
"title": "Path",
"type": "string"
},
"reason": {
"description": "What civex expected versus what it found; empty when online.",
"title": "Reason",
"type": "string"
},
"state": {
"description": "online, offline (path not there, e.g. drive unplugged), wrong_drive (something else is mounted there), readonly or retired.",
"title": "State",
"type": "string"
},
"unused_bytes": {
"default": 0,
"title": "Unused Bytes",
"type": "integer"
},
"unused_files": {
"default": 0,
"description": "Files on the volume that nothing uses; garbage collection can reclaim them.",
"title": "Unused Files",
"type": "integer"
},
"warning": {
"title": "Warning",
"type": "boolean"
}
},
"required": [
"name",
"path",
"allocated_gb",
"civex_used_bytes",
"disk_free_bytes",
"disk_total_bytes",
"available",
"state",
"reason",
"fix",
"warning",
"in_queue"
],
"title": "VolumeStatsResponse",
"type": "object"
}
DELETE /api/store/volumes/{name}
Remove Volume
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
force |
query | boolean | False | No | |
name |
path | string | No |
Responses
PATCH /api/store/volumes/{name}
Update Volume
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Schema of the request body
{
"properties": {
"allocated_gb": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Allocated Gb"
},
"clear_allocation": {
"default": false,
"title": "Clear Allocation",
"type": "boolean"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Path"
},
"state": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "active, readonly (readable, never written to) or retired.",
"title": "State"
}
},
"title": "UpdateVolumeRequest",
"type": "object"
}
Responses
{
"allocated_gb": null,
"available": true,
"civex_used_bytes": null,
"disk_free_bytes": null,
"disk_total_bytes": null,
"fix": "string",
"history_bytes": 0,
"history_files": 0,
"in_queue": true,
"name": "string",
"network": true,
"path": "string",
"reason": "string",
"state": "string",
"unused_bytes": 0,
"unused_files": 0,
"warning": true
}
Schema of the response body
{
"properties": {
"allocated_gb": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Allocated Gb"
},
"available": {
"description": "True if the volume's files can be read right now (online, read-only or retired).",
"title": "Available",
"type": "boolean"
},
"civex_used_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Civex Used Bytes"
},
"disk_free_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Disk Free Bytes"
},
"disk_total_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Disk Total Bytes"
},
"fix": {
"description": "A plain-language next step for an offline or wrong-drive volume; empty otherwise.",
"title": "Fix",
"type": "string"
},
"history_bytes": {
"default": 0,
"title": "History Bytes",
"type": "integer"
},
"history_files": {
"default": 0,
"description": "Files kept only because a workflow run took them as an input.",
"title": "History Files",
"type": "integer"
},
"in_queue": {
"title": "In Queue",
"type": "boolean"
},
"name": {
"title": "Name",
"type": "string"
},
"network": {
"default": false,
"description": "The volume's folder is on a network drive.",
"title": "Network",
"type": "boolean"
},
"path": {
"title": "Path",
"type": "string"
},
"reason": {
"description": "What civex expected versus what it found; empty when online.",
"title": "Reason",
"type": "string"
},
"state": {
"description": "online, offline (path not there, e.g. drive unplugged), wrong_drive (something else is mounted there), readonly or retired.",
"title": "State",
"type": "string"
},
"unused_bytes": {
"default": 0,
"title": "Unused Bytes",
"type": "integer"
},
"unused_files": {
"default": 0,
"description": "Files on the volume that nothing uses; garbage collection can reclaim them.",
"title": "Unused Files",
"type": "integer"
},
"warning": {
"title": "Warning",
"type": "boolean"
}
},
"required": [
"name",
"path",
"allocated_gb",
"civex_used_bytes",
"disk_free_bytes",
"disk_total_bytes",
"available",
"state",
"reason",
"fix",
"warning",
"in_queue"
],
"title": "VolumeStatsResponse",
"type": "object"
}
POST /api/store/volumes/{name}/adopt
Adopt Volume
Description
Declare that the drive at the volume's path is that volume.
Volumes are recognised by an identity marker in their root, so civex can
tell an unplugged drive from a different drive mounted at the same path.
Use this when a volume is reported as wrong_drive but the drive is in fact
the right one (the marker was deleted, or the drive was re-formatted): it
rewrites the marker. Nothing else on the drive is changed.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"allocated_gb": null,
"available": true,
"civex_used_bytes": null,
"disk_free_bytes": null,
"disk_total_bytes": null,
"fix": "string",
"history_bytes": 0,
"history_files": 0,
"in_queue": true,
"name": "string",
"network": true,
"path": "string",
"reason": "string",
"state": "string",
"unused_bytes": 0,
"unused_files": 0,
"warning": true
}
Schema of the response body
{
"properties": {
"allocated_gb": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Allocated Gb"
},
"available": {
"description": "True if the volume's files can be read right now (online, read-only or retired).",
"title": "Available",
"type": "boolean"
},
"civex_used_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Civex Used Bytes"
},
"disk_free_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Disk Free Bytes"
},
"disk_total_bytes": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Disk Total Bytes"
},
"fix": {
"description": "A plain-language next step for an offline or wrong-drive volume; empty otherwise.",
"title": "Fix",
"type": "string"
},
"history_bytes": {
"default": 0,
"title": "History Bytes",
"type": "integer"
},
"history_files": {
"default": 0,
"description": "Files kept only because a workflow run took them as an input.",
"title": "History Files",
"type": "integer"
},
"in_queue": {
"title": "In Queue",
"type": "boolean"
},
"name": {
"title": "Name",
"type": "string"
},
"network": {
"default": false,
"description": "The volume's folder is on a network drive.",
"title": "Network",
"type": "boolean"
},
"path": {
"title": "Path",
"type": "string"
},
"reason": {
"description": "What civex expected versus what it found; empty when online.",
"title": "Reason",
"type": "string"
},
"state": {
"description": "online, offline (path not there, e.g. drive unplugged), wrong_drive (something else is mounted there), readonly or retired.",
"title": "State",
"type": "string"
},
"unused_bytes": {
"default": 0,
"title": "Unused Bytes",
"type": "integer"
},
"unused_files": {
"default": 0,
"description": "Files on the volume that nothing uses; garbage collection can reclaim them.",
"title": "Unused Files",
"type": "integer"
},
"warning": {
"title": "Warning",
"type": "boolean"
}
},
"required": [
"name",
"path",
"allocated_gb",
"civex_used_bytes",
"disk_free_bytes",
"disk_total_bytes",
"available",
"state",
"reason",
"fix",
"warning",
"in_queue"
],
"title": "VolumeStatsResponse",
"type": "object"
}
update
GET /api/update
Update Status
Description
Whether a newer civex is available, and whether this copy can install it
from the app (the same check as civex update --check).
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
pre |
query | boolean | False | No | Look for pre-releases too. |
Responses
{
"blocked": "string",
"can_update": true,
"current": "string",
"error": "string",
"installer": "string",
"last": null,
"latest": null,
"newer": true,
"pre": true
}
Schema of the response body
{
"properties": {
"blocked": {
"description": "Why it can't, in plain words; blank when it can.",
"title": "Blocked",
"type": "string"
},
"can_update": {
"description": "Whether the app can update this copy.",
"title": "Can Update",
"type": "boolean"
},
"current": {
"description": "The version running now.",
"title": "Current",
"type": "string"
},
"error": {
"description": "Why PyPI couldn't be asked; blank when it was.",
"title": "Error",
"type": "string"
},
"installer": {
"description": "How this copy was installed: desktop, frozen, editable, pipx, uv or pip.",
"title": "Installer",
"type": "string"
},
"last": {
"anyOf": [
{
"$ref": "#/components/schemas/UpdateAttempt"
},
{
"type": "null"
}
],
"description": "The outcome of the last update started from the app."
},
"latest": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The newest version on PyPI (pre-releases too when asked for); null when PyPI couldn't be reached.",
"title": "Latest"
},
"newer": {
"description": "Whether `latest` is newer than `current`.",
"title": "Newer",
"type": "boolean"
},
"pre": {
"description": "Whether pre-releases were looked for.",
"title": "Pre",
"type": "boolean"
}
},
"required": [
"current",
"latest",
"newer",
"pre",
"installer",
"can_update",
"blocked",
"error",
"last"
],
"title": "UpdateStatusResponse",
"type": "object"
}
POST /api/update
Start Update
Description
Update civex and start it again. civex closes once this answers; the
update runs after it has exited (a running copy can't be replaced on
Windows), and its outcome is in last on the next status. 409 when this
copy can't be updated from the app (blocked says why).
Request body
Responses
workflows
GET /api/workflows
List Workflows
Responses
POST /api/workflows/{name}/run
Run Workflow
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Responses
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
Schema of the response body
{
"properties": {
"affected_records": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Affected Records"
},
"created_at": {
"format": "date-time",
"title": "Created At",
"type": "string"
},
"depth": {
"default": 0,
"description": "How many workflow-triggered-by-workflow hops deep this run is: 0 for a run started by a person or an ordinary edit, 1 for a run started by another run's save, and so on.",
"title": "Depth",
"type": "integer"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
},
"error_details": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Error Details"
},
"finished_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Finished At"
},
"id": {
"title": "Id",
"type": "string"
},
"log": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Log"
},
"record_id": {
"title": "Record Id",
"type": "string"
},
"schema_name": {
"title": "Schema Name",
"type": "string"
},
"started_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"title": "Started At"
},
"status": {
"title": "Status",
"type": "string"
},
"step_executions": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Step Executions"
},
"trigger": {
"title": "Trigger",
"type": "string"
},
"trigger_detail": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"description": "What caused the run. `changes` lists each field that changed, with a short `before` and `after` and whether the workflow was `watched` for it. `caused_by` is {job_id, workflow} when another run's own save started this one, else null. Null for a run started by hand.",
"title": "Trigger Detail"
},
"workflow_name": {
"title": "Workflow Name",
"type": "string"
}
},
"required": [
"id",
"workflow_name",
"record_id",
"schema_name",
"trigger",
"status",
"error",
"error_details",
"log",
"step_executions",
"affected_records",
"created_at",
"started_at",
"finished_at"
],
"title": "WorkflowJobResponse",
"type": "object"
}
POST /api/workflows/{name}/run-many
Run Workflow On Many
Description
Run one workflow on several records: one queued run per record, in one
request, one commit and one pass of the worker. A record that is missing, or
is not the schema the workflow is for, is listed under skipped with the
reason and the rest are still queued. A workflow that asks for files cannot
be run this way (422): the files differ per run. Refused (422) while
automation is paused.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
name |
path | string | No |
Request body
Schema of the request body
Responses
{
"skipped": [
{
"id": "string",
"reason": "string"
}
],
"started": [
{
"affected_records": null,
"created_at": "2022-04-13T15:42:05.901Z",
"depth": 0,
"error": null,
"error_details": null,
"finished_at": null,
"id": "string",
"log": null,
"record_id": "string",
"schema_name": "string",
"started_at": null,
"status": "string",
"step_executions": null,
"trigger": "string",
"trigger_detail": null,
"workflow_name": "string"
}
]
}
Schema of the response body
{
"properties": {
"skipped": {
"description": "Records the workflow was not run on, each with why: not found, or not the schema the workflow is for.",
"items": {
"$ref": "#/components/schemas/SkippedJob"
},
"title": "Skipped",
"type": "array"
},
"started": {
"description": "The runs that were queued, in the order asked.",
"items": {
"$ref": "#/components/schemas/WorkflowJobResponse"
},
"title": "Started",
"type": "array"
}
},
"required": [
"started",
"skipped"
],
"title": "RunManyResponse",
"type": "object"
}
DELETE /api/workflows/{stem}
Delete Workflow
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
force |
query | boolean | False | No | |
stem |
path | string | No |
Responses
GET /api/workflows/{stem}
Get Workflow
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
stem |
path | string | No |
Responses
{
"content": "string",
"description": null,
"filename": "string",
"inputs": null,
"name": "string",
"record_schema": null,
"stem": "string",
"step_list": [
{
"condition": null,
"config": {},
"id": "string",
"inputs": {},
"plugin": "string"
}
],
"steps": 0,
"triggers": null
}
Schema of the response body
{
"properties": {
"content": {
"title": "Content",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"filename": {
"title": "Filename",
"type": "string"
},
"inputs": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/WorkflowInputResponse"
},
"type": "object"
},
{
"type": "null"
}
],
"title": "Inputs"
},
"name": {
"title": "Name",
"type": "string"
},
"record_schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Record Schema"
},
"stem": {
"title": "Stem",
"type": "string"
},
"step_list": {
"default": [],
"items": {
"$ref": "#/components/schemas/WorkflowStepResponse"
},
"title": "Step List",
"type": "array"
},
"steps": {
"title": "Steps",
"type": "integer"
},
"triggers": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/WorkflowTriggerResponse"
},
"type": "object"
},
{
"type": "null"
}
],
"title": "Triggers"
}
},
"required": [
"name",
"description",
"steps",
"filename",
"stem",
"content"
],
"title": "WorkflowDetailResponse",
"type": "object"
}
PUT /api/workflows/{stem}
Save Workflow
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
stem |
path | string | No |
Request body
Responses
{
"content": "string",
"description": null,
"filename": "string",
"inputs": null,
"name": "string",
"record_schema": null,
"stem": "string",
"step_list": [
{
"condition": null,
"config": {},
"id": "string",
"inputs": {},
"plugin": "string"
}
],
"steps": 0,
"triggers": null
}
Schema of the response body
{
"properties": {
"content": {
"title": "Content",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"filename": {
"title": "Filename",
"type": "string"
},
"inputs": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/WorkflowInputResponse"
},
"type": "object"
},
{
"type": "null"
}
],
"title": "Inputs"
},
"name": {
"title": "Name",
"type": "string"
},
"record_schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Record Schema"
},
"stem": {
"title": "Stem",
"type": "string"
},
"step_list": {
"default": [],
"items": {
"$ref": "#/components/schemas/WorkflowStepResponse"
},
"title": "Step List",
"type": "array"
},
"steps": {
"title": "Steps",
"type": "integer"
},
"triggers": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/WorkflowTriggerResponse"
},
"type": "object"
},
{
"type": "null"
}
],
"title": "Triggers"
}
},
"required": [
"name",
"description",
"steps",
"filename",
"stem",
"content"
],
"title": "WorkflowDetailResponse",
"type": "object"
}
Schemas
AddFieldRequest
| Name | Type | Description |
|---|---|---|
default |
||
label |
Optional human-facing display name; free text. | |
name |
string | Machine key: lowercase letters, digits and underscores, not starting with a digit. This is what workflows and CSV headers reference. |
required |
boolean | |
restrictions |
||
type |
string |
AddVolumeRequest
| Name | Type | Description |
|---|---|---|
add_to_queue |
boolean | Also put the volume in the general write queue. Leave false for a volume that only homes particular collections. |
allocated_gb |
||
name |
string | |
path |
string |
AiConfigResponse
| Name | Type | Description |
|---|---|---|
base_url |
||
configured |
boolean | |
key_hint |
||
model |
string | |
provider |
string | |
source |
string |
AiConfigUpdate
| Name | Type | Description |
|---|---|---|
api_key |
||
base_url |
||
model |
||
provider |
AiTokenUsageResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
items |
Array<TokenUsageBucketResponse> |
AiUsageResponse
| Name | Type | Description |
|---|---|---|
by_model |
Array<ModelUsageResponse> | |
total |
UsageTotalsResponse |
AssistantMessage
| Name | Type | Description |
|---|---|---|
content |
string | |
role |
string |
AuditBatchResponse
| Name | Type | Description |
|---|---|---|
created_at |
string(date-time) | |
id |
string | |
kind |
string | import, delete, restore, purge or workflow. |
label |
A workflow's name or an import's file. | |
ref |
What started it, e.g. a workflow run's id. |
AuditChange
| Name | Type | Description |
|---|---|---|
after |
The value after; null if unset. | |
before |
The value before; null if unset. | |
deleted |
Set when this field has since been deleted: status (deleted = can still be restored, gone = permanently deleted), its id and, for a deleted one, the schema to restore it on and when it was deleted. | |
dtype |
The field's type, when it still exists. | |
field |
string | The field (record entries) or attribute (everything else) that changed, by name. |
label |
The field's display name now; null when it has since been renamed or deleted, or for a non-record entry. |
AuditEventCountsResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
items |
Array<AuditEventPointResponse> |
AuditEventPointResponse
| Name | Type | Description |
|---|---|---|
action |
string | One of: create, update, delete, purge. |
bucket |
string | |
count |
integer | |
entity_type |
string | One of: record, schema, field, dataset. |
AuditEventResponse
| Name | Type | Description |
|---|---|---|
actor |
Who made it, as reported by the machine that made it; for a batch, who made its changes. Null when it was not recorded. | |
batch |
What the batch was, for kind=batch. | |
count |
integer | Changes in it that match the filters. |
device |
For a synced change, the device it came through (verified by the authority). | |
entry |
The change itself, for kind=entry. | |
id |
string | The entry's id, or the batch's. |
kind |
string | entry (a single change) or batch. |
parts |
Array<AuditPart> | For a batch, what it holds by kind of thing and action. Its entries are listed at /audit/batches/{id}/entries. |
timestamp |
string(date-time) | The latest change in it. |
AuditLogResponse
| Name | Type | Description |
|---|---|---|
action |
string | One of: create, update, delete, restore, purge. |
actor |
Who made the change, as reported by the machine that made it (the name chosen in the project, else the operating-system user). Not verified. Null for entries from before this was recorded. | |
changes |
Array<AuditChange> | What the entry changed, field by field, in schema order. A delete or purge lists the values that were lost; a restore lists nothing. |
device |
For a synced change, the device it came through, as the authority stamped it from that device's token (verified). Null for a change made on the authority, not synced yet, or synced before this was kept. | |
entity_id |
string | |
entity_type |
string | One of: record, schema, field, dataset, view. |
id |
string | |
new_data |
The thing after the change: whole for a create, identity and the changed values for an edit or restore (see `old_data`). Null on delete. | |
now |
Where the record this entry is about is now, so a lost one can be told from one that was edited, deleted or purged. | |
old_data |
The thing before the change. A delete has it whole; an edit or restore, which is stored as only what changed, has the thing's identity (id, name, label, where it sits) and the values it changed, so anything absent was not changed. A record's values are keyed by field id, so an entry survives a rename; `changes` has them by current name. Null on create. | |
sync |
Array<> | What became of this change when it was sent to the authority, if it did not go in as made: one row per clash, refusal or edit against a delete (kind, field_label, yours, theirs, base, theirs_actor, status, resolution, message, attempted, changes; the same rows as `/remote/conflicts`), open or settled. Empty for a change that went in as made, and when the project follows no authority. |
timestamp |
string(date-time) |
AuditNow
| Name | Type | Description |
|---|---|---|
collection |
The collection it is in. | |
deleted_at |
||
kind |
string | What the entry is about: record, collection, schema or field. |
name |
Its name now. | |
ref |
What to restore or purge it by: a record's or field's id, else its name. | |
schema_name |
Its schema (for a field, the schema it belongs to); known even for a record that is gone for good. | |
status |
string | live (it exists), deleted (in Recently Deleted, restorable) or gone (permanently deleted). |
AuditPart
| Name | Type | Description |
|---|---|---|
action |
string | |
count |
integer | |
entity_type |
string |
AuthorityResponse
| Name | Type | Description |
|---|---|---|
devices |
Array<DeviceResponse> | The devices that joined. |
fingerprint |
This authority's key's short code; null until it first invites. | |
invites |
Array<InviteResponse> | Invites not used yet and not expired. |
library |
string | What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code). |
serving |
boolean | This project accepts devices. |
AuthorityUpdateRequest
| Name | Type | Description |
|---|---|---|
library |
off, workflows or all: what the library takes. | |
serving |
Accept devices, or stop accepting them. |
AutomationStatusResponse
| Name | Type | Description |
|---|---|---|
batch |
The current stretch of work with how many have succeeded and failed so far; null when nothing is waiting or running. | |
cancelled |
integer | How many runs the call just cancelled (stop only). |
paused |
boolean | True while automation is paused: triggers start nothing, waiting runs are not picked up, and manual runs are refused. |
pending |
integer | Runs waiting to start. |
running |
integer | Runs in progress. |
BatchResponse
| Name | Type | Description |
|---|---|---|
active |
integer | Of those, waiting or running. |
cancelled |
integer | Of those, cancelled. |
completed |
integer | Of those, finished successfully. |
failed |
integer | Of those, failed. |
started_at |
string(date-time) | When the earliest run in this stretch was queued. |
total |
integer | Every run in the current stretch of work: those finished since the queue was last empty, plus those still waiting or running. |
BlockerResponse
| Name | Type | Description |
|---|---|---|
id |
string | |
kind |
string | collection, schema or record. |
name |
string | What to call it: a name, or a record's name. |
Body_bulk_delete_records_api_records_bulk_delete_post
| Name | Type | Description |
|---|---|---|
force |
boolean | |
ids |
Array<string> |
Body_import_dump_api_restore_post
| Name | Type | Description |
|---|---|---|
file |
string |
Body_upload_file_api_files_post
| Name | Type | Description |
|---|---|---|
file |
string |
Body_upload_plugin_api_plugins_upload_post
| Name | Type | Description |
|---|---|---|
file |
string |
BuildResult
| Name | Type | Description |
|---|---|---|
log |
string | |
success |
boolean |
ChatRequest
| Name | Type | Description |
|---|---|---|
messages |
Array<> |
civex__server__routers__remote__LibraryPublishRequest
| Name | Type | Description |
|---|---|---|
kind |
string | workflow or plugin. |
name |
string | The workflow's or plugin file's name here. |
with_plugins |
boolean | A workflow: send the plugins its steps use too. |
civex__server__routers__remote__LibraryPublishResponse
| Name | Type | Description |
|---|---|---|
items |
Array<LibraryItemResponse> | The versions stored. |
warnings |
Array<string> | Shared workflows still on an older version of a plugin that the new version would break. |
civex__server__routers__sync_peer__LibraryPublishRequest
| Name | Type | Description |
|---|---|---|
items |
Array<LibraryItemBody> | A workflow and the plugins it uses, or a plugin. Taken whole or not at all; new text becomes the next version. |
civex__server__routers__sync_peer__LibraryPublishResponse
| Name | Type | Description |
|---|---|---|
items |
Array<> | The newest version of each item, without its text: kind, name, sha256, size, version, title, description, provides, needs, triggers, pins, contract, published_by, published_at, and its history (every version). |
warnings |
Array<string> | What to know: shared workflows still on an older version of a plugin that the new version would break. |
CollectionFilesResponse
| Name | Type | Description |
|---|---|---|
bytes_here |
integer | Their size. |
chosen |
boolean | Set for this collection, rather than following the project's setting. |
files_here |
integer | Files its records use that are here. |
files_on_server |
integer | Files its records use that are only on the server. |
id |
string | |
mode |
string | keep: a copy stays on this computer (fetched in the background); opened: fetched when opened or exported. |
name |
string |
CollectionModeRequest
| Name | Type | Description |
|---|---|---|
mode |
keep, opened, or null to follow the project's setting. |
CollectionStorageResponse
| Name | Type | Description |
|---|---|---|
bytes |
integer | Total size of the files the catalog knows. |
collection_id |
string | |
files |
integer | Distinct files the collection's records use. |
unlocated_files |
integer | Files records use that the catalog doesn't place on any volume. |
unlocated_place |
string | Where those are: `server` (this project follows one, so they are only there) or `missing`. |
volumes |
Array<CollectionVolumeShareResponse> | Each volume that holds some of them, largest first. |
CollectionUseResponse
| Name | Type | Description |
|---|---|---|
id |
string | |
name |
Null if the collection no longer exists. | |
records |
integer | Records in that collection that use the file. |
CollectionVolumeShareResponse
| Name | Type | Description |
|---|---|---|
available |
boolean | Whether the volume can be read right now. |
bytes |
integer | |
files |
integer | Files of the collection on this volume. |
shared_files |
integer | Of those, files another collection uses too (moving one affects both). |
state |
string | The volume's state now: online, offline, wrong_drive, readonly or retired. |
volume |
string |
CommandLineResponse
| Name | Type | Description |
|---|---|---|
available |
boolean | Whether this is the desktop app's civex, the only one this applies to (a uv, pipx or pip install is already a command). |
note |
string | What is still to do, or why it can't be done; blank if nothing. |
on_path |
boolean | Whether a new terminal finds this civex as `civex`. |
shadowed_by |
Another civex a terminal would find first, if there is one. | |
where |
The folder put on PATH (Windows) or the link made (macOS, Linux). |
ConflictResponse
| Name | Type | Description |
|---|---|---|
also_saved |
Array<> | Other values the same edit set that did go in: field_label, value. |
attempted |
For a refused change or an edit that met a delete: what was tried (create, update or delete). | |
base |
What the value was before either side changed it. | |
changes |
Array<> | The fields that attempt set, for showing it on the record: field_id, field_name, field_label, dtype, before, after and current. |
created_at |
string | |
current |
The value on the record now. | |
dataset_name |
Its collection. | |
device_name |
||
dtype |
The field's type. | |
entity_id |
string | |
entity_type |
string | |
field |
||
field_label |
The field's label now; null if the field is gone. | |
id |
string | |
kind |
string | conflict, rejected or edit_vs_delete. |
message |
||
record_deleted |
boolean | The record is deleted (restore it first). |
record_name |
The record's name as it is now (records only). | |
resolution |
mine, theirs, value, edited, delete or retry, once resolved. | |
resolved_at |
||
schema_name |
Its schema. | |
sits_under |
Array<> | For a refused record that sits under deleted records here: those records (id, schema_name, name), topmost first. `restore_above` brings them back and sends the record again. |
stale |
boolean | The record's value is no longer the one that stayed: it changed again since, so putting yours back would overwrite something newer. |
status |
string | open or resolved. |
takes |
Array<string> | What this can be settled with: theirs, mine, value, delete, retry (`edited` is also accepted for a clash, but is not a choice to offer). |
theirs |
The value the authority kept. | |
theirs_actor |
Who wrote the value that stayed. | |
theirs_at |
When they wrote it. | |
theirs_device |
The device their change came through (verified by the authority), when it came through one. | |
yours |
The value this device set. |
ConnectionCheckResponse
| Name | Type | Description |
|---|---|---|
error |
Why not, in plain words, when ok is false. | |
ok |
boolean | Whether a connection was made. |
ContainerFileSaveRequest
| Name | Type | Description |
|---|---|---|
content |
string | |
path |
string |
ContainerPluginDetail
| Name | Type | Description |
|---|---|---|
files |
||
name |
string |
ContainerPluginInfo
| Name | Type | Description |
|---|---|---|
files |
Array<string> | |
name |
string |
CreateDatasetRequest
| Name | Type | Description |
|---|---|---|
description |
||
name |
string | |
schemas |
Array<string> | Names of the schemas the collection is for. A child schema's parent schema must be listed too. |
scope |
string | 'local' (default) or 'global' -- see the collection's `scope`. |
timezone |
IANA timezone for datetime values in this collection. Omit or null to leave unset. |
CreateExportDefinitionRequest
| Name | Type | Description |
|---|---|---|
fields |
Array<string> | File fields to export; empty means every file field. |
files_layout |
string | 'tree': a folder per record above each file; 'grouped': the records that hold the files share one folder named for their kind (Encounter/Recording/Selections/...); 'flat': every file in one folder. |
filter_tree |
A filter on the records that hold the files; needs 'holder'. | |
holder |
The kind of record that holds the files: the schema itself or a kind beneath it. Omit for any kind beneath. | |
include_files |
boolean | False makes the export tables alone. |
name |
string | What the export is called, in your own words. |
tables |
Array<TableRequest> | Also make these tables. |
CreateFolderRequest
| Name | Type | Description |
|---|---|---|
name |
string | Name of the new folder (no slashes). |
parent |
string | Absolute path of the folder to create it in. |
CreateFolderResponse
| Name | Type | Description |
|---|---|---|
path |
string |
CreateRecordRequest
| Name | Type | Description |
|---|---|---|
data |
||
parent_record_id |
||
schema_name |
string |
CreateSchemaRequest
| Name | Type | Description |
|---|---|---|
description |
||
fields |
||
label |
Optional human-facing display name; free text. | |
name |
string | Machine key: lowercase letters, digits and underscores, not starting with a digit. |
parent |
CreateViewRequest
| Name | Type | Description |
|---|---|---|
columns |
Base schema field names to show, in order. May also include single-hop reference-field joins as 'ref_field.target_field'. | |
files_layout |
string | How the view's files are arranged when exported: 'tree' (a folder per record above each file) or 'flat' (all in one folder). |
filter_tree |
AND/OR filter tree, same shape as the records 'filter' query parameter (conditions may name an ancestor or descendant schema). | |
name |
string | What the view is called, in your own words -- spaces, capitals and punctuation are fine. Only '/', '\' and control characters are refused. Unique per schema. |
sort |
Ordered list of {field, direction} entries; direction is 'asc' or 'desc'. |
DatabaseSummaryResponse
| Name | Type | Description |
|---|---|---|
dialect |
string | 'sqlite' or 'postgresql'. |
error |
Why not, when unreachable. | |
label |
string | 'SQLite file', 'Docker PostgreSQL' or 'PostgreSQL server'. |
location |
string | Where it is, with any password hidden. |
reachable |
boolean | Whether it could be read. |
records |
integer | Number of records. |
rows |
integer | Rows across every table. |
size_bytes |
On-disk size, when known. |
DatasetResponse
| Name | Type | Description |
|---|---|---|
deleted_at |
When this collection was soft-deleted. Null means live. | |
description |
||
id |
string | |
name |
string | |
record_count |
integer | |
schemas |
Array<string> | Names of the schemas this collection is for. Records in it can only be of these schemas. |
scope |
string | Who may reference this collection's records: 'local' (only records in this collection) or 'global' (records in any collection). |
timezone |
IANA timezone (e.g. 'America/Chicago') that datetime values in this collection are read and shown in. Null means unset: offset-less input is read as UTC and the UI uses the viewer's own zone. A datetime field's own `timezone` restriction overrides this. |
DBStatusResponse
| Name | Type | Description |
|---|---|---|
ok |
boolean |
DbStatusResponse
| Name | Type | Description |
|---|---|---|
dialect |
string | |
docker |
||
docker_managed |
boolean | |
migration |
MigrationStatusResponse | |
url |
string |
DeletedFieldValue
| Name | Type | Description |
|---|---|---|
deleted_at |
When the field was deleted. | |
dtype |
string | |
id |
string | The deleted field's id. |
label |
string | Its display name. |
name |
string | |
schema_name |
string | The schema it was defined on, which is where to restore it. |
value |
What this record still holds for it; back in `data` once the field is restored. |
DeleteJobsRequest
| Name | Type | Description |
|---|---|---|
filter |
Instead of ids: delete every run this filter matches (the same filter tree as GET /jobs, at most 1000 runs). | |
ids |
Ids of the runs to delete. |
DeleteJobsResponse
| Name | Type | Description |
|---|---|---|
deleted |
integer | How many runs were deleted. |
DevicePublishRequest
| Name | Type | Description |
|---|---|---|
allowed |
boolean | May it publish to the library. |
DeviceResponse
| Name | Type | Description |
|---|---|---|
created_at |
string | When it joined. |
fingerprint |
string | Its key's short code, as `civex sync device list` shows it. |
last_seen_at |
When it last signed in; null if never. | |
may_publish |
boolean | It may publish workflows (and plugins, if taken) to the library. |
name |
string | |
revoked |
boolean | It can no longer sign in. |
DirectoryEntryResponse
| Name | Type | Description |
|---|---|---|
name |
string | |
path |
string | Absolute path of the folder. |
DirectoryListingResponse
| Name | Type | Description |
|---|---|---|
entries |
Array<DirectoryEntryResponse> | The folders directly inside it (never files). |
hint |
Why a drive might be missing from `locations`, where the platform has a known reason (for example a Windows drive not yet mounted under WSL). | |
locations |
Array<StorageLocationResponse> | Places to start browsing from: the project, home and mounted drives. |
parent |
Its parent folder; null at the top. | |
path |
string | The folder that was listed, as an absolute path. |
truncated |
boolean | True if there were more folders than are shown. |
DockerStatusResponse
| Name | Type | Description |
|---|---|---|
exists |
boolean | |
name |
string | |
running |
boolean | |
volume_exists |
boolean |
DurationHistogramBinResponse
| Name | Type | Description |
|---|---|---|
count |
integer | |
label |
string | Duration bucket, e.g. '1-2s' or '30s+'. |
DurationPercentileMarkerResponse
| Name | Type | Description |
|---|---|---|
bin_label |
string | Which histogram bucket this percentile falls in. |
label |
string | e.g. 'p50', 'p90', 'p99'. |
ExportDefinitionResponse
| Name | Type | Description |
|---|---|---|
fields |
Array<string> | The file fields exported; empty means every file field. |
files_layout |
string | |
filter_tree |
A filter on the records that hold the files (same shape as the records 'filter' parameter). | |
holder |
The kind of record that holds the files; null means any kind beneath the schema. | |
id |
string | |
include_files |
boolean | False: the export is tables alone. |
name |
string | |
schema_id |
string | |
schema_name |
string | The schema the export is saved with. |
tables |
Array<TableRequest> | The tables made beside the files. |
FailureGroupResponse
| Name | Type | Description |
|---|---|---|
count |
integer | How many runs failed this way. |
kind |
The failure type, such as timeout. | |
last_at |
string(date-time) | When one last did. |
message |
The failure's own message. | |
step |
The step that failed. | |
workflow |
string |
FieldKindResponse
| Name | Type | Description |
|---|---|---|
description |
string | What the kind is for. |
focus |
Restriction key the editor should lead with, if any. | |
key |
string | Stable identifier of the kind. |
label |
string | Name shown in the field-kind picker. |
type |
string | The field type a field of this kind is created as. |
FieldResponse
| Name | Type | Description |
|---|---|---|
default |
||
id |
string | |
label |
Human-facing display name. Null means none was set — render the name title-cased instead. | |
name |
string | |
required |
boolean | |
restrictions |
||
type |
string |
FieldTypeDescriptorResponse
| Name | Type | Description |
|---|---|---|
description |
string | What the type is for. |
entry_hint |
string | One line of guidance shown beside the input on the record page. |
example |
string | An example value as a person would type it. |
label |
string | Plain-language name of the type. |
restrictions |
Array<RestrictionDescriptorResponse> | The rules a field of this type can carry, in display order. |
stored_as |
string | How a value is held, in plain language. |
supports_default |
boolean | Whether a default value can be set when creating the field. |
type |
string | The field type name, as used in `type`. |
FieldTypesResponse
| Name | Type | Description |
|---|---|---|
kinds |
Array<FieldKindResponse> | The 'what kind of data is this?' picker, in display order. |
types |
Array<FieldTypeDescriptorResponse> | Every field type, with the rules each can carry. |
FileCopyResponse
| Name | Type | Description |
|---|---|---|
network |
boolean | The volume is on a network drive. |
path |
string | Where the object is, or would be, on that volume. |
present |
True if it is there; null if it is recorded there but the volume can't be checked now. | |
state |
string | The volume's state: online, offline, wrong_drive, readonly or retired. |
volume |
string |
FileExportRequest
| Name | Type | Description |
|---|---|---|
allow_partial |
boolean | Go ahead without files that can't be reached. Without it, a selection with unreachable files answers 409 and builds nothing. |
base |
A record (id or prefix) that paths start below; defaults to 'within'. | |
below |
boolean | Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files. |
collection |
Only this collection. | |
dest |
Advanced: a folder to build in, empty or an earlier export, instead of civex's own exports folder. Overrides 'name' and 'volume'. For 'link' it must be on the drive holding the files. | |
export |
An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has. | |
fields |
Only these file fields; omit for every one. | |
files |
boolean | False takes the tables alone, with no files (needs 'tables'). |
filter |
A filter tree, as for listing records. | |
kinds |
Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree. | |
layout |
string | 'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it. |
mode |
string | 'link' makes hard links in a folder on the drive that holds the files: no copying, no extra space, and refused (409 'files_scattered') when the files are on more than one drive. 'copy' makes real copies on one drive ('volume'), wherever the files are. |
name |
Names the folder: |
|
open |
boolean | Show the folder in the file manager, if the request came from the server's own machine. |
record_ids |
Exactly these records (the rows ticked in a list); the other selectors are then ignored. | |
schema_name |
Only records of this schema. | |
search |
Full-text search. | |
sort |
The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...]. | |
tables |
Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them. | |
view |
A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it). | |
volume |
For 'copy': the drive to copy onto (a volume name); the project folder if omitted. Ignored for 'link', which goes where the files are. | |
where |
Array<string> | 'field=value' terms. |
with_within |
boolean | With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too). |
within |
A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it. |
FileGatherRequest
| Name | Type | Description |
|---|---|---|
base |
A record (id or prefix) that paths start below; defaults to 'within'. | |
below |
boolean | Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files. |
collection |
Only this collection. | |
export |
An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has. | |
fields |
Only these file fields; omit for every one. | |
files |
boolean | False takes the tables alone, with no files (needs 'tables'). |
filter |
A filter tree, as for listing records. | |
include_shared |
boolean | Also move files that records not picked use (they move for those records too). By default those stay where they are. |
kinds |
Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree. | |
layout |
string | 'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it. |
name |
Only files whose name, or whose record's name, contains this. | |
place |
Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't). | |
record_ids |
Exactly these records (the rows ticked in a list); the other selectors are then ignored. | |
schema_name |
Only records of this schema. | |
search |
Full-text search. | |
shas |
Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked. | |
sort |
The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...]. | |
tables |
Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them. | |
used_by |
Only files used by exactly one of these numbers of live records (anywhere, not only in the selection). | |
view |
A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it). | |
volume |
string | The drive (volume name) to gather the selection's files onto. Only the files in the selection move, not the rest of their collections. |
where |
Array<string> | 'field=value' terms. |
with_within |
boolean | With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too). |
within |
A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it. |
FileInfoResponse
| Name | Type | Description |
|---|---|---|
collections |
Array<CollectionUseResponse> | |
copies |
Array<FileCopyResponse> | Every place the content is, or is recorded to be. |
deleted_records |
integer | Deleted records that still reference it: they keep it while they can be restored, but don't count as using it. |
jobs |
integer | Workflow runs that took it as an input. |
records |
integer | Live records that use this file, across all collections. |
sha256 |
string | |
size |
Size in bytes, if known. | |
uses |
Array<RecordUseResponse> | The live records that use it, named, with the records above each (at most 200; `records` is the full count). |
FileListRequest
| Name | Type | Description |
|---|---|---|
base |
A record (id or prefix) that paths start below; defaults to 'within'. | |
below |
boolean | Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files. |
collection |
Only this collection. | |
export |
An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has. | |
fields |
Only these file fields; omit for every one. | |
files |
boolean | False takes the tables alone, with no files (needs 'tables'). |
filter |
A filter tree, as for listing records. | |
kinds |
Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree. | |
layout |
string | 'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it. |
limit |
integer | |
name |
Only files whose name, or whose record's name, contains this. | |
offset |
integer | |
order |
string | path, name, size, record or place; a leading '-' reverses it. |
place |
Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't). | |
record_ids |
Exactly these records (the rows ticked in a list); the other selectors are then ignored. | |
schema_name |
Only records of this schema. | |
search |
Full-text search. | |
shas |
Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked. | |
sort |
The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...]. | |
tables |
Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them. | |
used_by |
Only files used by exactly one of these numbers of live records (anywhere, not only in the selection). | |
view |
A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it). | |
where |
Array<string> | 'field=value' terms. |
with_within |
boolean | With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too). |
within |
A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it. |
FilePickRequest
| Name | Type | Description |
|---|---|---|
base |
A record (id or prefix) that paths start below; defaults to 'within'. | |
below |
boolean | Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files. |
collection |
Only this collection. | |
export |
An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has. | |
fields |
Only these file fields; omit for every one. | |
files |
boolean | False takes the tables alone, with no files (needs 'tables'). |
filter |
A filter tree, as for listing records. | |
kinds |
Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree. | |
layout |
string | 'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it. |
name |
Only files whose name, or whose record's name, contains this. | |
place |
Only files in this place: a drive's name, `server` (only on the server), `missing`, or the groups `here` (on a drive that can be read now) and `unreachable` (on one that can't). | |
record_ids |
Exactly these records (the rows ticked in a list); the other selectors are then ignored. | |
schema_name |
Only records of this schema. | |
search |
Full-text search. | |
shas |
Only these files (by content hash), e.g. the ticked rows: each with every use of it in the selection. Records outside the selection that use the same file are not picked. | |
sort |
The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...]. | |
tables |
Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them. | |
used_by |
Only files used by exactly one of these numbers of live records (anywhere, not only in the selection). | |
view |
A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it). | |
where |
Array<string> | 'field=value' terms. |
with_within |
boolean | With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too). |
within |
A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it. |
FilePlanRequest
| Name | Type | Description |
|---|---|---|
base |
A record (id or prefix) that paths start below; defaults to 'within'. | |
below |
boolean | Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files. |
collection |
Only this collection. | |
export |
An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has. | |
fields |
Only these file fields; omit for every one. | |
files |
boolean | False takes the tables alone, with no files (needs 'tables'). |
filter |
A filter tree, as for listing records. | |
include_items |
boolean | Send the files too, not just the totals. |
kinds |
Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree. | |
layout |
string | 'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it. |
limit |
How many files to send. | |
offset |
integer | First file to send. |
record_ids |
Exactly these records (the rows ticked in a list); the other selectors are then ignored. | |
schema_name |
Only records of this schema. | |
search |
Full-text search. | |
sort |
The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...]. | |
tables |
Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them. | |
view |
A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it). | |
where |
Array<string> | 'field=value' terms. |
with_within |
boolean | With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too). |
within |
A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it. |
FileRefResponse
| Name | Type | Description |
|---|---|---|
filename |
string | |
sha256 |
string | |
size |
integer | |
volume |
string |
FileZipRequest
| Name | Type | Description |
|---|---|---|
allow_partial |
boolean | Zip what can be reached; the archive then holds MISSING.txt. |
base |
A record (id or prefix) that paths start below; defaults to 'within'. | |
below |
boolean | Also take the files of every record beneath each selected one (the selected encounters, and everything inside them). Without it, only the selected records' own files. |
collection |
Only this collection. | |
export |
An export saved with a schema, as 'schema/name': its kind of record, file fields, filter, layout and tables become the selection, run in 'collection' and/or within the record 'within'. Sending 'layout', 'tables' or 'files' overrides what it has. | |
fields |
Only these file fields; omit for every one. | |
files |
boolean | False takes the tables alone, with no files (needs 'tables'). |
filter |
A filter tree, as for listing records. | |
kinds |
Only records of these kinds (schema names), when 'schema_name' is not given: how a preview of an export that takes any kind beneath a schema stays within that schema's own tree. | |
layout |
string | 'tree' puts each file in a folder per record above it; 'grouped' gathers the files of the records that hold them into one folder named for their kind (Encounter/Recording/Selections/...); 'flat' puts every file in one folder. Names that clash in a shared folder are told apart by the record that owns each. A saved view carries its own (files_layout); sending this with 'view' overrides it. |
name |
Names the download: |
|
record_ids |
Exactly these records (the rows ticked in a list); the other selectors are then ignored. | |
schema_name |
Only records of this schema. | |
search |
Full-text search. | |
sort |
The order of the records, and so of the rows of a table: [{'field': name, 'direction': 'asc'|'desc'}, ...]. | |
tables |
Also make these tables. Each file column in one says where that file is in the export. Sending it overrides the tables a saved 'export' has; an empty list removes them. | |
view |
A saved view as 'schema/view': its filter, its file columns and its layout become the selection ('collection' and 'within' still narrow it). | |
where |
Array<string> | 'field=value' terms. |
with_within |
boolean | With `within` and `schema_name`: also the files of the `within` record itself (a list of what a record contains, taking the record's own files too). |
within |
A record (id or prefix): its files and those of everything beneath it. Paths start below it. With 'schema_name', only that schema's records under it. |
ForgetPurgedRequest
| Name | Type | Description |
|---|---|---|
dry_run |
boolean | Only count the entries that would be deleted. |
ForgetPurgedResponse
| Name | Type | Description |
|---|---|---|
dry_run |
boolean | |
entries |
integer | History entries about records that no longer exist. |
FreeUpResponse
| Name | Type | Description |
|---|---|---|
bytes |
integer | The space that frees. |
done |
boolean | False when only counted. |
files |
integer | Copies removed (or that would be, counting). |
kept_shared |
integer | Kept: also used by a collection kept on this computer. |
not_on_server |
integer | Kept: the server hasn't got them yet (never sent). |
GCReportResponse
| Name | Type | Description |
|---|---|---|
deleted |
Array<StoredObjectResponse> | |
deleted_bytes |
integer | |
deleted_count |
integer | Objects deleted (or, if dry_run, collectible). |
dry_run |
boolean | True if no objects were actually deleted. |
grace_days |
integer | |
protected_by_grace |
integer | Unreferenced objects skipped for being younger than the grace period. |
referenced |
integer | Distinct content hashes reachable from a live record or workflow job. |
scanned |
integer | Total objects found in the store. |
stale_scratch_removed |
integer | Abandoned upload scratch files (from an interrupted streamed upload) removed, or if dry_run, collectible. |
volume |
The volume this pass was limited to, or null for every volume. |
GCRequest
| Name | Type | Description |
|---|---|---|
apply |
boolean | Actually delete collectible objects. False (default) only reports what would be deleted. |
grace_days |
integer | Skip unreferenced objects written more recently than this many days. |
rebuild_refs |
boolean | Recompute the file-reference table from every record and job before collecting. Normally unnecessary; use if the table may have drifted. |
volume |
Only collect objects stored on this volume. Omit to clean up every volume. |
HistoryStorageResponse
| Name | Type | Description |
|---|---|---|
converting |
boolean | The conversion is running now. |
done |
Entries looked at since the conversion began. | |
free_bytes |
Room inside the file no longer used: what reclaiming gives back. Reclaiming needs about `size_bytes` of free disk while it runs. | |
size_bytes |
The database file's size (SQLite; null where the database manages its own space). | |
total |
What was left when the conversion began. | |
whole_entries |
integer | Edits still stored as two whole copies (written before history stored only what changed); converted in the background. |
HTTPValidationError
| Name | Type | Description |
|---|---|---|
detail |
Array<ValidationError> |
IdentityResponse
| Name | Type | Description |
|---|---|---|
chosen |
The name chosen for this project, or null when none is. | |
default |
What is used when none is chosen: the operating-system user. | |
name |
What changes made here are recorded as. |
InstallPlanResponse
| Name | Type | Description |
|---|---|---|
blocked |
Array<string> | Why it can't be installed as asked. |
breaks |
Array<string> | What the new plugin versions would break among the workflows here. |
runs_code |
boolean | It writes a plugin, which is code this computer will run. |
steps |
Array<InstallStepResponse> | |
warnings |
Array<string> | What to know first (what starts a workflow by itself). |
InstallStepResponse
| Name | Type | Description |
|---|---|---|
here |
string | absent, same, older or different, before installing. |
item |
LibraryItemResponse | |
local_version |
The library version here now, if any. | |
path |
string | Where it is written, in the project. |
InvitedResponse
| Name | Type | Description |
|---|---|---|
devices |
Array<DeviceResponse> | The devices that joined. |
fingerprint |
This authority's key's short code; null until it first invites. | |
invite |
string | The invite, for the device to connect with. Shown once: only its hash is kept. It works once. |
invites |
Array<InviteResponse> | Invites not used yet and not expired. |
library |
string | What devices allowed to publish may share through this server's library: off, workflows, or all (plugins too, which are code). |
serving |
boolean | This project accepts devices. |
InviteRequest
| Name | Type | Description |
|---|---|---|
hours |
integer | How long the invite works. |
name |
string | What to call the device. |
InviteResponse
| Name | Type | Description |
|---|---|---|
created_at |
string | |
expires_at |
string | |
name |
string | The device it is for. |
JobDurationStatsResponse
| Name | Type | Description |
|---|---|---|
avg_seconds |
||
bins |
Array<DurationHistogramBinResponse> | Duration distribution, bucketed into fixed-width ranges. |
count |
integer | Number of step executions the stats are over. |
max_seconds |
||
min_seconds |
||
p50_seconds |
||
p90_seconds |
||
p99_seconds |
||
percentile_markers |
Array<DurationPercentileMarkerResponse> | Which bucket each of p50/p90/p99 falls in, for a chart to draw as reference lines over `bins`. |
JobStatusCountsResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
items |
Array<JobStatusPointResponse> |
JobStatusPointResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
count |
integer | |
status |
string |
LibraryInstallRequest
| Name | Type | Description |
|---|---|---|
force |
boolean | Install even though it would break workflows here. |
replace |
boolean | Replace files here that were changed here. |
version |
Omit for the newest. | |
with_plugins |
boolean | A workflow: install the plugin versions it is pinned to too. |
LibraryItemBody
| Name | Type | Description |
|---|---|---|
content |
string | The file's text. |
contract |
A plugin: its contract (inputs, outputs, config schema) as the publisher's computer described it. | |
kind |
string | workflow or plugin. |
name |
string | The file's name without its extension. |
provides |
A plugin: the plugin id it registers as. | |
sha256 |
string | The hash of `content`, as UTF-8. |
size |
integer | Its size in bytes. |
LibraryItemResponse
| Name | Type | Description |
|---|---|---|
content |
Its text, when asked for one. | |
description |
||
filename |
string | |
here |
On this computer, against this version: absent, same, older (an earlier version from the library) or different (changed here). | |
history |
Array<LibraryVersionResponse> | Every version, newest first. |
kind |
string | workflow or plugin. |
local_version |
The library version this computer has, if any. | |
missing |
Array<string> | Plugins it needs that are neither here nor in the library. |
name |
string | |
needs |
Array<string> | A workflow: the plugins its steps use. |
pins |
A workflow: the version of each plugin it was published with. | |
provides |
A plugin: the plugin id it registers as. | |
published_at |
||
published_by |
||
sha256 |
string | |
size |
integer | |
title |
A workflow's own name. | |
triggers |
Array<string> | A workflow: what starts it by itself. |
version |
integer | This version's number (the newest in a list). |
LibraryListResponse
| Name | Type | Description |
|---|---|---|
items |
Array<> | The newest version of each item, without its text: kind, name, sha256, size, version, title, description, provides, needs, triggers, pins, contract, published_by, published_at, and its history (every version). |
LibraryVersionResponse
| Name | Type | Description |
|---|---|---|
pins |
A workflow: the plugin versions it was published with. | |
published_at |
||
published_by |
||
sha256 |
string | |
version |
integer |
LicenseResponse
| Name | Type | Description |
|---|---|---|
text |
string |
MapSettingsResponse
| Name | Type | Description |
|---|---|---|
attribution |
Credit shown on the map for the tile provider, as plain text. | |
tile_url |
XYZ tile URL for the location editor's street-level map, with {z}, {x} and {y} placeholders. Null means the editor uses only its bundled coastlines. |
MigrationStatusResponse
| Name | Type | Description |
|---|---|---|
current_revision |
||
error |
||
head_revision |
||
up_to_date |
boolean |
ModelUsageResponse
| Name | Type | Description |
|---|---|---|
input_tokens |
integer | |
model |
string | |
output_tokens |
integer | |
provider |
string | |
requests |
integer | |
total_tokens |
integer |
MoveJobResponse
| Name | Type | Description |
|---|---|---|
error |
Why it failed or was cancelled. | |
id |
string | Job id to poll. |
progress |
MoveProgressResponse | Latest progress. |
record |
The history entry, once the move has ended. | |
status |
string | State of the move. |
MovePreflightResponse
| Name | Type | Description |
|---|---|---|
can_proceed |
boolean | False when `problems` is not empty. |
estimate_seconds |
integer | Rough time the copy will take. |
problems |
Array<string> | Reasons the move can't go ahead. |
source |
DatabaseSummaryResponse | The database now in use. |
target |
DatabaseSummaryResponse | The destination. |
target_label |
string | Kind of destination, for display. |
warnings |
Array<string> | Things worth knowing that don't block it. |
MoveProgressResponse
| Name | Type | Description |
|---|---|---|
message |
string | What it is doing, for display. |
phase |
string | 'copy', 'verify' or 'finalize'. |
rows_done |
integer | Rows copied so far. |
rows_total |
integer | Rows to copy in all. |
table |
Table being copied. | |
tables_done |
integer | Tables finished. |
tables_total |
integer | Tables to copy. |
MoveRecordResponse
| Name | Type | Description |
|---|---|---|
counts |
Rows copied per table. | |
error |
Why it didn't finish. | |
finished_at |
When it ended. | |
id |
string | Identifier of the move. |
problems |
Array<string> | What didn't match, if verification failed. |
reverted_at |
When it was undone, if it was. | |
seconds |
How long the copy took. | |
source_label |
string | Kind of database moved from. |
source_location |
string | Where it was, password hidden. |
started_at |
string | When it started (ISO 8601). |
status |
string | Outcome. Only 'done' means the project now uses the new database. |
target_label |
string | Kind of database moved to. |
target_location |
string | Where it is, password hidden. |
MoveTargetRequest
| Name | Type | Description |
|---|---|---|
database |
Database name, for kind 'postgres'. | |
host |
Server host, for kind 'postgres'. | |
kind |
string | Where to move to: 'sqlite' (a new file in the project), 'docker' (this project's Civex-managed PostgreSQL container) or 'postgres' (a PostgreSQL server you run). |
password |
Password, for kind 'postgres'. | |
path |
File to create, for kind 'sqlite'. Defaults to a new file in _civex/. | |
port |
integer | Server port, for kind 'postgres'. |
url |
Full connection URL, for kind 'postgres' (instead of the fields below). | |
user |
User name, for kind 'postgres'. |
NameIssueResponse
| Name | Type | Description |
|---|---|---|
kind |
string | 'schema' or 'field'. |
name |
string | |
schema_name |
string | |
suggestion |
Slugified alternative; null if undecidable. |
OpenBatchRequest
| Name | Type | Description |
|---|---|---|
kind |
string | What the batch is. Only an import is opened by a client; the server opens its own for deletes, restores and workflow runs. |
label |
E.g. the file imported. |
OrphanResponse
| Name | Type | Description |
|---|---|---|
above |
Array<RecordRef> | The deleted records directly above it, topmost first. |
collection |
The collection it is in. | |
record |
RecordRef |
OrphansResponse
| Name | Type | Description |
|---|---|---|
items |
Array<OrphanResponse> | Up to `limit` of them. |
total |
integer | How many live records sit under a deleted one. |
PaginatedAuditEventsResponse
| Name | Type | Description |
|---|---|---|
items |
Array<AuditEventResponse> | |
limit |
integer | |
offset |
integer | |
total |
integer |
PaginatedAuditLogResponse
| Name | Type | Description |
|---|---|---|
items |
Array<AuditLogResponse> | |
limit |
integer | |
offset |
integer | |
total |
integer |
PaginatedRecordResponse
| Name | Type | Description |
|---|---|---|
items |
Array<RecordResponse> | |
limit |
integer | |
offset |
integer | |
total |
integer |
PathInspectionResponse
| Name | Type | Description |
|---|---|---|
existing_volume |
The configured volume already at this path, if any. | |
exists |
boolean | |
free_bytes |
||
has_civex_data |
boolean | |
inside_project |
boolean | |
is_dir |
boolean | |
is_network |
boolean | The folder is on a network filesystem. |
marker_volume |
The configured volume whose drive this is, if any. | |
path |
string | |
problems |
Array<string> | Reasons it can't be added as a volume. |
same_disk_as_project |
||
total_bytes |
||
warnings |
Array<string> | Things to know; they don't block adding it. |
will_create |
boolean | The folder doesn't exist and would be created. |
writable |
boolean |
PlacementResponse
| Name | Type | Description |
|---|---|---|
collection_id |
string | Id of the collection this placement is for. |
collection_name |
The collection's name, or null if it no longer exists. | |
on_unavailable |
string | spill: use the general write queue when the home volume can't take a file. fail: refuse the upload instead. |
volume |
string | The collection's home volume. |
PluginFailureCountsResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
items |
Array<PluginFailurePointResponse> |
PluginFailurePointResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
count |
integer | |
plugin |
string |
PluginInfo
| Name | Type | Description |
|---|---|---|
builtin |
boolean | |
capabilities |
Array<string> | |
category |
string | |
config_schema |
||
description |
string | |
filename |
||
id |
string | |
inputs |
||
name |
string | |
outputs |
PluginIOSpec
| Name | Type | Description |
|---|---|---|
description |
string | |
name |
string | |
required |
boolean | |
type |
string |
PluginLoadError
| Name | Type | Description |
|---|---|---|
error |
string | |
filename |
string |
PluginSaveRequest
| Name | Type | Description |
|---|---|---|
code |
string | |
name |
string |
PluginSource
| Name | Type | Description |
|---|---|---|
code |
string | |
filename |
string |
PolicyResponse
| Name | Type | Description |
|---|---|---|
content |
string | |
stem |
string | |
title |
string |
PreviewNameRequest
| Name | Type | Description |
|---|---|---|
kind |
string | 'record' renders a record's name; 'file' renders a download name, where `{ext}` is available and a blank value makes the result null. |
template |
string | The template to try, e.g. '{site}-{taken_on:YYYY-MM}'. |
values |
Field values (keyed by field name) of the sample record to render against. |
PreviewNameResponse
| Name | Type | Description |
|---|---|---|
error |
Why the template is not valid, if it is not. | |
name |
The rendered text, or null when the template renders to nothing. |
PreviewViewRequest
| Name | Type | Description |
|---|---|---|
columns |
Same shape as a view's 'columns' -- base schema field names and/or single-hop reference-field joins. Validated the same way, but not persisted. | |
filter_tree |
Same shape as a view's 'filter_tree'. | |
limit |
integer | |
offset |
integer | |
sort |
Same shape as a view's 'sort': the schema's own or an inherited field, each ascending or descending. |
PreviewViewResponse
| Name | Type | Description |
|---|---|---|
rows |
Array<> | One dict per matching record, keyed by column (joined columns use the 'ref_field.target_field' key). |
total |
integer | Total matching records regardless of 'limit'/'offset'. |
RecordCountResponse
| Name | Type | Description |
|---|---|---|
count |
integer | |
dataset |
string | |
schema_name |
string |
RecordCountsResponse
| Name | Type | Description |
|---|---|---|
items |
Array<RecordCountResponse> |
RecordGrowthPointResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | ISO date the bucket starts on. |
count |
integer | |
dataset |
string | |
schema_name |
string |
RecordGrowthResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | Bucket size applied: day, week, or month. |
items |
Array<RecordGrowthPointResponse> |
RecordLabelResponse
| Name | Type | Description |
|---|---|---|
deleted |
boolean | True for a record in Recently Deleted (it can still be restored). |
deleted_at |
When it was deleted; null for a live record. | |
id |
string | |
natural_name |
The record's name as it is now: its schema's display template applied to its current values. Null when nothing in it can name it. | |
schema_name |
string | The record's schema. |
RecordLabelsRequest
| Name | Type | Description |
|---|---|---|
ids |
Array<string> | Record ids to look up. Anything that isn't a record is skipped. |
RecordRef
| Name | Type | Description |
|---|---|---|
id |
string | |
natural_name |
||
schema_name |
string |
RecordResponse
| Name | Type | Description |
|---|---|---|
ancestors |
Only on a single-record fetch: the parent chain, root first, for breadcrumbs. | |
child_counts |
Only when requested ('child_counts=true'): how many live child records this record has, per child schema name. | |
collection |
Name of the collection this record lives in. | |
created_at |
string(date-time) | |
data |
||
dataset_id |
string | |
deleted_above |
Only on a single-record fetch of a live record: the deleted records directly above it, topmost first. Not empty means it is out of sight (nothing above it lists it); POST /records/{id}/restore-above brings them back. | |
deleted_at |
When this record was soft-deleted. Null means live. | |
deleted_fields |
Values this record still holds for fields that have been deleted from its schema. Nothing is lost: restoring the field (`POST /schemas/{schema_name}/fields/{id}/restore`) puts each back in `data`. Null when there are none. | |
derived |
Only when 'columns' were requested: the requested columns this record's own 'data' can't answer -- fields inherited from an ancestor record, and 'ref_field.target_field' joins -- keyed by column. | |
id |
string | |
natural_name |
||
parent_record_id |
||
reference_collections |
For reference/reference_list targets that live in a different collection (a global one), the target's id mapped to that collection's name. Targets in the record's own collection are left out. | |
reference_labels |
For every reference/reference_list value on this record, the target record's id mapped to its natural_name (null if the target has none). Lets clients render a reference as a link with a readable label without a lookup per value. | |
schema_name |
string | |
updated_at |
string(date-time) |
RecordUseResponse
| Name | Type | Description |
|---|---|---|
collection |
The collection it is in. | |
id |
string | |
name |
string | The record's name, as the app shows it. |
trail |
Array<string> | The names of the records above it, outermost first. |
ReferrerGroupResponse
| Name | Type | Description |
|---|---|---|
collection |
string | Name of that collection. |
count |
integer | Live records of this schema, in this collection, referencing it. |
dataset_id |
string | Id of the collection the referrers live in. |
dtype |
string | 'reference' or 'reference_list'. |
field_name |
string | The reference field that points at the record. |
schema_name |
string | Schema of the referring records; it owns the field. |
RemoteConnectRequest
| Name | Type | Description |
|---|---|---|
invite |
The invite the authority's admin gave. Leave out when this computer has joined that address before (trying a connect again). | |
url |
string | The authority's address. |
RemoteConnectResponse
| Name | Type | Description |
|---|---|---|
mode |
string | joined (became a copy), seeded (filled an empty authority), empty (both empty) or resumed (already the same project). |
RemoteStatusResponse
| Name | Type | Description |
|---|---|---|
configured |
boolean | Whether this project follows an authority. |
connect_error |
Why the last connect started here failed. | |
connecting |
boolean | A connect started here is still running. |
download_files |
string | Which files this device keeps a copy of: all, or opened. |
files_to_fetch |
integer | Files records here cite that aren't on this computer yet. |
interval_seconds |
integer | How often it looks for changes; 0 means only when asked. |
last_error |
Why the last attempt failed, if it did. | |
last_error_at |
||
last_result |
What the last sync run by this server did; null after a restart or before the first one. | |
last_synced_at |
||
open_conflicts |
integer | Values that did not go in as made. |
paused |
boolean | The schedule is stopped; Sync now still works. |
pending |
integer | Changes made here that have not been sent. |
progress |
How far a long step has got while one runs here: copying the project from the authority, filling an empty one, or fetching the history from before joining. | |
project_id |
string | |
remote |
The authority's address. | |
running |
boolean | A sync is in progress right now. |
serving |
boolean | This project is itself an authority. |
RemoteUpdateRequest
| Name | Type | Description |
|---|---|---|
download_files |
Keep a copy of every file (all), or only of files opened or exported (opened). | |
interval_seconds |
Seconds between looks for changes; 0 = never (only when asked). | |
paused |
Stop or start the schedule. |
RemoveExportsRequest
| Name | Type | Description |
|---|---|---|
paths |
Array<string> | Export folders to delete, as listed by GET /file-access/exports. |
ReopenRequest
| Name | Type | Description |
|---|---|---|
ids |
Array<string> | Conflicts to open again. |
ReopenResponse
| Name | Type | Description |
|---|---|---|
reopened |
integer | How many were opened again. Only conflicts settled with `theirs` can be: that changed nothing, so it can be taken back. |
ReorderFieldsRequest
| Name | Type | Description |
|---|---|---|
order |
Array<string> |
RerunJobsRequest
| Name | Type | Description |
|---|---|---|
filter |
Instead of ids: repeat every run this filter matches (the same filter tree as GET /jobs, at most 1000 runs). | |
ids |
Ids of the runs to repeat. Each is queued as a new run. |
RerunJobsResponse
| Name | Type | Description |
|---|---|---|
skipped |
Array<SkippedJob> | Runs that could not be repeated, such as one whose record has since been deleted. |
started |
Array<WorkflowJobResponse> | The new runs that were queued, in the order asked. |
ResolveFailure
| Name | Type | Description |
|---|---|---|
id |
string | |
message |
string |
ResolveManyRequest
| Name | Type | Description |
|---|---|---|
dry_run |
boolean | Only count what would be settled; change nothing. |
force |
boolean | For `mine`: put values back even where the record's value changed since. |
ids |
Only these conflicts. Omit for all that match. | |
kind |
Only this kind: conflict, rejected or edit_vs_delete. | |
record_id |
Only conflicts about this record. | |
take |
string | How to settle each one: `theirs`, `mine`, `delete` or `retry` (see the single resolve). `value` is not offered: it needs a value each. |
ResolveManyResponse
| Name | Type | Description |
|---|---|---|
done |
integer | Settled (with `dry_run`, how many would be). |
failed |
Array<ResolveFailure> | Left open because they failed their checks; the rest were settled. |
not_offered |
integer | Left open because they don't offer that way of settling. |
settled_ids |
Array<string> | Which were settled (empty for `dry_run`); `reopen` takes them back if the way was `theirs`. |
ResolveRequest
| Name | Type | Description |
|---|---|---|
force |
boolean | Put the value back even though the record's value changed since the conflict was recorded. |
take |
string | `theirs` keeps what the authority has (or lets a refused change go); `mine` puts your value back as a new edit; `value` puts the one in `value`; `delete` deletes a record that was deleted there; `retry` sends a refused change again from the record as it is now; `restore_above` brings back the deleted records a refused record sits under, then sends it again; `edited` closes a clash because the field was just set by hand on the record. |
value |
The value, for `take: value`. |
RestoreAllPlanResponse
| Name | Type | Description |
|---|---|---|
blocked |
integer | Matched, but under something deleted that is not in the set (for a field, also one whose name has since been taken). |
collections |
integer | Deleted collections matched. |
fields |
integer | Deleted fields matched. |
records |
integer | Deleted records matched. |
restores |
integer | Records that would be live afterwards, counting what came back with each, once. |
schemas |
integer | Deleted schemas matched. |
things |
integer | All of the above. |
truncated |
boolean | More matched than were looked at. |
RestoreAllRequest
| Name | Type | Description |
|---|---|---|
batch |
Only what this batch deleted: the id of a bulk delete (a record and everything beneath it) from `/audit/events`. | |
filter |
The history filter tree whose matches are restored (the one `GET /audit/events` takes), or null for everything deleted. | |
q |
Text the changes must contain. |
RestoreAllResultResponse
| Name | Type | Description |
|---|---|---|
blocked |
integer | Left deleted: a parent is deleted and not in the set, or a field's name has been taken. |
records |
integer | Records that came back in all. |
restored |
integer | Things brought back. |
RestoreConflictResponse
| Name | Type | Description |
|---|---|---|
existing_id |
string | The live record that now holds the same unique values. |
existing_name |
string | |
fields |
Array<string> | The unique key's field names. |
message |
string | The whole explanation, in plain words. |
record_id |
string | The record that can't come back. |
record_name |
string |
RestorePlanResponse
| Name | Type | Description |
|---|---|---|
blocked |
Why it can't be restored yet, in plain words. Null when it can. | |
blocked_by |
The deleted collection, schema or record that must be restored first. Null when it can be restored now. | |
can_restore |
boolean | |
collection |
For a record: the collection it will be in. | |
collection_id |
||
conflict |
Set when another record has taken the values of a uniqueness key while this one was deleted: restoring is refused until that record is changed or deleted. | |
deleted_at |
When it was deleted. | |
id |
string | |
kind |
string | record, collection, schema or field. |
name |
string | |
parents_needed |
For a record held back only by deleted records above it: how many of them. `POST .../restore?with_parents=true` brings each back by itself (not what was deleted alongside it), so just this record (`&only_this=true`) comes back as `parents_needed + 1` records and its deleted siblings stay deleted. Null otherwise. | |
records |
integer | How many records come back: those deleted together with this, the record itself included when it is one. Never something deleted on its own earlier. |
schema_name |
For a field: the schema it belongs to. |
RestoreResult
| Name | Type | Description |
|---|---|---|
datasets |
integer | |
plugins |
integer | |
records_restored |
integer | |
records_total |
integer | |
schemas |
integer | |
workflows |
integer |
RestoreSelectedRequest
| Name | Type | Description |
|---|---|---|
ids |
Array<string> | The deleted records to restore. |
with_parents |
boolean | Also restore the deleted records above a chosen one, each by itself. Without it, a record under a deleted record is left. |
RestoreSelectedResponse
| Name | Type | Description |
|---|---|---|
came_back |
integer | Records live again in all, counting the parents brought back. |
left |
integer | Chosen records still deleted, and why not. |
restored |
integer | Chosen records that came back. |
RestrictionDescriptorResponse
| Name | Type | Description |
|---|---|---|
control |
string | Which editor to show: number, integer, bytes, choices, accept, filename_template, schema, timezone, date_bound, datetime_bound, unit, precision, geometry_types or bbox. |
help |
string | One sentence of guidance; may be empty. |
key |
string | Key in a field's `restrictions` dict. |
label |
string | Name shown beside the control. |
RetentionReportResponse
| Name | Type | Description |
|---|---|---|
anything |
boolean | |
audit_batches |
integer | |
audit_entries |
integer | |
audit_kept_first_and_last |
integer | Older history kept because it is a thing's creation or its latest entry, which are kept however old. |
audit_kept_restorable |
integer | Older history kept because it is about something that can still be restored. |
audit_kept_unsynced |
integer | Older history kept because it has not been synced yet. |
deleted_collections |
integer | |
deleted_records |
integer | |
deleted_schemas |
integer | |
dry_run |
boolean | |
run_steps |
integer | |
runs |
integer | |
skipped |
Array<string> | Deleted things that could not be removed, with why. |
RetentionRunRequest
| Name | Type | Description |
|---|---|---|
audit_before |
Remove change history before this (not about anything that can still be restored, and with a remote, not yet pushed). | |
deleted_before |
Permanently delete everything deleted before this. | |
dry_run |
boolean | Only count what would be removed. |
from_settings |
boolean | Apply the retention settings (each kind left at keep-forever is left alone). |
runs_before |
Remove finished workflow runs, with their step logs, before this. |
RetentionSettingsResponse
| Name | Type | Description |
|---|---|---|
audit_days |
Change history older than this many days is removed by a clean-up. Null keeps it forever. | |
auto_purge_deleted |
boolean | Whether a clean-up permanently deletes items deleted more than `purge_after_days` ago. |
purge_after_days |
integer | Deleted items can be restored for this many days. A clean-up only deletes them permanently after that when `auto_purge_deleted` is on. |
run_days |
Finished workflow runs, with their step logs, older than this many days are removed by a clean-up. Null keeps them forever. |
RevertFieldResponse
| Name | Type | Description |
|---|---|---|
current |
What the record holds now. | |
dtype |
||
field |
string | |
label |
||
reason |
||
status |
string | apply (still as the entry left it), conflict (edited since; reverted only when forced), same (already the older value) or skipped (cannot be put back; see reason). |
target |
What reverting would put back. |
RevertPlanResponse
| Name | Type | Description |
|---|---|---|
audit_id |
string | |
blocked |
Why the entry can't be reverted at all. | |
blocker |
When a deleted record can't come back yet, what to restore first. | |
can_apply |
boolean | |
entity_id |
string | |
entity_type |
string | |
fields |
Array<RevertFieldResponse> | Per-field plan, for an update. |
has_conflicts |
boolean | |
kind |
update (put fields back), restore (undo a delete) or delete (undo a create). Null when nothing can be reverted. |
RevertRequest
| Name | Type | Description |
|---|---|---|
fields |
Only put these fields back. Omit to revert everything the entry changed. | |
force |
boolean | Also overwrite fields that were edited since the entry. |
RevertResultResponse
| Name | Type | Description |
|---|---|---|
applied |
Array<string> | Names of the fields that were put back (an update only). |
audit_id |
string | |
entity_id |
string | |
kind |
string |
RunFieldResponse
| Name | Type | Description |
|---|---|---|
choices |
Fixed choices, when there are any. | |
description |
string | |
label |
string | |
name |
string | |
operators |
Array<string> | Operators a condition on it accepts. |
type |
string | string, enum, integer or datetime. |
RunManyRequest
| Name | Type | Description |
|---|---|---|
record_ids |
Array<string> | Ids of the records to run the workflow on, one run each. |
RunManyResponse
| Name | Type | Description |
|---|---|---|
skipped |
Array<SkippedJob> | Records the workflow was not run on, each with why: not found, or not the schema the workflow is for. |
started |
Array<WorkflowJobResponse> | The runs that were queued, in the order asked. |
SchemaDeleteImpactResponse
| Name | Type | Description |
|---|---|---|
child_schema_count |
integer | Schemas that inherit from this one, directly or transitively — informational only, they are not deleted along with it, but their presence blocks a later purge. |
record_count |
integer | Records typed by this schema itself, across every collection — deleted along with it. |
SchemaResponse
| Name | Type | Description |
|---|---|---|
deleted_at |
When this schema was soft-deleted. Null means live. | |
description |
||
display_template |
Template that names this schema's records; fields in braces, formats after a colon. Null means the first plain value is used. | |
fields |
Array<FieldResponse> | |
id |
string | |
label |
Human-facing display name. Null means none was set — render the name title-cased instead. | |
name |
string | |
parent_id |
||
unique_keys |
Array<Array<string>> | Uniqueness policies: each a list of this schema's own field names whose values no two records may share, within the same parent record (or the same collection, for a top-level record). |
SetDbUrlRequest
| Name | Type | Description |
|---|---|---|
url |
string |
SetPlacementRequest
| Name | Type | Description |
|---|---|---|
on_unavailable |
string | spill (default) or fail. |
volume |
string | Name of the volume that becomes the home. |
SetQueueRequest
| Name | Type | Description |
|---|---|---|
queue |
Array<string> |
SetUniqueKeysRequest
| Name | Type | Description |
|---|---|---|
keys |
Array<Array<string>> | The schema's complete list of uniqueness keys, replacing the current one; each key is a list of the schema's own field names. An empty list removes every policy. |
ShortcutResponse
| Name | Type | Description |
|---|---|---|
exists |
boolean | Whether the Desktop shortcut for this project is there. |
path |
Where it is (or would be), when there is a Desktop. |
SkippedJob
| Name | Type | Description |
|---|---|---|
id |
string | |
reason |
string | Why this run could not be repeated. |
StartUpdateRequest
| Name | Type | Description |
|---|---|---|
pre |
boolean | Install a pre-release if it is the newest. |
StartUpdateResponse
| Name | Type | Description |
|---|---|---|
restarting |
boolean | civex is closing to update and will start again; poll `/health` and reload when it answers. |
StorageLocationResponse
| Name | Type | Description |
|---|---|---|
free_bytes |
Free space; null if unknown, and not read for network drives. | |
kind |
string | project, home or drive. |
label |
string | |
network |
boolean | True for a drive that lives on another machine. |
path |
string | |
source |
Where a network drive really lives, e.g. nas:/export. | |
total_bytes |
StoredObjectResponse
| Name | Type | Description |
|---|---|---|
mtime |
number | Unix timestamp the object was written. |
sha256 |
string | Content hash identifying the object. |
size |
integer | Object size in bytes. |
volume |
string | Volume the object was found on. |
SyncFeedResponse
| Name | Type | Description |
|---|---|---|
entries |
Array<> | Changes past `after`, in the authority's order, each with its `hub_seq` and whether it was `superseded` by a later settled state. |
head_seq |
integer | |
more |
boolean | There are more past this page. |
SyncFilesRequest
| Name | Type | Description |
|---|---|---|
sha256 |
Array<string> | Content hashes of files the device holds. |
SyncFilesResponse
| Name | Type | Description |
|---|---|---|
missing |
Array<string> | Those the authority does not have yet. |
SyncHelloResponse
| Name | Type | Description |
|---|---|---|
capabilities |
Array<string> | Optional features it has, by name. Adding one is not a protocol change. |
counts |
How many of each kind it holds, deleted ones included, so a device copying it can show how far along it is. | |
device_name |
string | What the token used is called here. |
empty |
boolean | True when it holds none of the project's things yet (an empty authority can be filled from a project that has data). |
feed_floor |
integer | The highest number the feed no longer holds (history pruned here). A device whose cursor is below it copies the project again. |
head_seq |
integer | The latest number the authority has handed out. |
project_id |
string | The project's id, shared by every copy. |
protocol_max |
integer | The newest sync protocol it speaks. |
protocol_min |
integer | The oldest sync protocol it speaks. |
protocol_version |
integer | The sync protocol this server and the calling device agreed on. |
seeded_by |
The device that put the first data in, if any. | |
server_version |
The civex release it runs. |
SyncJoinRequest
| Name | Type | Description |
|---|---|---|
device_id |
string | This device's id (a UUID). |
invite |
string | The invite code the authority's admin gave. |
public_key |
string | This device's Ed25519 public key, base64 of its 32 bytes. |
SyncJoinResponse
| Name | Type | Description |
|---|---|---|
authority_key |
string | The authority's public key: it signs its answers to sign-ins. |
device_name |
string | What the device was invited as. |
project_id |
string | The project's id, shared by every copy. |
SyncOpResponse
| Name | Type | Description |
|---|---|---|
conflicts |
Array<> | Values that did not go in as made: field, yours, theirs, kind. |
hub_seq |
Where the authority numbered it, once taken. | |
message |
||
op_id |
string | |
status |
string | applied, merged, conflict, duplicate, rejected or deferred (deferred: not taken yet; send it again). |
SyncProgressResponse
| Name | Type | Description |
|---|---|---|
bytes_done |
integer | Downloading files: bytes so far. |
done |
integer | Things (or history entries) done so far. |
kind |
The kind of thing it is on (schema, record...). | |
phase |
string | copying, filling or history. |
rate |
number | Downloading files: bytes per second, lately. |
total |
Out of how many; null when not known. |
SyncPushRequest
| Name | Type | Description |
|---|---|---|
entries |
Array<> | Changes made on the device, oldest first: history entries with their snapshots. Each is identified by its id, so sending one twice is harmless. |
SyncPushResponse
| Name | Type | Description |
|---|---|---|
head_seq |
integer | |
results |
Array<SyncOpResponse> | One answer per change, in order. Fewer than were sent means the rest were held back behind one that has to wait. |
SyncResultResponse
| Name | Type | Description |
|---|---|---|
conflicts |
integer | Values that did not go in as made. |
files_sent |
integer | |
pulled |
integer | Changes from others brought in. |
pushed |
integer | Changes of this project's that were sent. |
rejected |
integer | Changes the authority refused. |
SyncSessionRequest
| Name | Type | Description |
|---|---|---|
at |
integer | Now, in unix seconds, as the device's clock says. |
device_id |
string | The device signing in. |
signature |
string | The device's signature over the session request (the authority's key, the device id and `at`). |
SyncSessionResponse
| Name | Type | Description |
|---|---|---|
expires_at |
integer | When the token stops working, unix seconds. |
signature |
string | The authority's signature over its answer to this request. |
token |
string | Send as `Authorization: Bearer` until it expires. |
SyncSnapshotResponse
| Name | Type | Description |
|---|---|---|
head_seq |
integer | Taken before reading: what changes meanwhile is in the feed past it. |
items |
Array<> | Things of this kind as they are now, in the shape a history entry stores them. |
kind |
string | |
more |
boolean | |
next |
Pass as `after` for the next page; null on the last page. |
TableRequest
| Name | Type | Description |
|---|---|---|
columns |
Which columns, in order: field names, 'ref_field.target_field' joins, or 'id', 'schema', 'created_at', 'updated_at'. Omit for the id and every field. When the records are of several kinds, each kind's table takes the columns it has. | |
format |
string | The file format of the table. |
kind |
The schema whose records are the rows: the records the export takes, the ones above them, and (with 'below') the ones beneath. Omit for one table per kind the export holds, written at the top. | |
name |
The file's name without its extension. With 'kind' it is a template over the folder's record ('{schema}', '{id}' and its fields); without, the name when there is just one table. Omit to name it for what it holds ('Selections') or, for a record's own fields, 'Metadata'. | |
shape |
string | 'rows': a row per record. 'fields': the fields of one record as field/value pairs (a metadata sheet); needs 'where' to equal 'kind'. |
skip_empty |
boolean | False also writes a table (just its header) in a folder that has no rows. |
where |
Write the table in the folder of each record of this schema, holding the 'kind' records that are that record or beneath it. The same as 'kind' gives each record its own table. Omit to write it once, at the top. Needs the 'tree' layout. |
TargetShareResponse
| Name | Type | Description |
|---|---|---|
bytes |
integer | |
files |
integer | About how many files would go to this target. |
free_bytes |
Room the target has; null if it can't be read now. | |
volume |
string |
TokenUsageBucketResponse
| Name | Type | Description |
|---|---|---|
bucket |
string | |
input_tokens |
integer | |
model |
string | |
output_tokens |
integer | |
provider |
string |
ToolCallMessage
| Name | Type | Description |
|---|---|---|
id |
string | |
input |
||
name |
string | |
result |
string | |
role |
string |
TransferFailureResponse
| Name | Type | Description |
|---|---|---|
reason |
string | |
sha256 |
string | |
volume |
string | Where the file is (and stays). |
TransferPlanResponse
| Name | Type | Description |
|---|---|---|
already_there |
integer | Files already on a target, left alone. |
bytes |
integer | |
can_proceed |
boolean | |
copied |
integer | Of `files`, those copied rather than moved: the drive they come from is the home of another collection that uses them, and keeps its copy. |
copied_bytes |
integer | |
files |
integer | Files that would be moved (from the catalog, so close, not exact). |
problems |
Array<string> | Reasons the transfer can't start. |
targets |
Array<TargetShareResponse> | |
warnings |
Array<string> | Things worth knowing; they don't stop it. |
TransferProgressResponse
| Name | Type | Description |
|---|---|---|
bytes_done |
integer | |
bytes_total |
integer | |
current |
The file being copied (a hash prefix), if any. | |
current_bytes |
integer | Bytes of the current file copied so far; add to bytes_done for a smooth bar. |
current_total |
integer | |
eta_seconds |
||
files_done |
integer | |
files_failed |
integer | |
files_skipped |
integer | Already on a target. |
files_total |
integer | |
message |
string | |
rate_bytes_per_second |
number |
TransferRequest
| Name | Type | Description |
|---|---|---|
collection_ids |
Array<string> | consolidate: ids of the collections to move. |
freeze_sources |
boolean | drain: make the sources read-only while it runs, so new uploads don't keep landing on them, and put them back afterwards. |
kind |
string | drain: move everything off the `sources` volumes. consolidate: move the files of the `collection_ids` collections. |
sources |
Array<string> | drain: the volumes to empty. |
targets |
Array<string> | Volumes to put the files on, in order of preference: a file goes to the first that is usable and has room. |
verify |
string | copy: each file is hashed as it is copied and must match its recorded hash. full: the copy is also read back and hashed (about twice the reading). |
TransferResponse
| Name | Type | Description |
|---|---|---|
auto_resume |
boolean | Paused only because a volume stopped answering, and will carry on by itself when it does. |
control |
A pause or cancel asked for and not yet acted on. | |
created_at |
||
error |
||
failures |
Array<TransferFailureResponse> | Files that couldn't be moved (the first few hundred). |
failures_total |
integer | |
finished_at |
||
frozen |
Volumes made read-only for the duration, and what each was before. | |
id |
string | |
kind |
string | |
live |
boolean | Running on a thread of this server right now. |
pause_reason |
||
plan |
||
progress |
TransferProgressResponse | |
spec |
TransferRequest | |
started_at |
||
status |
string | running, paused, completed, failed, cancelled or interrupted (the process died; resumable). |
updated_at |
TriggerBreakdownPointResponse
| Name | Type | Description |
|---|---|---|
count |
integer | |
trigger |
string | One of: record_created, record_updated, manual. |
TriggerBreakdownResponse
| Name | Type | Description |
|---|---|---|
items |
Array<TriggerBreakdownPointResponse> |
UISettingsResponse
| Name | Type | Description |
|---|---|---|
show_advanced |
boolean |
UpdateAttempt
| Name | Type | Description |
|---|---|---|
at |
string | When it finished (UTC, `YYYY-MM-DDTHH:MM:SSZ`). |
from_version |
string | The version it updated from. |
message |
string | What went wrong; blank when it worked. |
ok |
boolean | Whether a newer version was installed. |
to_version |
The version installed afterwards. |
UpdateDatasetRequest
| Name | Type | Description |
|---|---|---|
description |
||
rename |
||
schemas |
Replace the collection's schema list. Omit or null to leave unchanged. A schema with records in the collection can't be removed. | |
scope |
'local' or 'global'. Omit or null to leave unchanged. A global collection that other collections reference can't become local. | |
timezone |
IANA timezone for datetime values in this collection. Omit or null to leave unchanged; an empty string clears it back to unset. |
UpdateExportDefinitionRequest
| Name | Type | Description |
|---|---|---|
fields |
Replace the file fields; omit to leave as is. | |
files_layout |
Change the layout; omit to leave as is. | |
filter_tree |
Replace the filter; send null to clear it. | |
holder |
Change the kind; send null for 'any beneath'. | |
include_files |
Take the files or not; omit to leave as is. | |
rename |
New name. | |
tables |
Replace the tables; send an empty list to remove them. |
UpdateFieldRequest
| Name | Type | Description |
|---|---|---|
default |
||
label |
New display name. Send an empty string to clear it and fall back to the derived label; omit the key to leave it unchanged. | |
rename |
||
required |
||
restrictions |
UpdateIdentityRequest
| Name | Type | Description |
|---|---|---|
name |
The name to record on changes made in this project; blank or null goes back to the default (the operating-system user). Saved in the project's config.toml. |
UpdateMapSettingsRequest
| Name | Type | Description |
|---|---|---|
attribution |
Plain-text credit for the provider, or null. | |
tile_url |
XYZ tile URL (http or https, with {z}, {x}, {y}), or null to clear. |
UpdateRecordRequest
| Name | Type | Description |
|---|---|---|
data |
UpdateRetentionSettingsRequest
| Name | Type | Description |
|---|---|---|
audit_days |
||
auto_purge_deleted |
||
purge_after_days |
||
run_days |
UpdateSchemaRequest
| Name | Type | Description |
|---|---|---|
description |
||
display_template |
Template that names the schema's records. Send an empty string to clear it; omit the key to leave it unchanged. | |
label |
New display name. Send an empty string to clear it and fall back to the derived label; omit the key to leave it unchanged. | |
rename |
UpdateStatusResponse
| Name | Type | Description |
|---|---|---|
blocked |
string | Why it can't, in plain words; blank when it can. |
can_update |
boolean | Whether the app can update this copy. |
current |
string | The version running now. |
error |
string | Why PyPI couldn't be asked; blank when it was. |
installer |
string | How this copy was installed: desktop, frozen, editable, pipx, uv or pip. |
last |
The outcome of the last update started from the app. | |
latest |
The newest version on PyPI (pre-releases too when asked for); null when PyPI couldn't be reached. | |
newer |
boolean | Whether `latest` is newer than `current`. |
pre |
boolean | Whether pre-releases were looked for. |
UpdateUISettingsRequest
| Name | Type | Description |
|---|---|---|
show_advanced |
boolean |
UpdateViewRequest
| Name | Type | Description |
|---|---|---|
columns |
Replace the column list; omit the key to leave it unchanged. | |
files_layout |
Change how the view's files are arranged when exported; omit the key to leave it unchanged. | |
filter_tree |
Replace the filter tree; send null to clear it, omit the key to leave it unchanged. | |
rename |
New name; same rules as when creating. | |
sort |
Replace the sort order; omit the key to leave it unchanged. |
UpdateVolumeRequest
| Name | Type | Description |
|---|---|---|
allocated_gb |
||
clear_allocation |
boolean | |
path |
||
state |
active, readonly (readable, never written to) or retired. |
UploadResult
| Name | Type | Description |
|---|---|---|
filename |
string | |
plugin_id |
string |
UsageTotalsResponse
| Name | Type | Description |
|---|---|---|
input_tokens |
integer | |
output_tokens |
integer | |
requests |
integer | |
total_tokens |
integer |
UserMessage
| Name | Type | Description |
|---|---|---|
content |
string | |
role |
string |
ValidationError
| Name | Type | Description |
|---|---|---|
ctx |
||
input |
||
loc |
Array<> | |
msg |
string | |
type |
string |
ViewResponse
| Name | Type | Description |
|---|---|---|
columns |
Array<string> | Base schema field names to show, in order (own or inherited). May also include single-hop reference-field joins as 'ref_field.target_field' (e.g. 'customer.email'). |
files_layout |
string | How the view's files are arranged when exported as a folder or zip: 'tree' puts each file in a folder per record above it (Encounter/Recording/Selection/...), 'grouped' keeps the folders above the records that hold the files but gathers those records' files into one folder named for their kind (Encounter/Recording/Selections/...), 'flat' puts every file in one folder. |
filter_tree |
AND/OR filter tree, same shape as the records 'filter' query parameter (conditions may name an ancestor or descendant schema). | |
id |
string | |
name |
string | |
schema_id |
string | |
schema_name |
string | |
sort |
Array<> | Ordered list of {field, direction} entries; direction is 'asc' or 'desc'. |
VolumeStatsResponse
| Name | Type | Description |
|---|---|---|
allocated_gb |
||
available |
boolean | True if the volume's files can be read right now (online, read-only or retired). |
civex_used_bytes |
||
disk_free_bytes |
||
disk_total_bytes |
||
fix |
string | A plain-language next step for an offline or wrong-drive volume; empty otherwise. |
history_bytes |
integer | |
history_files |
integer | Files kept only because a workflow run took them as an input. |
in_queue |
boolean | |
name |
string | |
network |
boolean | The volume's folder is on a network drive. |
path |
string | |
reason |
string | What civex expected versus what it found; empty when online. |
state |
string | online, offline (path not there, e.g. drive unplugged), wrong_drive (something else is mounted there), readonly or retired. |
unused_bytes |
integer | |
unused_files |
integer | Files on the volume that nothing uses; garbage collection can reclaim them. |
warning |
boolean |
WorkflowDetailResponse
| Name | Type | Description |
|---|---|---|
content |
string | |
description |
||
filename |
string | |
inputs |
||
name |
string | |
record_schema |
||
stem |
string | |
step_list |
Array<WorkflowStepResponse> | |
steps |
integer | |
triggers |
WorkflowInputResponse
| Name | Type | Description |
|---|---|---|
description |
||
label |
||
type |
string |
WorkflowJobResponse
| Name | Type | Description |
|---|---|---|
affected_records |
||
created_at |
string(date-time) | |
depth |
integer | How many workflow-triggered-by-workflow hops deep this run is: 0 for a run started by a person or an ordinary edit, 1 for a run started by another run's save, and so on. |
error |
||
error_details |
||
finished_at |
||
id |
string | |
log |
||
record_id |
string | |
schema_name |
string | |
started_at |
||
status |
string | |
step_executions |
||
trigger |
string | |
trigger_detail |
What caused the run. `changes` lists each field that changed, with a short `before` and `after` and whether the workflow was `watched` for it. `caused_by` is {job_id, workflow} when another run's own save started this one, else null. Null for a run started by hand. | |
workflow_name |
string |
WorkflowResponse
| Name | Type | Description |
|---|---|---|
description |
||
filename |
string | |
inputs |
||
name |
string | |
record_schema |
||
runs_on |
Array<string> | What starts it by itself, one line each ("record_created on sample (site)"); empty if only run by hand. |
stem |
string | |
steps |
integer |
WorkflowSaveRequest
| Name | Type | Description |
|---|---|---|
content |
string |
WorkflowStepResponse
| Name | Type | Description |
|---|---|---|
condition |
||
config |
||
id |
string | |
inputs |
||
plugin |
string |
WorkflowTriggerResponse
| Name | Type | Description |
|---|---|---|
fields |
||
schema_name |
string |
Tags
| Name | Description |
|---|---|
| sync | What an authority offers to the devices that follow it: handshake, push, feed, snapshot and files. For other civex installs, not people; only reachable remotely on an instance set to serve. |
| schemas | Define the shape of your data: schemas are named collections of typed fields (integer, float, string, boolean, date, datetime, file, file_list, reference), with restrictions (min/max, choices, accepted file types, ...) and optional inheritance from a parent schema. Create a schema before creating any records. |
| collections | Datasets are named containers of records that all conform to the same schema. Use this to create, rename, or delete the datasets you organize records into. |
| records | Create, read, update, delete, and bulk-import the individual rows of data that live inside a dataset. Record data is validated against its schema's field types and restrictions on every write. |
| files | Upload binary attachments (referenced from file / file_list record fields) and download them back out by content hash. |
| workflows | Author and manage YAML workflow definitions: chains of plugin steps, triggered automatically on record create/update or run manually, that read and write record fields. |
| jobs | Inspect the queue of workflow runs — one job per trigger firing or manual run — including their status, inputs, and outputs. |
| audit | Read the change history recorded for records, schemas, fields, and datasets — every create/update/delete with a full before/after data snapshot and timestamp. |
| retention | Clean up by age: deleted items, change history and finished workflow runs older than the retention settings or a given date. |
| plugins | Discover the built-in and project-defined plugins available to use as workflow steps, along with their declared inputs and outputs. Also handles uploading container-tier (Tier 2) plugins. |
| ai | AI-assisted helpers layered on top of the data model — schema suggestions, record extraction, and similar model-backed endpoints — plus the AI provider configuration they run against. |
| remote | Push and pull a project's schemas, datasets, and records to/from a remote civex server, and check the current sync status. |
| store | Manage the object volumes that back file storage — add, update, or remove a volume, and inspect per-volume usage stats. |
| db | Inspect and configure the underlying database connection: connection status, pending migrations, the configured URL, and (when using the bundled Docker Postgres) container lifecycle. Deliberately reachable even when the database itself is down. |
| dump | Export a full project (schemas, datasets, records) to a single portable archive, and restore a project from one — the basis for backups and moving a project between machines. |
| legal | Read-only endpoints for the software's own license text and acceptable-use policy, independent of any particular project. |
| status | Live health checks, such as a round-trip database query, for monitoring whether a running server is actually functional. |
| terminal | A WebSocket-backed interactive shell in the project directory, used by the web UI's embedded terminal panel. |
| update | Updating civex itself from the app: whether a newer version is on PyPI, and updating and starting again. The update runs after civex has exited, so a running copy is never replaced. |
| settings | Per-project UI preferences, such as whether the Advanced navigation section (terminal, YAML editing, plugin editors) is shown by default. |
| analytics | Aggregate, filterable, time-bucketed reads over records, workflow jobs, audit events, and AI usage — the read path dashboard widgets call. Every endpoint shares one query-param filter contract (date range, dataset, schema, workflow_id, plugin_id, status, trigger); each documents which of those it actually applies. |