API
| method | path | |
|---|---|---|
POST |
/api/auth/login |
{username, password} → bearer token |
GET |
/api/auth/me |
the current user |
POST |
/api/auth/password |
change your own password |
GET |
/api/records/{model}/{id}/history |
who did what to a record, newest first — which fields, never a value |
GET/PUT |
/api/access/{username} |
one person's access, and their own rules replaced whole (administrators) |
GET |
/api/quills/{id}/brought |
what a Quill brought, with how many records hold each (administrators) |
DELETE |
/api/quills/{id}?drop= |
remove a Quill; what drop names goes with it, records and all |
GET |
/api/secrets?env= |
the keys, without the values (&reveal=true for those) |
GET |
/api/secrets/vaults |
the vaults that hold something, with counts |
GET |
/api/secrets/environments |
environments that hold something, in this vault |
GET/PUT/DELETE |
/api/secrets/item/{key}?env= |
one secret, value included |
POST |
/api/secrets/import |
set many at once — what a .env becomes |
GET |
/api/secrets/export?env= |
a .env file, or &format=json |
DELETE |
/api/secrets/environment/{env} |
drop a whole environment |
DELETE |
/api/secrets/vault/{vault} |
drop a whole vault |
GET |
/api/types |
every kind of data there is: fields, scopes, what is sealed, who uses it |
GET |
/api/quills |
the installed Quills, each with its screens and its datamodels in full |
GET |
/api/quills/catalog |
the Quill Catalog, with what is installed |
POST |
/api/quills/plan |
{id} or {source, ref} — what installing would add (administrators) |
POST/DELETE |
/api/quills, /api/quills/{id} |
install, or remove; records are kept (administrators) |
POST |
/api/quills/upload |
a .tar.gz of a Quill's folder, as a development Quill — cm quill dev |
GET |
/api/datamodels |
every datamodel on the server, with its fields and the Quills that use it |
GET/POST |
/api/records/{model} |
your records of a datamodel (?field=value filters on indexed fields, ?field__gte=… and __gt, __lte, __lt are ranges); make one (scope for a space) |
GET/PATCH/DELETE |
/api/records/{model}/{id} |
one record; send rev with a change to get a 409 rather than overwrite |
POST |
/api/records/{model}/{id}/move |
{fields, index} — another lane or group, and a place in it |
POST |
/api/records/{model} with scope, members, unique |
a space — a channel, a calendar — made public or shared, with its people; unique finds the one with exactly those people instead of making another |
POST |
/api/records/{model}/{id}/members |
{username} — put somebody in a shared space; they are told |
DELETE |
/api/records/{model}/{id}/members/{username} |
take somebody out, or with your own name leave |
POST |
/api/records/{model}/{id}/seen |
you have looked in a space: what is in it is not unread |
POST |
/api/snapshots |
a frozen copy of a space's records, with a digest, sealed and locked (ATTESTATIONS.md) |
GET |
/api/snapshots/{id}, …/bundle |
the snapshot with its attestations and whether its bundle is intact; the bundle's bytes |
POST |
/api/snapshots/{id}/attestations |
bring somebody's signed verdict back; checked against the digest before it is kept |
POST/GET/DELETE |
/api/snapshots/{id}/guests[/{n}] |
a link that opens the one snapshot to somebody outside; the links given out; take one back |
GET/POST |
/api/guest/snapshots/{id}?token=, …/bundle, …/attestations |
what a guest link opens, with no account |
GET/POST |
/api/identity, /api/attest |
this server's signing key; an attestation signed with it, in your name |
GET |
/api/records/{model}?_last=50&_since=… |
the newest fifty, still in order; only what changed at or after a moment |
GET |
/api/changes |
a server-sent events stream of the records you may see being made, changed or deleted; ?since=<seq> to catch up |
GET |
/api/people |
everybody a space could be shared with, or written to |
GET/POST |
/api/shares |
your fileshares and the ones shared with you; {name, members, path} makes one (path for administrators); a share carries its url, access, members and, for its owner, warnings |
GET/PATCH/DELETE |
/api/shares/{name} |
one share; PATCH {description, path} (path for administrators); ?remove_files=true deletes a folder in Shares |
PUT |
/api/shares/{name}/members |
{kind: user|circle|everyone, who, access: write|read} — share it, or change what they may do |
DELETE |
/api/shares/{name}/members/{kind}/{who} |
stop sharing it; with your own username, leave it |
GET |
/api/shares/candidates |
who a share could be shared with: people, circles, and whether everybody |
GET |
/api/shares/check?path= |
administrators: whether a directory could be a share, and what is wrong with it |
* |
/dav/{name}/… |
the share itself, as WebDAV — Basic auth with your password or token |
GET/POST/DELETE |
/api/agents… |
your machines |
POST |
/api/agents/{id}/jobs |
queue work |
GET/POST |
/api/notifications |
what the machines have been doing |
POST |
/api/notifications/read |
mark them read; omit ids for all of them |
GET |
/api/push/key |
the VAPID public key, to subscribe a browser with |
POST |
/api/push/subscribe |
a PushSubscription, as the browser gives it |
POST |
/api/push/unsubscribe |
{endpoint} — forget this device |
GET |
/api/push/devices |
the devices this account pushes to |
GET |
/api/push/badge |
{messages, notifications, badge} — the number on the icon |
POST |
/api/push/test |
push yourself, to find out whether this phone is wired up |
POST |
/api/agent/enroll, /heartbeat, /jobs/claim |
the agent's own endpoints |
POST |
/api/agent/notifications |
a machine saying what it just did |
GET |
/api/server/features |
what this server offers |
PATCH |
/api/server/features/{key} |
{enabled} — switch one for everybody, admin only |
GET |
/api/me/features |
what you may switch, and your answer on each |
PATCH |
/api/me/features/{key} |
{enabled} — switch one for yourself |
GET/POST/PATCH/DELETE |
/api/users… |
admin only |
GET |
/api/health |
no auth; carries the cloud's name and whether it still needs setup |
GET |
/setup |
the first-boot page, while the server has no accounts; redirects to /app after |
POST |
/api/setup |
{name, username, password} — name the cloud and make its administrator; 409 once anybody exists |
GET/PATCH |
/api/server/settings |
{name} — what this cloud is called; PATCH is admin only |
GET |
/api/client |
what cloudmorrow update should install, no auth |
POST |
/api/server/update |
deploy from git and restart — admin only |
GET |
/, /install.sh |
the install page and script, no auth |
POST |
/mcp |
the MCP server, JSON-RPC over HTTP — an MCP token, or a user token |
GET |
/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server |
how an MCP client finds the sign-in flow, no auth |
POST |
/oauth/register, /oauth/token |
an MCP client registering itself, and trading its code for tokens |
GET/POST |
/oauth/authorize |
the page where you sign in and let an assistant in |
GET/DELETE |
/api/mcp/connections… |
the assistants you have let in; delete one to cut it off |
Interactive docs at /docs.
Send X-Cloudmorrow-Vault: <vault> (or ?vault=<vault>) to say which vault
a secrets call is about; without one it is the default vault. Nothing
else reads it — everything else belongs to the account outright.
Secret values are handed out one at a time, or all at once by /export; a
listing describes them instead. Those responses carry Cache-Control: no-store.
PUT takes the rev you last read; a stale rev gets a 409 carrying the
current revision and content, which is what drives the conflict dialog.
Agent tokens are a separate credential from user tokens: an agent token cannot
read notes, and a user token cannot claim jobs.
MCP tokens are a third: handed out by /oauth/token after somebody said yes
on the sign-in page, kept hashed, and good for /mcp alone.
From docs/MANUAL.md in the Cloudmorrow repository. Something wrong? A pull request there fixes it here.