Skip to content

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.

FieldTypeRequired
tablesobject[]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)

FieldTypeRequired
namestringyes
slugstringno
descriptionstring | nullno
columnsobject[]no
keyUniquebooleanno
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.

FieldTypeRequired
tableobjectyes
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.

FieldTypeRequired
limitsobjectyes
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

NameInTypeRequired
idpathstringyes

Responses

200 — The table.

FieldTypeRequired
tableobjectyes

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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
namestringno
slugstringno
descriptionstring | nullno
keyUniquebooleanno
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.

FieldTypeRequired
tableobjectyes

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

NameInTypeRequired
idpathstringyes

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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
keystringno
labelstringyes
type"text" | "number" | "boolean" | "date" | "datetime" | "select" | "email"no
isKeybooleanno
requiredbooleanno
optionsstring[]no
descriptionstring | nullno
positionintegerno
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.

FieldTypeRequired
tableobjectyes

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

NameInTypeRequired
idpathstringyes
keypathstringyes

Request body (application/json)

FieldTypeRequired
keystringno
labelstringno
type"text" | "number" | "boolean" | "date" | "datetime" | "select" | "email"no
isKeybooleanno
requiredbooleanno
optionsstring[]no
widthinteger | nullno
descriptionstring | nullno
positionintegerno
forcebooleanno
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.

FieldTypeRequired
tableobjectyes

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

NameInTypeRequired
idpathstringyes
keypathstringyes

Responses

200 — The table, without the column.

FieldTypeRequired
tableobjectyes

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

NameInTypeRequired
idpathstringyes
qquerystringno
filterquerystringno
matchquery"all" | "any"no
sortquerystringno
dirquery"asc" | "desc"no
offsetqueryintegerno
limitqueryintegerno

Responses

200 — A page of rows.

FieldTypeRequired
rowsobject[]yes
totalintegeryes
totalUnfilteredintegeryes
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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
valuesobjectyes
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.

FieldTypeRequired
rowobjectyes
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

NameInTypeRequired
idpathstringyes
rowIdpathstringyes

Request body (application/json)

FieldTypeRequired
valuesobjectyes
expectedUpdatedAtstringno
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.

FieldTypeRequired
rowobjectyes

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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
rowIdsstring[]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.

FieldTypeRequired
deletedintegeryes
restorableobject[]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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
rowsobject[]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.

FieldTypeRequired
restoredintegeryes
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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
csvstringyes
delimiter"," | ";" | "\t" | "auto"no
hasHeaderbooleanno
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.

FieldTypeRequired
columnsstring[]yes
samplestring[][]yes
suggestedMappingobjectyes
rowCountintegeryes
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

NameInTypeRequired
idpathstringyes

Request body (application/json)

FieldTypeRequired
csvstringyes
delimiter"," | ";" | "\t" | "auto"no
hasHeaderbooleanno
mappingobjectyes
onConflict"skip" | "update" | "replace" | "append"yes
truncatebooleanno
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.

FieldTypeRequired
createdintegeryes
updatedintegeryes
deletedintegeryes
skippedobject[]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

NameInTypeRequired
idpathstringyes

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

NameInTypeRequired
idpathstringyes

Responses

200 — The usages.

FieldTypeRequired
usagesobject[]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.