REST API
Everything the UI does is a REST endpoint your scripts can call too.
Batuta is API-first: the web UI itself runs on this API. Agents and scripts authenticate with an API key and get the same power as the UI.
Base URL and auth
All endpoints live under /api on your instance:
API=https://acme.batutadev.com/api
KEY=bat_xxxxxxxx_...
curl -s "$API/projects" -H "Authorization: Bearer $KEY"
Agents and scripts use Authorization: Bearer bat_… with an API key. The browser uses an httpOnly session cookie instead — the two never mix.
Full reference
An interactive OpenAPI reference (Scalar) is served by your own instance at /docs, generated from the OpenAPI 3.1 document at /api/openapi.json. It always matches the version you are running.
Resources at a glance
| Resource | What it does |
|---|---|
projects |
Create, list, rename, archive and delete projects (with their fields and views). |
fields / options |
Add custom fields and their select options (a new Status column is an option). |
views |
Create and edit BOARD/TABLE views with filters and sort. |
cards |
Create, update, move, archive and list cards; GET /views/:id/items returns a whole board in one call. |
comments |
Read and write card comments. |
search |
Full-text search over titles, descriptions and comments. |
activity |
Audit trails per card and per project. |
directory |
People and agents assignable to USER fields, with their user:/key: refs. |
keys |
Create and revoke API keys (owner only). |
users / invites |
Invite people and manage members (owner only). |
webhooks |
Push board events to your URL — see Realtime and webhooks. |
automations |
Trigger → action rules — see Automations. |
batch |
Up to 50 writes in one call, with idempotencyKey for safe retries. |
events |
Inbound board events (pr_merged) via POST /projects/:id/events. |
Pagination, filtering and sort
List endpoints accept page/pageSize or limit/offset (pageSize is capped at 200). Card lists also accept:
status— a status option id or a column name.number— a card number (e.g.107findsBAT-107).q— free-text query.filter— a JSON array of field filters, same operators as views:
[{ "fieldId": "Priority", "operator": "eq", "value": "P0" }]
Operators: eq, ne, in, contains, is_empty, is_not_empty, before, after. fieldId accepts an id or a field name, and in select fields the value accepts an id or an option name.
sort—positionorupdatedAt.archived— include archived cards.
Errors
Errors return a JSON body with the shape { "error": "code", "message": "...?", "details": ... } and one of these codes: 400 (invalid body), 401 (missing or invalid credentials), 403 (owner role required), 404, 409 (conflicts with current state), 429 (rate limited).
Rate limits
600 requests per minute per API key or session, and 30 per minute per IP on the unauthenticated endpoints (/api/setup, /api/auth/*). Responses carry standard RateLimit-* headers; exceeding the limit returns 429.
Session cookies are httpOnly, same-site and secure in production, and are used only by the web UI on the same origin.