Skip to main content
A table is a durable, typed, multi-tenant store of structured data — the Airtable-class capability, built native so it composes with HQ’s agents, identity chain, and audit. You define typed fields, then read and write rows; the data persists across conversations, and every write is stamped with who made it (human or agent) and recorded in the audit log. Tables serves two audiences over one store:
  • Your team — “save these leads”, “track this pipeline” — edited through this API or the web-UI grid. Tables created here are workspace-owned.
  • Your agents — a durable relational scratchpad they read and write through the hq:tables MCP server. Agents can own their own tables and even evolve schema under governance.
This guide covers the HTTP API. All routes live under https://api.hq.zone/v1/api/tables and authenticate with a personal access token: Authorization: Bearer hq_pat_.... Reads need the tables:read scope; writes need tables:write.
The tables subsystem is provisioned per deployment. If it isn’t configured for your workspace, these routes return 503 — enable the hq:tables integration (it ships opt-in/off) and ensure your workspace has the tables data plane provisioned.

Field types

Each field has a logical type that maps to real typed storage. Pass the type as the type string when you create a table or add a field:
formula, rollup, and lookup (computed fields) are a planned fast-follow, not yet available.
Every field accepts required, is_unique, and indexed booleans (all default false), plus a free-form options object the surfaces interpret per type (for example, a link_to_record field records its target_table there).

Create a table

POST /v1/api/tables creates a workspace-owned table with its fields in one call.
1

Define the fields

Each field is { "name", "type", ... }. Optional per-field flags: required, is_unique, indexed, options, and link_target (for link_to_record).
2

POST the table

The body takes name (required), an optional slug and description, and the fields array.
Field names are slugified into stable field slugs (e.g. Companycompany) — you reference rows by those slugs. An invalid spec (unknown type, a link_to_record with no link_target) returns 400.
See the full request and response shapes on Create a table. To list every table in the workspace, use List tables (GET /v1/api/tables); to read one table with its fields, Get a table (GET /v1/api/tables/{id}).

Write rows

A row is a JSON object keyed by field slug. POST /v1/api/tables/{id}/rows inserts one or many.
Update one row’s fields with PATCH /v1/api/tables/{id}/rows/{row_id} — only the slugs you include change:
Delete a row with DELETE /v1/api/tables/{id}/rows/{row_id} (→ { "deleted": true }). A missing row returns 404. References: Insert rows, Update a row, Delete a row.

Query rows

POST /v1/api/tables/{id}/rows/query reads rows with filters, sorting, projection, and pagination. An empty body returns the first page of all rows.
  • filters — each { "field": "<slug>", "op": "<op>", "value": <any> }. Operators: eq, neq, gt, gte, lt, lte, contains, is_empty, is_not_empty. Multiple filters combine with AND.
  • sorts — each { "field": "<slug>", "desc": <bool> }.
  • select — field slugs to return; omit for all fields.
  • limit / offset — page the result set.
Full shape on Query rows.

Evolve the schema

Add a field at any time with POST /v1/api/tables/{id}/fields (the same field shape as create):
Drop a field with DELETE /v1/api/tables/{id}/fields/{field_id}, and delete a whole table with DELETE /v1/api/tables/{id}.
Additive changes (add a table, add a field) apply immediately. Destructive changes (drop a field, delete a table) are governed: a response of { "status": "applied" } means it took effect, while { "status": "pending", "change_id": "..." } means it was queued for a workspace admin to approve. Agent-initiated destructive changes on shared tables always queue; the typed confirmation in the web-UI grid is the human equivalent.
References: Add a field, Drop a field, Delete a table.

Export to CSV

GET /v1/api/tables/{id}/export.csv streams the whole table as a UTF-8 CSV attachment (RFC 4180, with a BOM for Excel and formula-injection defanged). It’s keyset-paged server-side, so the download is constant-memory and never capped at a page size.
Requires tables:read. See Export a table as CSV.

Provenance and audit

Every table and row carries system columns — created_by, updated_by, timestamps — populated from the identity chain, so each row records whether a human or a specific agent (and which conversation) wrote it. Every mutation also emits an event to the always-on audit log. This per-row, tamper-evident provenance is what makes agent-written data accountable — see the security concept.
Agents reach the same store through the hq:tables MCP server (tables.* / rows.* tools), governed by the same identity and audit. Install it from the Integrations page and attach it to an agent as you would any MCP server.