API reference
Five routes. Requests and responses are JSON. The CLI and the dashboard use exactly these.
Authentication
Send the workspace key as a Bearer token: Authorization: Bearer wl_... (the word Bearer is case-insensitive). POST /api/workspaces needs no key. A missing, malformed or wrong key returns 401 with WWW-Authenticate: Bearer. API responses are sent with Cache-Control: no-store, and there are no CORS headers: browsers can call the API only from the Whyline site itself.
POST /api/workspaces
Create a workspace. Body: {"name": "..."}, 1 to 100 characters (trimmed). Returns 201 with id, name and key. The key is not stored in readable form and cannot be retrieved again.
Creation is limited to 10 workspaces per hour per client address (per /64 network for IPv6); beyond that you get 429. On the hosted service the address is the one Vercel reports. A self-hosted server uses the connection's address and ignores X-Forwarded-For unless it is told to trust a proxy; see self-hosting.
curl -X POST https://whyline.wrklyst.com/api/workspaces \
-H 'content-type: application/json' \
-d '{"name":"acme-backend"}'POST /api/events
Record one event. Requires the Bearer key. Returns 201 with {"id": ...}.
To make retries safe, send an event_id. An event whose event_id is already stored in the workspace is not stored again: the answer is 200 with the stored event's id. Use a new event_id for every new event; the CLI sends a random UUID. Events without one are always stored.
curl -X POST https://whyline.wrklyst.com/api/events \
-H "authorization: Bearer $WHYLINE_KEY" \
-H 'content-type: application/json' \
-d '{"agent":"claude-code","kind":"prompt","prompt":"..."}'Event fields
agent and kind are required. Every other field is optional. The official tools send kind values of prompt, edit and commit, but any string up to the limit is accepted.
| Field | Type | Limit | Notes |
|---|---|---|---|
agent | string | 100 characters | Required. For example claude-code, or none for unattributed commits. |
kind | string | 50 characters | Required. |
ts | string | 40 characters | ISO 8601 time the event happened. Defaults to the time received. |
author | string | 200 characters | The CLI sends the git author email. |
session | string | 200 characters | Agent session identifier. |
prompt | string | 20,000 characters | Prompt text. |
summary | string | 5,000 characters | Commit message, or tool and file for edits. |
commit_sha | string | 64 characters | Commit hash. |
files | array of strings | 1,000 items of up to 1,000 characters | Paths, relative to the repository when sent by the CLI. |
event_id | string | 100 characters | Letters, digits, - and _. Idempotency key, unique per workspace. |
The request body can be at most 1,000,000 characters (413 beyond that, also for chunked uploads that send no Content-Length).
GET /api/events
List events, newest first. Requires the Bearer key. Returns 200 with {"workspace": "name", "events": [...]}. Each event has id, ts and the fields above.
| Parameter | Meaning |
|---|---|
since | Only events with an id greater than this. Default 0. |
before | Only events with an id less than this. Use the last id of a page to get the next page. |
commit | Only events for this commit. Must be a full 40-character lowercase hex hash, otherwise 400. |
limit | Maximum number of events, 1 to 500. Default 100. A page holds fewer when events are large, so that a response stays under about 4 MB. To read everything, keep paging with before until a page is empty. |
curl "https://whyline.wrklyst.com/api/events?limit=20" \ -H "authorization: Bearer $WHYLINE_KEY"
POST /api/key
Replace the workspace's API key. Requires the Bearer key; no body. Returns 200 with {"name": "...", "key": "wl_..."}. The old key stops working at once. whyline rotate-key calls this and saves the new key.
curl -X POST "https://whyline.wrklyst.com/api/key" \ -H "authorization: Bearer $WHYLINE_KEY"
DELETE /api/workspaces
Delete the workspace and all of its events. Requires the Bearer key. Returns 200 with {"deleted": "name"}. It cannot be undone, and the key stops working.
Errors
Errors are JSON: {"error": "message"}.
| Status | When |
|---|---|
400 | Invalid JSON, a missing required field, or a field over its limit. |
401 | Missing, malformed or invalid API key. |
404 | Unknown route. |
413 | Request body too large. |
429 | Too many workspaces created from one IP in the last hour. |
500 | Server error. |