Settings, renames, exports and account deletion
The four administrative doors that have a reference page each and belonged on one page together: the organization's settings registry, renaming an organization or a space, getting your data out, and closing an account.
Everything here is the API. Where a console screen does the same thing it is named, but the API is the authority — the console calls these endpoints.
The settings registry
An organization's behaviour is a flat list of keys. There is one catalogue and it is served, not written down:
GET /api/orgs/{orgId}/settingsEach entry carries everything needed to drive it:
Field | What it tells you |
|---|---|
| What you |
| What a person reads. The console shows these. |
| How the console groups it. |
|
|
| The platform default, which applies until you override it. |
| Integer bounds, where the key has them. |
| The allowed values, for an |
| The ceiling, for a |
| What this organization currently gets. |
| Whether that value is the default or an override you set. |
| Machinery; the console hides it behind a disclosure. |
Read it before you write. It is the only published list of valid keys, and a key that is not in it is a 404 rather than a stored unknown — we do not keep settings we do not honour.
Setting one key
PUT /api/orgs/{orgId}/settings/community.max_tags_per_topic
{ "value": 8 }valuemust be the type the key declares. A wrong type is a 422.An unknown key is a 404.
Idempotent: sending the value it already has answers 200 and writes nothing.
The change is audit-logged against the caller, so
GET /api/orgs/{orgId}/auditsays who moved it and when.Answers
{ "setting": { … } }— the whole entry, including the newvalueandisDefault: false.
Putting one back
DELETE /api/orgs/{orgId}/settings/community.max_tags_per_topicThis is not "set it to false" or "set it to zero". It clears your override so the key follows the platform default, including if we ever change that default. Explicitly writing today's default value would pin you to it. The reply is the setting as it now reads, with isDefault: true.
Who may
Both writes need the org.manage_settings capability — owners and admins have it, and a custom role can be built with it. A token also needs the write scope; GET needs read.
Renaming an organization or a space
A slug is not cosmetic: it is the first segment of every public address the organization owns, and an accepted value for {orgId} on every route under /orgs/{orgId}/….
PATCH /api/orgs/{orgId}/slug { "slug": "acme" }
PATCH /api/orgs/{orgId}/spaces/{spaceId}/slug { "slug": "handbook" }Both answer { "slug": "acme", "previous": "acme-inc" }. previous is what a redirect table or a cache purge needs, which is why it comes back rather than having to be remembered.
The rules, which are the same ones POST /api/orgs and space create enforce — there is one answer to "what may I call it?", not one per door:
lowercase letters, digits and hyphens; never starting or ending with one;
at least 2 characters, and at most 63 for an organization (it is handed out as a DNS label,
acme.forumulate.com, and 63 is the limit on one) or 48 for a space, which sits in a path and has no reason to be longer;an inner double dash (
a--b) is accepted for an organization and refused for a space, because the signup door has always minted organization names that way and tightening it would make an existing name unrenamable to itself;globally unique, and a name another organization used before stays theirs;
a reserved platform name —
api,docs,admin,login,status, the reader prefixes — is refused with a 409, so a rename cannot shadow our own routes.
The uuid never changes and keeps working, whatever you rename things to. Any route that takes {orgId} takes either form.
What happens to the old address
That is a setting, and it is the one worth knowing about before you rename anything in public:
| After a rename |
|---|---|
| The old address keeps working and redirects to the new one. |
| The old name is released immediately and stops resolving. |
Turn it off when the old name was a mistake or gives something away, and leave it on otherwise — a released name can be taken by somebody else.
A space remembers every name it has answered to, and you can read and prune that list:
GET /api/orgs/{orgId}/spaces/{spaceId}/slug/history
DELETE /api/orgs/{orgId}/spaces/{spaceId}/slug/history/{slug}The DELETE stops the old name answering and releases it. It is the per-name version of turning links.keep_renamed off, after the fact.
Getting your data out
Two exports, with different subjects. Both are synchronous JSON attachments — a database read, not a job, so there is nothing to poll.
GET /api/orgs/{orgId}/export # the organization: every space, collection, page, topic
GET /api/users/me/export # the caller's own account, across every org it belongs toThe organization export is the document POST /api/orgs/{orgId}/import takes, so an export of one organization is a migration into another. The import is idempotent — matched by slug at every level, so re-importing updates what it created rather than making a second copy — and additive: nothing is deleted because the document does not mention it.
Content, never credentials. An export carries no tokens, no secrets, no password hashes and no webhook signing keys. It is safe to hand to a customer and it is not enough to clone an installation.
The organization export needs org.view_audit. The account export needs nothing but the account: it is yours.
For the privacy framing of the same two endpoints — which regime asks for which, and what to tell a reader who writes to you — see Privacy, GDPR and data requests.
Streaming the audit log to your SIEM
The audit log records who did what in your organization. If your security team keeps its own record, point the organization at an HTTPS collector and every audit event is pushed to it as it happens. Both routes need org.manage_settings.
PUT /orgs/{orgId}/siem
{ "url": "https://siem.example.com/ingest/forumulate", "token": "s3cret-collector-token" }urlmust behttps; anything else is a422. Sendnullto turn the stream off, which also clears the token.tokenis optional. When set, each delivery carries it asAuthorization: Bearer <token>. It is stored encrypted and never returned. Leave it out to keep the stored one; sendnullto remove it.
GET /orgs/{orgId}/siem answers { "url": ..., "configured": true, "tokenSet": true }. When nothing is set it is { "url": null, "configured": false, "tokenSet": false }, not a 404.
Each event is one POST with a JSON body of { "type": "audit", "event": { ... } }. The event has organizationId, actorUserId, impersonatorUserId, action, targetType, targetId, source and at. Delivery goes through a retrying queue, so a collector that is down for a few minutes catches up rather than losing that stretch. A 4xx or a timeout counts as a failure and is retried; events that exhaust their retries are kept on our side as the record of what your collector never received. A change to the URL or token takes effect at once.
Closing an account
POST /api/users/me/delete
{ "confirm": "you@example.com" }Irreversible. It anonymises the account and revokes every session, including the one making the request — the session cookie is cleared in the response, so a client must treat a 200 as a logout.
confirm is the account's own email address. Credentials live in Atlas, so there is no local password to re-check; a live session plus the address is what proves the human. Anything else is a 400.
Content the account authored is detached from it rather than deleted, so a forum thread does not lose its replies and an answer somebody relies on does not disappear out of the middle of a conversation.
Export first:
GET /api/users/me/exportAfterwards there is nothing left to export.
Audit records outlive the account on purpose. An audit log that can be erased by the person it describes is not an audit log.
Your own account, short of deleting it
These are separate endpoints rather than fields on one profile patch, because each is a deliberate act with its own rules:
Endpoint | What it changes |
|---|---|
| Read it all back. |
|
|
| The |
| The UI language, platform-wide. |
|
|
In the API
Every operation below is also reachable from the other surfaces without a dedicated command. forumulate api <Operation> calls it from the CLI, the JavaScript SDK has a typed method for each one (the last column names it; the Python and Go clients are generated from the same spec), and an agent reaches the organization-scoped ones through the MCP call_api tool. Where a CLI command or MCP tool exists too, the last column names it. Operation names link to the API reference.
Org siem
Operation | Request | What it does | Shortcuts |
|---|---|---|---|
| Get the SIEM in an organization |
| |
| Replace the SIEM in an organization |
|
Space slug
Operation | Request | What it does | Shortcuts |
|---|---|---|---|
| Update the slug in a space |
| |
| Get the history in a space |
| |
| Delete the history |
|
User
Operation | Request | What it does | Shortcuts |
|---|---|---|---|
| Your account |
| |
| Update your account |
| |
| Set your interface language |
| |
| Change your @handle |
| |
| Hide or show your public profile |
| |
| Export this account’s personal data (GDPR Article 15) |
| |
| Erase this account (GDPR Article 17) |
|