Datasets API

Read and write an agent's dataset rows from external code using scoped API keys and a PostgREST-style REST API.

New to the API? Read the API Overview first — it covers the base URL, authentication, scopes, the response envelope, error codes, and key management that apply to every endpoint below.

Overview

The Datasets API exposes your agent's datasets over a small, REST-standard HTTP interface. It uses the same scoped API keys and PostgREST-style query syntax described in the API Overview, and reuses the exact same permission checks, plan limits, and validation as the agent itself.

All paths are relative to the base URL https://communa.io/api/v1, and every request sends a Authorization: Bearer header. Remember to call the API from a server-side proxy — never directly from the browser (why).

API reference

MethodPathScopeDescription
GET/datasetsdatasets:readList datasets the key's agent owns
GET/datasets/{captureId}/rowsdatasets:readQuery rows (filter, sort, paginate)
POST/datasets/{captureId}/rowsdatasets:writeInsert one or more rows
PATCH/datasets/{captureId}/rowsdatasets:writeBulk-update rows matching a condition
DELETE/datasets/{captureId}/rowsdatasets:writeBulk-delete rows by ID
GET/datasets/{captureId}/rows/{rowId}datasets:readFetch a single row
PATCH/datasets/{captureId}/rows/{rowId}datasets:writeUpdate a single row
DELETE/datasets/{captureId}/rows/{rowId}datasets:writeDelete a single row

Endpoints

List datasets

GET /datasets

Returns the datasets the key's agent owns. Requires datasets:read.

curl https://communa.io/api/v1/datasets \
  -H "Authorization: Bearer $COMMUNA_API_KEY"

Response

json
{ "data": [ { "id": "abc123", "name": "Leads", "row_count": 42 } ] }

Query rows

GET /datasets/{captureId}/rows

Requires datasets:read. Supports a PostgREST-style query string:

ParamExampleMeaning
select?select=name,statusReturn only these columns
filter?amount=gte.100&status=eq.active{field}={op}.{value}
search?search=acmeFree-text across all columns
order?order=created_at.descSort (field.asc / field.desc)
limit / offset?limit=50&offset=100Pagination — limit 1–1000, offset ≥ 0
distinct?distinct=statusDistinct values + counts (filter dropdowns)

Filter operators: eq, neq, gt, gte, lt, lte, contains, starts_with (like/ilike are accepted as aliases for contains).

Sorting is type-aware: ?order=amount.asc sorts numeric columns numerically (75, 150, 1200) and text columns alphabetically — you don't need a numeric filter present for numeric ordering. Sorting by created_at/updated_at/row_index uses the row's metadata.

Pagination is strict: a limit outside 1–1000, a negative offset, or a non-integer value returns 400 invalid_query rather than being silently clamped.

curl "https://communa.io/api/v1/datasets/abc123/rows?status=eq.active&amount=gte.100&select=name,amount&order=amount.desc&limit=20" \
  -H "Authorization: Bearer $COMMUNA_API_KEY"

Response

json
{ "data": { "rows": [ { "id": "r1", "name": "Acme", "amount": 1200 } ], "total": 1, "columns": ["name","amount"] } }

Insert rows

POST /datasets/{captureId}/rows

Requires datasets:write. Respects the agent's dataset row plan limit.

curl -X POST https://communa.io/api/v1/datasets/abc123/rows \
  -H "Authorization: Bearer $COMMUNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "rows": [ { "name": "Acme", "status": "active" } ] }'

Response

json
{ "data": { "inserted": 1, "rows": [ { "id": "r9", "name": "Acme", "status": "active" } ] } }

Update rows (bulk)

PATCH /datasets/{captureId}/rows

Requires datasets:write. Updates all rows matching every where condition. Omit where to update all rows. The API builds and validates the SQL server-side — raw SQL is never accepted from the caller.

curl -X PATCH https://communa.io/api/v1/datasets/abc123/rows \
  -H "Authorization: Bearer $COMMUNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "where": { "status": "pending" }, "set": { "status": "active" } }'

Response

json
{ "data": { "updated": 7 } }

Delete rows (bulk)

DELETE /datasets/{captureId}/rows

Requires datasets:write. Get row IDs from a GET query (each row includes its id).

curl -X DELETE https://communa.io/api/v1/datasets/abc123/rows \
  -H "Authorization: Bearer $COMMUNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "row_ids": ["r1", "r2"] }'

Response

json
{ "data": { "deleted": 2 } }

Single row operations

Rows are a sub-resource of a dataset, so a single row has its own REST URL with both IDs — the dataset captureId (which scopes authorization) and the rowId (which identifies the row):

GET    /datasets/{captureId}/rows/{rowId}
PATCH  /datasets/{captureId}/rows/{rowId}
DELETE /datasets/{captureId}/rows/{rowId}

This is the right choice when your dashboard already knows the row's id (e.g. a user clicks Edit or Delete on one row). For changing many rows at once by a condition, use the bulk collection endpoints above.

Fetch one row

GET /datasets/{captureId}/rows/{rowId}

Requires datasets:read. Returns the single row { id, row_index, ...fields }, or 404 if it doesn't exist in this dataset.

curl https://communa.io/api/v1/datasets/abc123/rows/r1 \
  -H "Authorization: Bearer $COMMUNA_API_KEY"

Response

json
{ "data": { "id": "r1", "row_index": 0, "name": "Acme", "status": "active" } }

Update one row

PATCH /datasets/{captureId}/rows/{rowId}

Requires datasets:write. The rowId in the path is the scope — no where body. Returns 404 row_not_found if the row doesn't exist in this dataset.

curl -X PATCH https://communa.io/api/v1/datasets/abc123/rows/r1 \
  -H "Authorization: Bearer $COMMUNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "set": { "status": "active", "notes": "Reviewed" } }'

Response

json
{ "data": { "id": "r1", "status": "active", "notes": "Reviewed" } }

Delete one row

DELETE /datasets/{captureId}/rows/{rowId}

Requires datasets:write. Returns { "data": { "deleted": true, "id": "<uuid>" } }, or 404 row_not_found if the row didn't exist.

curl -X DELETE https://communa.io/api/v1/datasets/abc123/rows/r1 \
  -H "Authorization: Bearer $COMMUNA_API_KEY"

Response

json
{ "data": { "deleted": true, "id": "r1" } }

An invalid (non-UUID) rowId returns 400 invalid_row_id.

Response shape

Row queries return a consistent { rows, total, columns } shape, where total is the number of rows matching your query (filter/search aware):

json
{ "data": { "rows": [ ... ], "total": 42, "columns": ["name","status"] } }

A distinct query instead returns { values, total_unique, ... }. For the full success/error envelope and error codes, see the API Overview.

What's Next?

  • API Overview — Auth, scopes, errors, and key management
  • Datasets — How datasets are created and managed in the UI