Developers Beta
The API
A script or an LLM agent can act as you on textshelf.com with an access
token. This page covers getting a token, sending it, and the endpoint to
start from. It is the public half of docs/AGENT_API.md; change them
together.
Get a token
API access is part of the Standard and Organization plans. On the Free plan the page won't issue a token, and a token issued while subscribed stops working if the subscription ends.
- Signed in, open Account → Access tokens (
/users/~tokens/), name the token, choose its scopes and when it expires, and copy the key. It is shown once. An account can hold ten active tokens. - Send it on every request:
text
Authorization: Bearer ts_…
The request is then made as you. A token also exempts the request from CSRF
checks, so a JSON POST needs no cookie. Don't post to the sign-in form from
a script.
A token is accepted on /api/, /notate/api/ and /registry/api/ only.
Anywhere else, an HTML page or the admin, it is refused with
not_an_api_path, whatever its scopes. Changing your password revokes every
token on the account. Creating a token emails you its name and first
characters, never the key. Only a SHA-256 of the key is kept: if you lose it,
revoke it and issue another.
Scopes: read allows GET, HEAD and OPTIONS; write allows everything.
Refusals
Every refusal is JSON with an error:
| Status | error |
Meaning |
|---|---|---|
| 401 | invalid_token |
Missing, revoked, expired or wrong |
| 401 | authentication_required |
No credential at all |
| 403 | not_an_api_path |
A valid token, on a path that doesn't take tokens |
| 403 | plan_required |
The token's account isn't on a paid plan |
| 403 | insufficient_scope |
A read token, and the request writes |
| 403 | browser_only |
A path that answers a signed-in browser only: a Word file's preview and the live event streams |
Start here: GET /api/v1/me/
Who the token belongs to, how the request was authenticated, and every shelf
the account belongs to with its roles (owner, organizer, reviewer,
submitter, member).
{
"user": {"id": 7, "email": "you@example.org", "name": "Ada Reader"},
"auth": {"kind": "token", "name": "my script", "scopes": ["read"]},
"workspaces": [
{
"slug": "spring-2026-playwriting",
"name": "Spring 2026 Playwriting Prize",
"workspace_type": "literary_contest",
"roles": ["reviewer", "member"]
}
]
}
The annotation endpoints under /notate/api/ take a token as they take a
signed-in session. Everything else, the review queue and writing a review
among them, is still the web pages only.
A token is what an AI assistant holds, so it follows the shelf's rule for
readers' own assistants. Where that rule allows yours none, on the work as
it arrived or for your role, the annotation list, an update's reply and the
export answer with the highlights and comments but without the work's own
words: selected_text is null, the selector loses its exact, prefix
and suffix, the export has no quotes, and a list says
"words_withheld": true. Work keeps the rule it arrived under: a shelf can
tighten its rule at any time, and loosening it reaches only work sent
afterwards. On a shelf of submitted work the rule covers the organizers'
assistants only; on a shelf of its members' own documents, any member's.
The files the web and the Mac app exchange are specified under file formats.