Reports

Report tiles ("reports") are per-table widgets that summarise a table's records as markdown, a single value, a progress bar, an aggregate table, or a chart (bar / line / area / pie). Over the Public API you can list, read, create, update, delete, reorder, preview, and fetch the computed values of a table's report tiles.

Access

  • Account API keys (il_live_) with access to the workspace get full report access. Reads (list, get, execute) work for any table member; mutations (create, update, delete, reorder, preview) require the key to act as a workspace admin — report authoring is an admin-level surface.
  • Personal API keys (il_user_) are read-only for reports: reports/list, report/<id>/get, and report/<id>/execute. Authoring endpoints are not available to personal keys.
  • Read-only keys can read/execute but cannot create, update, delete, or reorder.

A report lives on a display table (table_id) but aggregates a source table (source_table_id). The source defaults to the display table itself, but may be a table exactly one lookup-hop away in the same workspace (a parent it looks up to, or a child / sub-table that looks up to it). Field, group, and filter ids are validated against the source table.

The report object

{
  "id": 12,
  "account_id": 1,
  "table_id": 101,
  "source_table_id": 101,
  "title": "Open deals by stage",
  "type": "vbar",
  "config": { "action": "count", "group": "fld_stage", "sort": "value_desc", "limit": 200, "filters": [] },
  "position": 0,
  "created_by": 5,
  "created_at": "2026-07-01 09:00:00",
  "updated_at": "2026-07-01 09:00:00"
}

Types and their config shape

The type selects the tile, and config is validated/normalized per type. Field ids (field, group, filter column) must exist on the source table.

Type Purpose config keys
markdown Static markdown text text
value Single aggregate number action, field?, filters?, prefix?, suffix?, numlabel?, decimals?
progress Progress bar vs a target value keys plus max, threshold1?, threshold2?, direction ("higher"|"lower")
table Grouped aggregate table action, field?, group, filters?, limit?, sort?
vbar / hbar / line / area / pie Charts same as table
  • action is one of count, sum, avg, min, max. Every action except count requires field (the numeric field to aggregate).
  • group (table/chart types) is required and must be a groupable field.
  • filters is an array of {column, compare, value, connector?}:
    • compare=, !=, >, <, >=, <=, contains, not_contains, starts_with, ends_with, is_empty, is_not_empty.
    • value is ignored for is_empty / is_not_empty.
    • connector (AND | OR, default AND) joins the row with the previous one.
  • sortvalue_desc, value_asc, label_asc, label_desc (defaults: label_asc for line/area, value_desc otherwise).
  • limit on grouped types is capped at 200 rows.

Unknown / malformed config is normalized away, and the config is compiled against the source table on save — an invalid field, group, or filter is rejected with a validation error rather than persisted.

List reports for a table

GET /api/table/<table_id>/reports/list

Returns the report objects for the table, ordered by position. Readable by any table member.

Get a single report

GET /api/table/<table_id>/report/<report_id>/get

Returns the full report object (including config). The read-before-edit endpoint.

Fetch computed values (execute)

GET /api/table/<table_id>/report/<report_id>/execute

Runs the report against the source table and returns the renderer payload. Cached for ~30s and auto-invalidated when the source table's data changes. Shape depends on type:

// markdown
{ "type": "markdown", "text": "…" }
// value / progress
{ "type": "value", "scalar": 42 }
// table
{ "type": "table", "columns": ["Stage", "Count"], "rows": [{ "label": "Won", "value": 12 }] }
// chart (vbar/hbar/line/area/pie)
{ "type": "vbar", "group": [{ "label": "Won", "value": 12 }, { "label": "Lost", "value": 3 }] }

If the report can't be computed (e.g. the source table was removed), the payload carries an error string instead of the data keys: { "type": "value", "error": "Source table not found" }.

Create a report

POST /api/table/<table_id>/reports/create
{
  "title": "Open deals by stage",
  "type": "vbar",
  "source_table_id": 101,
  "config": { "action": "count", "group": "fld_stage", "sort": "value_desc" }
}

title and a valid type are required. source_table_id is optional (defaults to the display table; must be self or a one-hop related table in the same workspace). Returns the created report. Admin-only.

Update a report

POST /api/table/<table_id>/report/<report_id>/update

Body may contain any of title, type, source_table_id, config. Omitted keys keep their current value. The resulting config is re-validated against the source table. Returns the updated report. Admin-only.

Delete a report

POST /api/table/<table_id>/report/<report_id>/delete

Admin-only. Returns no body.

Reorder reports

POST /api/table/<table_id>/reports/reorder

Body {"ids": [12, 9, 15]} — the desired left-to-right / top-to-bottom order. Ids not on the table are ignored. Returns the reordered list. Admin-only.

Preview (dry run)

POST /api/table/<table_id>/reports/preview

Body {"type": "...", "config": {...}, "source_table_id": <id?>}. Runs the aggregation without saving and returns the same payload shape as execute. Use it to build a tile interactively before create. Admin-only.

  1. Fetch the source table schema (GET /api/table/<id>/get) for field ids.
  2. reports/preview your type + config until the payload looks right.
  3. reports/create the tile.
  4. Poll report/<id>/execute for live values.

Errors

Status Message When
403 Endpoint not available to personal API keys A personal (il_user_) key called a mutating report endpoint.
403 API key is read-only Read-only key called create / update / delete / reorder.
500 API key not authorized for this workspace Key's space whitelist excludes the table's workspace.
500 Not Authorized Key's user is not a workspace admin (mutations).
500 Invalid Table table_id doesn't exist or isn't accessible.
500 Report not found report_id doesn't belong to the table.
500 Invalid report type / validation message type or config failed validation on create/update.