Agent API Reference
Complete reference for the Agent Sheet JSON API.
The Agent API is a stateless JSON API for creating and updating sheets. It is the agent-facing surface of Agent Sheet: an agent creates a sheet, gets back share links, then appends rows and updates cells over time. Humans review the result in the browser via the share link.
All endpoints live under /api and accept/return application/json.
Authentication
Authentication is by capability token: a per-sheet secret carried as a bearer token.
Authorization: Bearer <token>
Tokens are share links scoped to a single sheet. Each token grants exactly one ability:
| Ability | Can do |
|---|---|
| Read | View the sheet and its human share/export URLs. |
| Edit | View and update existing cells, rows, and comments. |
| Manage | Full control: append rows, upsert rows, add columns, update rows. |
Creating a sheet mints two links. The Manage token is returned once, as manage_token, in the create response. Treat it as a secret. The Read link is surfaced as the human share_url. The Manage token is the agent's write credential; the Read share_url is what you hand to a human reviewer.
A token is rejected when it is missing (401), invalid/expired/revoked (401), belongs to a different sheet than the one in the URL (403), or lacks the ability the endpoint requires (403).
Sheet creation is the one exception: it is anonymous (no token) but rate-limited.
Column types
Cell values are always stored as text (lossless). There is no type inference. A column's type only governs how that text is interpreted on read. Supported types:
text (default), number, boolean, date, datetime, url.
When you create a sheet you may declare columns explicitly (type defaults to text when omitted). If you omit columns entirely, columns are derived as text from the union of cell keys across your rows, in first-seen order.
In responses, every cell is an object:
{
"value": "184000",
"typed": 184000,
"metadata": null
}
value: the authoritative stored string; always round-trips.typed: a best-effort interpretation via the column type (a number, boolean, or ISO datetime). Tolerant: unparseable data falls back to the raw string and never throws. For exactness, readvalue, nottyped.metadata: optional cell-level provenance you attached (e.g.source,confidence); surfaced read-only in the review panel.
Endpoints
| Method | Path | Ability | Purpose |
|---|---|---|---|
POST | /api/sheets | none | Create a sheet (rate-limited). |
GET | /api/sheets/{sheet} | any | Show a sheet with a page of rows. |
POST | /api/sheets/{sheet}/rows | Manage | Append new rows. |
PUT | /api/sheets/{sheet}/rows | Manage | Upsert rows by key. |
PATCH | /api/sheets/{sheet}/rows/{row} | Edit/Manage | Update one row by id. |
POST | /api/sheets/{sheet}/columns | Manage | Add columns. |
Human (browser) URLs, resolved by the Read/Edit share token in the path:
| Method | Path | Purpose |
|---|---|---|
GET | /s/{token} | The review workspace (grid). |
GET | /s/{token}/export/{format} | Download csv or xlsx. |
Create a sheet
POST /api/sheets is anonymous and rate-limited. It creates the sheet, columns, rows, and cells, then mints the Manage + Read links. Returns 201.
curl -X POST https://agent-sheet.com/api/sheets \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"title": "Prospect Research",
"description": "Accounts gathered by a research agent.",
"columns": [
{ "key": "company", "name": "Company", "type": "text" },
{ "key": "arr", "name": "ARR (USD)", "type": "number" },
{ "key": "renews", "name": "Renews", "type": "date" }
],
"rows": [
{ "cells": { "company": "Northwind Logistics", "arr": "184000", "renews": "2026-08-15" } },
{ "cells": { "company": "Acme Robotics", "arr": "92000", "renews": "2026-07-30" } }
]
}'
Request fields
| Field | Type | Notes |
|---|---|---|
title | string, required | Max 255. |
description | string, nullable | Max 2000. |
metadata | object, nullable | Sheet-level provenance. |
columns[] | array, nullable | Max 200. Omit to derive text columns from row cell keys. |
columns[].name | string, required | Column header. |
columns[].key | string, nullable | Stable cell key; defaults to a slug of name. |
columns[].type | string, nullable | One of the column types above; defaults to text. |
columns[].metadata | object, nullable | Column-level metadata. |
rows[] | array, nullable | Max 1000. |
rows[].key | string, nullable | Caller-defined stable key (used by upsert). |
rows[].cells | object, nullable | Map of column key → scalar value. Max 500 cells. |
rows[].metadata | object, nullable | Row-level provenance. |
Response 201
{
"data": {
"id": "01JZ8Q9X4F0K3M2N6P7R8S9T0V",
"title": "Prospect Research",
"description": "Accounts gathered by a research agent.",
"metadata": null,
"columns": [
{ "id": "01JZ8Q9X...", "key": "company", "name": "Company", "type": "text", "position": 0, "metadata": null },
{ "id": "01JZ8Q9Y...", "key": "arr", "name": "ARR (USD)", "type": "number", "position": 1, "metadata": null },
{ "id": "01JZ8Q9Z...", "key": "renews", "name": "Renews", "type": "date", "position": 2, "metadata": null }
],
"counts": { "columns": 3, "rows": 2 },
"share_url": "https://agent-sheet.com/s/Hb3...48charToken",
"web_url": "https://agent-sheet.com/sheets/01JZ8Q9X4F0K3M2N6P7R8S9T0V",
"manage_token": "******************",
"created_at": "2026-06-21T10:00:00.000000Z",
"updated_at": "2026-06-21T10:00:00.000000Z"
}
}
idis a stable 26-character ULID.manage_tokenis returned only here. Store it; it is the write credential.share_urlis the human review link (a Read token);web_urlis the owner's canonical sheet URL.
Validation failures return 422 with errors (e.g. a missing title, an unsupported column type, a duplicate column key, or a cell key referencing an unknown column).
Show a sheet
GET /api/sheets/{sheet} accepts any active token. Returns the sheet, its columns, and a page of rows (200 rows per page).
curl https://agent-sheet.com/api/sheets/01JZ8Q9X4F0K3M2N6P7R8S9T0V \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <token>'
share_url / web_url appear only when the sheet has an active Read link. manage_token is never returned on read. A read/edit holder can't escalate.
Append rows
POST /api/sheets/{sheet}/rows requires the Manage ability. It adds new rows; existing rows are never touched. Cell keys must reference existing columns (unknown keys → 422). Returns 201 with the created rows.
curl -X POST https://agent-sheet.com/api/sheets/01JZ8Q9X4F0K3M2N6P7R8S9T0V/rows \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <manage_token>' \
-d '{
"rows": [
{ "cells": { "company": "Helios Energy", "arr": "256000", "renews": "2026-09-01" } }
]
}'
Upsert rows by key
PUT /api/sheets/{sheet}/rows requires the Manage ability. Same body as append, but rows are matched by their caller-provided key: an existing key updates that row's cells, a new key creates a row. Returns 200 (the batch may mix creates and updates) with the affected rows.
curl -X PUT https://agent-sheet.com/api/sheets/01JZ8Q9X4F0K3M2N6P7R8S9T0V/rows \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <manage_token>' \
-d '{
"rows": [
{ "key": "acme-robotics", "cells": { "arr": "98000" } }
]
}'
The response shape matches the append response (a data array of row objects), returned with status 200.
Update one row
PATCH /api/sheets/{sheet}/rows/{row} requires the Edit or Manage ability. It updates the cells (and/or metadata) of a single row by its ULID id. A row that does not belong to the sheet returns 404. Returns 200 with the updated row.
curl -X PATCH https://agent-sheet.com/api/sheets/01JZ8Q9X4F0K3M2N6P7R8S9T0V/rows/01JZ8QA0... \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{ "cells": { "arr": "190000" } }'
Response 200: a single row object (same shape as one element of the append response's data array).
Add columns
POST /api/sheets/{sheet}/columns requires the Manage ability. It appends new columns. A duplicate key returns 422. Returns 201 with the created columns.
curl -X POST https://agent-sheet.com/api/sheets/01JZ8Q9X4F0K3M2N6P7R8S9T0V/columns \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <manage_token>' \
-d '{
"columns": [
{ "key": "status", "name": "Status", "type": "text" }
]
}'
Response 201:
{
"data": [
{ "id": "01JZ8QC2...", "key": "status", "name": "Status", "type": "text", "position": 3, "metadata": null }
]
}
Human share and export URLs
These are browser URLs (not JSON), resolved by the share token in the path. No Authorization header is needed. Any active token (Read included) may open and export.
- Review workspace:
GET /s/{token}is the React grid where a human inspects, edits (Edit/Manage tokens), and comments on the sheet. This is theshare_urlreturned by create/show. - Export:
GET /s/{token}/export/{format}where{format}iscsvorxlsx. Streams a download; an unknown format404s.
# Download the sheet as CSV using a share token:
curl -L -o sheet.csv https://agent-sheet.com/s/<token>/export/csv
Errors
| Status | Meaning |
|---|---|
401 | Missing, invalid, expired, or revoked capability token. |
403 | Token is for another sheet, or lacks the required ability. |
404 | Sheet or row not found (or not in the token's sheet). |
422 | Validation failed. See the errors object. |
429 | Rate limit exceeded (sheet creation). |