English
Tables
Routes are relative to <PUBLIC_BASE_URL>; request and response bodies are JSON unless stated otherwise. Authentication, scopes, pagination and the error format are described in the REST API guides.
GET /api/v1/tables
List tables
Every table of the instance with its columns and row count. Tables are shared by the whole team.
Access — Member session or API key with scope tables:read.
Responses
200 — The tables.
| Field | Type | Required |
|---|---|---|
tables | object[] | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"tables": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"slug": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_-]*$"
},
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
"description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"columns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
},
"label": { "type": "string", "minLength": 1, "maxLength": 120 },
"type": {
"type": "string",
"enum": [
"text",
"number",
"boolean",
"date",
"datetime",
"select",
"email"
]
},
"isKey": { "type": "boolean" },
"required": { "type": "boolean" },
"options": {
"maxItems": 100,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"width": {
"anyOf": [
{ "type": "integer", "minimum": 80, "maximum": 800 },
{ "type": "null" }
]
},
"description": {
"anyOf": [ { "type": "string", "maxLength": 400 }, { "type": "null" } ]
}
},
"required": [
"key",
"label",
"type",
"isKey",
"required",
"options",
"width",
"description"
],
"additionalProperties": false
}
},
"keyUnique": { "type": "boolean" },
"rowCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"createdAt": { "type": "string" },
"updatedAt": { "type": "string" }
},
"required": [
"id",
"slug",
"name",
"description",
"columns",
"keyUnique",
"rowCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
}
},
"required": [ "tables" ],
"additionalProperties": false
}401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
POST /api/v1/tables
Create a table
Administrators only. The slug is derived from the name when absent and made unique. Columns may be declared at once; keyUnique (default true) makes the key column reject duplicate rows.
Access — Member session or API key with scope tables:write.
Request body (application/json)
| Field | Type | Required |
|---|---|---|
name | string | yes |
slug | string | no |
description | string | null | no |
columns | object[] | no |
keyUnique | boolean | no |
JSON Schema
json
{
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
"slug": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_-]*$"
},
"description": { "anyOf": [ { "type": "string", "maxLength": 1000 }, { "type": "null" } ] },
"columns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
},
"label": { "type": "string", "minLength": 1, "maxLength": 120 },
"type": {
"default": "text",
"type": "string",
"enum": [
"text",
"number",
"boolean",
"date",
"datetime",
"select",
"email"
]
},
"isKey": { "default": false, "type": "boolean" },
"required": { "default": false, "type": "boolean" },
"options": {
"default": [],
"maxItems": 100,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"description": {
"anyOf": [ { "type": "string", "maxLength": 400 }, { "type": "null" } ]
}
},
"required": [ "label" ]
}
},
"keyUnique": { "default": true, "type": "boolean" }
},
"required": [ "name" ]
}Responses
201 — The table.
| Field | Type | Required |
|---|---|---|
table | object | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"table": {
"type": "object",
"properties": {
"id": { "type": "string" },
"slug": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_-]*$"
},
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
"description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"columns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
},
"label": { "type": "string", "minLength": 1, "maxLength": 120 },
"type": {
"type": "string",
"enum": [
"text",
"number",
"boolean",
"date",
"datetime",
"select",
"email"
]
},
"isKey": { "type": "boolean" },
"required": { "type": "boolean" },
"options": {
"maxItems": 100,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"width": {
"anyOf": [
{ "type": "integer", "minimum": 80, "maximum": 800 },
{ "type": "null" }
]
},
"description": {
"anyOf": [ { "type": "string", "maxLength": 400 }, { "type": "null" } ]
}
},
"required": [
"key",
"label",
"type",
"isKey",
"required",
"options",
"width",
"description"
],
"additionalProperties": false
}
},
"keyUnique": { "type": "boolean" },
"rowCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"createdAt": { "type": "string" },
"updatedAt": { "type": "string" }
},
"required": [
"id",
"slug",
"name",
"description",
"columns",
"keyUnique",
"rowCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [ "table" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
This operation accepts an Idempotency-Key header: replaying the same request with the same key returns the original response instead of acting twice. See Idempotency.
Error codes — request.bad_request, auth.forbidden, tables.limit_reached, tables.duplicate_slug, tables.duplicate_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
Example request
json
{
"name": "Départements → consultants",
"columns": [
{ "label": "Département", "type": "text", "isKey": true, "required": true },
{ "label": "Consultant", "type": "email", "required": true }
]
}GET /api/v1/tables/limits
Read the table limits
The ceilings of the instance: tables, columns per table, rows per table, characters per cell. Reaching one is a 409 tables.limit_reached.
Access — Member session or API key with scope tables:read.
Responses
200 — The limits.
| Field | Type | Required |
|---|---|---|
limits | object | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"limits": {
"type": "object",
"properties": {
"maxTables": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"maxColumns": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"maxRows": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"maxCellChars": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
}
},
"required": [ "maxTables", "maxColumns", "maxRows", "maxCellChars" ],
"additionalProperties": false
}
},
"required": [ "limits" ],
"additionalProperties": false
}401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
GET /api/v1/tables/{id}
Read a table
By id or by slug. The structure only; rows are read separately.
Access — Member session or API key with scope tables:read.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Responses
200 — The table.
| Field | Type | Required |
|---|---|---|
table | object | yes |
Same schema as POST /api/v1/tables.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — tables.not_found. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
PATCH /api/v1/tables/{id}
Update a table
Name, slug, description, key uniqueness. Administrators only. Partial: only the fields present change.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
name | string | no |
slug | string | no |
description | string | null | no |
keyUnique | boolean | no |
JSON Schema
json
{
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
"slug": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_-]*$"
},
"description": { "anyOf": [ { "type": "string", "maxLength": 1000 }, { "type": "null" } ] },
"keyUnique": { "type": "boolean" }
}
}Responses
200 — The table.
| Field | Type | Required |
|---|---|---|
table | object | yes |
Same schema as POST /api/v1/tables.
400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — request.bad_request, tables.not_found, auth.forbidden, tables.duplicate_slug. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
DELETE /api/v1/tables/{id}
Delete a table
Administrators only. Rows go with it. Read usage first: workflows that rely on the table are not stopped.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Responses
204 — Deleted.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — tables.not_found, auth.forbidden. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
POST /api/v1/tables/{id}/columns
Add a column
Administrators only. The key is derived from the label when absent. position inserts it at a given rank; appended otherwise. Existing rows get an empty cell.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
key | string | no |
label | string | yes |
type | "text" | "number" | "boolean" | "date" | "datetime" | "select" | "email" | no |
isKey | boolean | no |
required | boolean | no |
options | string[] | no |
description | string | null | no |
position | integer | no |
JSON Schema
json
{
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
},
"label": { "type": "string", "minLength": 1, "maxLength": 120 },
"type": {
"default": "text",
"type": "string",
"enum": [ "text", "number", "boolean", "date", "datetime", "select", "email" ]
},
"isKey": { "default": false, "type": "boolean" },
"required": { "default": false, "type": "boolean" },
"options": {
"default": [],
"maxItems": 100,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"description": { "anyOf": [ { "type": "string", "maxLength": 400 }, { "type": "null" } ] },
"position": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }
},
"required": [ "label" ]
}Responses
200 — The table, with the column.
| Field | Type | Required |
|---|---|---|
table | object | yes |
Same schema as POST /api/v1/tables.
400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
This operation accepts an Idempotency-Key header: replaying the same request with the same key returns the original response instead of acting twice. See Idempotency.
Error codes — request.bad_request, tables.not_found, auth.forbidden, tables.limit_reached, tables.duplicate_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
PATCH /api/v1/tables/{id}/columns/{key}
Update a column
Rename, retype, move, change the options or the flags. Administrators only. A type change converts every cell first and is refused as a whole (tables.conversion_failed, with the failing cells) if one does not fit.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
key | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
key | string | no |
label | string | no |
type | "text" | "number" | "boolean" | "date" | "datetime" | "select" | "email" | no |
isKey | boolean | no |
required | boolean | no |
options | string[] | no |
width | integer | null | no |
description | string | null | no |
position | integer | no |
force | boolean | no |
JSON Schema
json
{
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
},
"label": { "type": "string", "minLength": 1, "maxLength": 120 },
"type": {
"type": "string",
"enum": [ "text", "number", "boolean", "date", "datetime", "select", "email" ]
},
"isKey": { "type": "boolean" },
"required": { "type": "boolean" },
"options": {
"maxItems": 100,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"width": {
"anyOf": [
{ "type": "integer", "minimum": 80, "maximum": 800 },
{ "type": "null" }
]
},
"description": { "anyOf": [ { "type": "string", "maxLength": 400 }, { "type": "null" } ] },
"position": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"force": { "default": false, "type": "boolean" }
}
}Responses
200 — The table, updated.
| Field | Type | Required |
|---|---|---|
table | object | yes |
Same schema as POST /api/v1/tables.
400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — request.bad_request, tables.not_found, auth.forbidden, tables.unknown_column, tables.duplicate_column, tables.conversion_failed. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
DELETE /api/v1/tables/{id}/columns/{key}
Remove a column
Administrators only. Its cells are dropped from every row. The last column of a table cannot be removed.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
key | path | string | yes |
Responses
200 — The table, without the column.
| Field | Type | Required |
|---|---|---|
table | object | yes |
Same schema as POST /api/v1/tables.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — tables.not_found, auth.forbidden, tables.unknown_column, tables.last_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
GET /api/v1/tables/{id}/rows
List rows
Filtered (q across cells, filter conditions combined by match), sorted by a column, paginated by offset and limit (max 500, offset capped). total counts the filtered rows, totalUnfiltered the table. Authors are resolved to names.
Access — Member session or API key with scope tables:read.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
q | query | string | no |
filter | query | string | no |
match | query | "all" | "any" | no |
sort | query | string | no |
dir | query | "asc" | "desc" | no |
offset | query | integer | no |
limit | query | integer | no |
Responses
200 — A page of rows.
| Field | Type | Required |
|---|---|---|
rows | object[] | yes |
total | integer | yes |
totalUnfiltered | integer | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"data": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"anyOf": [
{ "type": "string" },
{ "type": "number" },
{ "type": "boolean" },
{ "type": "null" }
]
}
},
"createdAt": { "type": "string" },
"updatedAt": { "type": "string" },
"createdBy": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [ "member", "workflow", "import", "unknown" ]
},
"id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "kind", "id", "label" ],
"additionalProperties": false
},
"updatedBy": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [ "member", "workflow", "import", "unknown" ]
},
"id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "kind", "id", "label" ],
"additionalProperties": false
}
},
"required": [ "id", "data", "createdAt", "updatedAt", "createdBy", "updatedBy" ],
"additionalProperties": false
}
},
"total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"totalUnfiltered": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }
},
"required": [ "rows", "total", "totalUnfiltered" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — request.bad_request, tables.not_found. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
POST /api/v1/tables/{id}/rows
Add a row
Any member. values is keyed by column key; each value is converted to its column type, and every refusal is returned together in details.rejections. A duplicate key on a table with keyUnique is a 409.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
values | object | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"values": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"anyOf": [
{ "type": "string" },
{ "type": "number" },
{ "type": "boolean" },
{ "type": "null" }
]
}
}
},
"required": [ "values" ]
}Responses
201 — The row.
| Field | Type | Required |
|---|---|---|
row | object | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"row": {
"type": "object",
"properties": {
"id": { "type": "string" },
"data": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"anyOf": [
{ "type": "string" },
{ "type": "number" },
{ "type": "boolean" },
{ "type": "null" }
]
}
},
"createdAt": { "type": "string" },
"updatedAt": { "type": "string" },
"createdBy": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [ "member", "workflow", "import", "unknown" ]
},
"id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "kind", "id", "label" ],
"additionalProperties": false
},
"updatedBy": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [ "member", "workflow", "import", "unknown" ]
},
"id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "kind", "id", "label" ],
"additionalProperties": false
}
},
"required": [ "id", "data", "createdAt", "updatedAt", "createdBy", "updatedBy" ],
"additionalProperties": false
}
},
"required": [ "row" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
This operation accepts an Idempotency-Key header: replaying the same request with the same key returns the original response instead of acting twice. See Idempotency.
Error codes — request.bad_request, tables.not_found, tables.limit_reached, tables.duplicate_key, tables.invalid_value, tables.required_value, tables.unknown_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
Example request
json
{ "values": { "departement": "Nord", "consultant": "alice@example.test" } }PATCH /api/v1/tables/{id}/rows/{rowId}
Update cells of a row
Partial: only the cells present change. expectedUpdatedAt guards against a concurrent edit: if the row changed since that date, 409 tables.row_conflict and nothing is written.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
rowId | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
values | object | yes |
expectedUpdatedAt | string | no |
JSON Schema
json
{
"type": "object",
"properties": {
"values": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"anyOf": [
{ "type": "string" },
{ "type": "number" },
{ "type": "boolean" },
{ "type": "null" }
]
}
},
"expectedUpdatedAt": { "type": "string" }
},
"required": [ "values" ]
}Responses
200 — The row.
| Field | Type | Required |
|---|---|---|
row | object | yes |
Same schema as POST /api/v1/tables/{id}/rows.
400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — request.bad_request, tables.not_found, tables.duplicate_key, tables.row_conflict, tables.invalid_value, tables.required_value, tables.unknown_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
POST /api/v1/tables/{id}/rows/delete
Delete rows
Up to 500 rows by id, in one body. The response returns the deleted rows as they were, so that restore can undo the gesture without a server-side trash. Ids that match nothing are ignored.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
rowIds | string[] | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"rowIds": {
"minItems": 1,
"maxItems": 500,
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"required": [ "rowIds" ]
}Responses
200 — The count and the restorable rows.
| Field | Type | Required |
|---|---|---|
deleted | integer | yes |
restorable | object[] | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"deleted": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"restorable": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"data": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"anyOf": [
{ "type": "string" },
{ "type": "number" },
{ "type": "boolean" },
{ "type": "null" }
]
}
},
"createdAt": { "type": "string" },
"updatedAt": { "type": "string" },
"createdBy": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [ "member", "workflow", "import", "unknown" ]
},
"id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "kind", "id", "label" ],
"additionalProperties": false
},
"updatedBy": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [ "member", "workflow", "import", "unknown" ]
},
"id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "kind", "id", "label" ],
"additionalProperties": false
}
},
"required": [ "id", "data", "createdAt", "updatedAt", "createdBy", "updatedBy" ],
"additionalProperties": false
}
}
},
"required": [ "deleted", "restorable" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
This operation accepts an Idempotency-Key header: replaying the same request with the same key returns the original response instead of acting twice. See Idempotency.
Error codes — request.bad_request, tables.not_found. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
POST /api/v1/tables/{id}/rows/restore
Restore deleted rows
Re-inserts rows returned by rows/delete, with their original ids. A row that exists again, or whose key is now taken, is skipped; the row limit stops the restore. restored counts what came back.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
rows | object[] | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"rows": {
"minItems": 1,
"maxItems": 500,
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string", "minLength": 1 },
"values": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"anyOf": [
{ "type": "string" },
{ "type": "number" },
{ "type": "boolean" },
{ "type": "null" }
]
}
}
},
"required": [ "id", "values" ]
}
}
},
"required": [ "rows" ]
}Responses
200 — How many rows came back.
| Field | Type | Required |
|---|---|---|
restored | integer | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"restored": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }
},
"required": [ "restored" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
This operation accepts an Idempotency-Key header: replaying the same request with the same key returns the original response instead of acting twice. See Idempotency.
Error codes — request.bad_request, tables.not_found, tables.invalid_value, tables.required_value, tables.unknown_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
POST /api/v1/tables/{id}/import/preview
Preview a CSV import
Reads a CSV or pasted text, detects the delimiter, proposes a mapping from file columns to table columns and returns sample rows. Changes nothing.
Access — Member session or API key with scope tables:read.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
csv | string | yes |
delimiter | "," | ";" | "\t" | "auto" | no |
hasHeader | boolean | no |
JSON Schema
json
{
"type": "object",
"properties": {
"csv": { "type": "string", "minLength": 1, "maxLength": 4194304 },
"delimiter": { "default": "auto", "type": "string", "enum": [ ",", ";", "\t", "auto" ] },
"hasHeader": { "default": true, "type": "boolean" }
},
"required": [ "csv" ]
}Responses
200 — The proposed mapping and samples.
| Field | Type | Required |
|---|---|---|
columns | string[] | yes |
sample | string[][] | yes |
suggestedMapping | object | yes |
rowCount | integer | yes |
delimiter | "," | ";" | "\t" | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"columns": { "type": "array", "items": { "type": "string" } },
"sample": {
"type": "array",
"items": { "type": "array", "items": { "type": "string" } }
},
"suggestedMapping": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
}
},
"rowCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"delimiter": { "type": "string", "enum": [ ",", ";", "\t" ] }
},
"required": [ "columns", "sample", "suggestedMapping", "rowCount", "delimiter" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — request.bad_request, tables.not_found, tables.invalid_csv. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
POST /api/v1/tables/{id}/import
Import rows from a CSV
Writes the mapped rows; conflicts on the key are handled per onConflict, and the response counts created, updated and skipped rows with the reason of each skip. truncate empties the table first and requires the administrator role. File columns mapped to unknown table columns are ignored; if none remains, 400.
Access — Member session or API key with scope tables:write.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Request body (application/json)
| Field | Type | Required |
|---|---|---|
csv | string | yes |
delimiter | "," | ";" | "\t" | "auto" | no |
hasHeader | boolean | no |
mapping | object | yes |
onConflict | "skip" | "update" | "replace" | "append" | yes |
truncate | boolean | no |
JSON Schema
json
{
"type": "object",
"properties": {
"csv": { "type": "string", "minLength": 1, "maxLength": 4194304 },
"delimiter": { "default": "auto", "type": "string", "enum": [ ",", ";", "\t", "auto" ] },
"hasHeader": { "default": true, "type": "boolean" },
"mapping": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
}
},
"onConflict": { "type": "string", "enum": [ "skip", "update", "replace", "append" ] },
"truncate": { "default": false, "type": "boolean" }
},
"required": [ "csv", "mapping", "onConflict" ]
}Responses
200 — The import report.
| Field | Type | Required |
|---|---|---|
created | integer | yes |
updated | integer | yes |
deleted | integer | yes |
skipped | object[] | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"created": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"updated": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"deleted": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"skipped": {
"type": "array",
"items": {
"type": "object",
"properties": {
"row": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"reason": {
"type": "string",
"enum": [
"missing_required",
"invalid_value",
"missing_key",
"duplicate",
"row_limit"
]
},
"column": {
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 60,
"pattern": "^[a-z][a-z0-9_]*$"
},
{ "type": "null" }
]
}
},
"required": [ "row", "reason", "column" ],
"additionalProperties": false
}
}
},
"required": [ "created", "updated", "deleted", "skipped" ],
"additionalProperties": false
}400 — The request does not match its schema.
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
This operation accepts an Idempotency-Key header: replaying the same request with the same key returns the original response instead of acting twice. See Idempotency.
Error codes — request.bad_request, tables.not_found, auth.forbidden, tables.invalid_csv, tables.unknown_column. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
GET /api/v1/tables/{id}/export.csv
Export a table as CSV
The whole table, RFC 4180, semicolon-separated with a UTF-8 BOM so that a French spreadsheet opens it correctly. Served as a download named after the slug.
Access — Member session or API key with scope tables:read.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Responses
200 — The CSV file.
Content type : text/csv
401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — tables.not_found. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.
GET /api/v1/tables/{id}/usage
Which workflows use a table
The workflows whose nodes read or write this table, with whether each is published and whether it writes — renaming a column under a writing node loses data.
Access — Member session or API key with scope tables:read.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | yes |
Responses
200 — The usages.
| Field | Type | Required |
|---|---|---|
usages | object[] | yes |
JSON Schema
json
{
"type": "object",
"properties": {
"usages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"workflowId": { "type": "string" },
"workflowName": { "type": "string" },
"published": { "type": "boolean" },
"nodeTypes": { "type": "array", "items": { "type": "string" } },
"writes": { "type": "boolean" }
},
"required": [ "workflowId", "workflowName", "published", "nodeTypes", "writes" ],
"additionalProperties": false
}
}
},
"required": [ "usages" ],
"additionalProperties": false
}401 — No valid session or API key (auth.unauthenticated).
403 — Refused: insufficient role (auth.forbidden), missing scope (api_key.scope_missing, details.required names it) or a route closed to API keys (api_key.session_required).
429 — The API key exceeded its rate limit (api_key.rate_limited); Retry-After says when to retry.
Error codes — tables.not_found. The common codes (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) apply to every route; see Errors.