The HTTP API
Every route the server serves, who may call it, and how a refusal looks: one table per area, read from the server's route table.
The web application and anything else speak to the server over one JSON API
under /api. This page lists every route in the server's route table, 67 of
them, and the pages the server serves beside them.
Status. Release
0.0.1. The HTTP surface may change in a later release.
Calling it
A session comes from the sign-in steps: POST /api/sign-in with the email and
password answers a challenge, and POST /api/sign-in/code with that challenge
and an authenticator code answers a session. Send it as
authorization: Bearer <session>. Bodies are JSON. A field the route does not know
is refused, except in the two passkey bodies and the issuer-link return.
Records, keys and files cross the API sealed. The server checks who may do what and that a revision, a share or a wrap is shaped right; it cannot check what is inside, because it cannot open it.
Refusals
Every refusal is a body with two fields, error_code and message, and
nothing else beside it.
| Status | When |
|---|---|
400 | a body or a path the route cannot accept, a password too weak to set among them |
401 | no session, or one the server does not know |
403 | a session whose standing is too low for the route |
404 | something the caller does not reach: another company's anything, a record not shared with them, a request that does not exist |
409 | a conflict with what is there now: a revision or a share list that moved since it was read, a target the record is already shared with |
429 | too many requests in the current window; try again shortly |
503 | the store did not answer, so nothing was decided; try again |
Another company's admin who names your company is answered exactly as if it did
not exist. Every route but the two that name no account
(GET /api/sign-in/methods and POST /api/sign-in/passkey/begin) is called in
the test suite unsigned, with an unknown session, as a lower standing and as
another company, and each answers with the refusal its row expects.
"Who" below is the lowest standing that may call the route: an admin may do what a member may, and an owner what an admin may.
Account and companies
| Method | Path | Who | What it does |
|---|---|---|---|
GET | /api/companies | signed in | the companies the caller belongs to; every company for the platform admin |
POST | /api/companies | platform admin | create a company and name its owner; answers the owner's enrolment token |
POST | /api/companies/{company}/resume | platform admin | resume a company |
POST | /api/companies/{company}/suspend | platform admin | suspend a company |
GET | /api/me | signed in | the caller's account and companies |
Signing in and joining
| Method | Path | Who | What it does |
|---|---|---|---|
POST | /api/enrolment/begin | anyone, with a token | open an enrolment |
POST | /api/enrolment/complete | anyone, with a token | set the sign-in password and the authenticator |
POST | /api/me/identities/oidc | signed in | begin linking an identity at the issuer |
POST | /api/me/identities/oidc/return | signed in | finish linking it |
POST | /api/me/passkeys | signed in | register a passkey |
POST | /api/me/passkeys/begin | signed in | a passkey registration challenge |
DELETE | /api/session | signed in | sign out |
POST | /api/sign-in | anyone | the password step; answers a challenge |
POST | /api/sign-in/code | anyone, with a challenge | the authenticator step; answers a session |
GET | /api/sign-in/methods | anyone | which ways in this server offers |
GET | /api/sign-in/oidc | anyone | begin sign-in at the OpenID Connect issuer |
GET | /api/sign-in/oidc/return | anyone, with the flow's state | finish sign-in at the issuer |
POST | /api/sign-in/passkey | anyone, with a passkey | sign in with a passkey |
POST | /api/sign-in/passkey/begin | anyone | a sign-in challenge that names no account |
Members and the trail
| Method | Path | Who | What it does |
|---|---|---|---|
GET | /api/companies/{company}/audit | admin | the trail, newest first |
GET | /api/companies/{company}/audit/verify | admin | check the chain over the company's events |
GET | /api/companies/{company}/members | member | the members, their roles and states |
POST | /api/companies/{company}/members | admin | add a member with an email, a name and a role |
DELETE | /api/companies/{company}/members/{account} | admin | remove a member |
PATCH | /api/companies/{company}/members/{account} | admin | change a member's role or state; only an owner makes or unmakes an owner |
POST | /api/companies/{company}/members/{account}/enrolment | admin | issue a member's single-use enrolment token |
Departments and teams
| Method | Path | Who | What it does |
|---|---|---|---|
GET | /api/companies/{company}/groups | member | departments and teams |
POST | /api/companies/{company}/groups | admin | make a department or a team, with an optional parent |
DELETE | /api/companies/{company}/groups/{group} | admin | delete a group that holds no other group; its members leave it |
PATCH | /api/companies/{company}/groups/{group} | admin | rename a group |
GET | /api/companies/{company}/groups/{group}/key | member | a group's public key and the caller's own wrap of it |
PUT | /api/companies/{company}/groups/{group}/key | admin | key a group: its public key and the members' wraps |
GET | /api/companies/{company}/groups/{group}/key/pending | admin | the members still waiting for a wrap |
POST | /api/companies/{company}/groups/{group}/key/wraps | admin | add wraps for waiting members |
GET | /api/companies/{company}/groups/{group}/members | member | a group's members |
POST | /api/companies/{company}/groups/{group}/members | admin | add a member to a group |
DELETE | /api/companies/{company}/groups/{group}/members/{account} | admin | take a member out of a group |
Records, shares and files
| Method | Path | Who | What it does |
|---|---|---|---|
GET | /api/companies/{company}/record-types | member | the company's record types |
POST | /api/companies/{company}/record-types | admin | define a record type and the roles that may use it |
GET | /api/companies/{company}/records | member | the records the caller can read |
POST | /api/companies/{company}/records | member | create a record |
DELETE | /api/companies/{company}/records/{record} | author or admin | delete a record, every revision, share and file, with a reason |
GET | /api/companies/{company}/records/{record} | author or reader | the latest sealed revision and the caller's wrap |
PUT | /api/companies/{company}/records/{record} | author or editor | write a revision over the one it was read at |
POST | /api/companies/{company}/records/{record}/files | author or editor | begin a file |
GET | /api/companies/{company}/records/{record}/files/{file} | author or reader | read a complete file by offset and limit |
PUT | /api/companies/{company}/records/{record}/files/{file} | author or editor | write the next part, up to 4 MiB, at offset |
GET | /api/companies/{company}/records/{record}/shares | author or editor | the record's shares and its author's key |
POST | /api/companies/{company}/records/{record}/shares | author or editor | share with a member or a group, carrying the wrapped record key |
DELETE | /api/companies/{company}/records/{record}/shares/{target} | author or editor | take a share back |
Keys and vouching
| Method | Path | Who | What it does |
|---|---|---|---|
GET | /api/companies/{company}/keys | member | the company's public keys |
GET | /api/companies/{company}/keys/me | member | the caller's key set |
PUT | /api/companies/{company}/keys/me | member | keep the caller's key set |
GET | /api/companies/{company}/statements | member | the vouching chain |
POST | /api/companies/{company}/statements | admin | append a signed statement |
Recovery
| Method | Path | Who | What it does |
|---|---|---|---|
GET | /api/companies/{company}/keys/me/escrow | member | which recovery key the caller escrowed to |
PUT | /api/companies/{company}/keys/me/escrow | member | escrow the caller's keys to the recovery key |
POST | /api/companies/{company}/keys/me/rewrap | member | wrap the recovered keys under a new unlock password |
GET | /api/companies/{company}/keys/{account}/escrow | owner | a member's escrow; the read is shown to that member |
GET | /api/companies/{company}/notices/me | member | who reached the caller's keys |
GET | /api/companies/{company}/recovery-key | member | the recovery key's public half |
POST | /api/companies/{company}/recovery-key | owner | keep the company's recovery key |
GET | /api/companies/{company}/recovery-key/mine | owner | the caller's own wrap of the recovery key |
GET | /api/companies/{company}/recovery-requests | owner | the open requests |
POST | /api/companies/{company}/recovery-requests | member | ask for recovery with a one-time public key |
POST | /api/companies/{company}/recovery-requests/{request}/handoff | owner | hand a member's keys to their one-time key |
POST | /api/companies/{company}/recovery-requests/{request}/redeem | the member who asked | redeem once, within 72 hours |
Pages
GET /, /app.js, /app.css, /favicon.svg and /vault-crypto.wasm serve the
web application: the same committed bytes to anyone, holding no data. They are
compiled into the binary.