API and agentsAPI reference
Accounts
Local accounts and authentication.
34 operations on 20 paths.
/api/auth/entry
GETAuthentication entry information
Sign-in No sign-in
The instance name, sign-in message, lost-password contact, landing page, the shortest password a password chosen on these screens needs, and setup availability. The landing page value does not change navigation. Before setup, the legacy display name may prefill Name. Never returns a signed-in person's identity or account preferences. Private, no-store.
Responses
HEADRead response headers
Sign-in No sign-inAnswers 200, 405, 503, defaultAllow
GET, HEAD, OPTIONSAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/auth/setup
POSTCreate the first account
Sign-in No sign-in
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Cookie mutations and entry submissions require an Origin matching the trusted request origin. Explicit bearer authentication does not use cookies. Responses are private, no-store. Atomically creates the sole initial admin, adopts legacy preferences and establishes a cookie session. Once any account exists, setup_complete refuses further creation. Password derivations share two active slots and at most eight waiters: six ordinary and two reserved protected, each waiting at most five seconds. FIFO within each class; validated links and signed-in current-password work are protected, including the second password-change derivation. Protected work takes the next free slot but at most one active slot, even with ordinary slots idle. Ordinary work may use both; running work is never pre-empted. A fourth simultaneous protected caller is refused at once and may retry immediately without a login lockout; the busy response advises a one-second retry. Known and unknown sign-ins are ordinary. Overflow or deadline answers authentication_busy. Cancellation removes waiters; native work owns its slot until it settles. Recovery issuance derives nothing.
Parameters
OriginHeaderrequiredThe address the instance is opened at, its scheme, host and port, such as http://localhost:3000. Missing or another origin: 403 forbidden.
string
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
namestringrequiredemailstringrequiredLocal email identity, normalized for case and surrounding whitespace.
passwordstringrequiredmin length8At least eight characters; very common passwords are refused. No character classes are required.
No other keys.
Responses
200
Success.
application/json400401403409413default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
OPTIONS, POST
503
ingress_unavailable when provenance is missing, or authentication_busy: Authentication is busy. Try again shortly. Capacity refusal has error.retryAfter: 1, Retry-After: 1 and private, no-store; no credentials, link consumption, profile or password changes, or login failures result.
application/jsonRetry-AfterHeaderOne second for authentication_busy.
integeralways
1
Also on this path: OPTIONS under System.
/api/auth/sign-in
POSTSign in
Sign-in No sign-in
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Cookie mutations and entry submissions require an Origin matching the trusted request origin. Explicit bearer authentication does not use cookies. Responses are private, no-store. Unknown email and wrong password share invalid_credentials. Valid credentials for a deactivated account return account_deactivated. Account failure limits apply only to sources with recent failures; a correct password from a source without recent failures can sign in even when the account budget is exhausted. Failures from every source count against the account, and source limits always apply. Cancellation after derivation starts retains the source reservation against its per-address budget (the instance setting, twenty attempts by default) until the fifteen-minute window expires, refunds the account reservation and adds no failures, preserving the clean-source exception. Limits return rate_limited with Retry-After, retryAfter seconds and retryAt (ISO timestamp); waiting restores admission. Password derivations share two active slots and at most eight waiters: six ordinary and two reserved protected, each waiting at most five seconds. FIFO within each class; validated links and signed-in current-password work are protected, including the second password-change derivation. Protected work takes the next free slot but at most one active slot, even with ordinary slots idle. Ordinary work may use both; running work is never pre-empted. A fourth simultaneous protected caller is refused at once and may retry immediately without a login lockout; the busy response advises a one-second retry. Known and unknown sign-ins are ordinary. Overflow or deadline answers authentication_busy. Cancellation removes waiters; native work owns its slot until it settles. Recovery issuance derives nothing.
Parameters
OriginHeaderrequiredThe address the instance is opened at, its scheme, host and port, such as http://localhost:3000. Missing or another origin: 403 forbidden.
string
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
emailstringrequiredLocal email identity, normalized for case and surrounding whitespace.
passwordstringrequired
No other keys.
Responses
200
Success.
application/json400401403409413
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
OPTIONS, POST
429
Error with a machine-readable code and human message.
application/jsonRetry-AfterHeaderSeconds until another attempt is permitted.
integerminimum
1
503
ingress_unavailable when provenance is missing, or authentication_busy: Authentication is busy. Try again shortly. Capacity refusal has error.retryAfter: 1, Retry-After: 1 and private, no-store; no credentials, link consumption, profile or password changes, or login failures result.
application/jsonRetry-AfterHeaderOne second for authentication_busy.
integeralways
1
Example
Sign in as Ana Diaz
Needs an account on the instance. Origin names the address the instance is opened at. The answer sets the session cookie, which creating a token accepts.
curl
curl -s http://localhost:3000/api/auth/sign-in \ -H "Content-Type: application/json" \ -H "Origin: http://localhost:3000" \JavaScript
const response = await fetch("http://localhost:3000/api/auth/sign-in", { method: "POST", headers: { "Content-Type": "application/json", Origin: "http://localhost:3000", }, body: JSON.stringify({ password: "<YOUR_PASSWORD>", }),});console.log(JSON.stringify(await response.json(), null, 2));Answers 200 application/json
{ "account": { "id": "5f0c2d9e-8a41-4b7e-9c3a-2e6f1b8d7a40", "name": "Ana Diaz", "sqlName": "ana_diaz", "isAdmin": true, "status": "active", "isOriginal": true, "createdAt": "2026-10-20T09:00:00.626Z", "updatedAt": "2026-10-20T09:00:00.626Z", "lastSignInAt": "2026-10-20T09:00:00.787Z" }}Also on this path: OPTIONS under System.
/api/auth/redeem
POSTRedeem a sign-in link
Sign-in No sign-in
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Cookie mutations and entry submissions require an Origin matching the trusted request origin. Explicit bearer authentication does not use cookies. Responses are private, no-store. An ordinary admin-issued link expires after the instance's link lifetime it was issued with, security.linkDays, seven days by default; local filesystem recovery issues a fifteen-minute link. Both are consumed once. Invalid, expired, replaced and reused links return invalid_link without changing the password or session. Success replaces the browser's cookie with the recipient's session, even when another account was signed in. Password derivations share two active slots and at most eight waiters: six ordinary and two reserved protected, each waiting at most five seconds. FIFO within each class; validated links and signed-in current-password work are protected, including the second password-change derivation. Protected work takes the next free slot but at most one active slot, even with ordinary slots idle. Ordinary work may use both; running work is never pre-empted. A fourth simultaneous protected caller is refused at once and may retry immediately without a login lockout; the busy response advises a one-second retry. Known and unknown sign-ins are ordinary. Overflow or deadline answers authentication_busy. Cancellation removes waiters; native work owns its slot until it settles. Recovery issuance derives nothing.
Parameters
OriginHeaderrequiredThe address the instance is opened at, its scheme, host and port, such as http://localhost:3000. Missing or another origin: 403 forbidden.
string
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
secretstringrequiredpasswordstringrequiredmin length8At least eight characters; very common passwords are refused. No character classes are required.
No other keys.
Responses
200
Success.
application/json400401403409413default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
OPTIONS, POST
503
ingress_unavailable when provenance is missing, or authentication_busy: Authentication is busy. Try again shortly. Capacity refusal has error.retryAfter: 1, Retry-After: 1 and private, no-store; no credentials, link consumption, profile or password changes, or login failures result.
application/jsonRetry-AfterHeaderOne second for authentication_busy.
integeralways
1
Also on this path: OPTIONS under System.
/api/auth/session
GETRead your current session identity
Sign-in Session cookie or Bearer token
Rechecks the presented cookie or bearer against current account and credential state. Invalid or revoked credentials return authentication_required. Private, no-store.
Responses
200
Success.
application/json401403503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 401, 403, 405, 503, defaultAllow
GET, HEAD, OPTIONSAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/auth/sign-out
POSTSign out
Sign-in Session cookie or Bearer token
Cookie mutations and entry submissions require an Origin matching the trusted request origin. Explicit bearer authentication does not use cookies. Responses are private, no-store. Ends the current browser session and clears its cookie. A bearer has no browser session to end; API tokens are revoked through their own controls.
Responses
Also on this path: OPTIONS under System.
/api/account
GETRead your account
Sign-in Session cookie or Bearer tokenMCP tool get_account
Cookie or bearer authentication is required. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Returns only the authenticated account's profile. No password or credential material is returned.
Responses
200
Success.
application/json400401403503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS, PATCH
Example
Read the account a token belongs to
Needs a token.
curl
curl -s http://localhost:3000/api/account \ -H "Authorization: Bearer <YOUR_TOKEN>"JavaScript
const response = await fetch("http://localhost:3000/api/account", { headers: { Authorization: "Bearer <YOUR_TOKEN>" },});console.log(JSON.stringify(await response.json(), null, 2));Answers 200 application/json
{ "account": { "id": "5f0c2d9e-8a41-4b7e-9c3a-2e6f1b8d7a40", "name": "Ana Diaz", "sqlName": "ana_diaz", "isAdmin": true, "status": "active", "isOriginal": true, "createdAt": "2026-10-20T09:00:00.626Z", "updatedAt": "2026-10-20T09:00:00.626Z", "lastSignInAt": "2026-10-20T09:00:00.787Z" }}PATCHUpdate your account
Sign-in Session cookie or Bearer tokenMCP tool update_account
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Password derivations share two active slots and at most eight waiters: six ordinary and two reserved protected, each waiting at most five seconds. FIFO within each class; validated links and signed-in current-password work are protected, including the second password-change derivation. Protected work takes the next free slot but at most one active slot, even with ordinary slots idle. Ordinary work may use both; running work is never pre-empted. A fourth simultaneous protected caller is refused at once and may retry immediately without a login lockout; the busy response advises a one-second retry. Known and unknown sign-ins are ordinary. Overflow or deadline answers authentication_busy. Cancellation removes waiters; native work owns its slot until it settles. Recovery issuance derives nothing.Cookie or bearer authentication is required. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Changes only your own name or email. An email change requires currentPassword and replaces the sign-in email. Duplicate emails return email_taken, regardless of case or surrounding whitespace. Missing or incorrect current passwords return current_password_required. Current-password checks on password and email changes share one allowance per account, apart from sign-in accounting: the Failed sign-ins per account count (security.failedPerAccount, five by default) within a fixed fifteen minutes. Missing or incorrect current passwords count; busy refusals, failing password work and a caller who leaves before the check starts do not; a caller who leaves after it starts keeps that place taken until the window ends. Concurrent checks never exceed what is left. Past the count, checks return rate_limited with Retry-After, retryAfter seconds and retryAt (ISO timestamp) before any password work. A correct current password clears this count and leaves sign-in's untouched; a sign-in clears only its own. The complete patch is validated before any write; account identity, role and status cannot be submitted.
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
namestringmin length1max length80emailstringcurrentPasswordstringYour current password.
No other keys.
Any of:
Responses
200
Success.
application/json400401403409413503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS, PATCH
429
rate_limited: too many wrong current passwords for this account within the window.
application/jsonRetry-AfterHeaderSeconds until another check is permitted.
integerminimum
1
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 400, 401, 403, 405, 503, defaultAllow
GET, HEAD, OPTIONS, PATCHAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/account/password
POSTChange your password
Sign-in Session cookie or Bearer tokenMCP tool change_password
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Password derivations share two active slots and at most eight waiters: six ordinary and two reserved protected, each waiting at most five seconds. FIFO within each class; validated links and signed-in current-password work are protected, including the second password-change derivation. Protected work takes the next free slot but at most one active slot, even with ordinary slots idle. Ordinary work may use both; running work is never pre-empted. A fourth simultaneous protected caller is refused at once and may retry immediately without a login lockout; the busy response advises a one-second retry. Known and unknown sign-ins are ordinary. Overflow or deadline answers authentication_busy. Cancellation removes waiters; native work owns its slot until it settles. Recovery issuance derives nothing.Cookie or bearer authentication is required. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Requires currentPassword. The new password needs at least eight characters and cannot be very common; no character classes are required. Wrong current passwords return current_password_required; weak new passwords return weak_password. Current-password checks on password and email changes share one allowance per account, apart from sign-in accounting: the Failed sign-ins per account count (security.failedPerAccount, five by default) within a fixed fifteen minutes. Missing or incorrect current passwords count; busy refusals, failing password work and a caller who leaves before the check starts do not; a caller who leaves after it starts keeps that place taken until the window ends. Concurrent checks never exceed what is left. Past the count, checks return rate_limited with Retry-After, retryAfter seconds and retryAt (ISO timestamp) before any password work. A correct current password clears this count and leaves sign-in's untouched; a sign-in clears only its own. Keeps the calling browser session, ends your other sessions and leaves API tokens valid. A bearer caller has no browser session to preserve.
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
currentPasswordstringrequiredYour current password.
passwordstringrequiredmin length8
No other keys.
Responses
200
Success.
application/json400401403413503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
OPTIONS, POST
429
rate_limited: too many wrong current passwords for this account within the window.
application/jsonRetry-AfterHeaderSeconds until another check is permitted.
integerminimum
1
Also on this path: OPTIONS under System.
/api/account/tokens
GETList your API tokens
Sign-in Session cookie or Bearer tokenMCP tool list_api_tokens
Cookie or bearer authentication is required. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Lists only your own tokens, including revoked and expired ones, each with when it expires. Secrets and hashes are never returned.
Responses
200
Success.
application/json400401403503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS, POST
Example
List your tokens
Needs a token. Lists the two tokens made above, without their secrets.
curl
curl -s http://localhost:3000/api/account/tokens \ -H "Authorization: Bearer <YOUR_TOKEN>"JavaScript
const response = await fetch("http://localhost:3000/api/account/tokens", { headers: { Authorization: "Bearer <YOUR_TOKEN>" },});console.log(JSON.stringify(await response.json(), null, 2));Answers 200 application/json
{ "tokens": [ { "id": "3c9e7a14-5b2f-4d81-9e6a-0f4b8c2d1e73", "name": "Quickstart", "createdAt": "2026-10-20T09:00:00.791Z", "lastUsedAt": "2026-10-20T09:00:00.795Z", "revokedAt": null, "expiresAt": null }, { "id": "a81f3d52-7c64-4e09-b2d7-6e5c9f0a3b18", "name": "Nightly import", "createdAt": "2026-10-20T09:00:00.794Z", "lastUsedAt": null, "revokedAt": null, "expiresAt": null } ]}POSTCreate an API token
Sign-in Session cookie or Bearer tokenMCP tool create_api_token
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Cookie or bearer authentication is required. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Creates a named API/MCP token for your own account. The secret is returned only on creation. It authenticates with your current account permissions and is refused while the account is deactivated. It lasts as long as the instance's rule for new tokens said at its creation, or never expires; expiresAt says when, a later change of the rule moves no token's expiry, and once it passes the token is refused with token_expired.
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
namestringrequiredmin length1
No other keys.
Responses
201
Success.
application/json400401403413503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS, POST
Examples
Create the token Quickstart
Needs a signed-in session: the cookie signing in sets, sent with Origin, or a token. The secret is in this answer only; send it as the bearer token from then on.
curl
curl -s http://localhost:3000/api/account/tokens \ -H "Authorization: Bearer <YOUR_TOKEN>" \ -H "Content-Type: application/json" \ -d '{"name": "Quickstart"}'JavaScript
const response = await fetch("http://localhost:3000/api/account/tokens", { method: "POST", headers: { Authorization: "Bearer <YOUR_TOKEN>", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Quickstart" }),});console.log(JSON.stringify(await response.json(), null, 2));Answers 201 application/json
{ "id": "3c9e7a14-5b2f-4d81-9e6a-0f4b8c2d1e73", "name": "Quickstart", "createdAt": "2026-10-20T09:00:00.791Z", "lastUsedAt": null, "revokedAt": null, "expiresAt": null, "secret": "<YOUR_TOKEN>"}Create a second token with the first
Needs a token.
curl
curl -s http://localhost:3000/api/account/tokens \ -H "Authorization: Bearer <YOUR_TOKEN>" \ -H "Content-Type: application/json" \ -d '{"name": "Nightly import"}'JavaScript
const response = await fetch("http://localhost:3000/api/account/tokens", { method: "POST", headers: { Authorization: "Bearer <YOUR_TOKEN>", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Nightly import" }),});console.log(JSON.stringify(await response.json(), null, 2));Answers 201 application/json
{ "id": "a81f3d52-7c64-4e09-b2d7-6e5c9f0a3b18", "name": "Nightly import", "createdAt": "2026-10-20T09:00:00.794Z", "lastUsedAt": null, "revokedAt": null, "expiresAt": null, "secret": "<NEW_TOKEN>"}HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 400, 401, 403, 405, 503, defaultAllow
GET, HEAD, OPTIONS, POSTAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/account/tokens/{id}
DELETERevoke your API token
Sign-in Session cookie or Bearer tokenMCP tool revoke_api_token
Cookie or bearer authentication is required. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Permanently refuses this token on later requests. Only your own tokens can be revoked; unknown or other-account IDs return not_found without changes. Repeated revocation is harmless.
Parameters
idPathrequiredYour token's ID, never its secret.
string
Responses
200
Success.
application/json400401403404503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
DELETE, OPTIONS
Example
Revoke the token Nightly import
Needs a token and the id of the token to revoke. The revoked token's next call answers authentication_required.
curl
curl -s -X DELETE http://localhost:3000/api/account/tokens/a81f3d52-7c64-4e09-b2d7-6e5c9f0a3b18 \ -H "Authorization: Bearer <YOUR_TOKEN>"JavaScript
const response = await fetch("http://localhost:3000/api/account/tokens/a81f3d52-7c64-4e09-b2d7-6e5c9f0a3b18", { method: "DELETE", headers: { Authorization: "Bearer <YOUR_TOKEN>" },});console.log(JSON.stringify(await response.json(), null, 2));Answers 200 application/json
{ "revoked": true}Also on this path: OPTIONS under System.
/api/users/{id}/deletion-preview
GETPreview user deletion
Sign-in Session cookie or Bearer tokenMCP tool preview_user_deletion
Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Returns only the account identity already visible in Users, totals per owned kind and distinct other active people whose present reach shrinks. Never returns private names, project references, rosters or content. The opaque confirmation is bound to the target, requesting admin, eligibility generation, inventory identities, publication links, grants and filings. Same-count swaps, publication changes and a reactivate/deactivate cycle invalidate it; unrelated surviving-document edits do not. A pending deletion returns its identifier and unfinished state instead. Self and active-target refusals are identical to deletion. This read erases nothing.
Parameters
idPathrequiredThe other account to preview.
string
Responses
200
Success.
application/json400401403404409503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 400, 401, 403, 404, 405, 409, 503, defaultAllow
GET, HEAD, OPTIONSAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/users/deletions/{id}
GETRead user deletion status
Sign-in Session cookie or Bearer tokenMCP tool get_user_deletion
Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Returns pending or needs-retry for unfinished deletion. A pending deletion also carries admittedReads, the reads admitted before it that it still waits on: erasure starts once they settle, and a count that stays above zero means a reader has not let go. An unreadable deletion record returns 409 deletion_unreadable and remains untouched. No stage, failure detail or content is exposed. Completed identifiers return 404 not_found because their temporary records have been removed; after an accepted response, clients may refresh list_users to reconcile a missing identifier. A missing identifier without prior acceptance is not proof that an account was deleted.
Parameters
idPathrequiredThe accepted deletion identifier, not an account id.
string
Responses
200
Success.
application/json400401403404409503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 400, 401, 403, 404, 405, 409, 503, defaultAllow
GET, HEAD, OPTIONSAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/users/deletions/{id}/finish
POSTFinish deleting a user
Sign-in Session cookie or Bearer tokenMCP tool finish_user_deletion
Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Deletion is permanent erasure of the account and everything it owns, wherever filed; shared reach and published links end. Owned projects dissolve and surviving members' work becomes unfiled. No handover occurs. Deactivation keeps shared reads, copies, runs and links. Except for never-redeemed invitations, deletion purges all geocode, isochrone and Overpass answer caches; later requests contact providers again. The identifying SQL name stays reserved forever for an ever-active account; completion frees its email. Others' derived datasets and stored SQL, lineage and run text remain theirs and can retain names or personal text. Issued private copies keep their shipped lifetime; completion waits for prepared files to settle or expire and cleanup to finish. Recorded input evidence identifies affected foreign card images, tiles, renders and prepared files; existing unattributed card images owned by others remain. Deleting a workflow removes its run records while its output datasets remain. Host snapshots, backups, logs, providers, browser-local SQL/conversations, exports, downloaded files and databases written through connections are outside erasure; restoring a backup can revive data and credentials. This is neither disk-remanence erasure nor anonymization. Pending or needs-retry is unfinished, never completed success: use status or Finish deleting with the same identifier; the account and its work stay inaccessible. Finishing rewrites the whole metadata store and pauses every response. An outside database reader or insufficient free working space on the data volume or SQLite temporary filesystem can prevent compaction; release the reader or restore space, then Finish deleting safely with the same identifier. Resumes the accepted deletion, including after restart, without changing its identifier or repeating completed dissolution. Concurrent requests join the same work. An unreadable record returns 409 deletion_unreadable without changing any files. Completed identifiers return 404 not_found.
Parameters
idPathrequiredThe accepted deletion identifier, not an account id.
string
Responses
200
Deletion completed.
application/json202
Deletion is pending or needs retry; erasure is unfinished.
application/json400401403404409503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
OPTIONS, POST
Also on this path: OPTIONS under System.
/api/users
GETList users
Sign-in Session cookie or Bearer tokenMCP tool list_users
Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Lists invited, active and deactivated accounts, their role and last sign-in. isOriginal permanently identifies the first account. The separate deletions array lists unfinished reservations with their deletion id, pending or needs-retry state and the existing Users identity; it remains available after profile erasure and disappears on completion. An unreadable deletion appears separately as {id, state: unreadable}, without an account identity. It does not block other users, invitations or access changes; its status and continuation return deletion_unreadable. Deleted accounts are absent from users. Passwords, credential hashes and sign-in links are never returned.
Responses
200
Success.
application/json400401403409503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS, POST
POSTInvite a user
Sign-in Session cookie or Bearer tokenMCP tool invite_user
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Reserves a name and normalized email and returns a signInUrl once. The recipient chooses a password when opening the link; this instance sends no email. The link expires after the instance's link lifetime, security.linkDays, seven days by default, and keeps the lifetime it was issued with. isAdmin defaults to false and an admin may explicitly grant it. Duplicate emails return email_taken regardless of case or surrounding whitespace, including invited and deactivated accounts. An email awaiting deletion completion remains reserved, including after its profile is removed, and never offers reactivation. For a deactivated duplicate the error carries accountId and canReactivate: true; reactivate that account instead of creating another.
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
namestringrequiredmin length1emailstringrequiredisAdminbooleandefaultfalse
No other keys.
Responses
201
Success.
application/json400401403413503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS, POST
409
Email already reserved.
application/json
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 400, 401, 403, 405, 409, 503, defaultAllow
GET, HEAD, OPTIONS, POSTAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/users/{id}
DELETEDelete a user
Sign-in Session cookie or Bearer tokenMCP tool delete_user
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Deletion is permanent erasure of the account and everything it owns, wherever filed; shared reach and published links end. Owned projects dissolve and surviving members' work becomes unfiled. No handover occurs. Deactivation keeps shared reads, copies, runs and links. Except for never-redeemed invitations, deletion purges all geocode, isochrone and Overpass answer caches; later requests contact providers again. The identifying SQL name stays reserved forever for an ever-active account; completion frees its email. Others' derived datasets and stored SQL, lineage and run text remain theirs and can retain names or personal text. Issued private copies keep their shipped lifetime; completion waits for prepared files to settle or expire and cleanup to finish. Recorded input evidence identifies affected foreign card images, tiles, renders and prepared files; existing unattributed card images owned by others remain. Deleting a workflow removes its run records while its output datasets remain. Host snapshots, backups, logs, providers, browser-local SQL/conversations, exports, downloaded files and databases written through connections are outside erasure; restoring a backup can revive data and credentials. This is neither disk-remanence erasure nor anonymization. Pending or needs-retry is unfinished, never completed success: use status or Finish deleting with the same identifier; the account and its work stay inaccessible. Finishing rewrites the whole metadata store and pauses every response. An outside database reader or insufficient free working space on the data volume or SQLite temporary filesystem can prevent compaction; release the reader or restore space, then Finish deleting safely with the same identifier. First deactivate an ever-active target separately and call preview_user_deletion. Submit confirm: true, the opaque confirmation and the exact current email for an ever-active account. A never-redeemed invitation requires explicit confirmation but no email; it is removed wholly and frees its SQL name. No private content read is granted. Missing confirmation returns invalid_request; self_change_refused takes precedence over account_not_deactivated. Acceptance rechecks eligibility and the owned inventory in the same transaction; a stale eligible preview returns deletion_changed without effects. A repeated acceptance returns the same unfinished identifier and state without restarting cleanup. After completion, this target and the completed deletion identifier return not_found.
Parameters
idPathrequiredThe other account to delete.
string
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
confirmbooleanalwaystruerequiredconfirmationstringrequiredpattern^[a-f0-9]{64}$Opaque value from this admin's current deletion preview.
emailstringExact account email, required when the account has ever signed in.
No other keys.
Responses
200
Deletion completed.
application/json202
Deletion is pending or needs retry; erasure is unfinished.
application/json400401403404409413503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
DELETE, OPTIONS, PATCH
PATCHChange user access
Sign-in Session cookie or Bearer tokenMCP tool update_user_access
At most 65,536 wire bytes; a larger body is refused with request_body_too_large before JSON parsing. Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Grants or removes admin status, deactivates or reactivates the same account. Self-deactivation and self-removal of admin status return self_change_refused even with another admin. Competing changes cannot remove every active admin. A patch is applied atomically or not at all. Deactivation ends sessions and refuses tokens; reactivation restores token eligibility without reviving ended sessions. Reactivating an unaccepted invitation returns it to invited status. This operation does not delete accounts or content. Accepted deletion refuses reactivation with deletion_in_progress, including during final cleanup after the profile is removed.
Parameters
idPathrequiredThe account to change.
string
Request body
At most 65,536 bytes (64 KiB); a larger body is refused with request_body_too_large.
application/json
object
isAdminbooleanstatusstringOne of
active,deactivated
No other keys.
Any of:
Responses
200
Success.
application/json400401403404409413503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
DELETE, OPTIONS, PATCH
Also on this path: OPTIONS under System.
/api/users/{id}/sign-in-link
POSTIssue a new sign-in link
Sign-in Session cookie or Bearer tokenMCP tool issue_user_sign_in_link
Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Returns a one-time signInUrl expiring after the instance's link lifetime, security.linkDays, seven days by default; the link keeps the lifetime it was issued with. Replaces every earlier unused link, invalidates the current password and ends browser sessions while API tokens stay valid. The recipient chooses their password and enters as this account even if another account was signed in. An expired, replaced or consumed link grants no access. This instance sends no email; share the returned link with its recipient.
Parameters
idPathrequiredThe account receiving the sign-in link.
string
Responses
200
Success.
application/json400401403404409503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
OPTIONS, POST
Also on this path: OPTIONS under System.
/api/accounts/search
GETFind people to share with
Sign-in Session cookie or Bearer tokenMCP tool find_accounts
Requires a current cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. The directory of active people, for sharing a project: any signed-in account can find other active accounts by any part of their display name (case-insensitive, the query trimmed) or by their exact email (trimmed, case-insensitive), never by part of one. This is the one deliberate exception to account reads being admin-only, and it is minimal: each result carries the person's display name, SQL name and, while they have a picture, its pictureVersion, and nothing else, never an email, an admin flag or an account identity. Deactivated accounts and invitations not yet redeemed are never offered, nor the caller's own account, and nobody answers twice. An empty query answers nobody; at most 20 people answer, an exact email match first, then by display name. The SQL name is how the sharing operations name the person. Managing accounts stays admin-only.
Parameters
qQueryrequiredPart of a display name, or an exact email.
stringmax length
320
Responses
200
Success.
application/json400401403503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 400, 401, 403, 405, 503, defaultAllow
GET, HEAD, OPTIONSAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
/api/account/picture
PUTSet your picture
Sign-in Session cookie or Bearer tokenMCP tool set_account_picture
Requires a current cookie session or bearer token; a cookie-signed request needs the instance's Origin. Responses, including refusals, are private, no-store. It acts on the signed-in account's own picture, never another's, and an account whose deletion has been accepted is refused before anything is read. multipart/form-data with exactly one file part named file: a still JPEG, PNG or WebP image, recognised by its content whatever its name or declared type. The file is at most 10,485,760 bytes (10 MB, a fixed limit) and the whole body at most 65,536 bytes more, counted as they arrive whatever length is declared: one byte over answers 413 upload_too_large. An SVG, a GIF, an animated image, or one that is damaged or incomplete, answers 415 unsupported_image; more than 64 million pixels, read from the header before any pixel is decoded, 413 image_too_large. The body has 120 seconds to arrive: one still arriving then answers 408 data_processing_timeout, and one that sends no body byte for 60 seconds answers 408 upload_stalled. The first refusal is delivered without waiting for the rest of the body, and the refused connection closes within five seconds. A caller who leaves before the body is received changes nothing. Processing takes at most 20 seconds, waiting included, and runs one picture at a time on the instance with eight more waiting; past that, 503 operation_queue_full. The server keeps its own copy: turned the way its orientation says, the largest centred square scaled to 320 pixels, a WebP with transparency kept and every embedded record dropped. Writes to one account's picture take effect in the order they were admitted: a change overtaken by one admitted after it changes nothing and answers the account as it stands. A refusal or failure leaves the current picture. Answers the account, its new pictureVersion included. Through MCP the file travels as base64 in content_base64; a file of the full 10,485,760 bytes fits the 16,777,216-byte envelope.
Request body
multipart/form-data
object
filestringrequiredformatbinaryA still JPEG, PNG or WebP image of at most 10,485,760 bytes. Through MCP the file travels as base64 in content_base64; a file of the full 10,485,760 bytes fits the 16,777,216-byte envelope.
Responses
200
Success.
application/json400401403408413415503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
DELETE, OPTIONS, PUT
DELETERemove your picture
Sign-in Session cookie or Bearer tokenMCP tool remove_account_picture
Requires a current cookie session or bearer token; a cookie-signed request needs the instance's Origin. Responses, including refusals, are private, no-store. It acts on the signed-in account's own picture, never another's, and an account whose deletion has been accepted is refused before anything is read. Your initials stand in again; removing when there is no picture changes nothing. Writes to one account's picture take effect in the order they were admitted: a change overtaken by one admitted after it changes nothing and answers the account as it stands. Answers the account, without a pictureVersion.
Responses
200
Success.
application/json400401403503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
DELETE, OPTIONS, PUT
Also on this path: OPTIONS under System.
/api/users/{id}/picture
DELETERemove a person's picture
Sign-in Session cookie or Bearer tokenMCP tool remove_user_picture
Requires a current admin account through a cookie session or bearer token. Cookie mutations require the same trusted Origin. Responses, including refusals, are private, no-store. Removes the account's picture, a deactivated account's included; its initials stand in again, and removing when there is none changes nothing. An admin removes a picture and never sets one: no operation sets another account's picture. An account whose deletion has been accepted, or an unknown one, answers 404 not_found, and a caller who is not an admin, or no longer one when the change commits, 403 forbidden; either way the picture stays. Writes to one account's picture take effect in the order they were admitted: a change overtaken by one admitted after it changes nothing and answers the account as it stands. Answers the account.
Parameters
idPathrequiredThe account's id.
string
Responses
200
Success.
application/json400401403404503default
Error with a machine-readable code and human message.
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
DELETE, OPTIONS
Also on this path: OPTIONS under System.
/api/accounts/{sqlName}/picture
GETRead a person's picture
Sign-in Session cookie or Bearer tokenMCP tool read_account_picture
Requires a current cookie session or bearer token. Any active account reads any person's current picture, with or without a shared project: the people the account, Users, directory, project people and owner reads name, a deactivated person included. The picture is a WebP, 320 pixels square, the server's own copy with no embedded records. v names the version a read gave: the current version is served, an earlier one answers 404, and without v the current picture is served. A person with no picture, under deletion or unknown answers the same 404. Every answer carries an entity tag of its bytes and Cache-Control: private, no-cache, so a client may keep it but asks again before each use; a request whose If-None-Match names the current tag is answered 304 without the bytes, after the same checks as a full read. Refusals are private, no-store. Agents receive the image as an attachment.
Parameters
sqlNamePathrequiredThe person's SQL name.
string
vQueryThe picture version a read gave (pictureVersion); absent reads the current picture.
string
Responses
200
The picture, as an attachment.
image/webpstringformat
binaryETagHeaderThe entity tag of these bytes.
string
Cache-ControlHeaderprivate, no-cache
stringalways
private, no-cacheContent-DispositionHeaderattachment, named <sqlName>.webp
string
304
The picture is unchanged: its entity tag matches If-None-Match.
401403503default
Error with a machine-readable code and human message.
application/json404
No picture at this address: none, an earlier version, a person under deletion or nobody by that SQL name (not_found).
application/json405
method_not_allowed: the method is unsupported for this path.
application/jsonAllowHeaderExactly the documented methods for this path.
stringalways
GET, HEAD, OPTIONS
HEADRead response headers
Sign-in Session cookie or Bearer tokenAnswers 200, 304, 401, 403, 404, 405, 503, defaultAllow
GET, HEAD, OPTIONSAutomatic HEAD uses GET with no response body.
Also on this path: OPTIONS under System.
7439201b