Saaslivery API
/*
undocumented /*
/*
/.well-known/microsoft-identity-association.json
undocumented /.well-known/microsoft-identity-association.json
/.well-known/microsoft-identity-association.json
/totps
Disable 2FA
password
string · min length: 1
propertyName
anything
/totps
/totps
Verify code and enable 2FA
code
string · min length: 6 · max length: 6
propertyName
anything
/totps
/ai/commands
Ask about the current app
POST /ai/commands — answer a question about the app the member is in.
app
string · min length: 1 · max length: 64
q
string · min length: 1 · max length: 2000
propertyName
anything
/ai/commands
/api-keys
Create API key
POST /api-keys: mint a key; the secret appears in this response only. A scoped key may start with an empty grant list: like a fresh role, it holds nothing until permissions are ticked on its detail page.
name
string · min length: 1 · max length: 100
full_access
scopes
array
expires_at
string · max length: 40
propertyName
anything
/api-keys
/api-keys/:key_id
Update or revoke API key
PUT /api-keys/:key_id: rename, re-scope, or revoke a key.
key_id
string · path
name
string · min length: 1 · max length: 100
full_access
scopes
array
status
propertyName
anything
/api-keys/example
/about
undocumented /about
/about
/me/notification-preferences
Patch notification prefs
channel
patch
object
propertyName
anything
/me/notification-preferences
/finance/accounts
Create an account
code
string · min length: 1 · max length: 20
name
string · min length: 1 · max length: 200
type
parent_id
string
description
string · max length: 1000
normal_balance
is_contra
is_bank
propertyName
anything
/finance/accounts
/finance/accounts/:account_id
Update an account
account_id
string · path
display_name
string · max length: 200
show_in_unified
propertyName
anything
/finance/accounts/example
/activity
undocumented /activity
/activity
/admin/file-members/:member_mrn/folders
undocumented /admin/file-members/:member_mrn/folders
member_mrn
string · path
/admin/file-members/example/folders
/admin/file-members/:member_mrn/files
undocumented /admin/file-members/:member_mrn/files
member_mrn
string · path
/admin/file-members/example/files
/admin/file-stats
undocumented /admin/file-stats
GET /admin/file-stats — workspace storage overview for the admin view.
/admin/file-stats
/admin/activity-exports
undocumented /admin/activity-exports
GET /admin/activity-exports — the audit trail as a CSV download. Optional ``after`` / ``before`` ISO instants bound the window.
/admin/activity-exports
/admin/file-transfers
Transfer file ownership
POST /admin/file-transfers — move every file and folder one member owns to another member (offboarding). Root-level name collisions in the recipient's space are suffixed, never merged or replaced.
from_mrn
string · min length: 1
to_mrn
string · min length: 1
propertyName
anything
/admin/file-transfers
/elevations
Break glass into admin mode
POST /elevations — break glass. Re-authentication is the point of the exercise: a stolen session should not be able to elevate itself just because the person it was stolen from happens to be an admin. TOTP when the account has it (a second factor beats a password an attacker may already have), password otherwise, and a recovery code as the way back in for someone who lost their phone. Deliberately never a mailed code: admin actions must not depend on reaching a mailbox, least of all one we host.
reason
string · min length: 3 · max length: 500
code
string · min length: 6 · max length: 6
totp
string · min length: 6 · max length: 10
propertyName
anything
/elevations
/admin-audit
undocumented /admin-audit
GET /admin-audit — what admins did while elevated. The workspace-facing trail. Reads are coalesced by core.elevation.record, so a row can represent many identical views; `hits` says how many.
/admin-audit
/api-keys/:key_id
undocumented /api-keys/:key_id
DELETE /api-keys/:key_id: remove the key and its audit row.
key_id
string · path
/api-keys/example
/api-keys
undocumented /api-keys
GET /api-keys: list the workspace's API keys (never the secrets).
/api-keys
/api-keys/:key_id/secret
undocumented /api-keys/:key_id/secret
PUT /api-keys/:key_id/secret: replace the secret; old one dies now.
key_id
string · path
/api-keys/example/secret
/app/:slug
undocumented /app/:slug
slug
string · path
/app/example
/app/mail/
undocumented /app/mail/
Main mail screen. Renders the not-configured landing until the workspace has a domain or a connected account; otherwise the three-pane client.
/app/mail/
/app/mail/settings
undocumented /app/mail/settings
Admin: email hosting — add a domain, view DNS to publish, provision mailboxes, manage group mailboxes + the wildcard catch-all. Renders the same SPA on its settings view (deep-link target).
/app/mail/settings
/app/calls/
undocumented /app/calls/
/app/calls/
/app/calls/recordings
undocumented /app/calls/recordings
/app/calls/recordings
/app/calls/join/:slug
undocumented /app/calls/join/:slug
slug
string · path
/app/calls/join/example
/app/calls/partials/forms/schedule-call
undocumented /app/calls/partials/forms/schedule-call
Form partial — loaded by HTMX into #form-panel.
/app/calls/partials/forms/schedule-call
/app/calls/partials/call/:call_id
undocumented /app/calls/partials/call/:call_id
Call detail card (core/details) for the history sidepane.
call_id
string · path
/app/calls/partials/call/example
/app/canvas/
undocumented /app/canvas/
GET /app/canvas/ — dashboard: templates row + recent boards + New board.
/app/canvas/
/app/canvas/board/:board_id
undocumented /app/canvas/board/:board_id
GET /app/canvas/board/:board_id — the canvas editor.
board_id
string · path
/app/canvas/board/example
/app/canvas/partials/boards
undocumented /app/canvas/partials/boards
GET /app/canvas/partials/boards — board grid (HTMX refresh after create/delete).
/app/canvas/partials/boards
/app/canvas/assets/:asset_id
undocumented /app/canvas/assets/:asset_id
GET /app/canvas/assets/:asset_id — redirect to a fresh presigned R2 URL. Same-origin (wildcard subdomain) so <img> loads carry the session cookie.
asset_id
string · path
/app/canvas/assets/example
/app/chat/
undocumented /app/chat/
Main chat view — chat list sidebar plus message area.
/app/chat/
/app/chat/chats/:chat_id
undocumented /app/chat/chats/:chat_id
Deep link to a specific conversation.
chat_id
string · path
/app/chat/chats/example
/app/chat/partials/chats
undocumented /app/chat/partials/chats
Refreshed chat sidebar.
/app/chat/partials/chats
/app/chat/partials/chats/:chat_id/messages
undocumented /app/chat/partials/chats/:chat_id/messages
Older messages for a conversation, for the load-more control.
chat_id
string · path
/app/chat/partials/chats/example/messages
/app/chat/partials/chats/:chat_id/header
undocumented /app/chat/partials/chats/:chat_id/header
Chat title and participants bar.
chat_id
string · path
/app/chat/partials/chats/example/header
/app/chat/partials/chats/:chat_id/info
undocumented /app/chat/partials/chats/:chat_id/info
Details slide-out. Serves both group info and DM contact info. One template branches on chat.type. It used to render the group panel for both, so opening "Contact info" on a DM showed a group avatar, the literal word "None" as the title (DMs have no name), a member count, and a "Leave Group" button that the API rejects for DMs.
chat_id
string · path
/app/chat/partials/chats/example/info
/app/contacts/
undocumented /app/contacts/
Dashboard — a MicroDash board. The page is a shell; every figure comes from GET /contacts/dashboard so the board can refresh without a reload.
/app/contacts/
/app/contacts/contacts
undocumented /app/contacts/contacts
Contact directory with filters.
/app/contacts/contacts
/app/contacts/contacts/:contact_id
undocumented /app/contacts/contacts/:contact_id
Contact detail — company info, interactions timeline, segment membership.
contact_id
string · path
/app/contacts/contacts/example
/app/contacts/companies
undocumented /app/contacts/companies
Company directory with filters.
/app/contacts/companies
/app/contacts/companies/:company_id
undocumented /app/contacts/companies/:company_id
Company detail — all contacts, all interactions.
company_id
string · path
/app/contacts/companies/example
/app/contacts/segments
undocumented /app/contacts/segments
Segment list.
/app/contacts/segments
/app/contacts/segments/:segment_id
undocumented /app/contacts/segments/:segment_id
Segment detail — resolved members.
segment_id
string · path
/app/contacts/segments/example
/app/contacts/inbox
undocumented /app/contacts/inbox
The outsider inbox — conversations by status, with the thread alongside.
/app/contacts/inbox
/app/contacts/settings
undocumented /app/contacts/settings
Widget settings — the embed snippet, key rotation, origins, appearance. A shell only: the page loads its values from GET /contacts/settings so the greeting and origins never have to survive a trip through an x-data attribute.
/app/contacts/settings
/app/contacts/partials/conversations
undocumented /app/contacts/partials/conversations
HTMX: the inbox list, filtered by status, assignee and priority.
/app/contacts/partials/conversations
/app/contacts/partials/conversations/:conversation_id
undocumented /app/contacts/partials/conversations/:conversation_id
HTMX: one thread with its reply box. Staff see everything, internal notes included: this partial is behind contacts.conversations.view and never reaches a visitor.
conversation_id
string · path
/app/contacts/partials/conversations/example
/app/contacts/partials/contacts/:contact_id/conversations
undocumented /app/contacts/partials/contacts/:contact_id/conversations
HTMX: the conversations section on a contact page.
contact_id
string · path
/app/contacts/partials/contacts/example/conversations
/app/contacts/partials/import
undocumented /app/contacts/partials/import
HTMX: the CSV import drawer. A generic drawer rather than the form system: the fields depend on the pasted file's header, so there is no static Form class to declare.
/app/contacts/partials/import
/app/contacts/partials/contacts/:contact_id/merge
undocumented /app/contacts/partials/contacts/:contact_id/merge
HTMX: pick a duplicate to fold into this contact.
contact_id
string · path
/app/contacts/partials/contacts/example/merge
/app/contacts/partials/contact-list
undocumented /app/contacts/partials/contact-list
HTMX: contact table with filters.
/app/contacts/partials/contact-list
/app/contacts/partials/contacts/:contact_id/detail
undocumented /app/contacts/partials/contacts/:contact_id/detail
HTMX: contact detail panel.
contact_id
string · path
/app/contacts/partials/contacts/example/detail
/app/contacts/partials/company-list
undocumented /app/contacts/partials/company-list
HTMX: company table with filters.
/app/contacts/partials/company-list
/app/contacts/partials/companies/:company_id/detail
undocumented /app/contacts/partials/companies/:company_id/detail
HTMX: company detail panel with contacts.
company_id
string · path
/app/contacts/partials/companies/example/detail
/app/contacts/partials/interactions
undocumented /app/contacts/partials/interactions
HTMX: interaction timeline for a contact or company.
/app/contacts/partials/interactions
/app/contacts/partials/segment-list
undocumented /app/contacts/partials/segment-list
HTMX: segment cards.
/app/contacts/partials/segment-list
/app/contacts/partials/segments/:segment_id/members
undocumented /app/contacts/partials/segments/:segment_id/members
HTMX: resolved segment members.
segment_id
string · path
/app/contacts/partials/segments/example/members
/app/contacts/partials/forms/new-contact
undocumented /app/contacts/partials/forms/new-contact
HTMX: contact form with company auto-suggest.
/app/contacts/partials/forms/new-contact
/app/contacts/partials/forms/new-company
undocumented /app/contacts/partials/forms/new-company
HTMX: company form.
/app/contacts/partials/forms/new-company
/app/contacts/partials/forms/new-interaction
undocumented /app/contacts/partials/forms/new-interaction
HTMX: log interaction form.
/app/contacts/partials/forms/new-interaction
/app/contacts/partials/forms/new-segment
undocumented /app/contacts/partials/forms/new-segment
HTMX: segment form.
/app/contacts/partials/forms/new-segment
/app/contacts/partials/forms/contacts/:contact_id/edit
undocumented /app/contacts/partials/forms/contacts/:contact_id/edit
HTMX: edit-contact form, prefilled with the contact's current values.
contact_id
string · path
/app/contacts/partials/forms/contacts/example/edit
/app/contacts/partials/forms/companies/:company_id/edit
undocumented /app/contacts/partials/forms/companies/:company_id/edit
HTMX: edit-company form, prefilled with the company's current values.
company_id
string · path
/app/contacts/partials/forms/companies/example/edit
/app/crm/
undocumented /app/crm/
The CRM home: a MicroDash widget board, role-branched manager/rep. Layout, widget choice, and every number are client-side; the server only stamps what the board needs to know before it can fetch (role, the default pipeline for the funnel widget, and the currency rollups are shown in).
/app/crm/
/app/crm/pipelines
undocumented /app/crm/pipelines
The pipelines card grid. Was the app landing page before the board.
/app/crm/pipelines
/app/crm/deals
undocumented /app/crm/deals
Global deal list: every deal in the workspace, no pipeline required. Pipelines and members are fetched client-side rather than stamped here: a name carrying an apostrophe would break the inline filter config.
/app/crm/deals
/app/crm/leads
undocumented /app/crm/leads
Leads: contacts in the lead lifecycle, ranked by score, from the projection.
/app/crm/leads
/app/crm/targets
undocumented /app/crm/targets
Workspace-level targets and the rep leaderboard. The old targets view lived inside one pipeline, which hid every workspace-wide quota and left the leaderboard endpoint with no UI at all.
/app/crm/targets
/app/crm/scoring
undocumented /app/crm/scoring
Lead and deal scoring rules. Wires the previously orphaned rule form.
/app/crm/scoring
/app/crm/pipeline/:pipeline_id
undocumented /app/crm/pipeline/:pipeline_id
pipeline_id
string · path
/app/crm/pipeline/example
/app/crm/partials/kanban/:pipeline_id
undocumented /app/crm/partials/kanban/:pipeline_id
pipeline_id
string · path
/app/crm/partials/kanban/example
/app/crm/partials/deal/:deal_id
undocumented /app/crm/partials/deal/:deal_id
deal_id
string · path
/app/crm/partials/deal/example
/app/crm/partials/targets/:pipeline_id
undocumented /app/crm/partials/targets/:pipeline_id
pipeline_id
string · path
/app/crm/partials/targets/example
/app/crm/partials/reports/:pipeline_id
undocumented /app/crm/partials/reports/:pipeline_id
pipeline_id
string · path
/app/crm/partials/reports/example
/app/crm/partials/stages/:pipeline_id
undocumented /app/crm/partials/stages/:pipeline_id
Stage editor: the pipeline's stages, ordered, with their templates.
pipeline_id
string · path
/app/crm/partials/stages/example
/app/crm/partials/forms/new-pipeline
undocumented /app/crm/partials/forms/new-pipeline
/app/crm/partials/forms/new-pipeline
/app/crm/partials/forms/edit-pipeline/:pipeline_id
undocumented /app/crm/partials/forms/edit-pipeline/:pipeline_id
pipeline_id
string · path
/app/crm/partials/forms/edit-pipeline/example
/app/crm/partials/forms/new-stage/:pipeline_id
undocumented /app/crm/partials/forms/new-stage/:pipeline_id
pipeline_id
string · path
/app/crm/partials/forms/new-stage/example
/app/crm/partials/forms/new-deal
undocumented /app/crm/partials/forms/new-deal
/app/crm/partials/forms/new-deal
/app/crm/partials/forms/edit-deal/:deal_id
undocumented /app/crm/partials/forms/edit-deal/:deal_id
deal_id
string · path
/app/crm/partials/forms/edit-deal/example
/app/crm/partials/forms/deal-proposal/:deal_id
undocumented /app/crm/partials/forms/deal-proposal/:deal_id
deal_id
string · path
/app/crm/partials/forms/deal-proposal/example
/app/crm/partials/forms/new-target
undocumented /app/crm/partials/forms/new-target
/app/crm/partials/forms/new-target
/app/crm/partials/forms/edit-target/:target_id
undocumented /app/crm/partials/forms/edit-target/:target_id
target_id
string · path
/app/crm/partials/forms/edit-target/example
/app/crm/partials/forms/new-scoring-rule
undocumented /app/crm/partials/forms/new-scoring-rule
/app/crm/partials/forms/new-scoring-rule
/app/feeds/
undocumented /app/feeds/
Main feeds page — 3-column Twitter-like layout.
/app/feeds/
/app/feeds/post/:post_id
undocumented /app/feeds/post/:post_id
Single post view with all replies — works for any depth of nesting.
post_id
string · path
/app/feeds/post/example
/app/feeds/explore
undocumented /app/feeds/explore
Explore page — trending posts and search.
/app/feeds/explore
/app/feeds/notifications
undocumented /app/feeds/notifications
Notifications page — reactions, replies, and follows on your content.
/app/feeds/notifications
/app/feeds/bookmarks
undocumented /app/feeds/bookmarks
Bookmarks page — saved posts.
/app/feeds/bookmarks
/app/feeds/profile/:member_mrn
undocumented /app/feeds/profile/:member_mrn
Profile page — user's posts, follower/following counts.
member_mrn
string · path
/app/feeds/profile/example
/app/feeds/partials/feed
undocumented /app/feeds/partials/feed
Load feed posts — used for infinite scroll / refresh.
/app/feeds/partials/feed
/app/feeds/partials/post/:post_id
undocumented /app/feeds/partials/post/:post_id
Single post card partial.
post_id
string · path
/app/feeds/partials/post/example
/app/feeds/partials/compose
undocumented /app/feeds/partials/compose
Compose form partial.
/app/feeds/partials/compose
/app/feeds/partials/replies/:post_id
undocumented /app/feeds/partials/replies/:post_id
Load replies for a post.
post_id
string · path
/app/feeds/partials/replies/example
/app/feeds/partials/trending
undocumented /app/feeds/partials/trending
Trending posts sidebar partial.
/app/feeds/partials/trending
/app/feeds/partials/who-to-follow
undocumented /app/feeds/partials/who-to-follow
Who to follow sidebar partial.
/app/feeds/partials/who-to-follow
/app/feeds/partials/profile/:member_mrn
undocumented /app/feeds/partials/profile/:member_mrn
Profile sidebar card for a member.
member_mrn
string · path
/app/feeds/partials/profile/example
/app/feeds/partials/share/:post_id
undocumented /app/feeds/partials/share/:post_id
Share drawer partial — loaded via HTMX into #share-panel.
post_id
string · path
/app/feeds/partials/share/example
/app/files/
undocumented /app/files/
The Files landing page: a MicroDash board over /file-statistics. Nothing is queried here. The board fetches its own data so the widgets can show skeletons while it lands, and so a refresh after an upload is one API call rather than a page render.
/app/files/
/app/files/browse
undocumented /app/files/browse
File manager — personal root with sidebar.
/app/files/browse
/app/files/folders/:folder_id
undocumented /app/files/folders/:folder_id
Deep link into a specific folder.
folder_id
string · path
/app/files/folders/example
/app/files/recents
undocumented /app/files/recents
Recently uploaded/updated files + recently viewed files (two tabs).
/app/files/recents
/app/files/shared
undocumented /app/files/shared
Sharing, in three tabs: with me, by me, and public links. Only the requested tab is queried. The other two are a click away and loading all three would triple the work for a view of one.
/app/files/shared
/app/files/trash
undocumented /app/files/trash
Trash view.
/app/files/trash
/app/files/activity
undocumented /app/files/activity
Activity log.
/app/files/activity
/app/files/admin/members
undocumented /app/files/admin/members
Admin: browse all members' file trees.
/app/files/admin/members
/app/files/s/:token
undocumented /app/files/s/:token
Old in-app share path — the link format before shares went public.
token
string · path
/app/files/s/example
/app/files/partials/folders/:folder_id/contents
undocumented /app/files/partials/folders/:folder_id/contents
folder_id
string · path
/app/files/partials/folders/example/contents
/app/files/partials/folders/:folder_id/breadcrumb
undocumented /app/files/partials/folders/:folder_id/breadcrumb
folder_id
string · path
/app/files/partials/folders/example/breadcrumb
/app/files/partials/sidebar
undocumented /app/files/partials/sidebar
/app/files/partials/sidebar
/app/files/partials/items/:item_id/detail
undocumented /app/files/partials/items/:item_id/detail
item_id
string · path
/app/files/partials/items/example/detail
/app/files/partials/shares/dialog
undocumented /app/files/partials/shares/dialog
/app/files/partials/shares/dialog
/app/files/partials/forms/new-folder
undocumented /app/files/partials/forms/new-folder
/app/files/partials/forms/new-folder
/app/finance/
undocumented /app/finance/
/app/finance/
/app/finance/console
undocumented /app/finance/console
/app/finance/console
/app/finance/console/requests
undocumented /app/finance/console/requests
Employee Requests — the approvals queue inside the console. Gated in AUTHZ on finance.requests.manage.
/app/finance/console/requests
/app/finance/requests
undocumented /app/finance/requests
My Requests — the portal-side page. Every portal member sees ONLY their own requests here (withdraw, message the reviewers) without ever entering the console. Reviewers handle the queue at /app/finance/console/requests.
/app/finance/requests
/app/finance/quotes
undocumented /app/finance/quotes
/app/finance/quotes
/app/finance/quotes/:entry_id
undocumented /app/finance/quotes/:entry_id
entry_id
string · path
/app/finance/quotes/example
/app/finance/purchase-orders
undocumented /app/finance/purchase-orders
/app/finance/purchase-orders
/app/finance/purchase-orders/:entry_id
undocumented /app/finance/purchase-orders/:entry_id
entry_id
string · path
/app/finance/purchase-orders/example
/app/finance/orders
undocumented /app/finance/orders
/app/finance/orders
/app/finance/orders/:entry_id
undocumented /app/finance/orders/:entry_id
entry_id
string · path
/app/finance/orders/example
/app/finance/invoices
undocumented /app/finance/invoices
/app/finance/invoices
/app/finance/invoices/:entry_id
undocumented /app/finance/invoices/:entry_id
entry_id
string · path
/app/finance/invoices/example
/app/finance/bills
undocumented /app/finance/bills
/app/finance/bills
/app/finance/bills/:entry_id
undocumented /app/finance/bills/:entry_id
entry_id
string · path
/app/finance/bills/example
/app/finance/credit-notes
undocumented /app/finance/credit-notes
/app/finance/credit-notes
/app/finance/credit-notes/:entry_id
undocumented /app/finance/credit-notes/:entry_id
entry_id
string · path
/app/finance/credit-notes/example
/app/finance/purchase-credit-notes
undocumented /app/finance/purchase-credit-notes
/app/finance/purchase-credit-notes
/app/finance/purchase-credit-notes/:entry_id
undocumented /app/finance/purchase-credit-notes/:entry_id
entry_id
string · path
/app/finance/purchase-credit-notes/example
/app/finance/journal
undocumented /app/finance/journal
/app/finance/journal
/app/finance/journal/:entry_id
undocumented /app/finance/journal/:entry_id
entry_id
string · path
/app/finance/journal/example
/app/finance/payments
undocumented /app/finance/payments
The payments list. Rows are not fetched here: like every other finance list, the grid loads them from GET /finance/payments, which owns the filtering, sorting, searching and paging.
/app/finance/payments
/app/finance/accounts
undocumented /app/finance/accounts
/app/finance/accounts
/app/finance/accounts/:account_id
undocumented /app/finance/accounts/:account_id
account_id
string · path
/app/finance/accounts/example
/app/finance/reports
undocumented /app/finance/reports
/app/finance/reports
/app/finance/reconciliation
undocumented /app/finance/reconciliation
/app/finance/reconciliation
/app/finance/settings
undocumented /app/finance/settings
/app/finance/settings
/app/finance/partials/branding-preview
undocumented /app/finance/partials/branding-preview
The Branding tab's preview: the real document, sample contents. Rendered server-side through the same build_document the PDF and the portal use, so the tab cannot show something the customer will never receive.
/app/finance/partials/branding-preview
/app/finance/partials/forms/new-quote
undocumented /app/finance/partials/forms/new-quote
/app/finance/partials/forms/new-quote
/app/finance/partials/forms/edit-quote/:entry_id
undocumented /app/finance/partials/forms/edit-quote/:entry_id
entry_id
string · path
/app/finance/partials/forms/edit-quote/example
/app/finance/partials/forms/revise-quote/:entry_id
undocumented /app/finance/partials/forms/revise-quote/:entry_id
entry_id
string · path
/app/finance/partials/forms/revise-quote/example
/app/finance/partials/forms/new-purchase-order
undocumented /app/finance/partials/forms/new-purchase-order
/app/finance/partials/forms/new-purchase-order
/app/finance/partials/forms/new-order
undocumented /app/finance/partials/forms/new-order
/app/finance/partials/forms/new-order
/app/finance/partials/forms/new-invoice
undocumented /app/finance/partials/forms/new-invoice
/app/finance/partials/forms/new-invoice
/app/finance/partials/forms/new-bill
undocumented /app/finance/partials/forms/new-bill
/app/finance/partials/forms/new-bill
/app/finance/partials/forms/new-credit-note
undocumented /app/finance/partials/forms/new-credit-note
The credit note drawer, from either entry point. With a source_entry_id on the query string the invoice is already decided (the button lives on that invoice's page), so it rides in hidden and the picker is not offered. Without one, the list page opened this, and the invoice has to be chosen.
/app/finance/partials/forms/new-credit-note
/app/finance/partials/forms/new-purchase-credit-note
undocumented /app/finance/partials/forms/new-purchase-credit-note
The purchase credit note drawer, from either entry point. The mirror of new_credit_note_form: with a source_entry_id on the query string the bill is already decided (the button lives on that bill's page), so it rides in hidden and the picker is not offered.
/app/finance/partials/forms/new-purchase-credit-note
/app/finance/partials/forms/new-journal
undocumented /app/finance/partials/forms/new-journal
/app/finance/partials/forms/new-journal
/app/finance/partials/forms/new-payment
undocumented /app/finance/partials/forms/new-payment
/app/finance/partials/forms/new-payment
/app/finance/partials/forms/new-account
undocumented /app/finance/partials/forms/new-account
/app/finance/partials/forms/new-account
/app/finance/partials/forms/new-period
undocumented /app/finance/partials/forms/new-period
/app/finance/partials/forms/new-period
/app/finance/partials/forms/new-dimension
undocumented /app/finance/partials/forms/new-dimension
/app/finance/partials/forms/new-dimension
/app/finance/partials/forms/new-tax-rate
undocumented /app/finance/partials/forms/new-tax-rate
/app/finance/partials/forms/new-tax-rate
/app/finance/partials/forms/new-payment-term
undocumented /app/finance/partials/forms/new-payment-term
/app/finance/partials/forms/new-payment-term
/app/finance/partials/forms/new-bank-rule
undocumented /app/finance/partials/forms/new-bank-rule
/app/finance/partials/forms/new-bank-rule
/app/finance/partials/forms/new-budget
undocumented /app/finance/partials/forms/new-budget
/app/finance/partials/forms/new-budget
/app/finance/partials/forms/new-recurring
undocumented /app/finance/partials/forms/new-recurring
/app/finance/partials/forms/new-recurring
/app/finance/partials/forms/new-expense-claim
undocumented /app/finance/partials/forms/new-expense-claim
/app/finance/partials/forms/new-expense-claim
/app/finance/partials/forms/new-advance
undocumented /app/finance/partials/forms/new-advance
/app/finance/partials/forms/new-advance
/app/finance/partials/forms/new-purchase-request
undocumented /app/finance/partials/forms/new-purchase-request
/app/finance/partials/forms/new-purchase-request
/app/finance/partials/entry-list
undocumented /app/finance/partials/entry-list
/app/finance/partials/entry-list
/app/finance/partials/entry/:entry_id
undocumented /app/finance/partials/entry/:entry_id
entry_id
string · path
/app/finance/partials/entry/example
/app/finance/partials/payment-list
undocumented /app/finance/partials/payment-list
/app/finance/partials/payment-list
/app/finance/partials/settings-tree
undocumented /app/finance/partials/settings-tree
/app/finance/partials/settings-tree
/app/finance/partials/settings/:account_id/ledger
undocumented /app/finance/partials/settings/:account_id/ledger
account_id
string · path
/app/finance/partials/settings/example/ledger
/app/finance/partials/report/:report
undocumented /app/finance/partials/report/:report
report
string · path
/app/finance/partials/report/example
/app/finance/partials/bank-imports
undocumented /app/finance/partials/bank-imports
/app/finance/partials/bank-imports
/app/finance/partials/matching/:import_id
undocumented /app/finance/partials/matching/:import_id
import_id
string · path
/app/finance/partials/matching/example
/app/growth/
undocumented /app/growth/
/app/growth/
/app/growth/console
undocumented /app/growth/console
/app/growth/console
/app/growth/concerns
undocumented /app/growth/concerns
Staff triage for concerns: both the anonymous voice stream and named complaints. Route-gated to growth.results.view.
/app/growth/concerns
/app/growth/dashboard/:campaign_id
undocumented /app/growth/dashboard/:campaign_id
Engagement deep-link to a specific campaign (from the Surveys list).
campaign_id
string · path
/app/growth/dashboard/example
/app/growth/respond
undocumented /app/growth/respond
/app/growth/respond
/app/growth/campaigns
undocumented /app/growth/campaigns
/app/growth/campaigns
/app/growth/goals
undocumented /app/growth/goals
/app/growth/goals
/app/growth/feedback
undocumented /app/growth/feedback
/app/growth/feedback
/app/growth/one-on-ones
undocumented /app/growth/one-on-ones
/app/growth/one-on-ones
/app/growth/one-on-ones/log
undocumented /app/growth/one-on-ones/log
The full-page 1:1 composer. Accepts series_id and subject_mrn so logging from a recurring series lands inside that series (carrying its agenda forward) instead of starting an unattached 1:1.
/app/growth/one-on-ones/log
/app/growth/one-on-ones/interaction/:signal_id
undocumented /app/growth/one-on-ones/interaction/:signal_id
One logged 1:1, reopened. Same surface as the composer: past interactions stay editable so private notes and follow-ups can be added after the conversation.
signal_id
string · path
/app/growth/one-on-ones/interaction/example
/app/growth/reviews
undocumented /app/growth/reviews
/app/growth/reviews
/app/growth/plans
undocumented /app/growth/plans
/app/growth/plans
/app/growth/team
undocumented /app/growth/team
/app/growth/team
/app/growth/frameworks
undocumented /app/growth/frameworks
Competencies, values, question bank and role profiles (Grow pillar).
/app/growth/frameworks
/app/growth/partials/board/:tab
undocumented /app/growth/partials/board/:tab
One dashboard tab's board, swapped into #growth-tabpanel by HTMX.
tab
string · path
/app/growth/partials/board/example
/app/growth/partials/forms/new-campaign
undocumented /app/growth/partials/forms/new-campaign
The survey builder: pick drivers, add custom questions, eNPS + comment.
/app/growth/partials/forms/new-campaign
/app/growth/partials/forms/new-goal
undocumented /app/growth/partials/forms/new-goal
Create-goal modal form (Align pillar).
/app/growth/partials/forms/new-goal
/app/growth/partials/forms/log-progress
undocumented /app/growth/partials/forms/log-progress
Log-progress modal form for a specific goal.
/app/growth/partials/forms/log-progress
/app/growth/partials/forms/give-praise
undocumented /app/growth/partials/forms/give-praise
Give-praise modal form (Connect pillar). Values chips come from the workspace framework (falling back to the built-in defaults).
/app/growth/partials/forms/give-praise
/app/growth/partials/forms/give-feedback
undocumented /app/growth/partials/forms/give-feedback
Give-feedback modal form (Connect pillar). Accepts parent_id (the feedback_request being answered) and subject_mrn as query params so a request and its answer are threaded.
/app/growth/partials/forms/give-feedback
/app/growth/partials/forms/new-checkin
undocumented /app/growth/partials/forms/new-checkin
New check-in modal form (Connect pillar).
/app/growth/partials/forms/new-checkin
/app/growth/partials/forms/new-cycle
undocumented /app/growth/partials/forms/new-cycle
New review-cycle modal form (Grow pillar).
/app/growth/partials/forms/new-cycle
/app/growth/partials/forms/write-review
undocumented /app/growth/partials/forms/write-review
Write-a-review modal form (Grow pillar). The cycle picker is populated per-request from the workspace's open review cycles; one per-competency star rating is appended for each workspace competency (empty = not rated). Accepts campaign_id and subject_mrn query params so a review task opens pre-addressed.
/app/growth/partials/forms/write-review
/app/growth/partials/forms/new-plan
undocumented /app/growth/partials/forms/new-plan
New plan / PIP modal form (Grow pillar).
/app/growth/partials/forms/new-plan
/app/growth/partials/forms/new-attribute
undocumented /app/growth/partials/forms/new-attribute
New competency / value / bank question modal form (Grow pillar).
/app/growth/partials/forms/new-attribute
/app/growth/partials/forms/new-role-profile
undocumented /app/growth/partials/forms/new-role-profile
New role profile modal form (Grow pillar).
/app/growth/partials/forms/new-role-profile
/app/growth/partials/forms/new-series
undocumented /app/growth/partials/forms/new-series
Start-a-recurring-1:1 modal form (Connect pillar).
/app/growth/partials/forms/new-series
/app/growth/partials/forms/edit-series
undocumented /app/growth/partials/forms/edit-series
Edit a recurring 1:1: rhythm, title and next session. Participants are fixed once a series exists (changing who it is with would orphan its history), and the standing agenda is owned by the carry-over, not by hand.
/app/growth/partials/forms/edit-series
/app/growth/partials/forms/nominate-reviewer
undocumented /app/growth/partials/forms/nominate-reviewer
Nominate-a-reviewer modal form (Grow pillar). The cycle picker holds the open review cycles; subject defaults to the nominator server-side.
/app/growth/partials/forms/nominate-reviewer
/app/growth/partials/forms/new-concern
undocumented /app/growth/partials/forms/new-concern
Raise-a-concern modal form (portal). Anonymous by default.
/app/growth/partials/forms/new-concern
/app/leaves/
undocumented /app/leaves/
Dashboard — balances, upcoming PTOs, pending approvals.
/app/leaves/
/app/leaves/ptos
undocumented /app/leaves/ptos
My PTOs — list with status filter.
/app/leaves/ptos
/app/leaves/approvals
undocumented /app/leaves/approvals
Approvals — requests the current user can act on, split into Current/History. Both tabs list exactly what the viewer is authorized for (manager → direct reports, default approver → their no-manager workers, owner → everyone), using the shared ``can_decide_pto_rule``. Current = pending requests (clicking opens the detail drawer with Approve / Deny); History = settled decisions.
/app/leaves/approvals
/app/leaves/policies
undocumented /app/leaves/policies
Leave policies list — scoped by authz (managers all, members their own).
/app/leaves/policies
/app/leaves/policies/:id
undocumented /app/leaves/policies/:id
Leave policy detail page — read-only info + members; Edit opens the editor drawer. Renders inside the Policies section (nav stays on Policies) but shows the detail view instead of the list, mirroring the workers app's detail page.
id
string · path
/app/leaves/policies/example
/app/leaves/holidays
undocumented /app/leaves/holidays
Holidays list.
/app/leaves/holidays
/app/leaves/partials/policies/:id
undocumented /app/leaves/partials/policies/:id
Policy detail drawer — loaded into #form-panel.
id
string · path
/app/leaves/partials/policies/example
/app/leaves/partials/balances
undocumented /app/leaves/partials/balances
/app/leaves/partials/balances
/app/leaves/partials/ptos
undocumented /app/leaves/partials/ptos
/app/leaves/partials/ptos
/app/leaves/partials/availability
undocumented /app/leaves/partials/availability
/app/leaves/partials/availability
/app/leaves/partials/forms/new-pto
undocumented /app/leaves/partials/forms/new-pto
New PTO request form — rendered as platform form drawer.
/app/leaves/partials/forms/new-pto
/app/leaves/partials/forms/new-policy
undocumented /app/leaves/partials/forms/new-policy
New leave policy form — rendered as platform form drawer.
/app/leaves/partials/forms/new-policy
/app/leaves/partials/forms/new-holiday
undocumented /app/leaves/partials/forms/new-holiday
New holiday form — rendered as platform form drawer.
/app/leaves/partials/forms/new-holiday
/app/leaves/partials/forms/reconciliation
undocumented /app/leaves/partials/forms/reconciliation
Working-pattern reconciliation drawer — future bookings to recount. Data is fetched client-side from GET /leave-reconciliation (which enforces the balance-adjust capability), so this handler only renders the shell.
/app/leaves/partials/forms/reconciliation
/app/leaves/partials/ptos/:id
undocumented /app/leaves/partials/ptos/:id
id
string · path
/app/leaves/partials/ptos/example
/app/papers/
undocumented /app/papers/
GET /app/papers/ — templates row + recent documents.
/app/papers/
/app/papers/doc/:document_id
undocumented /app/papers/doc/:document_id
GET /app/papers/doc/:document_id — document editor page.
document_id
string · path
/app/papers/doc/example
/app/papers/partials/documents
undocumented /app/papers/partials/documents
GET /app/papers/partials/documents — recent documents list (HTMX refresh).
/app/papers/partials/documents
/app/papers/partials/trash
undocumented /app/papers/partials/trash
GET /app/papers/partials/trash — the trash list (HTMX swap on the index). Scoped exactly like GET /papers/trash: only documents the caller could actually restore or destroy, which means owner/manage access, not merely being shared into them.
/app/papers/partials/trash
/app/papers/partials/doc/:document_id/comments
undocumented /app/papers/partials/doc/:document_id/comments
GET /app/papers/partials/doc/:document_id/comments — comments panel.
document_id
string · path
/app/papers/partials/doc/example/comments
/app/papers/partials/doc/:document_id/versions
undocumented /app/papers/partials/doc/:document_id/versions
GET /app/papers/partials/doc/:document_id/versions — version history panel.
document_id
string · path
/app/papers/partials/doc/example/versions
/app/settings/
undocumented /app/settings/
Account tab default view. The Lobby is the workspace home now; Account is a normal tab opened from a Lobby button, so its entry point lands on the member's own profile settings.
/app/settings/
/app/settings/account
undocumented /app/settings/account
/app/settings/account
/app/settings/account/:section
undocumented /app/settings/account/:section
section
string · path
/app/settings/account/example
/app/settings/organisation
undocumented /app/settings/organisation
/app/settings/organisation
/app/settings/organisation/members
undocumented /app/settings/organisation/members
/app/settings/organisation/members
/app/settings/organisation/members/:member_id
undocumented /app/settings/organisation/members/:member_id
member_id
string · path
/app/settings/organisation/members/example
/app/settings/organisation/roles
undocumented /app/settings/organisation/roles
/app/settings/organisation/roles
/app/settings/organisation/roles/:role_id
undocumented /app/settings/organisation/roles/:role_id
role_id
string · path
/app/settings/organisation/roles/example
/app/settings/organisation/apps
undocumented /app/settings/organisation/apps
Admin page — configure per-app access policy and allowed roles. The partial fetches installed apps + roles from /installations?policy=1 and /roles at mount time, so we only need the shell render here.
/app/settings/organisation/apps
/app/settings/organisation/apps/:slug
undocumented /app/settings/organisation/apps/:slug
Per-app access page (specs/app-access-and-portals.md): admins, tile access, permission matrix, config document, exception grants. Reachable by workspace admins and the app's own admins; the partial fetches everything from GET /apps/:slug/access.
slug
string · path
/app/settings/organisation/apps/example
/app/settings/organisation/billing
undocumented /app/settings/organisation/billing
/app/settings/organisation/billing
/app/settings/organisation/billing/invoices
undocumented /app/settings/organisation/billing/invoices
/app/settings/organisation/billing/invoices
/app/settings/organisation/billing/methods
undocumented /app/settings/organisation/billing/methods
/app/settings/organisation/billing/methods
/app/settings/organisation/settings
undocumented /app/settings/organisation/settings
/app/settings/organisation/settings
/app/settings/organisation/tokens
undocumented /app/settings/organisation/tokens
Admin page listing workspace API keys, with a create modal. Mirrors the roles list: rows render server-side, and each key's settings icon opens its in-card detail page where permissions live.
/app/settings/organisation/tokens
/app/settings/organisation/tokens/:key_id
undocumented /app/settings/organisation/tokens/:key_id
Admin page for one API key: permission scoping, rotate, revoke, delete. Mirrors the role detail page; the permission tree renders from the same manifest catalogue with the key's granted scopes pre-checked.
key_id
string · path
/app/settings/organisation/tokens/example
/app/settings/organisation/email
undocumented /app/settings/organisation/email
Admin page — MX email hosting (domains, mailboxes, group mailboxes, catch-all). Reuses the shared mail/partials/hosting_admin.html component (talks to the /mail/* API).
/app/settings/organisation/email
/app/sign/
undocumented /app/sign/
Sign home: the insights dashboard. Backward compatibility: pre-sidenav deep links used /app/sign/?open={id}; those now land on the owning section (templates or contracts), which opens the builder.
/app/sign/
/app/sign/contracts
undocumented /app/sign/contracts
Contracts: one-off and template-born documents with Draft/Sent/Completed tabs.
/app/sign/contracts
/app/sign/templates
undocumented /app/sign/templates
Templates: reusable templates with usage history.
/app/sign/templates
/app/sign/signatories
undocumented /app/sign/signatories
Signatories: everyone ever added to a visible document.
/app/sign/signatories
/app/sign/partials/forms/envelope-settings/:envelope_id
undocumented /app/sign/partials/forms/envelope-settings/:envelope_id
GET /app/sign/partials/forms/envelope-settings/:envelope_id — settings drawer (subject, message, signing order, expiry), prefilled from the envelope.
envelope_id
string · path
/app/sign/partials/forms/envelope-settings/example
/app/sign/partials/forms/new-signer/:envelope_id
undocumented /app/sign/partials/forms/new-signer/:envelope_id
GET /app/sign/partials/forms/new-signer/:envelope_id — add-signer drawer with a workspace-member lookup (signer_mrn) or plain name/email for external guests.
envelope_id
string · path
/app/sign/partials/forms/new-signer/example
/app/sign/partials/forms/edit-signer/:envelope_id/:recipient_id
undocumented /app/sign/partials/forms/edit-signer/:envelope_id/:recipient_id
GET /app/sign/partials/forms/edit-signer/:envelope_id/:recipient_id — edit a signer's name, email, role and order in a drawer, prefilled from the record.
envelope_id
string · path
recipient_id
string · path
/app/sign/partials/forms/edit-signer/example/example
/app/sign/partials/forms/access-code/:envelope_id/:recipient_id
undocumented /app/sign/partials/forms/access-code/:envelope_id/:recipient_id
GET /app/sign/partials/forms/access-code/:envelope_id/:recipient_id — set or replace one signer's access code (the current code is never shown back).
envelope_id
string · path
recipient_id
string · path
/app/sign/partials/forms/access-code/example/example
/app/sign/partials/forms/new-public-link/:envelope_id
undocumented /app/sign/partials/forms/new-public-link/:envelope_id
GET /app/sign/partials/forms/new-public-link/:envelope_id — mint a self-serve link on a template (optional expiry + submission cap).
envelope_id
string · path
/app/sign/partials/forms/new-public-link/example
/app/sign/partials/signatory/:email
undocumented /app/sign/partials/signatory/:email
GET /app/sign/partials/signatory/:email — one signatory's floating detail card: their documents (with per-document state) and audit activity, scoped to what the caller can see. Deep-linkable via /app/sign/signatories?signatory=.
email
string · path
/app/sign/partials/signatory/example
/app/sign/partials/template-usage/:envelope_id
undocumented /app/sign/partials/template-usage/:envelope_id
GET /app/sign/partials/template-usage/:envelope_id — the template's usage history as a floating detail card: every document created from it, newest first. Deep-linkable via /app/sign/templates?usage=.
envelope_id
string · path
/app/sign/partials/template-usage/example
/app/slides/
undocumented /app/slides/
GET /app/slides/. Templates + recent decks (Papers listing).
/app/slides/
/app/slides/deck/:id
undocumented /app/slides/deck/:id
GET /app/slides/deck/:id. Design studio (Phase 1: chrome only).
id
string · path
/app/slides/deck/example
/app/slides/present/:id
undocumented /app/slides/present/:id
GET /app/slides/present/:id. Full-screen present (Phase 1: placeholder).
id
string · path
/app/slides/present/example
/app/slides/partials/decks
undocumented /app/slides/partials/decks
GET /app/slides/partials/decks. Recent list (HTMX refresh).
/app/slides/partials/decks
/app/slides/partials/trash
undocumented /app/slides/partials/trash
GET /app/slides/partials/trash. Trash list (HTMX swap on the index).
/app/slides/partials/trash
/app/slides/assets/:asset_id
undocumented /app/slides/assets/:asset_id
GET /app/slides/assets/:asset_id. Redirect to a fresh presigned R2 URL. Same-origin (wildcard subdomain) so an <img> load carries the session cookie. The gate in authz.py has already resolved read access on the owning deck.
asset_id
string · path
/app/slides/assets/example
/app/tables/
undocumented /app/tables/
GET /app/tables/ — templates row + recent tables.
/app/tables/
/app/tables/:table_id
undocumented /app/tables/:table_id
GET /app/tables/:table_id — editor view for a specific table.
table_id
string · path
/app/tables/example
/app/tasks/
undocumented /app/tasks/
/app/tasks/
/app/tasks/board/:board_id
undocumented /app/tasks/board/:board_id
board_id
string · path
/app/tasks/board/example
/app/tasks/partials/task-list
undocumented /app/tasks/partials/task-list
/app/tasks/partials/task-list
/app/tasks/partials/card/:task_id
undocumented /app/tasks/partials/card/:task_id
A single kanban card, for realtime patch-in-place on the board tab.
task_id
string · path
/app/tasks/partials/card/example
/app/tasks/partials/task/:task_id
undocumented /app/tasks/partials/task/:task_id
task_id
string · path
/app/tasks/partials/task/example
/app/tasks/partials/task/:task_id/expanded
undocumented /app/tasks/partials/task/:task_id/expanded
task_id
string · path
/app/tasks/partials/task/example/expanded
/app/tasks/partials/forms/new-board
undocumented /app/tasks/partials/forms/new-board
/app/tasks/partials/forms/new-board
/app/tasks/partials/forms/new-task
undocumented /app/tasks/partials/forms/new-task
/app/tasks/partials/forms/new-task
/app/tasks/partials/board/:board_id/tab
undocumented /app/tasks/partials/board/:board_id/tab
board_id
string · path
/app/tasks/partials/board/example/tab
/app/tasks/partials/board/:board_id/lane-settings
undocumented /app/tasks/partials/board/:board_id/lane-settings
board_id
string · path
/app/tasks/partials/board/example/lane-settings
/app/tasks/partials/board/:board_id/settings
undocumented /app/tasks/partials/board/:board_id/settings
board_id
string · path
/app/tasks/partials/board/example/settings
/app/tasks/partials/forms/new-incubator-task
undocumented /app/tasks/partials/forms/new-incubator-task
/app/tasks/partials/forms/new-incubator-task
/app/tasks/partials/forms/new-schedule
undocumented /app/tasks/partials/forms/new-schedule
/app/tasks/partials/forms/new-schedule
/app/tasks/partials/schedule/:schedule_id
undocumented /app/tasks/partials/schedule/:schedule_id
Schedule detail card (core/details) + linked tasks.
schedule_id
string · path
/app/tasks/partials/schedule/example
/app/tasks/partials/wiki/:task_id
undocumented /app/tasks/partials/wiki/:task_id
Detail card (core/details) for previewing and editing a task's wiki.
task_id
string · path
/app/tasks/partials/wiki/example
/app/tasks/partials/member-tasks
undocumented /app/tasks/partials/member-tasks
Side panel showing all tasks for a given assignee, with actions.
/app/tasks/partials/member-tasks
/app/wands/
undocumented /app/wands/
Overview dashboard — the app's landing page. All numbers arrive via the /wands/stats API (fetched by the page), so the handler stays thin.
/app/wands/
/app/wands/spells
undocumented /app/wands/spells
/app/wands/spells
/app/wands/spells/:spell_id
undocumented /app/wands/spells/:spell_id
spell_id
string · path
/app/wands/spells/example
/app/wands/macros
undocumented /app/wands/macros
/app/wands/macros
/app/wands/runs
undocumented /app/wands/runs
/app/wands/runs
/app/wands/partials/spells
undocumented /app/wands/partials/spells
/app/wands/partials/spells
/app/wands/partials/spells/:spell_id
undocumented /app/wands/partials/spells/:spell_id
spell_id
string · path
/app/wands/partials/spells/example
/app/wands/partials/spells/:spell_id/builder
undocumented /app/wands/partials/spells/:spell_id/builder
spell_id
string · path
/app/wands/partials/spells/example/builder
/app/wands/partials/spells/:spell_id/runs
undocumented /app/wands/partials/spells/:spell_id/runs
spell_id
string · path
/app/wands/partials/spells/example/runs
/app/wands/partials/run/:run_id
undocumented /app/wands/partials/run/:run_id
run_id
string · path
/app/wands/partials/run/example
/app/wands/partials/macros
undocumented /app/wands/partials/macros
/app/wands/partials/macros
/app/wands/partials/forms/new-spell
undocumented /app/wands/partials/forms/new-spell
/app/wands/partials/forms/new-spell
/app/wiki/
undocumented /app/wiki/
GET /app/wiki/ — main wiki page with sidebar tree + editor area.
/app/wiki/
/app/wiki/page/:page_id
undocumented /app/wiki/page/:page_id
GET /app/wiki/page/:page_id — view a specific page.
page_id
string · path
/app/wiki/page/example
/app/wiki/partials/tree
undocumented /app/wiki/partials/tree
GET /app/wiki/partials/tree — page tree sidebar.
/app/wiki/partials/tree
/app/wiki/partials/page/:page_id
undocumented /app/wiki/partials/page/:page_id
GET /app/wiki/partials/page/:page_id — page content area.
page_id
string · path
/app/wiki/partials/page/example
/app/wiki/partials/page/:page_id/comments
undocumented /app/wiki/partials/page/:page_id/comments
GET /app/wiki/partials/page/:page_id/comments — comments panel.
page_id
string · path
/app/wiki/partials/page/example/comments
/app/wiki/partials/page/:page_id/versions
undocumented /app/wiki/partials/page/:page_id/versions
GET /app/wiki/partials/page/:page_id/versions — version history panel.
page_id
string · path
/app/wiki/partials/page/example/versions
/app/wiki/partials/page/:page_id/breadcrumbs
undocumented /app/wiki/partials/page/:page_id/breadcrumbs
GET /app/wiki/partials/page/:page_id/breadcrumbs — breadcrumb trail.
page_id
string · path
/app/wiki/partials/page/example/breadcrumbs
/app/workers/
undocumented /app/workers/
The Workers landing — the self-service portal (specs/app-access-and-portals.md). Everyone with app access lands here. Holders of workers.portal.view get the portal (their own profile card plus squares per their capabilities, and an "Enter HRIS console" button for HR staff). Members without the key get the request-access wall instead of a dead end. Deliberately has no AUTHZ entry: the branching IS the gate; app access still applies upstream.
/app/workers/
/app/workers/directory
undocumented /app/workers/directory
Workers directory — MicroTable fetches data via API.
/app/workers/directory
/app/workers/colleagues
undocumented /app/workers/colleagues
Portal-side colleague directory: read-only cards with directory-grade fields only (name, title, department, work contact). Deliberately NOT the console workers table — that is an HR management surface. Inline cards, no click-through (specs/app-access-and-portals.md).
/app/workers/colleagues
/app/workers/workers/:worker_id
undocumented /app/workers/workers/:worker_id
Single worker profile page.
worker_id
string · path
/app/workers/workers/example
/app/workers/departments
undocumented /app/workers/departments
Departments list with hierarchy.
/app/workers/departments
/app/workers/departments/:department_id
undocumented /app/workers/departments/:department_id
Single department — workers, head, description.
department_id
string · path
/app/workers/departments/example
/app/workers/org-chart
undocumented /app/workers/org-chart
Organisational chart — tree view built from workers.manager_id.
/app/workers/org-chart
/app/workers/checklists
undocumented /app/workers/checklists
All checklist templates — filterable by type, with workflow analytics.
/app/workers/checklists
/app/workers/checklists/:checklist_id
undocumented /app/workers/checklists/:checklist_id
Single checklist template — items, auto-assign settings, and assignments.
checklist_id
string · path
/app/workers/checklists/example
/app/workers/compensation
undocumented /app/workers/compensation
Aggregate compensation view across all workers.
/app/workers/compensation
/app/workers/fields
undocumented /app/workers/fields
Custom profile fields admin — definitions grouped into profile sections.
/app/workers/fields
/app/workers/reports
undocumented /app/workers/reports
People analytics — headcount trend, joiners vs leavers, attrition, tenure, upcoming people dates, composition breakdowns, payroll by team.
/app/workers/reports
/app/workers/attendance
undocumented /app/workers/attendance
Attendance reconciliation — present / absent / on-leave per worker for a week. The visible week follows ?date=YYYY-MM-DD (defaults to today). Reads the worker_attendance_index projection (populated by events.py from system.attendance.* + core.leaves.pto.*). Absence is *derived* at read time for elapsed working days with no row, using each worker's location timezone and working days (attendance_location_index). No writes here: rule 5.
/app/workers/attendance
/app/workers/hours
undocumented /app/workers/hours
Payable-hours report — worked time split into payable / off-hours / off-day. For the selected month, each worker's closed punches (worker_punch_projection) are overlapped with their location's schedule (attendance_location_index: timezone, working days, work window) to separate payable time (inside the window on a working day) from off-schedule time. Derived at read time against the location's CURRENT schedule, so it self-heals if the schedule changes. No writes (rule 5). Historical punches from before this report existed populate as workers clock out; a one-off re-emit can backfill older sessions.
/app/workers/hours
/app/workers/locations
undocumented /app/workers/locations
Work locations management — timezone + working days per site. Chrome only: the table runs client-side against the core /attendance/locations API (admin-gated writes); create/edit use the standard platform form drawer (new_location_form / edit_location_form). The Workers projection (attendance_location_index) is updated via events, not from here. See specs/attendance-locations.md.
/app/workers/locations
/app/workers/partials/attendance-calendar
undocumented /app/workers/partials/attendance-calendar
Mini-month calendar popover for the Attendance week picker. ?date= keeps the selected week highlighted; ?cal=YYYY-MM browses months without leaving the popover (month arrows swap only this fragment).
/app/workers/partials/attendance-calendar
/app/workers/partials/worker-list
undocumented /app/workers/partials/worker-list
Filtered worker list partial.
/app/workers/partials/worker-list
/app/workers/partials/workers/:worker_id
undocumented /app/workers/partials/workers/:worker_id
Single worker card partial.
worker_id
string · path
/app/workers/partials/workers/example
/app/workers/partials/department-list
undocumented /app/workers/partials/department-list
Department list partial.
/app/workers/partials/department-list
/app/workers/partials/department/:department_id
undocumented /app/workers/partials/department/:department_id
Single department detail partial.
department_id
string · path
/app/workers/partials/department/example
/app/workers/partials/org-chart
undocumented /app/workers/partials/org-chart
Org chart tree partial — for HTMX refresh.
/app/workers/partials/org-chart
/app/workers/partials/forms/new-worker
undocumented /app/workers/partials/forms/new-worker
New worker form — rendered as platform form drawer.
/app/workers/partials/forms/new-worker
/app/workers/partials/forms/new-department
undocumented /app/workers/partials/forms/new-department
New department form — rendered as platform form drawer.
/app/workers/partials/forms/new-department
/app/workers/partials/forms/new-checklist
undocumented /app/workers/partials/forms/new-checklist
New checklist template form — rendered as platform form drawer.
/app/workers/partials/forms/new-checklist
/app/workers/partials/forms/assign-checklist
undocumented /app/workers/partials/forms/assign-checklist
Assign a checklist to a worker — rendered as platform form drawer.
/app/workers/partials/forms/assign-checklist
/app/workers/partials/forms/checklist-responsible
undocumented /app/workers/partials/forms/checklist-responsible
Assign-responsible modal for a checklist assignment, PUT to the worker-specific assignment, pre-selecting the current responsible worker.
/app/workers/partials/forms/checklist-responsible
/app/workers/partials/compensation/:worker_id
undocumented /app/workers/partials/compensation/:worker_id
Compensation detail card (core/details) for one worker.
worker_id
string · path
/app/workers/partials/compensation/example
/app/workers/partials/forms/new-compensation
undocumented /app/workers/partials/forms/new-compensation
New compensation form — rendered as platform form drawer.
/app/workers/partials/forms/new-compensation
/app/workers/partials/forms/nested-compensation
undocumented /app/workers/partials/forms/nested-compensation
Add the first compensation package for a worker (nested form, level 2).
/app/workers/partials/forms/nested-compensation
/app/workers/partials/forms/edit-compensation
undocumented /app/workers/partials/forms/edit-compensation
Edit the current package — saves a NEW effective-dated version, pre-filled from the current one. Never overwrites: the prior record stays as history.
/app/workers/partials/forms/edit-compensation
/app/workers/partials/forms/new-employment
undocumented /app/workers/partials/forms/new-employment
Add an employment record (contract/role period) for a worker.
/app/workers/partials/forms/new-employment
/app/workers/partials/forms/edit-employment
undocumented /app/workers/partials/forms/edit-employment
Edit an existing employment record, pre-filled from the stored record.
/app/workers/partials/forms/edit-employment
/app/workers/partials/forms/terminate-worker
undocumented /app/workers/partials/forms/terminate-worker
Terminate a worker's employment — closes all open/upcoming contracts.
/app/workers/partials/forms/terminate-worker
/app/workers/partials/forms/new-location
undocumented /app/workers/partials/forms/new-location
Add-location drawer — standard platform form posting to the attendance API.
/app/workers/partials/forms/new-location
/app/workers/partials/forms/edit-location
undocumented /app/workers/partials/forms/edit-location
Edit-location drawer. Prefill values are echoed from the row the page already loaded client-side (this page is chrome over the attendance API), so there is no DB read here — which also keeps the Workers app off the attendance-owned table.
/app/workers/partials/forms/edit-location
/app/workers/partials/forms/edit-personal
undocumented /app/workers/partials/forms/edit-personal
Edit personal details drawer — pre-filled from workers.personal.
/app/workers/partials/forms/edit-personal
/app/workers/partials/forms/edit-bank
undocumented /app/workers/partials/forms/edit-bank
Edit bank details drawer — flat fields only (identifiers have their own editor in the profile section).
/app/workers/partials/forms/edit-bank
/app/workers/partials/forms/field-definition
undocumented /app/workers/partials/forms/field-definition
Create/edit a custom profile field — custom drawer (needs the per-line options editor and an immutable type on edit, which the form system can't express; mirrors the nested_compensation_form precedent).
/app/workers/partials/forms/field-definition
/app/lobby/
undocumented /app/lobby/
GET/POST /app/lobby/, the workspace home dashboard.
/app/lobby/
/app/mail/
undocumented /app/mail/
Main mail screen. Renders the not-configured landing until the workspace has a domain or a connected account; otherwise the three-pane client.
/app/mail/
/app/mail/settings
undocumented /app/mail/settings
Admin: email hosting — add a domain, view DNS to publish, provision mailboxes, manage group mailboxes + the wildcard catch-all. Renders the same SPA on its settings view (deep-link target).
/app/mail/settings
/app/calls/
undocumented /app/calls/
/app/calls/
/app/chat/
undocumented /app/chat/
Main chat view — chat list sidebar plus message area.
/app/chat/
/app/contacts/
undocumented /app/contacts/
Dashboard — a MicroDash board. The page is a shell; every figure comes from GET /contacts/dashboard so the board can refresh without a reload.
/app/contacts/
/app/crm/
undocumented /app/crm/
The CRM home: a MicroDash widget board, role-branched manager/rep. Layout, widget choice, and every number are client-side; the server only stamps what the board needs to know before it can fetch (role, the default pipeline for the funnel widget, and the currency rollups are shown in).
/app/crm/
/app/crm/pipelines
undocumented /app/crm/pipelines
The pipelines card grid. Was the app landing page before the board.
/app/crm/pipelines
/app/crm/deals
undocumented /app/crm/deals
Global deal list: every deal in the workspace, no pipeline required. Pipelines and members are fetched client-side rather than stamped here: a name carrying an apostrophe would break the inline filter config.
/app/crm/deals
/app/crm/leads
undocumented /app/crm/leads
Leads: contacts in the lead lifecycle, ranked by score, from the projection.
/app/crm/leads
/app/crm/targets
undocumented /app/crm/targets
Workspace-level targets and the rep leaderboard. The old targets view lived inside one pipeline, which hid every workspace-wide quota and left the leaderboard endpoint with no UI at all.
/app/crm/targets
/app/crm/scoring
undocumented /app/crm/scoring
Lead and deal scoring rules. Wires the previously orphaned rule form.
/app/crm/scoring
/app/feeds/
undocumented /app/feeds/
Main feeds page — 3-column Twitter-like layout.
/app/feeds/
/app/files/
undocumented /app/files/
The Files landing page: a MicroDash board over /file-statistics. Nothing is queried here. The board fetches its own data so the widgets can show skeletons while it lands, and so a refresh after an upload is one API call rather than a page render.
/app/files/
/app/finance/
undocumented /app/finance/
/app/finance/
/app/growth/
undocumented /app/growth/
/app/growth/
/app/leaves/
undocumented /app/leaves/
Dashboard — balances, upcoming PTOs, pending approvals.
/app/leaves/
/app/settings/
undocumented /app/settings/
Account tab default view. The Lobby is the workspace home now; Account is a normal tab opened from a Lobby button, so its entry point lands on the member's own profile settings.
/app/settings/
/app/sign/
undocumented /app/sign/
Sign home: the insights dashboard. Backward compatibility: pre-sidenav deep links used /app/sign/?open={id}; those now land on the owning section (templates or contracts), which opens the builder.
/app/sign/
/app/tasks/
undocumented /app/tasks/
/app/tasks/
/app/wands/
undocumented /app/wands/
Overview dashboard — the app's landing page. All numbers arrive via the /wands/stats API (fetched by the page), so the handler stays thin.
/app/wands/
/app/workers/
undocumented /app/workers/
The Workers landing — the self-service portal (specs/app-access-and-portals.md). Everyone with app access lands here. Holders of workers.portal.view get the portal (their own profile card plus squares per their capabilities, and an "Enter HRIS console" button for HR staff). Members without the key get the request-access wall instead of a dead end. Deliberately has no AUTHZ entry: the branching IS the gate; app access still applies upstream.
/app/workers/
/app/lobby/
undocumented /app/lobby/
GET/POST /app/lobby/, the workspace home dashboard.
/app/lobby/
/applications/:slug/status
undocumented /applications/:slug/status
GET /accounts/apps/status/:slug — Check install status for a specific app.
slug
string · path
/applications/example/status
/applications/:slug/requests
undocumented /applications/:slug/requests
POST /applications/:slug/requests — Request app install (any authenticated member).
slug
string · path
/applications/example/requests
/apps/:slug/access
undocumented /apps/:slug/access
GET /apps/:slug/access — everything configured for one app, in one envelope: tile access, permission matrix, config document, and exception grants. The audit surface for "who can see what in this app".
slug
string · path
/apps/example/access
/apps/:slug/settings
undocumented /apps/:slug/settings
GET /apps/:slug/settings — the app's effective config document.
slug
string · path
/apps/example/settings
/applications/:slug/installations
Install app
POST /accounts/apps/install — Install an app (admin/owner only).
slug
string · path
access_policy
allowed_roles
array
propertyName
anything
/applications/example/installations
/applications/:slug/access-requests
Request access to restricted app
POST /apps/:slug/access-requests — Request access to a restricted app. Notifies all workspace admins (owner + admin roles). Mirrors the install- request flow (api_request_install) but for apps that ARE installed yet gated by access_policy='roles' the requester doesn't hold.
slug
string · path
message
string · max length: 280
propertyName
anything
/applications/example/access-requests
/applications/:slug/access
Set app access policy
Update which roles can reach an installed app. Body: {access_policy: "everyone"|"roles"|"approval", allowed_roles?: [role_id]} When access_policy is 'everyone' the allowed_roles list is cleared.
slug
string · path
access_policy
allowed_roles
array
redlist
array
propertyName
anything
/applications/example/access
/apps/:slug/roles/:role_id/permissions
Set one app's permission slice on a role
PUT /apps/:slug/roles/:role_id/permissions — replace ONE app's slice of a role's permissions. The only role-editing power an app admin has: other apps' slices, platform roles, and role membership are out of reach.
slug
string · path
role_id
string · path
permissions
array
propertyName
anything
/apps/example/roles/example/permissions
/apps/:slug/settings
undocumented /apps/:slug/settings
PUT /apps/:slug/settings — replace the app's config document. The body is the full document. It is validated against the pytastic schema the app registered via core.appconfig (rule 12's schema-first requirement is satisfied per-app; a static route schema is impossible for a surface whose shape each app defines).
slug
string · path
/apps/example/settings
/assets/*
undocumented /assets/*
/assets/*
/attendance/locations/:id
undocumented /attendance/locations/:id
Permanently delete a location. Workers assigned to it must be reassigned first (the Workers app handles that via its own reassignment endpoint, driven by the delete dialog). Here we just remove the row and emit .deleted so projections drop their copy.
id
string · path
/attendance/locations/example
/attendance/status
undocumented /attendance/status
/attendance/status
/attendance/entries
undocumented /attendance/entries
/attendance/entries
/attendance/timesheets
undocumented /attendance/timesheets
/attendance/timesheets
/attendance/timesheets/:id
undocumented /attendance/timesheets/:id
id
string · path
/attendance/timesheets/example
/attendance/timezones
undocumented /attendance/timezones
Friendly timezone search for the location form's picker. Searchable by city, US state, country, or zone (e.g. "houston", "texas", "port louis"). Returns {timezone, label}; the picker stores the IANA value and shows the label. Reference data only — no workspace scoping needed, but still requires an authenticated session. See core/timezones.py.
/attendance/timezones
/attendance/locations
undocumented /attendance/locations
/attendance/locations
/attendance/timesheets/:id
Update a timesheet
id
string · path
status
string · min length: 1 · max length: 20
propertyName
anything
/attendance/timesheets/example
/attendance/locations/:id
Update a location
id
string · path
name
string · min length: 1 · max length: 120
timezone
string · min length: 1 · max length: 64
workdays
work_start
string · max length: 5
work_end
string · max length: 5
is_default
propertyName
anything
/attendance/locations/example
/attendance/clock-ins
Clock in
note
string · max length: 500
source
string · max length: 50
propertyName
anything
/attendance/clock-ins
/attendance/clock-outs
Clock out
note
string · max length: 500
propertyName
anything
/attendance/clock-outs
/attendance/locations
Create a location
name
string · min length: 1 · max length: 120
timezone
string · min length: 1 · max length: 64
workdays
work_start
string · max length: 5
work_end
string · max length: 5
is_default
propertyName
anything
/attendance/locations
/audit
undocumented /audit
GET /audit — audit log feed page.
/audit
/sessions/links
Email a sign-in link
POST /sessions/links — mail proof of mailbox for one workspace. Always answers the same way. Whether the address exists, belongs to this workspace, or is a stranger's is not something an unauthenticated caller gets to learn: this endpoint would otherwise be a membership oracle for any workspace whose slug you can guess.
email
string · min length: 1 · email
workspace
string · min length: 1 · max length: 100
propertyName
anything
/sessions/links
/sessions
Sign in
POST /sessions — sign in. Three ways in, all landing on the same seat lookup and 2FA gate: * a password (`email` + `password` + `workspace`), * a confirmed link (`token`), * the fast path (`email` + `workspace`) for a caller already holding a live session for that identity, which mints and mails nothing. Whichever route, 2FA is asked for exactly once at the end, and only if the account has it. There is no mailed code: see core/magiclink.py for why.
email
string · min length: 1 · email
workspace
string · min length: 1 · max length: 100
password
string · min length: 1
token
string · min length: 1 · max length: 200
totp
string · min length: 6 · max length: 8
is_recovery_code
propertyName
anything
/sessions
/workspaces/lookup
Find a workspace by name
POST /workspaces/lookup — resolve a typed workspace name to its address. Unlike the sign-in endpoints this one DOES confirm existence, because a finder that refuses to say whether it found anything is not a finder. The exposure is small: a workspace slug is already its public subdomain, so this tells an enumerator nothing the DNS name does not. Rate limited by IP to keep that from being cheap at scale.
slug
string · min length: 1 · max length: 100
propertyName
anything
/workspaces/lookup
/workspaces
Sign up
company_name
string · min length: 1 · max length: 200
full_name
string · min length: 1 · max length: 200
email
string · min length: 1 · email
terms_agreed
company_location
string
industry
string
company_size
string
job_title
string
propertyName
anything
/workspaces
/verifications
Verify OTP
code
string · min length: 1
password
string · min length: 8
propertyName
anything
/verifications
/invitations/:token
Accept invitation
PUT /invitations/:token — Accept a workspace invitation and set a password. Acceptance flips the membership from "invited" to "joined", which is the gate `_seat` enforces on every sign-in afterwards. Holding the invitation mail already proves the mailbox, so the password chosen here is not a second proof: it is the credential for every sign-in after this one, so that getting in never depends on reaching a mailbox again.
token
string · path
password
string · min length: 8
totp
string · min length: 6 · max length: 8
propertyName
anything
/invitations/example
/avatars/:member_id
undocumented /avatars/:member_id
DELETE /avatars/:member_id — clear avatar, revert to initials.
member_id
string · path
/avatars/example
/avatars/:member_id
undocumented /avatars/:member_id
POST /avatars/:member_id — upload profile avatar to R2.
member_id
string · path
/avatars/example
/payment-methods
Add payment method
POST /accounts/billing/payment-methods — Add a payment method via Flutterwave v4.
card_number
string · min length: 13 · max length: 19
expiry_month
string · min length: 1 · max length: 2
expiry_year
string · min length: 2 · max length: 4
cvv
string · min length: 3 · max length: 4
propertyName
anything
/payment-methods
/plan
Switch plan
PUT /plan — Switch plan (tier or Per-App) immediately, with upgrade proration.
plan
propertyName
anything
/plan
/plan/interval
Update billing interval
PUT /plan/interval — Switch billing interval (monthly/annual). The live invoice loop reads the interval fresh on its next firing, so no loop surgery is needed for annual→monthly. Switching an ACTIVE workspace TO annual bills the year upfront now: an immediate 'seats' invoice.due is emitted, and the existing monthly loop converts itself to the usage loop when it next fires.
billing_interval
propertyName
anything
/plan/interval
/finance/bills/:entry_id
Receive/approve/void a bill
entry_id
string · path
status
propertyName
anything
/finance/bills/example
/finance/bills
Create a bill
date
string · min length: 10
items
array
company_mrn
string
contact_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
due_date
string · min length: 10
memo
string · max length: 5000
tags
array
sources
array
adjustments
array
dimensions
idempotency_key
string · max length: 100
propertyName
anything
/finance/bills
/finance/bills/:entry_id
Update a draft bill
entry_id
string · path
date
string · min length: 10
items
array
company_mrn
string
contact_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
due_date
string · min length: 10
memo
string · max length: 5000
tags
array
adjustments
array
dimensions
propertyName
anything
/finance/bills/example
/boards/:board_id/tasks/:task_id
undocumented /boards/:board_id/tasks/:task_id
Return a single task from the board to the incubator.
board_id
string · path
task_id
string · path
/boards/example/tasks/example
/boards/:board_id/tasks
undocumented /boards/:board_id/tasks
DELETE /boards/:board_id/tasks?scheduled=false — clear unplanned tasks from board.
board_id
string · path
/boards/example/tasks
/boards/:board_id
Delete a board
board_id
string · path
confirm_key
string · min length: 1
propertyName
anything
/boards/example
/boards/:board_id/members/:member_id
undocumented /boards/:board_id/members/:member_id
board_id
string · path
member_id
string · path
/boards/example/members/example
/boards
undocumented /boards
/boards
/boards/:board_id/members
undocumented /boards/:board_id/members
board_id
string · path
/boards/example/members
/boards/:board_id
Rename a topic
Rename a topic across all tasks in a board.
board_id
string · path
old_name
string · min length: 1
new_name
string · min length: 1
propertyName
anything
/boards/example
/boards/:board_id/columns
Rename a board column
Rename a board column (lane) and update all tasks referencing it.
board_id
string · path
old_name
string · min length: 1
new_name
string · min length: 1
propertyName
anything
/boards/example/columns
/boards/:board_id/members/:member_id
Change a project member's role
board_id
string · path
member_id
string · path
role
propertyName
anything
/boards/example/members/example
/boards
Create a board
title
string · min length: 1 · max length: 200
description
string · max length: 2000
template_id
string
is_template
grid
object
propertyName
anything
/boards
/boards/:board_id/tasks
Pull tasks onto a board
POST /boards/:board_id/tasks — pull tasks from incubator onto a board. Accepts either explicit task_ids or a schedule_id, exactly one. With schedule_id, every incubator task in that schedule is pulled at once.
board_id
string · path
task_ids
array
schedule_id
string
propertyName
anything
/boards/example/tasks
/boards/:board_id/members
Add a project member
board_id
string · path
member_id
string · min length: 1
role
propertyName
anything
/boards/example/members
/views
Save a board view
board_id
string
name
string · min length: 1 · max length: 80
tab
string · min length: 1 · max length: 40
schedule_id
string
propertyName
anything
/views
/boards/:board_id
Update board settings
Update board settings (name, description, columns).
board_id
string · path
title
string · min length: 1 · max length: 200
description
string · max length: 2000
grid
object
propertyName
anything
/boards/example
/finance/budgets/:budget_id
Update a budget
budget_id
string · path
account_id
string · min length: 1
period_start
string · min length: 10
period_end
string · min length: 10
amount
number
dimensions
object
notes
string · max length: 2000
propertyName
anything
/finance/budgets/example
/finance/budgets
Create a budget
account_id
string · min length: 1
period_start
string · min length: 10
period_end
string · min length: 10
amount
number
dimensions
object
notes
string · max length: 2000
propertyName
anything
/finance/budgets
/calls/:id
undocumented /calls/:id
id
string · path
/calls/example
/calls/:id/participants/:member_mrn
undocumented /calls/:id/participants/:member_mrn
id
string · path
member_mrn
string · path
/calls/example/participants/example
/calls/:id/sessions
undocumented /calls/:id/sessions
id
string · path
/calls/example/sessions
/calls/:id/recordings/:recording_id
undocumented /calls/:id/recordings/:recording_id
id
string · path
recording_id
string · path
/calls/example/recordings/example
/calls
undocumented /calls
/calls
/calls/:id
undocumented /calls/:id
id
string · path
/calls/example
/calls/:id/participants
undocumented /calls/:id/participants
id
string · path
/calls/example/participants
/calls/:id/admission
undocumented /calls/:id/admission
Poll endpoint for a member who knocked under the lobby policy. Mirrors the guest admission poll. Returns one of: - {state: 'waiting'} — host hasn't decided yet - {state: 'denied'} — host declined - {state: 'admitted'} — host let them in; the member then navigates to the room, where api_join_call mints their LK token - {state: 'idle'} — no pending knock for this member
id
string · path
/calls/example/admission
/calls/:id/links
undocumented /calls/:id/links
id
string · path
/calls/example/links
/calls/:id/messages
undocumented /calls/:id/messages
id
string · path
/calls/example/messages
/calls/:id/recordings
undocumented /calls/:id/recordings
id
string · path
/calls/example/recordings
/calls/:id
Update a call
id
string · path
title
string · max length: 200
scheduled_at
string
status
format
access_policy
settings
object
attendees_can_mic
attendees_can_camera
attendees_can_screenshare
attendees_can_chat
hide_attendee_tiles
propertyName
anything
/calls/example
/calls
Create a call
type
mode
format
title
string · max length: 200
participants
array
source_mrn
string
scheduled_at
string
max_participants
integer · min: 2 · max: 200
access_policy
settings
object
external_invitees_text
string · max length: 4000
propertyName
anything
/calls
/calls/:id/sessions
undocumented /calls/:id/sessions
id
string · path
/calls/example/sessions
/calls/:id/sessions/leave
undocumented /calls/:id/sessions/leave
id
string · path
/calls/example/sessions/leave
/calls/:id/token
undocumented /calls/:id/token
Mint a fresh LiveKit token for a call the member is already in. Used by the client's proactive refresh timer before the current token's `exp` kicks in. No side effects — does not update participant status or emit events.
id
string · path
/calls/example/token
/calls/:id/recordings/:recording_id/parts
undocumented /calls/:id/recordings/:recording_id/parts
Receive one chunk of an in-progress recording and stream it into R2 as a multipart part. Binary multipart body (not JSON). Host-only. The server holds at most one part (~8 MiB) in memory, so even long recordings never balloon it.
id
string · path
recording_id
string · path
/calls/example/recordings/example/parts
/chats/:id/call-requests
Request a call from chat
POST /chats/:id/call-requests — ask the Calls app to start a call.
id
string · path
mode
propertyName
anything
/chats/example/call-requests
/calls/:call_id
undocumented /calls/:call_id
call_id
string · path
/calls/example
/canvas/boards/:board_id
undocumented /canvas/boards/:board_id
DELETE /canvas/boards/:board_id — soft-delete + drop grants (owner only).
board_id
string · path
/canvas/boards/example
/canvas/boards/:board_id/comments/:comment_id
undocumented /canvas/boards/:board_id/comments/:comment_id
DELETE /canvas/boards/:board_id/comments/:comment_id — author or board manager.
board_id
string · path
comment_id
string · path
/canvas/boards/example/comments/example
/canvas/boards/:board_id/vote-sessions/:session_id/votes/:object_id
undocumented /canvas/boards/:board_id/vote-sessions/:session_id/votes/:object_id
DELETE /canvas/boards/:board_id/vote-sessions/:session_id/votes/:object_id. Takes back ONE of the caller's votes on that object (a session that allows repeats can hold several), and only ever their own.
board_id
string · path
session_id
string · path
object_id
string · path
/canvas/boards/example/vote-sessions/example/votes/example
/canvas/boards/:board_id/exports/:target
undocumented /canvas/boards/:board_id/exports/:target
DELETE /canvas/boards/:board_id/exports/:target — take this board's saved exports back out of Files. Files refuses to delete anything Canvas owns, so removing an export has to happen here, in the app that put it there.
board_id
string · path
target
string · path
/canvas/boards/example/exports/example
/canvas/boards
undocumented /canvas/boards
GET /canvas/boards — boards the caller can access. ?is_template=true filters templates.
/canvas/boards
/canvas/templates
undocumented /canvas/templates
GET /canvas/templates — sugar for ?is_template=true.
/canvas/templates
/canvas/boards/:board_id
undocumented /canvas/boards/:board_id
GET /canvas/boards/:board_id — board metadata (no content).
board_id
string · path
/canvas/boards/example
/canvas/boards/:board_id/content
undocumented /canvas/boards/:board_id/content
GET /canvas/boards/:board_id/content — opaque board content to bootstrap the client.
board_id
string · path
/canvas/boards/example/content
/canvas/boards/:board_id/comments
undocumented /canvas/boards/:board_id/comments
GET /canvas/boards/:board_id/comments — threaded comments for a board.
board_id
string · path
/canvas/boards/example/comments
/canvas/boards/:board_id/vote-sessions
undocumented /canvas/boards/:board_id/vote-sessions
GET /canvas/boards/:board_id/vote-sessions — history, newest first.
board_id
string · path
/canvas/boards/example/vote-sessions
/canvas/boards/:board_id/vote-sessions/:session_id
undocumented /canvas/boards/:board_id/vote-sessions/:session_id
GET /canvas/boards/:board_id/vote-sessions/:session_id — one session + counts.
board_id
string · path
session_id
string · path
/canvas/boards/example/vote-sessions/example
/canvas/boards/:board_id
Update a board
PATCH /canvas/boards/:board_id — title, description, grid settings.
board_id
string · path
title
string · min length: 1 · max length: 200
description
string · max length: 2000
grid
object
propertyName
anything
/canvas/boards/example
/canvas/boards/:board_id/content
Save board content
PATCH /canvas/boards/:board_id/content — persist the (debounced) content snapshot.
board_id
string · path
ydoc_state
string · min length: 1
thumbnail_key
string · max length: 512
restore_snapshot_id
string
asset_ids
array
propertyName
anything
/canvas/boards/example/content
/canvas/boards/:board_id/comments/:comment_id
Edit/resolve a comment
PATCH /canvas/boards/:board_id/comments/:comment_id — edit body (author) or resolve.
board_id
string · path
comment_id
string · path
body
string · min length: 1 · max length: 4000
resolved
propertyName
anything
/canvas/boards/example/comments/example
/canvas/boards/:board_id/vote-sessions/:session_id
Close a vote session
PATCH /canvas/boards/:board_id/vote-sessions/:session_id — close the round. Closing freezes the tally into `results` so history survives the board being edited afterwards, and stops badges reading from a session nobody is in.
board_id
string · path
session_id
string · path
status
object_labels
array
propertyName
anything
/canvas/boards/example/vote-sessions/example
/canvas/boards
Create a board
POST /canvas/boards — create a board (optionally cloned from a template).
title
string · min length: 1 · max length: 200
description
string · max length: 2000
template_id
string
is_template
grid
object
propertyName
anything
/canvas/boards
/canvas/boards/:board_id/duplications
undocumented /canvas/boards/:board_id/duplications
POST /canvas/boards/:board_id/duplications — copy a board (or instantiate a template).
board_id
string · path
/canvas/boards/example/duplications
/canvas/boards/:board_id/assets
Register a board image
POST /canvas/boards/:board_id/assets — register an uploaded board image. Called by the editor right after the platform upload confirm so the asset is servable immediately, instead of waiting on the upload-confirmed event round trip. The event handler in events.py remains the idempotent backup.
board_id
string · path
asset_id
string · min length: 6 · max length: 64
storage_key
string · min length: 1 · max length: 512
filename
string · min length: 1 · max length: 255
content_type
string · min length: 1 · max length: 100
size_bytes
integer · min: 0
width
integer · min: 0
height
integer · min: 0
propertyName
anything
/canvas/boards/example/assets
/canvas/boards/:board_id/comments
Add a comment
POST /canvas/boards/:board_id/comments — add a comment.
board_id
string · path
body
string · min length: 1 · max length: 4000
object_id
string · max length: 64
parent_id
string · max length: 64
nx
number
ny
number
propertyName
anything
/canvas/boards/example/comments
/canvas/boards/:board_id/vote-sessions
Start a vote session
POST /canvas/boards/:board_id/vote-sessions — open a round of dot voting.
board_id
string · path
label
string · max length: 120
max_votes_per_member
integer · min: 1 · max: 99
allow_repeat_votes
scope_frame_id
string · max length: 64
scope_ids
array
propertyName
anything
/canvas/boards/example/vote-sessions
/canvas/boards/:board_id/vote-sessions/:session_id/votes
Cast a vote
POST /canvas/boards/:board_id/vote-sessions/:session_id/votes — spend one vote.
board_id
string · path
session_id
string · path
object_id
string · min length: 1 · max length: 64
propertyName
anything
/canvas/boards/example/vote-sessions/example/votes
/canvas/boards/:board_id/exports
Export a board
POST /canvas/boards/:board_id/exports — download is client-side; target=files persists the client-rendered image to R2 and emits an event Files ingests.
board_id
string · path
format
target
data_url
string · min length: 1
filename
string · max length: 200
propertyName
anything
/canvas/boards/example/exports
/chats/:id
Update a chat
PATCH /chats/:id — update group name, description, or avatar.
id
string · path
name
string · max length: 100
description
string · max length: 500
avatar_key
string
propertyName
anything
/chats/example
/chats
Create a chat
POST /chats — create a conversation.
type
name
string · min length: 1 · max length: 100
description
string · max length: 500
participants
array
propertyName
anything
/chats
/chats/:id
undocumented /chats/:id
DELETE /chats/:id — delete a conversation. For a DM this is per-member: it clears the chat from the caller's own view only, leaving the other participant's copy and history intact. The chat reappears for them if a new message arrives, showing only the post-delete history. For a group it removes the conversation for everyone, so it needs the in-chat admin role or the workspace-wide manage override.
id
string · path
/chats/example
/chats/:id/messages
undocumented /chats/:id/messages
DELETE /chats/:id/messages — clear the conversation for the caller only.
id
string · path
/chats/example/messages
/chats/:id/messages/:msg_id
undocumented /chats/:id/messages/:msg_id
DELETE /chats/:id/messages/:msg_id — soft-delete a message.
id
string · path
msg_id
string · path
/chats/example/messages/example
/chats/:id/messages/:msg_id/reactions/:emoji
undocumented /chats/:id/messages/:msg_id/reactions/:emoji
DELETE /chats/:id/messages/:msg_id/reactions/:emoji — remove a reaction.
id
string · path
msg_id
string · path
emoji
string · path
/chats/example/messages/example/reactions/example
/chats/:id/participants/:member_mrn
undocumented /chats/:id/participants/:member_mrn
DELETE /chats/:id/participants/:member_mrn — remove from a group, or leave.
id
string · path
member_mrn
string · path
/chats/example/participants/example
/chats/lists/:list_id
undocumented /chats/lists/:list_id
DELETE /chats/lists/:list_id — delete a personal list. chat_list_items.list_id cascades, so memberships go with it instead of lingering as tags pointing at a list that no longer exists.
list_id
string · path
/chats/lists/example
/chats/:id/favourite
undocumented /chats/:id/favourite
DELETE /chats/:id/favourite — remove the favourite mark (per-user).
id
string · path
/chats/example/favourite
/chats/:id/lists/:list_id
undocumented /chats/:id/lists/:list_id
DELETE /chats/:id/lists/:list_id — remove the chat from one of the lists.
id
string · path
list_id
string · path
/chats/example/lists/example
/chats
undocumented /chats
GET /chats — the caller's conversations, newest first.
/chats
/chats/:id
undocumented /chats/:id
GET /chats/:id — conversation details.
id
string · path
/chats/example
/chats/:id/messages
undocumented /chats/:id/messages
GET /chats/:id/messages — messages in a conversation.
id
string · path
/chats/example/messages
/chats/:id/messages/:msg_id/receipts
undocumented /chats/:id/messages/:msg_id/receipts
GET /chats/:id/messages/:msg_id/receipts — who has read a message.
id
string · path
msg_id
string · path
/chats/example/messages/example/receipts
/chats/:id/participants
undocumented /chats/:id/participants
GET /chats/:id/participants — list participants.
id
string · path
/chats/example/participants
/chats/lists
undocumented /chats/lists
GET /chats/lists — the caller's personal chat lists, ordered.
/chats/lists
/chats/:id/read
undocumented /chats/:id/read
PUT /chats/:id/read — mark a conversation as read.
id
string · path
/chats/example/read
/chats/:id/favourite
undocumented /chats/:id/favourite
PUT /chats/:id/favourite — mark the chat as a favourite (per-user).
id
string · path
/chats/example/favourite
/chats/:id/lists/:list_id
undocumented /chats/:id/lists/:list_id
PUT /chats/:id/lists/:list_id — add the chat to one of the caller's lists.
id
string · path
list_id
string · path
/chats/example/lists/example
/checklists/:checklist_id/workers/:worker_id/items/:item_id
Toggle an assignment item
checklist_id
string · path
worker_id
string · path
item_id
string · path
completed
propertyName
anything
/checklists/example/workers/example/items/example
/checklists/:checklist_id/workers
Assign a checklist to a worker
checklist_id
string · path
worker_id
string · min length: 1
due_date
string
anchor_date
string · max length: 10
responsible_worker_id
string
propertyName
anything
/checklists/example/workers
/checklists/:checklist_id/workers/:worker_id
Update assignment status
checklist_id
string · path
worker_id
string · path
status
due_date
string
anchor_date
string · max length: 10
responsible_worker_id
string
propertyName
anything
/checklists/example/workers/example
/checklists/:checklist_id
undocumented /checklists/:checklist_id
checklist_id
string · path
/checklists/example
/checklists/:checklist_id/workers/:worker_id
undocumented /checklists/:checklist_id/workers/:worker_id
checklist_id
string · path
worker_id
string · path
/checklists/example/workers/example
/checklists
undocumented /checklists
/checklists
/checklists/:checklist_id
undocumented /checklists/:checklist_id
checklist_id
string · path
/checklists/example
/checklists/:checklist_id/workers
undocumented /checklists/:checklist_id/workers
checklist_id
string · path
/checklists/example/workers
/checklists
Create a checklist template
type
title
string · min length: 1 · max length: 200
items
array
auto_assign
object
propertyName
anything
/checklists
/checklists/:checklist_id
Update a checklist template
checklist_id
string · path
title
string · min length: 1 · max length: 200
type
items
array
auto_assign
object
propertyName
anything
/checklists/example
/companies/:company_id
undocumented /companies/:company_id
DELETE /companies/:company_id — delete company (fails if contacts still linked).
company_id
string · path
/companies/example
/companies
undocumented /companies
GET /companies — list companies with filters.
/companies
/companies/:company_id
undocumented /companies/:company_id
GET /companies/:company_id — get company with contacts and recent interactions.
company_id
string · path
/companies/example
/companies/:company_id/interactions
undocumented /companies/:company_id/interactions
GET /companies/:company_id/interactions — interactions for a company (across all contacts).
company_id
string · path
/companies/example/interactions
/companies
Create a company
POST /companies — create a company.
name
string · min length: 1 · max length: 200
domain
string · max length: 200
industry
string · max length: 100
size
website
string · max length: 500
address
string · max length: 500
phone
string · max length: 50
annual_revenue
string · max length: 50
tags
array
owner_mrn
string
notes
string · max length: 5000
propertyName
anything
/companies
/companies/:company_id
Update a company
PUT /companies/:company_id — update a company.
company_id
string · path
name
string · min length: 1 · max length: 200
domain
string · max length: 200
industry
string · max length: 100
size
website
string · max length: 500
address
string · max length: 500
phone
string · max length: 50
annual_revenue
string · max length: 50
tags
array
owner_mrn
string
notes
string · max length: 5000
propertyName
anything
/companies/example
/compensation/:compensation_id
undocumented /compensation/:compensation_id
compensation_id
string · path
/compensation/example
/compensation
undocumented /compensation
All workers with their latest compensation record.
/compensation
/compensation/changes
undocumented /compensation/changes
Recent compensation changes across all workers.
/compensation/changes
/workers/:worker_id/compensation
Add compensation record
worker_id
string · path
effective_date
string · min length: 1
items
array
reason
string · max length: 500
notes
string · max length: 2000
propertyName
anything
/workers/example/compensation
/contacts/suggestions/:suggestion_id
undocumented /contacts/suggestions/:suggestion_id
DELETE /contacts/suggestions/:suggestion_id — drop a suggestion outright.
suggestion_id
string · path
/contacts/suggestions/example
/contacts/:contact_id
undocumented /contacts/:contact_id
DELETE /contacts/:contact_id — delete a contact with soft warning if MRN-referenced.
contact_id
string · path
/contacts/example
/contacts
undocumented /contacts
GET /contacts — list contacts with filters.
/contacts
/contacts/search
undocumented /contacts/search
GET /contacts/search — unified search across contacts and companies.
/contacts/search
/contacts/suggestions
undocumented /contacts/suggestions
GET /contacts/suggestions — the pending review queue, most active first.
/contacts/suggestions
/contacts/dashboard
undocumented /contacts/dashboard
GET /contacts/dashboard — everything the board renders, in one round trip. Every figure is aggregated in SQL rather than by counting serialized rows, so a workspace with fifty thousand contacts still renders a dashboard. The kit only ever fetches members and preferences itself; app data comes from here (specs/dashboard-kit.md, rule 1).
/contacts/dashboard
/contacts/exports
undocumented /contacts/exports
GET /contacts/exports — CSV of contacts or companies, filters applied. The same filters the directory is showing, so what downloads is what the person is looking at rather than the whole table.
/contacts/exports
/contacts/duplicates
undocumented /contacts/duplicates
GET /contacts/duplicates — merge candidates, worth-a-look first. Two cheap heuristics, both from the spec: the same name under different addresses, and the same address differing only in casing. No fuzzy matching: a wrong suggestion here costs somebody a destructive merge.
/contacts/duplicates
/contacts/settings
undocumented /contacts/settings
GET /contacts/settings — named embed configurations and snippets.
/contacts/settings
/contacts/:contact_id
undocumented /contacts/:contact_id
GET /contacts/:contact_id — get contact with company info and recent interactions.
contact_id
string · path
/contacts/example
/contacts/:contact_id/interactions
undocumented /contacts/:contact_id/interactions
GET /contacts/:contact_id/interactions — interactions for a contact.
contact_id
string · path
/contacts/example/interactions
/contacts/suggestions/:suggestion_id
Accept or dismiss a contact suggestion
PATCH /contacts/suggestions/:suggestion_id — accept or dismiss. ``accepted`` promotes the address to a real contact (with domain/company auto-link, as a manual create would) and clears the suggestion. ``dismissed`` hides it for good — the upsert keeps it dismissed thereafter.
suggestion_id
string · path
status
name
string · min length: 1 · max length: 200
company_id
string
propertyName
anything
/contacts/suggestions/example
/contacts
Create a contact
POST /contacts — create a contact with domain extraction and auto company linking.
name
string · min length: 1 · max length: 200
email
string · min length: 1 · max length: 200
phone
string · max length: 50
mobile
string · max length: 50
secondary_email
string · max length: 200
title
string · max length: 100
department
string · max length: 100
company_id
string
linkedin_url
string · max length: 500
website
string · max length: 500
social_url
string · max length: 500
address
string · max length: 500
tags
array
role
string · max length: 50
lifecycle_stage
preferred_channel
timezone
string · max length: 60
birthday
string · max length: 10
avatar_url
string · max length: 500
notes
string · max length: 5000
custom_fields
array
owner_mrn
string
source
propertyName
anything
/contacts
/contacts/imports
Import contacts from CSV
POST /contacts/imports — CSV import with a column mapping. Deduped by email: a row whose address already exists UPDATES that contact rather than creating a second one. That is the whole point. An import that silently doubles a directory is worse than one that refuses to run. Rows without a usable email are reported back rather than dropped silently, so the person importing can see exactly what did not land.
csv
string · min length: 1 · max length: 2000000
mappings
array
has_header
company_id
string
propertyName
anything
/contacts/imports
/contacts/settings/widget-keys
undocumented /contacts/settings/widget-keys
POST /contacts/settings/widget-keys — rotate the first embed's key. Kept for callers that predate named embeds. Prefer ``POST /contacts/settings/embeds/:embed_id/rotate-key``.
/contacts/settings/widget-keys
/contacts/settings/embeds/:embed_id/rotate-key
undocumented /contacts/settings/embeds/:embed_id/rotate-key
POST /contacts/settings/embeds/:embed_id/rotate-key — rotate one embed.
embed_id
string · path
/contacts/settings/embeds/example/rotate-key
/contacts/:contact_id/merges
Merge a duplicate into this contact
POST /contacts/:id/merges — fold a duplicate into this contact. The survivor keeps everything it already had; blanks fill from the duplicate. Interactions, conversations and timeline rows re-point, then the duplicate row is deleted and consuming apps are told to re-point their party projections. Deliberately not reversible, and deliberately not a soft delete: a tombstone row would keep the duplicate resolvable through every lookup that made it a problem in the first place.
contact_id
string · path
duplicate_id
string · min length: 1
propertyName
anything
/contacts/example/merges
/contacts/settings
Configure the website chat widget
PUT /contacts/settings — create or update named website chat embeds. Keys are never taken from the client. Enabling an embed for the first time mints one; rotation is its own endpoint.
embeds
array
widget
object
propertyName
anything
/contacts/settings
/contacts/:contact_id
Update a contact
PUT /contacts/:contact_id — update a contact.
contact_id
string · path
phone_number
string · max length: 50
street
string · max length: 300
city
string · max length: 100
state
string · max length: 100
postal_code
string · max length: 20
country
string · max length: 100
propertyName
anything
/contacts/example
/contacts/:contact_id/state
Override a contact's state
PUT /contacts/:id/state — a human overriding the derived face. Recorded as ``manual`` and labelled as such in the UI, because a state somebody typed and a state the evidence produced are different claims. It lasts until the next real signal, which then takes the wheel back.
contact_id
string · path
state
reason
string · max length: 200
propertyName
anything
/contacts/example/state
/conversations
undocumented /conversations
GET /conversations — the inbox. Filters: status, assignee_mrn, priority, contact_id, channel, q.
/conversations
/conversations/:conversation_id
undocumented /conversations/:conversation_id
GET /conversations/:id — the thread, including internal notes. This is a staff route behind contacts.conversations.view; internal notes are stripped only on the visitor-facing widget routes.
conversation_id
string · path
/conversations/example
/conversations/:conversation_id
Assign, prioritise or resolve a conversation
PATCH /conversations/:id — status, assignee, priority and tag moves. Resolution is the CSAT moment: it stamps resolved_at, logs the thread as a touchpoint on the contact, and tells the spawning surface to prompt for a rating.
conversation_id
string · path
status
priority
assignee_mrn
string · max length: 200
tags
array
contact_id
string · max length: 60
propertyName
anything
/conversations/example
/conversations/:conversation_id/messages
Reply in a conversation or add an internal note
POST /conversations/:id/messages — a staff reply, or an internal note. Any holder of contacts.conversations.manage may reply in any thread; assignee_mrn is ownership, never exclusivity. An internal note is stored and shown to colleagues but never emitted and never delivered to the visitor.
conversation_id
string · path
body
string · min length: 1 · max length: 10000
is_internal
propertyName
anything
/conversations/example/messages
/coupons/:code/redemptions
undocumented /coupons/:code/redemptions
POST /coupons/:code/redemptions — apply a coupon to the current workspace.
code
string · path
/coupons/example/redemptions
/finance/credit-notes/:entry_id
Issue/void credit note
entry_id
string · path
status
propertyName
anything
/finance/credit-notes/example
/finance/credit-notes
Create a credit note
date
string · min length: 10
items
array
source_entry_id
string · min length: 1
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
adjustments
array
dimensions
idempotency_key
string · max length: 100
propertyName
anything
/finance/credit-notes
/finance/credit-notes/:entry_id/allocations
Set credit against an invoice
entry_id
string · path
entry_id
string · min length: 1
amount
number
entry_amount
number
propertyName
anything
/finance/credit-notes/example/allocations
/finance/credit-notes/:entry_id/pdfs
Generate credit note PDF
entry_id
string · path
template
string · max length: 100
propertyName
anything
/finance/credit-notes/example/pdfs
/finance/credit-notes/:entry_id/sends
Email a credit note
entry_id
string · path
to
string · min length: 1 · max length: 500
cc
string · max length: 500
subject
string · max length: 300
message
string · max length: 5000
propertyName
anything
/finance/credit-notes/example/sends
/finance/credit-notes/:entry_id
Update a credit note
entry_id
string · path
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
adjustments
array
dimensions
propertyName
anything
/finance/credit-notes/example
/crm/leads
undocumented /crm/leads
/crm/leads
/crm/reports/pipeline
undocumented /crm/reports/pipeline
/crm/reports/pipeline
/crm/reports/performance
undocumented /crm/reports/performance
/crm/reports/performance
/crm/reports/forecast
undocumented /crm/reports/forecast
/crm/reports/forecast
/crm/reports/activity
undocumented /crm/reports/activity
Activity report: target progress per rep.
/crm/reports/activity
/crm/reports/funnel
undocumented /crm/reports/funnel
Stage entry counts + conversion, from the indexed timeline.
/crm/reports/funnel
/crm/reports/trends
undocumented /crm/reports/trends
Monthly won/lost counts and won value (grouped by currency), last 12 months.
/crm/reports/trends
/crm/reports/losses
undocumented /crm/reports/losses
Loss reasons breakdown (count + value by currency).
/crm/reports/losses
/deals/:deal_id
undocumented /deals/:deal_id
deal_id
string · path
/deals/example
/deals/:deal_id/line-items/:item_id
undocumented /deals/:deal_id/line-items/:item_id
deal_id
string · path
item_id
string · path
/deals/example/line-items/example
/deals/:deal_id/links/:link_id
undocumented /deals/:deal_id/links/:link_id
deal_id
string · path
link_id
string · path
/deals/example/links/example
/deals/:deal_id/attachments/:file_id
undocumented /deals/:deal_id/attachments/:file_id
deal_id
string · path
file_id
string · path
/deals/example/attachments/example
/deals/:deal_id/checklist-items/:item_id
undocumented /deals/:deal_id/checklist-items/:item_id
deal_id
string · path
item_id
string · path
/deals/example/checklist-items/example
/deals
undocumented /deals
Global deal list. pipeline_id is an optional filter, no longer mandatory.
/deals
/deals/:deal_id
undocumented /deals/:deal_id
deal_id
string · path
/deals/example
/deals/:deal_id/line-items
undocumented /deals/:deal_id/line-items
deal_id
string · path
/deals/example/line-items
/deals/:deal_id/links
undocumented /deals/:deal_id/links
deal_id
string · path
/deals/example/links
/deals/:deal_id/activities
undocumented /deals/:deal_id/activities
deal_id
string · path
/deals/example/activities
/deals/:deal_id/checklist-items
undocumented /deals/:deal_id/checklist-items
deal_id
string · path
/deals/example/checklist-items
/deals/:deal_id/stage
Move a deal to another stage
deal_id
string · path
stage_id
string · min length: 1
pipeline_id
string
loss_reason
string · max length: 1000
propertyName
anything
/deals/example/stage
/deals
Create a deal
pipeline_id
string
title
string · min length: 1 · max length: 300
value
number
currency
string
stage_id
string
contact_mrn
string
company_mrn
string
owner_mrn
string
expected_close_date
string
source
line_items
array
tags
array
propertyName
anything
/deals
/deals/:deal_id/line-items
Add a line item to a deal
deal_id
string · path
name
string · min length: 1 · max length: 200
product_mrn
string
quantity
number
unit_price
number
currency
string
period
propertyName
anything
/deals/example/line-items
/deals/:deal_id/links
Mint a deal room link for a customer
deal_id
string · path
label
string · max length: 200
propertyName
anything
/deals/example/links
/deals/:deal_id/attachments
Attach a shared file to the deal room
deal_id
string · path
mrn
string · min length: 15 · max length: 200
name
string · min length: 1 · max length: 300
url
string · min length: 1 · max length: 500
share_id
string · max length: 100
propertyName
anything
/deals/example/attachments
/deals/:deal_id/activities
Add a note to a deal
deal_id
string · path
content
string · min length: 1 · max length: 10000
propertyName
anything
/deals/example/activities
/deals/:deal_id/checklist-items
Add a checklist item to a deal
deal_id
string · path
label
string · min length: 1 · max length: 200
stage_id
string
assignee_mrn
string
due_date
string
propertyName
anything
/deals/example/checklist-items
/deals/:deal_id/quote-requests
Ask Finance to draft a quote from this deal
POST /deals/:deal_id/quote-requests. Emits deal.quote_requested; Finance drafts the quote from the line items (apps/finance/events.py).
deal_id
string · path
memo
string · max length: 2000
propertyName
anything
/deals/example/quote-requests
/deals/:deal_id
Update a deal
deal_id
string · path
title
string · min length: 1 · max length: 300
value
number
currency
string
contact_mrn
string
company_mrn
string
owner_mrn
string
expected_close_date
string
source
tags
array
loss_reason
string
proposal
string · max length: 100000
propertyName
anything
/deals/example
/deals/:deal_id/line-items/:item_id
Update a deal line item
deal_id
string · path
item_id
string · path
name
string · min length: 1 · max length: 200
product_mrn
string
quantity
number
unit_price
number
currency
string
period
position
integer
propertyName
anything
/deals/example/line-items/example
/deals/:deal_id/checklist-items/:item_id
Update a deal checklist item
deal_id
string · path
item_id
string · path
done
label
string · min length: 1 · max length: 200
assignee_mrn
string
due_date
string
position
integer
propertyName
anything
/deals/example/checklist-items/example
/decks/trash
undocumented /decks/trash
DELETE /decks/trash. Destroy every trashed deck the caller manages.
/decks/trash
/decks/trash/:id
undocumented /decks/trash/:id
DELETE /decks/trash/:id. Destroy a trashed deck. Gate loaded ctx.authz.deck.
id
string · path
/decks/trash/example
/decks/:id
undocumented /decks/:id
DELETE /decks/:id. Soft-delete. Grants stay so restore still works.
id
string · path
/decks/example
/decks
undocumented /decks
GET /decks. Decks the caller can access.
/decks
/decks/trash
undocumented /decks/trash
GET /decks/trash. Decks in the trash that the caller can restore.
/decks/trash
/decks/:id
undocumented /decks/:id
GET /decks/:id. Metadata + deck_json. Gate loaded ctx.authz.deck.
id
string · path
/decks/example
/decks/:id/assets
undocumented /decks/:id/assets
GET /decks/:id/assets. Images uploaded to this deck. Gate loaded ctx.authz.deck.
id
string · path
/decks/example/assets
/
undocumented /
/
/
undocumented /
GET / — admin dashboard with stats + tabbed workspace/invoice/thread lists.
/
/
undocumented /
/
/
undocumented /
GET / on workspace subdomain — render the shell with initial workscreen state.
/
/
undocumented /
Account tab default view. The Lobby is the workspace home now; Account is a normal tab opened from a Lobby button, so its entry point lands on the member's own profile settings.
/
/deliverables/:deliverable_id
undocumented /deliverables/:deliverable_id
Delete a deliverable. Linked tasks keep existing — their deliverable link clears via the ON DELETE SET NULL foreign key.
deliverable_id
string · path
/deliverables/example
/deliverables
undocumented /deliverables
GET /deliverables?board_id=...&q=... — list a board's deliverables.
/deliverables
/deliverables
Create a deliverable
board_id
string
name
string · min length: 1 · max length: 200
due_date
string · min length: 1
description
string · max length: 5000
status
schedule_id
string
owner_mrn
string
propertyName
anything
/deliverables
/deliverables/:deliverable_id
Update a deliverable
deliverable_id
string · path
name
string · min length: 1 · max length: 200
description
string · max length: 5000
due_date
string
status
schedule_id
string
owner_mrn
string
propertyName
anything
/deliverables/example
/demo-requests/availability
undocumented /demo-requests/availability
GET /demo-requests/availability — open demo slots for the next weekdays.
/demo-requests/availability
/departments/:department_id
undocumented /departments/:department_id
department_id
string · path
/departments/example
/departments
undocumented /departments
/departments
/departments/:department_id
undocumented /departments/:department_id
department_id
string · path
/departments/example
/departments/:department_id
Update a department
department_id
string · path
name
string · min length: 1 · max length: 100
description
string · max length: 1000
parent_id
string
head_mrn
string
propertyName
anything
/departments/example
/departments
Create a department
name
string · min length: 1 · max length: 100
description
string · max length: 1000
parent_id
string
head_mrn
string
propertyName
anything
/departments
/developers
undocumented /developers
Developer docs landing page.
/developers
/developers/:section
undocumented /developers/:section
Single-segment paths under /developers: the search index, or a section slug that redirects to the section's first page.
section
string · path
/developers/example
/developers/:section/:page
undocumented /developers/:section/:page
section
string · path
page
string · path
/developers/example/example
/finance/dimensions/:dimension_key
Update a dimension
dimension_key
string · path
name
string · min length: 1 · max length: 100
key
string · min length: 1 · max length: 50
values
array
propertyName
anything
/finance/dimensions/example
/finance/dimensions
Define a dimension
name
string · min length: 1 · max length: 100
key
string · min length: 1 · max length: 50
values
array
propertyName
anything
/finance/dimensions
/sign/envelopes/:envelope_id
Update document metadata
PATCH /sign/envelopes/:envelope_id — update metadata OR transition state (sent/voided).
envelope_id
string · path
title
string · min length: 1 · max length: 300
subject
string · max length: 300
message
string · max length: 2000
signing_order_mode
jurisdiction
string · max length: 10
expires_at
string
status
reason
string · max length: 1000
propertyName
anything
/sign/envelopes/example
/sign/envelopes
Create a draft document
POST /sign/envelopes — create a draft (optionally cloning ?template_id).
title
string · min length: 1 · max length: 300
subject
string · max length: 300
message
string · max length: 2000
template_id
string
signing_order_mode
jurisdiction
string · max length: 10
is_template
source_mrn
string · max length: 200
propertyName
anything
/sign/envelopes
/sign/envelopes/:envelope_id/documents
Append a source PDF to the envelope
POST /sign/envelopes/:envelope_id/documents {storage_key, title, page_count} — append a source PDF. The first add on a legacy envelope promotes its single PDF into a row, so an envelope is always pure-legacy or pure-rows.
envelope_id
string · path
storage_key
string · min length: 1 · max length: 500
title
string · max length: 300
page_count
integer
propertyName
anything
/sign/envelopes/example/documents
/sign/envelopes/:envelope_id/exports
Save sealed document to Files
POST /sign/envelopes/:envelope_id/exports {target:"files"} — copy the sealed PDF into the caller's Files. Sign never auto-mirrors; this explicit action is the only path.
envelope_id
string · path
target
propertyName
anything
/sign/envelopes/example/exports
/sign/envelopes/:envelope_id/source
Attach the uploaded source PDF
PUT /sign/envelopes/:envelope_id/source {storage_key, page_count} — attach the uploaded source PDF SYNCHRONOUSLY. The client calls this right after PUTting the file to R2, so the document is attached deterministically instead of depending on the async upload-confirmed event (which, if the event bus doesn't deliver it, leaves the PDF unattached forever). The key must live under this workspace's own sign/ prefix — a client can't point the envelope at another workspace's or app's object.
envelope_id
string · path
storage_key
string · min length: 1 · max length: 500
page_count
integer
propertyName
anything
/sign/envelopes/example/source
/sign/settings
Choose the contract template
PUT /sign/settings {contract_template_id}: choose the contract template. An empty value clears the choice, which switches the cross-app handoff off: requests then arrive and are ignored rather than drafting the wrong document. Written through the registered config contract so the platform Settings editor and this picker stay one document with one validator.
contract_template_id
string · max length: 64
propertyName
anything
/sign/settings
/elevations
undocumented /elevations
DELETE /elevations — leave admin mode without waiting for the timer.
/elevations
/elevations/current
undocumented /elevations/current
GET /elevations/current — the caller's window, for the shell's ring. `totp_enabled` says which factor the prompt should ask for, because only the server knows. Without it the modal had to guess, guessed password, and an account with TOTP paid for a password that api_start_elevation never even looks at before being asked for a code anyway. Having a second factor should cost fewer steps, not more.
/elevations/current
/workers/:worker_id/employment
Add an employment record
worker_id
string · path
job_title
string · min length: 1 · max length: 200
start_date
string · min length: 1 · max length: 10
employment_type
end_date
string · max length: 10
reason
string · max length: 500
reminder_enabled
reminder_days_before
integer
propertyName
anything
/workers/example/employment
/workers/:worker_id/employment/termination
Terminate a worker's employment
Terminate employment: close every open/future contract at the effective date, set status=terminated, and fire the terminated event. Reason is required.
worker_id
string · path
reason
string · min length: 1 · max length: 500
effective_date
string · min length: 1 · max length: 10
propertyName
anything
/workers/example/employment/termination
/workers/:worker_id/employment/:record_id
Update an employment record
worker_id
string · path
record_id
string · path
job_title
string · min length: 1 · max length: 200
employment_type
start_date
string · max length: 10
end_date
string · max length: 10
reason
string · max length: 500
reminder_enabled
reminder_days_before
integer
propertyName
anything
/workers/example/employment/example
/events/:action
undocumented /events/:action
Internal webhook receiver — Amebo delivers events here. Route: POST /events/:action Amebo signs the JSON body with our HMAC secret and sends it as x-amebo-signature. We verify before processing.
action
string · path
/events/example
/events/attendance-location-backfill-requested
undocumented /events/attendance-location-backfill-requested
system.attendance.location.backfill.requested — re-emit every location. A projection consumer (the Workers app) calls this when its attendance_location_index has drifted: locations emitted before it first subscribed (Amebo never replays history to a late subscriber) or deliveries that exhausted their retries while the app was restarting. We re-emit each current location as system.attendance.location.created; the consumer's existing upsert handler rebuilds the projection. Idempotent on purpose: we pass NO deduper, so Amebo always redelivers (unlike _emit_location, whose per-state deduper would suppress a replay), and the consumer's ON CONFLICT upsert collapses repeats. This is the source side of the leaves worker_index backfill pattern. See specs/attendance-locations.md.
/events/attendance-location-backfill-requested
/events/attendance-autoclockout-due
undocumented /events/attendance-autoclockout-due
Close a session left open past the worker's daily hours. Staged by Workers on clock-in (Amebo sleep_until) to fire when the day's cumulative hours would reach the worker's expected_hours_per_day. We close the session at that mark — clock_in + the minutes this entry was allowed before the daily target — NOT "now", so a forgotten clock-out records the correct end time. expected_minutes (the worker's daily target) rides in the payload so core never reads worker data. Fully idempotent: a no-op when the entry was already closed (manual clock-out, fresh session, or duplicate delivery), and the punched_out deduper matches the manual one so they can't double-count.
/events/attendance-autoclockout-due
/events/calendar/reminder-due
undocumented /events/calendar/reminder-due
Fire the reminder toast to every current attendee at fires_at, then (for recurring meetings) schedule the next occurrence via sleep_until. Drops stale fires — deleted, cancelled, paused, or occurrence no longer matches the rule after an edit.
/events/calendar/reminder-due
/events/calendar/reminder-sweep
undocumented /events/calendar/reminder-sweep
Walks every active meeting and re-seeds its reminder event. Idempotent: deduper keyed on fires_at makes duplicate emits harmless. Heals chains severed by webhook failures.
/events/calendar/reminder-sweep
/events/system-workspace-member-removed-rooms
undocumented /events/system-workspace-member-removed-rooms
When a workspace member is removed, remove them from all rooms and disconnect if connected.
/events/system-workspace-member-removed-rooms
/events/core-people-member-removed-mail
undocumented /events/core-people-member-removed-mail
A workspace member was removed → disconnect their mail accounts + group memberships.
/events/core-people-member-removed-mail
/events/system-mx-message-delivered
undocumented /events/system-mx-message-delivered
New mail landed on the MX box → sync it into the cache and nudge open clients.
/events/system-mx-message-delivered
/events/chat-call-requested
undocumented /events/chat-call-requested
/events/chat-call-requested
/events/calls-call-reminder
undocumented /events/calls-call-reminder
Fire a persistent toast to every participant of a scheduled call. Mirrors the meeting reminder path — honours each recipient's preferences.notifications.calls settings (enabled / toast / sound) so a silenced recipient drops out cleanly.
/events/calls-call-reminder
/events/system-workspace-member-removed
undocumented /events/system-workspace-member-removed
/events/system-workspace-member-removed
/events/system-meeting-created
undocumented /events/system-meeting-created
/events/system-meeting-created
/events/system-meeting-deleted
undocumented /events/system-meeting-deleted
/events/system-meeting-deleted
/events/system-meeting-invitee-added
undocumented /events/system-meeting-invitee-added
/events/system-meeting-invitee-added
/events/calls-staleness-check
undocumented /events/calls-staleness-check
Held ~30 minutes by Amebo, then fired to re-check a call that went empty. Calls never auto-end on disconnect anymore, so this is a soft janitor only: if the call is still active and has people in it again, re-arm another delayed check; if it is empty (stale) we leave it active for the host to delete manually and let the chain stop. A broken chain is acceptable: the call just stays on the caller's calls list for manual cleanup.
/events/calls-staleness-check
/events/account-profile-updated
undocumented /events/account-profile-updated
/events/account-profile-updated
/events/system-canvas-upload-confirmed
undocumented /events/system-canvas-upload-confirmed
system.canvas.upload.confirmed -> create the canvas_assets row for a board image. Backup path: the editor registers the asset synchronously via POST /canvas/boards/:board_id/assets; this covers uploads confirmed by other clients or missed registrations. ensure_asset_row is idempotent.
/events/system-canvas-upload-confirmed
/events/core-canvas-board-purge-due
undocumented /events/core-canvas-board-purge-due
core.canvas.board.purge_due (delayed 30 days) -> hard-delete the board. No-op if the board no longer exists or was restored in the meantime; purge_board only touches boards still marked is_deleted.
/events/core-canvas-board-purge-due
/events/chat-message-sent
undocumented /events/chat-message-sent
Handle core.chat.message.sent. Acknowledge so Amebo marks the event delivered. Future: push notifications, unread badges, etc.
/events/chat-message-sent
/events/system-chat-upload-confirmed
undocumented /events/system-chat-upload-confirmed
Handle system.chat.upload.confirmed. Chat stores media inline in message JSON — no separate media table. The client attaches the storage_key when sending the message. This handler acknowledges the confirmation so Amebo marks it delivered.
/events/system-chat-upload-confirmed
/events/chat-member-removed
undocumented /events/chat-member-removed
Handle system.workspace.member.removed — drop the removed member from every chat's participant list in this workspace, so they no longer appear in DMs or groups. Without this, a removed member's MRN lingers in chats.participants and still resolves to their name.
/events/chat-member-removed
/events/calls-call-started
undocumented /events/calls-call-started
Handle core.calls.call.started — record a call card in the conversation.
/events/calls-call-started
/events/calls-call-ended
undocumented /events/calls-call-ended
Handle core.calls.call.ended — flip the call card to its ended state.
/events/calls-call-ended
/events/core-mail-email-sent
undocumented /events/core-mail-email-sent
Handle core.mail.email.sent — log an interaction per known recipient, and queue a contact suggestion for each recipient who isn't a contact yet. The mail app emits ``to_addresses`` (a list); older callers may send ``to``.
/events/core-mail-email-sent
/events/core-mail-email-received
undocumented /events/core-mail-email-received
Handle core.mail.email.received — log an inbound interaction if the sender is a known contact, otherwise queue them as a contact suggestion.
/events/core-mail-email-received
/events/core-calendar-event-completed
undocumented /events/core-calendar-event-completed
Handle core.calendar.event.completed — auto-log meeting interaction for attendees.
/events/core-calendar-event-completed
/events/core-calls-call-ended
undocumented /events/core-calls-call-ended
Handle core.calls.call.ended — auto-log call interaction.
/events/core-calls-call-ended
/events/core-crm-deal-won
undocumented /events/core-crm-deal-won
Handle core.crm.deal.won — auto-tag company as 'customer'.
/events/core-crm-deal-won
/events/core-crm-deal-lost
undocumented /events/core-crm-deal-lost
Handle core.crm.deal.lost — log a note interaction on the contact.
/events/core-crm-deal-lost
/events/core-suppliers-rfq-sent
undocumented /events/core-suppliers-rfq-sent
Handle core.suppliers.rfq.sent — auto-log RFQ interaction.
/events/core-suppliers-rfq-sent
/events/core-suppliers-po-issued
undocumented /events/core-suppliers-po-issued
Handle core.suppliers.po.issued — auto-log PO interaction.
/events/core-suppliers-po-issued
/events/core-finance-party-index-requested
undocumented /events/core-finance-party-index-requested
Replay current companies and contacts for a projection consumer. Bound to both core.finance.party_index.requested and core.crm.party_index.requested: any app that keeps a party projection asks for current state at install time and we answer with one company.created / contact.created per row, so the consumer's normal handlers do the projecting without a dedicated backfill event type. The payloads carry the same fields as a live create, so a consumer that projects lifecycle or firmographics backfills them too.
/events/core-finance-party-index-requested
/events/core-crm-party-index-requested
undocumented /events/core-crm-party-index-requested
Replay current companies and contacts for a projection consumer. Bound to both core.finance.party_index.requested and core.crm.party_index.requested: any app that keeps a party projection asks for current state at install time and we answer with one company.created / contact.created per row, so the consumer's normal handlers do the projecting without a dedicated backfill event type. The payloads carry the same fields as a live create, so a consumer that projects lifecycle or firmographics backfills them too.
/events/core-crm-party-index-requested
/events/core-vendibles-conversation-started
undocumented /events/core-vendibles-conversation-started
Handle core.vendibles.conversation.started — open a conversation. Idempotent on the visitor token: a redelivered event appends nothing and re-reports the conversation that already exists.
/events/core-vendibles-conversation-started
/events/core-vendibles-conversation-message
undocumented /events/core-vendibles-conversation-message
Handle core.vendibles.conversation.message — append a visitor follow-up.
/events/core-vendibles-conversation-message
/events/core-vendibles-conversation-rated
undocumented /events/core-vendibles-conversation-rated
Handle core.vendibles.conversation.rated — store CSAT and log it. The rating is the resolution's receipt: it lands on the conversation, on the contact's timeline as a ``csat`` interaction, and (from phase 2) on the state ladder.
/events/core-vendibles-conversation-rated
/events/core-vendibles-order-placed
undocumented /events/core-vendibles-order-placed
Handle core.vendibles.order.placed — project the purchase, resolve the buyer.
/events/core-vendibles-order-placed
/events/core-vendibles-order-paid
undocumented /events/core-vendibles-order-paid
Handle core.vendibles.order.paid — a paid order lifts the ladder, and the third one is proof of advocacy. Repeat purchase is the behavioural half of "promoter": someone who keeps buying is voting with money, which is harder evidence than a good mood.
/events/core-vendibles-order-paid
/events/core-vendibles-order-refunded
undocumented /events/core-vendibles-order-refunded
Handle core.vendibles.order.refunded — a refund pushes the ladder down.
/events/core-vendibles-order-refunded
/events/core-finance-invoice-issued
undocumented /events/core-finance-invoice-issued
Handle core.finance.invoice.issued — project the invoice.
/events/core-finance-invoice-issued
/events/core-finance-invoice-paid
undocumented /events/core-finance-invoice-paid
Handle core.finance.invoice.paid — project the settlement.
/events/core-finance-invoice-paid
/events/core-finance-payment-received
undocumented /events/core-finance-payment-received
Handle core.finance.payment.received — project money in from a contact.
/events/core-finance-payment-received
/events/core-sign-document-completed
undocumented /events/core-sign-document-completed
Handle core.sign.document.completed — project the signature. Sign addresses recipients by email rather than contact MRN, so the person is matched the same way the mail handlers match one.
/events/core-sign-document-completed
/events/core-contacts-state-decay-check
undocumented /events/core-contacts-state-decay-check
Handle core.contacts.state.decay_check — drift quiet contacts to neutral. Silence is not evidence of feeling either way. A contact nobody has touched for the configured window moves one step toward zero per elapsed window, so an old complaint stops branding someone angry forever, and an old delight stops flattering the numbers. Idempotent by construction: the step count is computed from how long the contact has actually been quiet, so running the sweep twice in one day applies the same result as running it once.
/events/core-contacts-state-decay-check
/events/crm/core-contacts-contact-created
undocumented /events/crm/core-contacts-contact-created
core.contacts.contact.created / .updated: project the contact.
/events/crm/core-contacts-contact-created
/events/crm/core-contacts-contact-updated
undocumented /events/crm/core-contacts-contact-updated
core.contacts.contact.created / .updated: project the contact.
/events/crm/core-contacts-contact-updated
/events/crm/core-contacts-contact-deleted
undocumented /events/crm/core-contacts-contact-deleted
core.contacts.contact.deleted: drop the projected contact.
/events/crm/core-contacts-contact-deleted
/events/crm/core-contacts-company-created
undocumented /events/crm/core-contacts-company-created
core.contacts.company.created / .updated: project the company. Also refreshes the cached company_name on every contact pointing at it, so a rename shows up on deal cards without waiting for a contact update.
/events/crm/core-contacts-company-created
/events/crm/core-contacts-company-updated
undocumented /events/crm/core-contacts-company-updated
core.contacts.company.created / .updated: project the company. Also refreshes the cached company_name on every contact pointing at it, so a rename shows up on deal cards without waiting for a contact update.
/events/crm/core-contacts-company-updated
/events/crm/core-contacts-company-deleted
undocumented /events/crm/core-contacts-company-deleted
core.contacts.company.deleted: drop the projected company.
/events/crm/core-contacts-company-deleted
/events/crm/core-contacts-interaction-created
undocumented /events/crm/core-contacts-interaction-created
core.contacts.interaction.created. Three effects: credit the actor's matching activity target, bump the party's interaction stats, and stamp last_interaction_at on the related deals so the going-cold sweep has something to read.
/events/crm/core-contacts-interaction-created
/events/crm/core-finance-quote-created
undocumented /events/crm/core-finance-quote-created
core.finance.quote.created / .sent / .accepted / .rejected on the deal timeline. The `event` data key is what the drawer's quote-state derivation reads; labels are display-only. A sent event also stamps deals.room_quote so the customer's deal room can link the quote portal.
/events/crm/core-finance-quote-created
/events/crm/core-finance-quote-sent
undocumented /events/crm/core-finance-quote-sent
core.finance.quote.created / .sent / .accepted / .rejected on the deal timeline. The `event` data key is what the drawer's quote-state derivation reads; labels are display-only. A sent event also stamps deals.room_quote so the customer's deal room can link the quote portal.
/events/crm/core-finance-quote-sent
/events/crm/core-finance-quote-accepted
undocumented /events/crm/core-finance-quote-accepted
core.finance.quote.created / .sent / .accepted / .rejected on the deal timeline. The `event` data key is what the drawer's quote-state derivation reads; labels are display-only. A sent event also stamps deals.room_quote so the customer's deal room can link the quote portal.
/events/crm/core-finance-quote-accepted
/events/crm/core-finance-quote-rejected
undocumented /events/crm/core-finance-quote-rejected
core.finance.quote.created / .sent / .accepted / .rejected on the deal timeline. The `event` data key is what the drawer's quote-state derivation reads; labels are display-only. A sent event also stamps deals.room_quote so the customer's deal room can link the quote portal.
/events/crm/core-finance-quote-rejected
/events/crm/core-finance-invoice-issued
undocumented /events/crm/core-finance-invoice-issued
core.finance.invoice.issued / .paid on the deal timeline. Issued also stamps deals.room_invoice (portal path from portal_token) so the deal room can offer the customer the pay link; paid flips it to a receipt line.
/events/crm/core-finance-invoice-issued
/events/crm/core-finance-invoice-paid
undocumented /events/crm/core-finance-invoice-paid
core.finance.invoice.issued / .paid on the deal timeline. Issued also stamps deals.room_invoice (portal path from portal_token) so the deal room can offer the customer the pay link; paid flips it to a receipt line.
/events/crm/core-finance-invoice-paid
/events/crm/core-finance-payment-received
undocumented /events/crm/core-finance-payment-received
core.finance.payment.received on the deal timeline.
/events/crm/core-finance-payment-received
/events/crm/core-finance-portal-viewed
undocumented /events/crm/core-finance-portal-viewed
core.finance.portal.viewed: the customer opened the quote or invoice.
/events/crm/core-finance-portal-viewed
/events/crm/core-sign-document-prepared
undocumented /events/crm/core-sign-document-prepared
core.sign.document.prepared: a draft contract is waiting for the deal owner. Separate from on_signature_event because this one is a call to action rather than a status report: the contract does NOT go out until its owner sends it.
/events/crm/core-sign-document-prepared
/events/crm/core-sign-document-viewed
undocumented /events/crm/core-sign-document-viewed
core.sign.document.viewed / .signed / .declined / .completed.
/events/crm/core-sign-document-viewed
/events/crm/core-sign-document-signed
undocumented /events/crm/core-sign-document-signed
core.sign.document.viewed / .signed / .declined / .completed.
/events/crm/core-sign-document-signed
/events/crm/core-sign-document-declined
undocumented /events/crm/core-sign-document-declined
core.sign.document.viewed / .signed / .declined / .completed.
/events/crm/core-sign-document-declined
/events/crm/core-sign-document-completed
undocumented /events/crm/core-sign-document-completed
core.sign.document.viewed / .signed / .declined / .completed.
/events/crm/core-sign-document-completed
/events/crm/core-crm-deal-won
undocumented /events/crm/core-crm-deal-won
core.crm.deal.won: credit the owner's revenue target for the period. Subscribing to our own event means every close path (API, deal room, automation) credits quota through exactly one code path.
/events/crm/core-crm-deal-won
/events/crm/core-crm-deal-health-check
undocumented /events/crm/core-crm-deal-health-check
core.crm.deal.health_check: the daily deal sweep. Emits stale / overdue / going_cold for open deals that crossed a configured threshold, refreshes stored deal scores, emits score threshold crossings, then re-arms tomorrow's sweep.
/events/crm/core-crm-deal-health-check
/events/crm/core-crm-target-period-check
undocumented /events/crm/core-crm-target-period-check
core.crm.target.period_check: the daily quota sweep. Closes out periods that ended (achieved / missed) and flags active targets that are behind pace with the clock running down, then re-arms.
/events/crm/core-crm-target-period-check
/events/crm/core-settings-application-installed
undocumented /events/crm/core-settings-application-installed
core.settings.application.installed. When CRM lands in a workspace that already has contacts, ask the contacts app to replay current state (the finance party_index handshake), and arm the two daily sweeps.
/events/crm/core-settings-application-installed
/events/system-feeds-upload-confirmed
undocumented /events/system-feeds-upload-confirmed
Handle system.feeds.upload.confirmed — insert feed_media row.
/events/system-feeds-upload-confirmed
/events/system-files-upload-confirmed
undocumented /events/system-files-upload-confirmed
Handle system.files.upload.confirmed — create the file row. The platform confirm endpoint has already verified the storage key sits in this workspace's namespace and HEAD-verified the object; this handler adds the app-level checks the platform cannot know about: the uploader must be able to write into the target folder, and a name collision suffixes to "name (1).ext" instead of silently replacing the existing file.
/events/system-files-upload-confirmed
/events/files-chat-file-shared
undocumented /events/files-chat-file-shared
Ingest a chat attachment for the sender AND everyone in the conversation. An attachment was shared *with people*, so it mirrors that audience: the sender gets it under My Apps/Chat, each other participant under My Apps/Chat/Shared with me. The participant list is a snapshot taken when the message was sent, which is why it rides on the event rather than being looked up here (Files may not read chat's tables).
/events/files-chat-file-shared
/events/files-canvas-board-exported
undocumented /events/files-canvas-board-exported
Ingest a Canvas board the exporter explicitly saved to Files (exporter only).
/events/files-canvas-board-exported
/events/files-sign-document-exported
undocumented /events/files-sign-document-exported
Ingest a sealed document exported from Sign into the exporter's My Apps/Sign. Sign never auto-mirrors; this only fires on the user's explicit 'Save to Files', which is a one-person act, so nobody else gets a row. The file points at Sign's sealed R2 object (source_ref = mrn:sign:envelope:{id}).
/events/files-sign-document-exported
/events/files-chat-message-deleted
undocumented /events/files-chat-message-deleted
A deleted chat message takes its attachments out of everyone's Files.
/events/files-chat-message-deleted
/events/files-chat-participant-removed
undocumented /events/files-chat-participant-removed
Someone left (or was removed from) a conversation: their links go too. Scoped to that one conversation and that one member. Attachments they received elsewhere, and everyone else's rows for this conversation, stay.
/events/files-chat-participant-removed
/events/files-sign-envelope-deleted
undocumented /events/files-sign-envelope-deleted
A deleted Sign envelope takes its saved copy out of Files.
/events/files-sign-envelope-deleted
/events/files-canvas-board-deleted
undocumented /events/files-canvas-board-deleted
A deleted Canvas board takes its exports out of Files.
/events/files-canvas-board-deleted
/events/files-sign-export-revoked
undocumented /events/files-sign-export-revoked
Someone undid a 'Save to Files' in the app that owns the document. Shared by Sign and Canvas: both carry the same source_ref this app filed the copy under. This is the only way a deliberate export leaves Files, since Files itself will not delete anything another app owns.
/events/files-sign-export-revoked
/events/files-canvas-export-revoked
undocumented /events/files-canvas-export-revoked
Someone undid a 'Save to Files' in the app that owns the document. Shared by Sign and Canvas: both carry the same source_ref this app filed the copy under. This is the only way a deliberate export leaves Files, since Files itself will not delete anything another app owns.
/events/files-canvas-export-revoked
/events/files-member-removed
undocumented /events/files-member-removed
/events/files-member-removed
/events/files-file-deleted
undocumented /events/files-file-deleted
Handle core.files.file.deleted — clean up R2 storage key.
/events/files-file-deleted
/events/files-folder-deleted
undocumented /events/files-folder-deleted
Handle core.files.folder.deleted — clean up R2 storage keys for all files in folder tree.
/events/files-folder-deleted
/events/finance/core-workers-payrun-executed
undocumented /events/finance/core-workers-payrun-executed
core.workers.payrun.executed → auto-create a draft journal entry. Expected payload: ``{"payrun_id", "period", "gross_total", "net_total", "tax_total", "actor_mrn"}``. We draft a balanced journal (debit Salaries, credit Cash / Tax Payable / Net Pay). The workspace operator posts it when they're ready — payroll isn't automatically reflected on the ledger until approved.
/events/finance/core-workers-payrun-executed
/events/finance/core-inventory-stock-issued
undocumented /events/finance/core-inventory-stock-issued
core.inventory.stock.issued → post COGS (debit 5100, credit 1300). Expected payload: ``{"movement_id", "cost", "currency", "sku", "location", "lot", "actor_mrn"}``. Cost is the inventory valuation (FIFO/LIFO/avg) computed by the Inventory app.
/events/finance/core-inventory-stock-issued
/events/finance/core-inventory-stock-received
undocumented /events/finance/core-inventory-stock-received
core.inventory.stock.received → if no bill exists yet, post Goods Received Not Invoiced: debit Inventory (1300), credit Accrued Expenses (2300). When the bill later approves, it reverses that accrual.
/events/finance/core-inventory-stock-received
/events/finance/core-inventory-stock-adjusted
undocumented /events/finance/core-inventory-stock-adjusted
core.inventory.stock.adjusted → post inventory variance. Expected payload: ``{"movement_id", "delta", "currency", "sku", "location", "lot", "actor_mrn"}``. Positive delta = write-up (debit Inventory, credit Inventory Adjustments). Negative = write-down.
/events/finance/core-inventory-stock-adjusted
/events/finance/core-crm-deal-won
undocumented /events/finance/core-crm-deal-won
core.crm.deal.won → create a draft invoice for the deal. The deal payload is a *fact* (already happened); Finance responds by drafting an invoice the workspace can review and issue. We do not auto- issue — revenue recognition stays under human control. If the deal has no company_mrn (contacts app not installed, or missing customer record), we skip silently — no draft is created.
/events/finance/core-crm-deal-won
/events/finance/core-crm-deal-quote-requested
undocumented /events/finance/core-crm-deal-quote-requested
core.crm.deal.quote_requested → draft a quote from the deal's line items. Mirror of on_deal_won: CRM states a fact (a rep wants a quote) and Finance, the authority for money documents, drafts one for a human to review and send. The deal MRN goes into ``sources`` so every later quote event can carry it back and land on the deal timeline. Re-requesting is idempotent while the quote is still a draft.
/events/finance/core-crm-deal-quote-requested
/events/finance/core-crm-deal-lost
undocumented /events/finance/core-crm-deal-lost
core.crm.deal.lost → delete the auto-drafted invoice if it's still a draft. If the invoice has already been issued, we leave it alone — that's a human decision to bill regardless of deal outcome.
/events/finance/core-crm-deal-lost
/events/finance/core-crm-deal-value-changed
undocumented /events/finance/core-crm-deal-value-changed
core.crm.deal.value_changed → resize the auto-drafted invoice if still draft.
/events/finance/core-crm-deal-value-changed
/events/finance/core-finance-invoice-due-check
undocumented /events/finance/core-finance-invoice-due-check
core.finance.invoice.due_check → emit invoice.overdue if still unpaid.
/events/finance/core-finance-invoice-due-check
/events/finance/core-finance-bill-due-check
undocumented /events/finance/core-finance-bill-due-check
core.finance.bill.due_check → emit bill.overdue if still unpaid.
/events/finance/core-finance-bill-due-check
/events/finance/core-finance-quote-expiry-check
undocumented /events/finance/core-finance-quote-expiry-check
core.finance.quote.expiry_check → emit quote.expired if still open.
/events/finance/core-finance-quote-expiry-check
/events/finance/core-finance-recurring-due-check
undocumented /events/finance/core-finance-recurring-due-check
core.finance.recurring.due_check → run the recurring entry, advance, re-emit. Self-perpetuating schedule: each firing creates the draft entry, advances the stored ``next_date``, and re-emits another ``due_check`` for the new date. Deletion of the recurring row naturally cancels the chain — when the delayed webhook arrives and the row is gone, this handler no-ops.
/events/finance/core-finance-recurring-due-check
/events/finance/core-finance-period-revalue-reverse
undocumented /events/finance/core-finance-period-revalue-reverse
core.finance.period.revalue_reverse → post the reversing JE. Idempotent: if the revaluation record already has ``reversed_at`` set, or the period/reval was deleted before delivery, the handler no-ops.
/events/finance/core-finance-period-revalue-reverse
/events/finance/core-finance-period-close-reminder
undocumented /events/finance/core-finance-period-close-reminder
core.finance.period.close_reminder → nudge operative if period still has no revaluation run past period_end. Emits ``core.finance.period.close_due`` which Notifications surfaces in-app. If this is the first nudge (``nudge=1``), schedules a second nudge 7 days later. Handler no-ops once a revaluation exists or the period was closed/deleted.
/events/finance/core-finance-period-close-reminder
/events/finance/core-contacts-company-created
undocumented /events/finance/core-contacts-company-created
core.contacts.company.created / .updated → project company name.
/events/finance/core-contacts-company-created
/events/finance/core-contacts-company-updated
undocumented /events/finance/core-contacts-company-updated
core.contacts.company.created / .updated → project company name.
/events/finance/core-contacts-company-updated
/events/finance/core-contacts-company-deleted
undocumented /events/finance/core-contacts-company-deleted
core.contacts.company.deleted → drop the projected name.
/events/finance/core-contacts-company-deleted
/events/finance/core-contacts-contact-created
undocumented /events/finance/core-contacts-contact-created
core.contacts.contact.created / .updated → project contact name.
/events/finance/core-contacts-contact-created
/events/finance/core-contacts-contact-updated
undocumented /events/finance/core-contacts-contact-updated
core.contacts.contact.created / .updated → project contact name.
/events/finance/core-contacts-contact-updated
/events/finance/core-contacts-contact-deleted
undocumented /events/finance/core-contacts-contact-deleted
core.contacts.contact.deleted → drop the projected name.
/events/finance/core-contacts-contact-deleted
/events/finance/core-account-application-installed
undocumented /events/finance/core-account-application-installed
core.settings.application.installed → backfill the party index on first install. When finance is installed into a workspace that already has contacts/companies, ask the contacts app to re-emit current state so we can populate the projection. Contacts responds by emitting company.created / contact.created per row, which the handlers above project.
/events/finance/core-account-application-installed
/events/growth-worker-created
undocumented /events/growth-worker-created
/events/growth-worker-created
/events/growth-worker-updated
undocumented /events/growth-worker-updated
/events/growth-worker-updated
/events/growth-worker-terminated
undocumented /events/growth-worker-terminated
/events/growth-worker-terminated
/events/growth-account-application-installed
undocumented /events/growth-account-application-installed
core.settings.application.installed — backfill the worker projection on first install.
/events/growth-account-application-installed
/events/growth-task-created
undocumented /events/growth-task-created
/events/growth-task-created
/events/growth-task-completed
undocumented /events/growth-task-completed
/events/growth-task-completed
/events/growth-task-deleted
undocumented /events/growth-task-deleted
/events/growth-task-deleted
/events/worker-created
undocumented /events/worker-created
/events/worker-created
/events/worker-updated
undocumented /events/worker-updated
/events/worker-updated
/events/worker-terminated
undocumented /events/worker-terminated
/events/worker-terminated
/events/account-application-installed
undocumented /events/account-application-installed
/events/account-application-installed
/events/leaves-attendance-location-upserted
undocumented /events/leaves-attendance-location-upserted
system.attendance.location.created/updated — mirror the location locally.
/events/leaves-attendance-location-upserted
/events/leaves-attendance-location-deleted
undocumented /events/leaves-attendance-location-deleted
system.attendance.location.deleted — drop the projected copy.
/events/leaves-attendance-location-deleted
/events/calls-call-scheduled
undocumented /events/calls-call-scheduled
/events/calls-call-scheduled
/events/feeds-post-created
undocumented /events/feeds-post-created
/events/feeds-post-created
/events/feeds-post-shared
undocumented /events/feeds-post-shared
/events/feeds-post-shared
/events/feeds-follow-created
undocumented /events/feeds-follow-created
/events/feeds-follow-created
/events/feeds-follow-deleted
undocumented /events/feeds-follow-deleted
/events/feeds-follow-deleted
/events/member-mentioned
undocumented /events/member-mentioned
/events/member-mentioned
/events/leaves-pto-created
undocumented /events/leaves-pto-created
/events/leaves-pto-created
/events/tasks-task-assigned
undocumented /events/tasks-task-assigned
/events/tasks-task-assigned
/events/tasks-task-resolved
undocumented /events/tasks-task-resolved
/events/tasks-task-resolved
/events/finance-bill-received
undocumented /events/finance-bill-received
/events/finance-bill-received
/events/finance-bill-approved
undocumented /events/finance-bill-approved
/events/finance-bill-approved
/events/chat-conversation-activity
undocumented /events/chat-conversation-activity
/events/chat-conversation-activity
/events/contacts-conversation-started
undocumented /events/contacts-conversation-started
A visitor opened a conversation. Everyone who can answer gets told. Unassigned by definition at this point, so the whole answering pool is notified; assignment later narrows it to one person.
/events/contacts-conversation-started
/events/contacts-conversation-message
undocumented /events/contacts-conversation-message
A visitor wrote back. Tell whoever owns the thread, or the whole pool if nobody does: an updated conversation is as much a person waiting as a new one is.
/events/contacts-conversation-message
/events/contacts-conversation-assigned
undocumented /events/contacts-conversation-assigned
A conversation now has an owner. Clear the pool's "new conversation" rows and tell the assignee it is theirs.
/events/contacts-conversation-assigned
/events/contacts-conversation-resolved
undocumented /events/contacts-conversation-resolved
Resolved: drop the "Needs you" row so a closed thread stops nagging.
/events/contacts-conversation-resolved
/events/billing-payment-failed
undocumented /events/billing-payment-failed
/events/billing-payment-failed
/events/billing-suspend-check
undocumented /events/billing-suspend-check
/events/billing-suspend-check
/events/billing-charge-retry
undocumented /events/billing-charge-retry
Delayed event (fires on days 3 and 7 after a failed charge). Re-attempts the invoice on the default card; idempotent — a paid invoice is a no-op.
/events/billing-charge-retry
/events/billing-trial-expiring
undocumented /events/billing-trial-expiring
Delayed event (fires 3 days before trial end). Notifies workspace admins.
/events/billing-trial-expiring
/events/billing-trial-ended
undocumented /events/billing-trial-ended
Delayed event (fires at trial end). Activates or suspends based on card_on_file.
/events/billing-trial-ended
/events/billing-invoice-due
undocumented /events/billing-invoice-due
Delayed event (fires every 30 or 365 days). Generates the invoice and charges the card. The billing interval is read FRESH from the subscription — never from the event payload — so a monthly↔annual switch takes effect on the loop's next firing. The payload's invoice_type identifies which loop this firing belongs to; a 'seats' firing under a now-monthly subscription retires itself (the monthly loop carries the billing), and an 'all' firing under a now-annual subscription continues as the 'usage' loop.
/events/billing-invoice-due
/events/billing-seat-changed
undocumented /events/billing-seat-changed
Immediate event. Handles annual proration when seats increase.
/events/billing-seat-changed
/events/system-sign-upload-confirmed
undocumented /events/system-sign-upload-confirmed
Handle system.sign.upload.confirmed — attach the uploaded source PDF to its envelope. Idempotent (a plain UPDATE keyed by envelope id) per the at-least-once event contract. The document SHA-256 fingerprint is computed later at seal time, when the bytes are downloaded anyway — not here, to avoid a large synchronous R2 read on the event loop.
/events/system-sign-upload-confirmed
/events/sign/core-crm-deal-signature-requested
undocumented /events/sign/core-crm-deal-signature-requested
core.crm.deal.signature_requested — prepare a draft contract for the deal. A DRAFT, deliberately, never an automatic send. This fires when a customer accepts a proposal, and nobody has yet checked which template applies, whether terms moved during negotiation, or that the right people are on it. A wrong contract auto-sent to a customer is very hard to walk back, so Sign prepares it and the deal owner sends it. Mirrors finance.on_deal_quote_requested, where the same reasoning keeps revenue documents under human control. Silent no-op (204) whenever the workspace has not configured a contract template, since a workspace that has not chosen one should never have a contract prepared on its behalf.
/events/sign/core-crm-deal-signature-requested
/events/system-slides-upload-confirmed
undocumented /events/system-slides-upload-confirmed
system.slides.upload.confirmed: create the slide_assets row for a deck image. Backup path. The editor registers the asset synchronously through POST /decks/:id/assets so the picture is servable at once; this covers an upload confirmed by another client, or a registration call that never landed. ensure_asset_row is idempotent, so both paths running is not a problem.
/events/system-slides-upload-confirmed
/events/system-tasks-upload-confirmed
undocumented /events/system-tasks-upload-confirmed
Handle system.tasks.upload.confirmed. Tasks stores attachments inline as JSON on the task row — no separate media table. The client attaches the storage_key when creating/updating the task. This handler acknowledges the confirmation so Amebo marks it delivered.
/events/system-tasks-upload-confirmed
/events/tasks-growth-action-item-promoted
undocumented /events/tasks-growth-action-item-promoted
Handle core.growth.action_item.promoted. Growth turns a 1:1 action item into a real task here rather than calling the Tasks API (rule 6). The task carries source_mrn back to the growth signal so the emitted core.tasks.task.created lets growth mirror it into its own projection. Idempotent: Amebo may redeliver, and a duplicate task for the same action item would be worse than a dropped one, so an existing source_mrn wins.
/events/tasks-growth-action-item-promoted
/events/account-member-removed
undocumented /events/account-member-removed
Handle core.settings.member.removed — purge the removed member from all wiki_pages.shares arrays in the workspace. The shares column is JSONB. We filter out entries where type='member' AND id=removed_member_id, leaving role-based shares intact.
/events/account-member-removed
/events/leaves-worker-index-requested
undocumented /events/leaves-worker-index-requested
Re-emit core.workers.worker.updated so a consumer can backfill its index. Triggered by leaves (or any future projection consumer) when it needs to backfill its local index. worker.updated carries full current state (event-carried state transfer), so consumers' existing handlers project each row without a separate event type. If the payload carries a ``member_mrn``, only that member's worker is re-emitted — a targeted self-heal for a single drifted row (e.g. leaves couldn't resolve a requester). Without it, the whole table is re-emitted (install / cron backfill).
/events/leaves-worker-index-requested
/events/growth-worker-index-requested
undocumented /events/growth-worker-index-requested
Re-emit core.workers.worker.updated so a consumer can backfill its index. Triggered by leaves (or any future projection consumer) when it needs to backfill its local index. worker.updated carries full current state (event-carried state transfer), so consumers' existing handlers project each row without a separate event type. If the payload carries a ``member_mrn``, only that member's worker is re-emitted — a targeted self-heal for a single drifted row (e.g. leaves couldn't resolve a requester). Without it, the whole table is re-emitted (install / cron backfill).
/events/growth-worker-index-requested
/events/attendance-punched-in
undocumented /events/attendance-punched-in
system.attendance.punched_in — schedule an auto clock-out safety net. If the worker has expected_hours_per_day set, stage a delayed system.attendance.autoclockout.due (held by Amebo via sleep_until) for the moment the worker's CUMULATIVE hours for the day would reach that target — so a lunch break doesn't reset the clock. Core attendance closes the session then, only if it's still the open one. No expected hours, no worker record, or the daily target already met => no timer. Idempotent: the deduper is per entry, and a manual clock-out or a fresh session makes the fired event a no-op for the now-closed entry.
/events/attendance-punched-in
/events/attendance-punched-out
undocumented /events/attendance-punched-out
system.attendance.punched_out — project the day's hours onto the worker. Sets (not increments) worked_minutes from the day running total in the payload, so redelivery and backfill stay idempotent. Leave status, set by the PTO handlers, always wins over a bare presence reading.
/events/attendance-punched-out
/events/leaves-pto-approved
undocumented /events/leaves-pto-approved
core.leaves.pto.approved — mark each covered WORKING day as on-leave. Only the worker's location working days are marked on-leave: a weekend or other non-working day inside a leave span is not "on leave" — the worker wasn't expected anyway. Non-working days are scrubbed of any stale leave marker (so a re-emit after a working-pattern change rebuilds correctly): a pure leave-marker row is dropped back to blank, a row with real presence keeps it. Idempotent — safe to redeliver.
/events/leaves-pto-approved
/events/leaves-pto-cancelled
undocumented /events/leaves-pto-cancelled
/events/leaves-pto-cancelled
/events/leaves-pto-revoked
undocumented /events/leaves-pto-revoked
/events/leaves-pto-revoked
/events/attendance-location-upserted
undocumented /events/attendance-location-upserted
system.attendance.location.created/updated — mirror the location locally. Full-state events (event-carried state transfer): upsert every field. The attendance_page reads timezone + workdays to derive absence in the worker's own timezone; the Hours report also reads work_start/work_end to split worked time into payable (in-window) vs off-hours. Carries only what's read (rule 5).
/events/attendance-location-upserted
/events/attendance-location-deleted
undocumented /events/attendance-location-deleted
system.attendance.location.deleted — drop the projected copy. Workers assigned to the location are reassigned by the delete flow before this fires, so removing the index row leaves no dangling reads.
/events/attendance-location-deleted
/events/workers-account-application-installed
undocumented /events/workers-account-application-installed
core.settings.application.installed — self-heal the location projection. When the Workers app is (re)installed we ask attendance to re-emit every location, rebuilding attendance_location_index from scratch. This closes the gap where locations created before Workers first subscribed never reached the projection (Amebo never replays history to a late subscriber). Mirrors the leaves install-time backfill. Idempotent — attendance's re-emit upserts.
/events/workers-account-application-installed
/events/workers-employment-reminder
undocumented /events/workers-employment-reminder
core.workers.employment.reminder — a scheduled contract-expiry reminder fired. Fire-and-no-op: only notify when the record still exists, still ends on the date the reminder was scheduled for, and reminders are still enabled. Otherwise this is a stale schedule (the contract was edited, deleted, or the reminder switched off) and we silently skip — we never cancel scheduled events.
/events/workers-employment-reminder
/events/workers-employment-transition
undocumented /events/workers-employment-transition
core.workers.employment.transition — re-snapshot at a contract boundary. A future-dated contract becoming active (or an active one ending) changes the worker's snapshot with no user action. Fire-and-no-op: recompute from the current records and only write / emit when something actually drifted. The lazy self-heal on the worker page is the backstop if a tick is ever missed.
/events/workers-employment-transition
/events/workers-audit
undocumented /events/workers-audit
Append a row to the worker audit trail for each subscribed Workers event. One handler for many actions (the delivered envelope carries ``action``). Idempotent enough for an append log: redelivery only happens on handler failure, and the normal 2xx path inserts exactly once.
/events/workers-audit
/events/workers-checklist-autoassign
undocumented /events/workers-checklist-autoassign
core.workers.worker.2026-06-23.created / .terminated — auto-assign checklists. Templates opt in via checklists.auto_assign ({enabled, trigger, department_ids}). Hire-triggered templates anchor item due-offsets to the worker's hire date; termination-triggered ones to their end date. Idempotent: an existing assignment for (checklist, worker) is skipped, so redelivery never duplicates (and never re-emits checklist.assigned).
/events/workers-checklist-autoassign
/exchanges/:exchange_id
undocumented /exchanges/:exchange_id
GET /exchanges/:exchange_id — one audit row, for the mint-capable caller only, which since the shared-only amendment means a workspace owner/admin. Anyone else gets the same 404 as a nonexistent id. No list-all-workspace-exchanges in V1.
exchange_id
string · path
/exchanges/example
/feeds/:post_id
undocumented /feeds/:post_id
DELETE /feeds/:post_id — soft-delete a post (author only).
post_id
string · path
/feeds/example
/feeds/:post_id/reactions/:reaction_type
undocumented /feeds/:post_id/reactions/:reaction_type
DELETE /feeds/:post_id/react — remove a reaction.
post_id
string · path
reaction_type
string · path
/feeds/example/reactions/example
/feeds/:post_id/bookmarks
undocumented /feeds/:post_id/bookmarks
DELETE /feeds/:post_id/bookmark — remove bookmark.
post_id
string · path
/feeds/example/bookmarks
/feeds
undocumented /feeds
GET /feeds — list top-level posts (timeline).
/feeds
/feeds/:post_id
undocumented /feeds/:post_id
GET /feeds/:post_id — get a single post.
post_id
string · path
/feeds/example
/feeds/:post_id/replies
undocumented /feeds/:post_id/replies
GET /feeds/:post_id/replies — list replies to a post.
post_id
string · path
/feeds/example/replies
/feeds/:post_id/shares
undocumented /feeds/:post_id/shares
GET /feeds/:post_id/shares — list people the current user shared this post with.
post_id
string · path
/feeds/example/shares
/feeds/bookmarks
undocumented /feeds/bookmarks
GET /feeds/bookmarks — list bookmarked posts.
/feeds/bookmarks
/feeds
Create a post
POST /feeds — create a new post.
content
string · max length: 5000
media
array
propertyName
anything
/feeds
/feeds/:post_id/replies
Reply to a post
POST /feeds/:post_id/replies — reply to a post.
post_id
string · path
content
string · max length: 5000
media
array
propertyName
anything
/feeds/example/replies
/feeds/:post_id/reactions
undocumented /feeds/:post_id/reactions
POST /feeds/:post_id/react — add a reaction.
post_id
string · path
/feeds/example/reactions
/feeds/:post_id/shares
Share a post with specific people
POST /feeds/:post_id/shares — share a post with specific people.
post_id
string · path
recipient_mrns
array
message
string · max length: 500
propertyName
anything
/feeds/example/shares
/feeds/:post_id/bookmarks
undocumented /feeds/:post_id/bookmarks
POST /feeds/:post_id/bookmark — bookmark a post.
post_id
string · path
/feeds/example/bookmarks
/sign/envelopes/:envelope_id/fields/:field_id
Move/resize/reassign a field
PATCH /sign/envelopes/:envelope_id/fields/:field_id — move/resize/reassign a field.
envelope_id
string · path
field_id
string · path
role
string · min length: 1 · max length: 100
recipient_id
string
kind
page_number
integer
nx
number
ny
number
nw
number
nh
number
label
string · max length: 200
required
default_value
string
options
object
propertyName
anything
/sign/envelopes/example/fields/example
/sign/envelopes/:envelope_id/fields
Add field placements
POST /sign/envelopes/:envelope_id/fields — add one or more field placements (bulk).
envelope_id
string · path
fields
array
propertyName
anything
/sign/envelopes/example/fields
/file-statistics
undocumented /file-statistics
GET /file-statistics — the caller's own storage and sharing overview. One call, because the dashboard draws every widget at once and a dozen round trips would show a dozen skeletons resolving at different times. Each aggregate is indexed on (workspace_id, owner_mrn, ...).
/file-statistics
/files/:file_id
undocumented /files/:file_id
file_id
string · path
/files/example
/files/:file_id/stars
undocumented /files/:file_id/stars
DELETE /files/:file_id/stars — remove the current member's star.
file_id
string · path
/files/example/stars
/files/:file_id/permissions
undocumented /files/:file_id/permissions
file_id
string · path
/files/example/permissions
/files
undocumented /files
/files
/files/:file_id
undocumented /files/:file_id
file_id
string · path
/files/example
/files/:file_id/download
undocumented /files/:file_id/download
file_id
string · path
/files/example/download
/files/:file_id/preview
undocumented /files/:file_id/preview
GET /files/:file_id/preview — presigned URL for inline preview.
file_id
string · path
/files/example/preview
/files/:file_id/versions
undocumented /files/:file_id/versions
GET /files/:file_id/versions — version history, newest first.
file_id
string · path
/files/example/versions
/files/:file_id/permissions
undocumented /files/:file_id/permissions
file_id
string · path
/files/example/permissions
/files/:file_id
Update a file
file_id
string · path
name
string · min length: 1 · max length: 255
folder_id
string
is_starred
restore_version_id
string
propertyName
anything
/files/example
/files/:file_id/stars
undocumented /files/:file_id/stars
POST /files/:file_id/stars — star a file for the current member.
file_id
string · path
/files/example/stars
/files/:file_id/copies
Copy a file
POST /files/:file_id/copies — duplicate a file (optionally into another folder). View access on the source suffices; the destination needs write.
file_id
string · path
folder_id
string
propertyName
anything
/files/example/copies
/files/bulk
Bulk file operation
action
ids
array
folder_id
string
propertyName
anything
/files/bulk
/finance/quotes/:entry_id
undocumented /finance/quotes/:entry_id
entry_id
string · path
/finance/quotes/example
/finance/purchase-orders/:entry_id
undocumented /finance/purchase-orders/:entry_id
entry_id
string · path
/finance/purchase-orders/example
/finance/orders/:entry_id
undocumented /finance/orders/:entry_id
entry_id
string · path
/finance/orders/example
/finance/invoices/:entry_id
undocumented /finance/invoices/:entry_id
entry_id
string · path
/finance/invoices/example
/finance/invoices/:entry_id/attachments/:attachment_id
undocumented /finance/invoices/:entry_id/attachments/:attachment_id
entry_id
string · path
attachment_id
string · path
/finance/invoices/example/attachments/example
/finance/bills/:entry_id
undocumented /finance/bills/:entry_id
entry_id
string · path
/finance/bills/example
/finance/credit-notes/:entry_id
undocumented /finance/credit-notes/:entry_id
entry_id
string · path
/finance/credit-notes/example
/finance/credit-notes/:entry_id/allocations/:target_entry_id
undocumented /finance/credit-notes/:entry_id/allocations/:target_entry_id
entry_id
string · path
target_entry_id
string · path
/finance/credit-notes/example/allocations/example
/finance/credit-notes/:entry_id/attachments/:attachment_id
undocumented /finance/credit-notes/:entry_id/attachments/:attachment_id
entry_id
string · path
attachment_id
string · path
/finance/credit-notes/example/attachments/example
/finance/purchase-credit-notes/:entry_id
undocumented /finance/purchase-credit-notes/:entry_id
entry_id
string · path
/finance/purchase-credit-notes/example
/finance/purchase-credit-notes/:entry_id/allocations/:target_entry_id
undocumented /finance/purchase-credit-notes/:entry_id/allocations/:target_entry_id
entry_id
string · path
target_entry_id
string · path
/finance/purchase-credit-notes/example/allocations/example
/finance/journal-entries/:entry_id
undocumented /finance/journal-entries/:entry_id
entry_id
string · path
/finance/journal-entries/example
/finance/accounts/:account_id
undocumented /finance/accounts/:account_id
account_id
string · path
/finance/accounts/example
/finance/bank-imports/:import_id
undocumented /finance/bank-imports/:import_id
import_id
string · path
/finance/bank-imports/example
/finance/requests/:request_id
undocumented /finance/requests/:request_id
DELETE /finance/requests/:id — the owner withdraws a submitted request.
request_id
string · path
/finance/requests/example
/finance/links/:link_id
undocumented /finance/links/:link_id
link_id
string · path
/finance/links/example
/finance/payment-credentials/:provider
undocumented /finance/payment-credentials/:provider
provider
string · path
/finance/payment-credentials/example
/finance/bank-connections/:id
undocumented /finance/bank-connections/:id
id
string · path
/finance/bank-connections/example
/finance/settings/logo
undocumented /finance/settings/logo
DELETE /finance/settings/logo: take the logo off every document. Deletes the object for real, because "remove my logo" has to mean the image stops being served, not merely that documents stop pointing at it. The key is dropped too, so the next upload mints a fresh unguessable one rather than resurrecting a URL that was already handed out.
/finance/settings/logo
/finance/fiscal-periods/:period_id
undocumented /finance/fiscal-periods/:period_id
period_id
string · path
/finance/fiscal-periods/example
/finance/dimensions/:dimension_key
undocumented /finance/dimensions/:dimension_key
dimension_key
string · path
/finance/dimensions/example
/finance/tax-rates/:tax_id
undocumented /finance/tax-rates/:tax_id
tax_id
string · path
/finance/tax-rates/example
/finance/payment-terms/:term_id
undocumented /finance/payment-terms/:term_id
term_id
string · path
/finance/payment-terms/example
/finance/bank-rules/:rule_id
undocumented /finance/bank-rules/:rule_id
rule_id
string · path
/finance/bank-rules/example
/finance/budgets/:budget_id
undocumented /finance/budgets/:budget_id
budget_id
string · path
/finance/budgets/example
/finance/recurring-entries/:recurring_id
undocumented /finance/recurring-entries/:recurring_id
recurring_id
string · path
/finance/recurring-entries/example
/finance/quotes
undocumented /finance/quotes
/finance/quotes
/finance/quotes/:entry_id
undocumented /finance/quotes/:entry_id
entry_id
string · path
/finance/quotes/example
/finance/purchase-orders
undocumented /finance/purchase-orders
/finance/purchase-orders
/finance/purchase-orders/:entry_id
undocumented /finance/purchase-orders/:entry_id
entry_id
string · path
/finance/purchase-orders/example
/finance/purchase-orders/:entry_id/receipts
undocumented /finance/purchase-orders/:entry_id/receipts
entry_id
string · path
/finance/purchase-orders/example/receipts
/finance/orders
undocumented /finance/orders
/finance/orders
/finance/orders/:entry_id
undocumented /finance/orders/:entry_id
entry_id
string · path
/finance/orders/example
/finance/orders/:entry_id/fulfillments
undocumented /finance/orders/:entry_id/fulfillments
entry_id
string · path
/finance/orders/example/fulfillments
/finance/invoices
undocumented /finance/invoices
/finance/invoices
/finance/invoices/:entry_id
undocumented /finance/invoices/:entry_id
entry_id
string · path
/finance/invoices/example
/finance/invoices/:entry_id/payments
undocumented /finance/invoices/:entry_id/payments
entry_id
string · path
/finance/invoices/example/payments
/finance/invoices/:entry_id/ledger-lines
undocumented /finance/invoices/:entry_id/ledger-lines
entry_id
string · path
/finance/invoices/example/ledger-lines
/finance/invoices/:entry_id/pdfs
undocumented /finance/invoices/:entry_id/pdfs
entry_id
string · path
/finance/invoices/example/pdfs
/finance/bills
undocumented /finance/bills
/finance/bills
/finance/bills/:entry_id
undocumented /finance/bills/:entry_id
entry_id
string · path
/finance/bills/example
/finance/bills/:entry_id/payments
undocumented /finance/bills/:entry_id/payments
entry_id
string · path
/finance/bills/example/payments
/finance/bills/:entry_id/ledger-lines
undocumented /finance/bills/:entry_id/ledger-lines
entry_id
string · path
/finance/bills/example/ledger-lines
/finance/credit-notes
undocumented /finance/credit-notes
/finance/credit-notes
/finance/credit-notes/:entry_id
undocumented /finance/credit-notes/:entry_id
entry_id
string · path
/finance/credit-notes/example
/finance/credit-notes/:entry_id/ledger-lines
undocumented /finance/credit-notes/:entry_id/ledger-lines
entry_id
string · path
/finance/credit-notes/example/ledger-lines
/finance/credit-notes/:entry_id/pdfs
undocumented /finance/credit-notes/:entry_id/pdfs
entry_id
string · path
/finance/credit-notes/example/pdfs
/finance/purchase-credit-notes
undocumented /finance/purchase-credit-notes
/finance/purchase-credit-notes
/finance/purchase-credit-notes/:entry_id
undocumented /finance/purchase-credit-notes/:entry_id
entry_id
string · path
/finance/purchase-credit-notes/example
/finance/purchase-credit-notes/:entry_id/ledger-lines
undocumented /finance/purchase-credit-notes/:entry_id/ledger-lines
entry_id
string · path
/finance/purchase-credit-notes/example/ledger-lines
/finance/journal-entries
undocumented /finance/journal-entries
/finance/journal-entries
/finance/journal-entries/:entry_id
undocumented /finance/journal-entries/:entry_id
entry_id
string · path
/finance/journal-entries/example
/finance/journal-entries/:entry_id/ledger-lines
undocumented /finance/journal-entries/:entry_id/ledger-lines
entry_id
string · path
/finance/journal-entries/example/ledger-lines
/finance/accounts
undocumented /finance/accounts
List the chart of accounts. Filters: ?type=, ?active=, ?bank=true, ?q= (matches code or name — the Lookup widget in every account picker sends q). Raw SQL because supersql renders OR conditions unparenthesized, which would break workspace scoping.
/finance/accounts
/finance/accounts/:account_id
undocumented /finance/accounts/:account_id
account_id
string · path
/finance/accounts/example
/finance/accounts/:account_id/ledger-lines
undocumented /finance/accounts/:account_id/ledger-lines
account_id
string · path
/finance/accounts/example/ledger-lines
/finance/chart-advice
undocumented /finance/chart-advice
Advisory guidance for the new-account form (see core.forms Form.advice). Returns the derived normal balance, a suggested free code in the chosen type's block, and a warning when the typed code sits in a different type's block. Nothing here rejects anything, because the code-range convention is advisory by design (ACCOUNT_CODE_RANGES explains why), and the rule that IS enforceable is enforced in api_create_account instead.
/finance/chart-advice
/finance/ledger
undocumented /finance/ledger
/finance/ledger
/finance/ledger/:line_id
undocumented /finance/ledger/:line_id
line_id
string · path
/finance/ledger/example
/finance/payments
undocumented /finance/payments
/finance/payments
/finance/payments/:payment_id
undocumented /finance/payments/:payment_id
payment_id
string · path
/finance/payments/example
/finance/payments/:payment_id/reversals
undocumented /finance/payments/:payment_id/reversals
payment_id
string · path
/finance/payments/example/reversals
/finance/bank-imports
undocumented /finance/bank-imports
/finance/bank-imports
/finance/bank-imports/:import_id
undocumented /finance/bank-imports/:import_id
import_id
string · path
/finance/bank-imports/example
/finance/bank-imports/:import_id/matches
undocumented /finance/bank-imports/:import_id/matches
import_id
string · path
/finance/bank-imports/example/matches
/finance/requests
undocumented /finance/requests
GET /finance/requests — reviewers see all, everyone else their own. The scope is deposited by the authz chain (scope_requests).
/finance/requests
/finance/requests/:request_id
undocumented /finance/requests/:request_id
request_id
string · path
/finance/requests/example
/finance/quotes/:entry_id/links
undocumented /finance/quotes/:entry_id/links
entry_id
string · path
/finance/quotes/example/links
/finance/invoices/:entry_id/links
undocumented /finance/invoices/:entry_id/links
entry_id
string · path
/finance/invoices/example/links
/finance/credit-notes/:entry_id/links
undocumented /finance/credit-notes/:entry_id/links
entry_id
string · path
/finance/credit-notes/example/links
/finance/payment-credentials
undocumented /finance/payment-credentials
/finance/payment-credentials
/finance/bank-connections
undocumented /finance/bank-connections
/finance/bank-connections
/finance/reconciliations
undocumented /finance/reconciliations
/finance/reconciliations
/finance/reconciliations/:recon_id
undocumented /finance/reconciliations/:recon_id
recon_id
string · path
/finance/reconciliations/example
/finance/settings
undocumented /finance/settings
/finance/settings
/finance/fiscal-periods
undocumented /finance/fiscal-periods
/finance/fiscal-periods
/finance/fiscal-periods/:period_id/revaluation-preview
undocumented /finance/fiscal-periods/:period_id/revaluation-preview
GET /finance/fiscal-periods/:period_id/revaluation-preview?as_of=...
period_id
string · path
/finance/fiscal-periods/example/revaluation-preview
/finance/fiscal-periods/:period_id/revaluations
undocumented /finance/fiscal-periods/:period_id/revaluations
GET /finance/fiscal-periods/:period_id/revaluations
period_id
string · path
/finance/fiscal-periods/example/revaluations
/finance/dimensions
undocumented /finance/dimensions
/finance/dimensions
/finance/dimensions/:dimension_key/values
undocumented /finance/dimensions/:dimension_key/values
dimension_key
string · path
/finance/dimensions/example/values
/finance/tax-rates
undocumented /finance/tax-rates
/finance/tax-rates
/finance/payment-terms
undocumented /finance/payment-terms
/finance/payment-terms
/finance/bank-rules
undocumented /finance/bank-rules
/finance/bank-rules
/finance/budgets
undocumented /finance/budgets
/finance/budgets
/finance/recurring-entries
undocumented /finance/recurring-entries
/finance/recurring-entries
/finance/reports/trial-balance
undocumented /finance/reports/trial-balance
/finance/reports/trial-balance
/finance/reports/income-statement
undocumented /finance/reports/income-statement
/finance/reports/income-statement
/finance/reports/balance-sheet
undocumented /finance/reports/balance-sheet
/finance/reports/balance-sheet
/finance/reports/aged-receivables
undocumented /finance/reports/aged-receivables
/finance/reports/aged-receivables
/finance/reports/aged-payables
undocumented /finance/reports/aged-payables
/finance/reports/aged-payables
/finance/reports/cash-flow
undocumented /finance/reports/cash-flow
/finance/reports/cash-flow
/finance/reports/revenue-by-customer
undocumented /finance/reports/revenue-by-customer
/finance/reports/revenue-by-customer
/finance/reports/budget-vs-actuals
undocumented /finance/reports/budget-vs-actuals
/finance/reports/budget-vs-actuals
/finance/reports/dimensions/:dimension_key
undocumented /finance/reports/dimensions/:dimension_key
dimension_key
string · path
/finance/reports/dimensions/example
/finance/bank-connections/:id/syncs
undocumented /finance/bank-connections/:id/syncs
id
string · path
/finance/bank-connections/example/syncs
/finance/fiscal-periods/:period_id/year-end-close
undocumented /finance/fiscal-periods/:period_id/year-end-close
POST /finance/fiscal-periods/:period_id/year-end-close Posts the closing JE for the fiscal year whose last day matches ``period.end``. No request body — the period alone is the command.
period_id
string · path
/finance/fiscal-periods/example/year-end-close
/finance/recurring-entries/:recurring_id/runs
undocumented /finance/recurring-entries/:recurring_id/runs
Manually trigger a recurring entry — creates a draft invoice or bill. Does NOT advance ``next_date`` or reschedule — that's the scheduled path's job. Manual run is an operator override for off-cycle generation.
recurring_id
string · path
/finance/recurring-entries/example/runs
/finance/settings/logo
undocumented /finance/settings/logo
PUT /finance/settings/logo: replace the logo shown on every document. The object key is generated ONCE and then reused for the life of the workspace, so a replacement overwrites in place. That is deliberate: a new key per upload would orphan the old object and, worse, break the logo in every invoice email already sitting in a customer's inbox. One workspace, one object, one stable URL. The key is flat, extensionless and 128 bits of randomness. Flat and random because the public bucket serves anyone holding the URL, so unguessability is the whole security boundary (listing is disabled, so the key is the only handle). Extensionless because the content type lives in R2 object metadata, which is what browsers, weasyprint and mail clients actually read: keeping an extension would mean a PNG-to-SVG switch silently orphaned the old object. The stored URL carries a ?v= token regenerated on every upload. Overwriting bytes under a cached URL would otherwise keep serving the old logo until the edge TTL lapsed, which reads as a broken save.
/finance/settings/logo
/folders/:folder_id
undocumented /folders/:folder_id
folder_id
string · path
/folders/example
/folders/:folder_id/permissions
undocumented /folders/:folder_id/permissions
folder_id
string · path
/folders/example/permissions
/folders
undocumented /folders
/folders
/folders/:folder_id
undocumented /folders/:folder_id
folder_id
string · path
/folders/example
/folders/:folder_id/files
undocumented /folders/:folder_id/files
folder_id
string · path
/folders/example/files
/folders/:folder_id/permissions
undocumented /folders/:folder_id/permissions
folder_id
string · path
/folders/example/permissions
/folders/:folder_id/archive
undocumented /folders/:folder_id/archive
GET /folders/:folder_id/archive — the folder tree as a ZIP download.
folder_id
string · path
/folders/example/archive
/folders/:folder_id
Update a folder
folder_id
string · path
name
string · min length: 1 · max length: 255
parent_id
string
color
string
is_pinned
propertyName
anything
/folders/example
/folders
Create a folder
name
string · min length: 1 · max length: 255
parent_id
string
color
string
propertyName
anything
/folders
/follows/:target_mrn
undocumented /follows/:target_mrn
DELETE /feeds/follow/:target_mrn — unfollow a member or team.
target_mrn
string · path
/follows/example
/follows
undocumented /follows
GET /feeds/following — list who the current user follows.
/follows
/follows
Follow a member
POST /feeds/follow — follow a member or team.
target_mrn
string · min length: 1
propertyName
anything
/follows
/grants/:id
undocumented /grants/:id
DELETE /grants/:id — revoke a grant. The grant row was loaded + authorized by can_manage_grant_by_id. Ownership grants are not revocable here.
id
string · path
/grants/example
/grants
undocumented /grants
GET /grants?resource_mrn=… — who has access to a record (members + roles, each with their level), plus whether the caller may manage it.
/grants
/grants
Grant access to a record
POST /grants — grant a member or role access to a record. Caps at the read/edit/manage ladder; ownership is never grantable here.
resource_mrn
string · min length: 5 · max length: 255
principal_type
principal_id
string · min length: 1 · max length: 100
action
propertyName
anything
/grants
/growth/goals/:id
undocumented /growth/goals/:id
id
string · path
/growth/goals/example
/growth/plans/:id
undocumented /growth/plans/:id
id
string · path
/growth/plans/example
/growth/signals/:id
undocumented /growth/signals/:id
id
string · path
/growth/signals/example
/growth/attributes/:id
undocumented /growth/attributes/:id
id
string · path
/growth/attributes/example
/growth/role-profiles/:id
undocumented /growth/role-profiles/:id
id
string · path
/growth/role-profiles/example
/growth/review-tasks/:id
undocumented /growth/review-tasks/:id
id
string · path
/growth/review-tasks/example
/growth/meeting-series/:id
undocumented /growth/meeting-series/:id
id
string · path
/growth/meeting-series/example
/growth/campaigns
undocumented /growth/campaigns
/growth/campaigns
/growth/campaigns/:id/results
undocumented /growth/campaigns/:id/results
Aggregated, min-group-size-suppressed engagement results for a campaign.
id
string · path
/growth/campaigns/example/results
/growth/goals
undocumented /growth/goals
/growth/goals
/growth/goals/summary
undocumented /growth/goals/summary
/growth/goals/summary
/growth/plans
undocumented /growth/plans
/growth/plans
/growth/signals
undocumented /growth/signals
/growth/signals
/growth/signals/:id
undocumented /growth/signals/:id
One signal. The full-page 1:1 view loads an interaction through here.
id
string · path
/growth/signals/example
/growth/signals/:id/action-items/tasks
undocumented /growth/signals/:id/action-items/tasks
GET /growth/signals/:id/action-items/tasks — the tasks this 1:1's action items were promoted into, read from the local projection (never from Tasks).
id
string · path
/growth/signals/example/action-items/tasks
/growth/attributes
undocumented /growth/attributes
/growth/attributes
/growth/role-profiles
undocumented /growth/role-profiles
/growth/role-profiles
/growth/role-profiles/:id
undocumented /growth/role-profiles/:id
GET /growth/role-profiles/:id — one career framework, ready to render. Carries the grid, the competencies its rows are drawn from, and the people who sit in the role. Those people come from growth_worker_index, growth's own projection of workers state (rule 5): matching is on the job title the worker events already carry, so nothing here reaches into the workers app.
id
string · path
/growth/role-profiles/example
/growth/review-tasks
undocumented /growth/review-tasks
/growth/review-tasks
/growth/meeting-series
undocumented /growth/meeting-series
/growth/meeting-series
/growth/skill-matrix
undocumented /growth/skill-matrix
Per-worker competency levels aggregated from structured review ratings. Attributed data, gated to growth.results.view in AUTHZ.
/growth/skill-matrix
/growth/concerns
undocumented /growth/concerns
GET /growth/concerns — the staff triage list: both streams, newest first. Gated to growth.results.view in AUTHZ (same crowd that reads anonymous pulse comments).
/growth/concerns
/growth/overview
undocumented /growth/overview
/growth/overview
/growth/campaigns
Create a survey
title
string · min length: 1 · max length: 120
kind
frequency
drivers
array
custom_questions
array
question_ids
array
review_kinds
array
enps
comment
starts_at
string
ends_at
string
propertyName
anything
/growth/campaigns
/growth/responses
Submit an anonymous pulse response
Submit an anonymous pulse response. NO identity is stored. ``actor_mrn`` is used ONLY to look up the respondent's coarse segment tags from the projection; it is never written to the response or the emitted event.
campaign_id
string · min length: 1
scores
object
custom_scores
array
enps
integer · min: 0 · max: 10
comment
string · max length: 2000
propertyName
anything
/growth/responses
/growth/responses/:id/replies
Reply to an anonymous comment
Reply to an anonymous comment. The reply is attributed (manager); the respondent stays anonymous. Routed by the opaque response id.
id
string · path
body
string · min length: 1 · max length: 2000
propertyName
anything
/growth/responses/example/replies
/growth/goals
Create a goal, KR or KPI
title
string · min length: 1 · max length: 200
kind
scope
subject_mrn
string · max length: 200
owner_mrn
string · max length: 200
parent_id
string · max length: 80
target
object
metric
string · max length: 120
start_value
number
target_value
number
unit
string · max length: 24
direction
period
string · max length: 40
starts_at
string
due_at
string
propertyName
anything
/growth/goals
/growth/goals/:id/progress
Log goal progress
id
string · path
value
number
note
string · max length: 500
propertyName
anything
/growth/goals/example/progress
/growth/plans
Create a development plan or PIP
title
string · min length: 1 · max length: 200
kind
subject_type
subject_mrn
string · max length: 200
owner_mrn
string · max length: 200
reason
string · max length: 4000
detail
object
milestones
array
starts_at
string
ends_at
string
propertyName
anything
/growth/plans
/growth/signals
Give feedback, praise, a 1:1 note or review
kind
subject_mrn
string · max length: 200
campaign_id
string · max length: 80
parent_id
string · max length: 80
series_id
string · max length: 80
visibility
body
object
text
string · max length: 8000
values
array
competencies
array
competency_ratings
array
agenda
array
action_items
array
check_in_items
array
private_note
string · max length: 8000
rating
number · min: 0 · max: 5
occurred_at
string
propertyName
anything
/growth/signals
/growth/signals/:id/action-items/:index/task
Turn a 1:1 action item into a task
POST /growth/signals/:id/action-items/:index/task — make this action item a real task. Growth never calls the Tasks API (rule 6): it emits, Tasks creates, and the resulting core.tasks.task.created comes back round the bus into growth_task_projection. So this answers 202, not 201 — the task does not exist yet when we reply.
id
string · path
index
string · path
board_id
string · min length: 1
propertyName
anything
/growth/signals/example/action-items/example/task
/growth/attributes
Create a competency, value or bank question
kind
name
string · min length: 1 · max length: 120
description
string · max length: 2000
category
string · max length: 80
levels
array
driver
scale
integer · min: 2 · max: 10
sort
integer · min: 0 · max: 999
propertyName
anything
/growth/attributes
/growth/role-profiles
Create a role profile
title
string · min length: 1 · max length: 120
track
string · max length: 80
level
string · max length: 40
description
string · max length: 2000
expectations
array
job_titles
array
propertyName
anything
/growth/role-profiles
/growth/review-tasks
Nominate a peer or upward reviewer
Peer / upward nomination. Self and manager tasks come from cycle launch.
campaign_id
string · min length: 1 · max length: 80
kind
reviewer_mrn
string · min length: 1 · max length: 200
subject_mrn
string · max length: 200
due_at
string
propertyName
anything
/growth/review-tasks
/growth/meeting-series
Start a recurring 1:1
participant_mrn
string · min length: 1 · max length: 200
title
string · max length: 120
cadence
next_at
string
agenda
array
propertyName
anything
/growth/meeting-series
/growth/concerns
Raise a concern, anonymously or named
POST /growth/concerns — file a concern, anonymously or named. Anonymous: actor_mrn is used ONLY to derive coarse segment tags (exactly like a pulse response); no identity is stored on the row or the event. Named: a complaint signal authored by the caller, visible to managers/HR.
body
string · min length: 1 · max length: 4000
anonymous
propertyName
anything
/growth/concerns
/growth/campaigns/:id
Update or launch a survey
id
string · path
title
string · min length: 1 · max length: 120
status
frequency
drivers
array
custom_questions
array
question_ids
array
review_kinds
array
enps
comment
starts_at
string
ends_at
string
propertyName
anything
/growth/campaigns/example
/growth/goals/:id
Update a goal
id
string · path
title
string · min length: 1 · max length: 200
status
owner_mrn
string · max length: 200
parent_id
string · max length: 80
target
object
period
string · max length: 40
due_at
string
propertyName
anything
/growth/goals/example
/growth/plans/:id
Update a plan
id
string · path
title
string · min length: 1 · max length: 200
status
owner_mrn
string · max length: 200
reason
string · max length: 4000
detail
object
starts_at
string
ends_at
string
propertyName
anything
/growth/plans/example
/growth/signals/:id
Update a signal
id
string · path
visibility
body
object
rating
number · min: 0 · max: 5
status
series_id
string · max length: 80
private_note
string · max length: 8000
propertyName
anything
/growth/signals/example
/growth/attributes/:id
Update a competency, value or question
id
string · path
name
string · min length: 1 · max length: 120
description
string · max length: 2000
category
string · max length: 80
levels
array
driver
scale
integer · min: 2 · max: 10
sort
integer · min: 0 · max: 999
status
propertyName
anything
/growth/attributes/example
/growth/role-profiles/:id
Update a role profile
id
string · path
title
string · min length: 1 · max length: 120
track
string · max length: 80
level
string · max length: 40
description
string · max length: 2000
expectations
array
job_titles
array
matrix
object
status
propertyName
anything
/growth/role-profiles/example
/growth/review-tasks/:id
Update a review task
id
string · path
status
due_at
string
extension_until
string
extension_note
string · max length: 500
extension
propertyName
anything
/growth/review-tasks/example
/growth/meeting-series/:id
Update a 1:1 series
id
string · path
title
string · max length: 120
cadence
next_at
string
agenda
array
status
propertyName
anything
/growth/meeting-series/example
/health
undocumented /health
/health
/holidays/:id
undocumented /holidays/:id
id
string · path
/holidays/example
/holidays
undocumented /holidays
/holidays
/holidays
Create a holiday
name
string · min length: 1 · max length: 100
date
string · min length: 1
is_recurring
propertyName
anything
/holidays
/holidays/:id
Update a holiday
id
string · path
name
string · min length: 1 · max length: 100
date
string · min length: 1
is_recurring
propertyName
anything
/holidays/example
/hooks/mxs
undocumented /hooks/mxs
POST /hooks/mxs — the MX box posts here when mail is delivered. Not session-authed; verified by HMAC over the raw body with MX_WEBHOOK_SECRET. Looks up the mailbox's workspace, syncs the new mail into the cache, and nudges its open clients.
/hooks/mxs
/installations/:slug
undocumented /installations/:slug
DELETE /installations/:slug — Uninstall an app (admin/owner only).
slug
string · path
/installations/example
/installations
undocumented /installations
GET /installations — List installed apps for the workspace. Default view returns apps the current member can access (UI grid). Pass ?policy=1 (owner/admin only) to include access_policy + allowed_roles for every installed app — used by the App Access admin screen.
/installations
/interactions/:interaction_id
undocumented /interactions/:interaction_id
DELETE /interactions/:interaction_id — delete an interaction.
interaction_id
string · path
/interactions/example
/interactions
undocumented /interactions
GET /interactions — all interactions (activity reports).
/interactions
/interactions
Log an interaction
POST /interactions — log an interaction.
contact_id
string
company_id
string
source_mrn
string
type
direction
subject
string · max length: 200
content
string · max length: 10000
occurred_at
string
duration_minutes
integer
rating
object
propertyName
anything
/interactions
/interactions/:interaction_id
Update an interaction
PUT /interactions/:interaction_id — update an interaction.
interaction_id
string · path
subject
string · max length: 200
content
string · max length: 10000
occurred_at
string
duration_minutes
integer
propertyName
anything
/interactions/example
/invitations/:token
undocumented /invitations/:token
token
string · path
/invitations/example
/invoices/:id
undocumented /invoices/:id
GET /invoices/:id — return full invoice data with line items.
id
string · path
/invoices/example
/finance/invoices/:entry_id
Issue/void an invoice
entry_id
string · path
status
propertyName
anything
/finance/invoices/example
/finance/invoices
Create an invoice
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
due_date
string · min length: 10
memo
string · max length: 5000
tags
array
sources
array
adjustments
array
dimensions
idempotency_key
string · max length: 100
propertyName
anything
/finance/invoices
/finance/invoices/:entry_id/pdfs
Generate invoice PDF
entry_id
string · path
template
string · max length: 100
propertyName
anything
/finance/invoices/example/pdfs
/finance/invoices/:entry_id/sends
Email an invoice
entry_id
string · path
to
string · min length: 1 · max length: 500
cc
string · max length: 500
subject
string · max length: 300
message
string · max length: 5000
attach_pdf
propertyName
anything
/finance/invoices/example/sends
/finance/invoices/:entry_id/reminders
Send an overdue reminder
entry_id
string · path
to
string · min length: 1 · max length: 500
subject
string · max length: 300
message
string · max length: 5000
propertyName
anything
/finance/invoices/example/reminders
/invoices/:id/charges
undocumented /invoices/:id/charges
POST /invoices/:id/charges — retry charging the default payment method.
id
string · path
/invoices/example/charges
/finance/invoices/:entry_id
Update a draft invoice
entry_id
string · path
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
due_date
string · min length: 10
memo
string · max length: 5000
tags
array
adjustments
array
dimensions
propertyName
anything
/finance/invoices/example
/finance/journal-entries/:entry_id
Post/void a journal
entry_id
string · path
status
propertyName
anything
/finance/journal-entries/example
/finance/journal-entries
Create a journal entry
date
string · min length: 10
lines
array
memo
string · max length: 5000
currency
string · min length: 3 · max length: 3
exchange_rate
number
tags
array
dimensions
idempotency_key
string · max length: 100
propertyName
anything
/finance/journal-entries
/finance/journal-entries/:entry_id
Update a draft journal
entry_id
string · path
date
string · min length: 10
lines
array
memo
string · max length: 5000
currency
string · min length: 3 · max length: 3
exchange_rate
number
tags
array
dimensions
propertyName
anything
/finance/journal-entries/example
/leave-balances/:id/adjustments
Adjust a leave balance
Manual balance adjustment (admin only).
id
string · path
amount
number
reason
string · min length: 1 · max length: 500
propertyName
anything
/leave-balances/example/adjustments
/leave-policies
Create a leave policy
name
string · min length: 1 · max length: 100
type
allowance
number
description
string · max length: 500
accrual
max_carry_over
number
requires_approval
min_notice_days
integer
max_consecutive_days
integer
applies_to
cycle_start
default_approver_mrns
array
propertyName
anything
/leave-policies
/leave-policies/:id/members
Assign workers to a leave policy
POST /leave-policies/:id/members — Assign workers to a policy and provision balances.
id
string · path
worker_mrns
array
propertyName
anything
/leave-policies/example/members
/leave-policies/:id
Update a leave policy
id
string · path
name
string · min length: 1 · max length: 100
description
string · max length: 500
allowance
number
accrual
max_carry_over
number
requires_approval
min_notice_days
integer
max_consecutive_days
integer
applies_to
cycle_start
is_active
default_approver_mrns
array
propertyName
anything
/leave-policies/example
/leave-balances
undocumented /leave-balances
List balances for the current user's worker record. Self view: only balances for policies the worker is currently assigned to. Orphan rows (pre-membership provisioning, or kept after unassignment because days were used) stay in the table for history but are not returned here; the manager view (GET /leave-balances/:worker_mrn) still exposes them.
/leave-balances
/leave-balances/:worker_mrn
undocumented /leave-balances/:worker_mrn
List balances for a specific worker (manager/admin).
worker_mrn
string · path
/leave-balances/example
/leave-calculate-days
undocumented /leave-calculate-days
Calculate working days between two dates.
/leave-calculate-days
/leave-calendar
undocumented /leave-calendar
Team calendar — approved PTOs + holidays for a date range.
/leave-calendar
/leave-policies/:id
undocumented /leave-policies/:id
id
string · path
/leave-policies/example
/leave-policies/:id/members/:worker_mrn
undocumented /leave-policies/:id/members/:worker_mrn
DELETE /leave-policies/:id/members/:worker_mrn — Remove a worker from a policy.
id
string · path
worker_mrn
string · path
/leave-policies/example/members/example
/leave-policies
undocumented /leave-policies
/leave-policies
/leave-policies/:id
undocumented /leave-policies/:id
id
string · path
/leave-policies/example
/leave-policies/:id/members
undocumented /leave-policies/:id/members
GET /leave-policies/:id/members — List workers assigned to a policy.
id
string · path
/leave-policies/example/members
/leave-reconciliation
undocumented /leave-reconciliation
GET /leave-reconciliation — future bookings whose day count changed under the current working pattern, with a read-only entitlement pro-ration hint.
/leave-reconciliation
/leave-reconciliation
undocumented /leave-reconciliation
POST /leave-reconciliation — recount every affected future booking and adjust its balance (admin sign-off). Past/in-progress untouched; approved bookings re-emit so the attendance projection rebuilds on the new pattern. Entitlement pro-ration is NOT done here — it's a separate audited adjustment.
/leave-reconciliation
/calls/:id/links/:link_id
Update a join link
id
string · path
link_id
string · path
is_active
external_join_mode
propertyName
anything
/calls/example/links/example
/calls/:id/links
Create a join link
id
string · path
expires_at
string
guest_name
string · max length: 200
guest_email
string · max length: 200
external_join_mode
propertyName
anything
/calls/example/links
/chats/lists/:list_id
Update a chat list
PATCH /chats/lists/:list_id — rename or reorder a list.
list_id
string · path
name
string · min length: 1 · max length: 50
position
integer
propertyName
anything
/chats/lists/example
/chats/lists
Create a chat list
POST /chats/lists — create a personal chat list.
name
string · min length: 1 · max length: 50
chat_ids
array
propertyName
anything
/chats/lists
/login
undocumented /login
GET / login on the ROOT domain: which workspace are you signing in to? There is no global login any more, so this page has no credential field. It takes a workspace name and forwards to that workspace's own sign-in page. It also lists any workspace this browser is already signed into, read straight out of the session. That is not the deferred "email me my workspaces" recovery flow, it is just showing what the cookie already knows, so somebody who is signed in never lands here with nothing to click.
/login
/login
undocumented /login
GET /login on a WORKSPACE subdomain: ask for the address, mail proof. The subdomain already names the workspace, so the page can say which one you are signing in to, and the session it eventually mints is scoped to it.
/login
/logout
undocumented /logout
/logout
/wands/macro-previews
Try a single macro against a sample event
Run a single macro against a sample event and return what it produced. The teaching sandbox behind the macro reference page. Reads run for real with the viewer's own permissions; anything that writes is simulated (dry_run is forced server-side and is not caller-controllable).
macro
string · min length: 2 · max length: 40
args
payload
event_name
string · max length: 200
propertyName
anything
/wands/macro-previews
/mail/accounts/:account_id
undocumented /mail/accounts/:account_id
account_id
string · path
/mail/accounts/example
/mail/accounts/:account_id/messages/:message_id
undocumented /mail/accounts/:account_id/messages/:message_id
account_id
string · path
message_id
string · path
/mail/accounts/example/messages/example
/mail/accounts/:account_id/signatures/:signature_id
undocumented /mail/accounts/:account_id/signatures/:signature_id
account_id
string · path
signature_id
string · path
/mail/accounts/example/signatures/example
/mail/accounts/:account_id/filters/:filter_id
undocumented /mail/accounts/:account_id/filters/:filter_id
account_id
string · path
filter_id
string · path
/mail/accounts/example/filters/example
/mail/accounts/:account_id/blocked-senders/:blocked_id
undocumented /mail/accounts/:account_id/blocked-senders/:blocked_id
account_id
string · path
blocked_id
string · path
/mail/accounts/example/blocked-senders/example
/mail/domains/:domain_id
undocumented /mail/domains/:domain_id
Remove a domain (pending typo or live). Cleans the MX box (virtual domain + DKIM, cascading its mailboxes) best-effort, then removes the platform rows.
domain_id
string · path
/mail/domains/example
/mail/mailboxes/:mailbox_id
undocumented /mail/mailboxes/:mailbox_id
mailbox_id
string · path
/mail/mailboxes/example
/mail/groups/:group_id
undocumented /mail/groups/:group_id
Remove a shared mailbox: tear down its aliases + backing mailbox on the MX box, then drop the group, its members, and the mailbox row. Best-effort on the box so a local cleanup still completes if the server is unreachable.
group_id
string · path
/mail/groups/example
/mail/groups/:group_id/members/:member_id
undocumented /mail/groups/:group_id/members/:member_id
group_id
string · path
member_id
string · path
/mail/groups/example/members/example
/mail/groups/:group_id/messages/:message_id
undocumented /mail/groups/:group_id/messages/:message_id
group_id
string · path
message_id
string · path
/mail/groups/example/messages/example
/mail/drafts/:draft_id
undocumented /mail/drafts/:draft_id
draft_id
string · path
/mail/drafts/example
/mail/mailboxes/:mailbox_id/outbox-keys/:key_id
undocumented /mail/mailboxes/:mailbox_id/outbox-keys/:key_id
Remove the audit row — only after revoke, same as API keys.
mailbox_id
string · path
key_id
string · path
/mail/mailboxes/example/outbox-keys/example
/mail/oauth/:provider/authorize
undocumented /mail/oauth/:provider/authorize
provider
string · path
/mail/oauth/example/authorize
/mail/oauth/:provider/callback
undocumented /mail/oauth/:provider/callback
provider
string · path
/mail/oauth/example/callback
/mail/accounts
undocumented /mail/accounts
/mail/accounts
/mail/recipients
undocumented /mail/recipients
Typeahead source for the compose recipient fields: workspace members who have been assigned a mail account (a personal mailbox or a connected Gmail/Outlook). The contacts directory — people already emailed or received from — is merged client-side from the contacts app, so mail never reads another app's tables (rule 6).
/mail/recipients
/mail/unified/messages
undocumented /mail/unified/messages
Merge one folder (default inbox) across the member's accounts flagged show_in_unified plus any shared inboxes the member belongs to. The folder is selectable so the "All inboxes" view works for Sent, Archive, Spam, etc. — not just Inbox.
/mail/unified/messages
/mail/accounts/:account_id/messages
undocumented /mail/accounts/:account_id/messages
account_id
string · path
/mail/accounts/example/messages
/mail/accounts/:account_id/messages/:message_id
undocumented /mail/accounts/:account_id/messages/:message_id
account_id
string · path
message_id
string · path
/mail/accounts/example/messages/example
/mail/accounts/:account_id/messages/:message_id/attachments/:index
undocumented /mail/accounts/:account_id/messages/:message_id/attachments/:index
Stream one attachment of a message as a download. Bytes live only in the IMAP message (not our storage), so they're fetched from the provider on demand.
account_id
string · path
message_id
string · path
index
string · path
/mail/accounts/example/messages/example/attachments/example
/mail/accounts/:account_id/messages/:message_id/calendar
undocumented /mail/accounts/:account_id/messages/:message_id/calendar
Parse the calendar invite(s) (.ics) attached to a message into platform-calendar event fields, so the client can add them via POST /meetings. Attachment bytes are only fetched from Saasmail (MX) inboxes — the same limitation as attachment download.
account_id
string · path
message_id
string · path
/mail/accounts/example/messages/example/calendar
/mail/accounts/:account_id/folders
undocumented /mail/accounts/:account_id/folders
account_id
string · path
/mail/accounts/example/folders
/mail/accounts/:account_id/signatures
undocumented /mail/accounts/:account_id/signatures
account_id
string · path
/mail/accounts/example/signatures
/mail/accounts/:account_id/filters
undocumented /mail/accounts/:account_id/filters
account_id
string · path
/mail/accounts/example/filters
/mail/accounts/:account_id/blocked-senders
undocumented /mail/accounts/:account_id/blocked-senders
account_id
string · path
/mail/accounts/example/blocked-senders
/mail/domains
undocumented /mail/domains
/mail/domains
/mail/mailboxes
undocumented /mail/mailboxes
/mail/mailboxes
/mail/groups
undocumented /mail/groups
/mail/groups
/mail/groups/:group_id/members
undocumented /mail/groups/:group_id/members
group_id
string · path
/mail/groups/example/members
/mail/groups/:group_id/drafts
undocumented /mail/groups/:group_id/drafts
In-progress (unsent) drafts for a group — co-editors open these to edit together. Reply tier required: read-only members don't see drafts still being composed.
group_id
string · path
/mail/groups/example/drafts
/mail/groups/:group_id/thread
undocumented /mail/groups/:group_id/thread
The group conversation — sent drafts in order, each showing who sent it.
group_id
string · path
/mail/groups/example/thread
/mail/groups/:group_id/messages
undocumented /mail/groups/:group_id/messages
group_id
string · path
/mail/groups/example/messages
/mail/groups/:group_id/messages/:message_id
undocumented /mail/groups/:group_id/messages/:message_id
group_id
string · path
message_id
string · path
/mail/groups/example/messages/example
/mail/groups/:group_id/messages/:message_id/attachments/:index
undocumented /mail/groups/:group_id/messages/:message_id/attachments/:index
group_id
string · path
message_id
string · path
index
string · path
/mail/groups/example/messages/example/attachments/example
/mail/groups/:group_id/messages/:message_id/calendar
undocumented /mail/groups/:group_id/messages/:message_id/calendar
Parse the calendar invite(s) (.ics) attached to a shared-inbox message into platform-calendar event fields (same as the personal-account endpoint).
group_id
string · path
message_id
string · path
/mail/groups/example/messages/example/calendar
/mail/drafts
undocumented /mail/drafts
The member's own personal (non-group) unsent drafts, newest first.
/mail/drafts
/mail/mailboxes/:mailbox_id/outbox-keys
undocumented /mail/mailboxes/:mailbox_id/outbox-keys
List a mailbox's outbox keys (prefix, name, status, last used) — never the secret. 404 for a caller who fails the mint-identity gate.
mailbox_id
string · path
/mail/mailboxes/example/outbox-keys
/mail/accounts/:account_id
Update mail account
account_id
string · path
display_name
string · max length: 200
show_in_unified
propertyName
anything
/mail/accounts/example
/mail/accounts/:account_id/messages/:message_id
Modify a message
account_id
string · path
message_id
string · path
is_read
is_starred
folder
string · min length: 1 · max length: 100
propertyName
anything
/mail/accounts/example/messages/example
/mail/groups/:group_id
undocumented /mail/groups/:group_id
Cosmetic group settings. Any member may set the shared inbox's badge color; only admins may rename it.
group_id
string · path
/mail/groups/example
/mail/groups/:group_id/messages/:message_id
Modify a shared-inbox message
group_id
string · path
message_id
string · path
is_read
is_starred
folder
string · min length: 1 · max length: 100
propertyName
anything
/mail/groups/example/messages/example
/mail/accounts/:account_id/messages
Send a message
account_id
string · path
to
array
cc
array
bcc
array
subject
string · max length: 998
body_text
string
body_html
string
is_draft
signature_id
string · min length: 1
attachments
array
in_reply_to
string · max length: 998
references
string · max length: 8000
propertyName
anything
/mail/accounts/example/messages
/mail/accounts/:account_id/signatures
Create signature
account_id
string · path
name
string · min length: 1 · max length: 100
body_html
string · max length: 40000
is_default
propertyName
anything
/mail/accounts/example/signatures
/mail/accounts/:account_id/images
undocumented /mail/accounts/:account_id/images
POST an inline image (multipart) for use inside a signature or a composed message. Stored in R2 and returned as a permanent public URL so it renders in recipients' mail clients (hosted images, not data-URIs or CID attachments).
account_id
string · path
/mail/accounts/example/images
/mail/accounts/:account_id/filters
Create filter
account_id
string · path
name
string · min length: 1 · max length: 200
conditions
object
actions
object
propertyName
anything
/mail/accounts/example/filters
/mail/accounts/:account_id/blocked-senders
Block a sender
account_id
string · path
blocked
string · min length: 3 · max length: 254
propertyName
anything
/mail/accounts/example/blocked-senders
/mail/domains/:domain_id/verifications
undocumented /mail/domains/:domain_id/verifications
Check DNS for the ownership token (+ the mail records). Only marks the domain verified/usable once the ownership TXT resolves.
domain_id
string · path
/mail/domains/example/verifications
/mail/drafts
Create draft
subject
string · max length: 998
body_html
string
recipients
object
attachments
array
group_id
string · min length: 1 · max length: 64
account_id
string · min length: 1 · max length: 64
in_reply_to
string · max length: 998
references
string · max length: 8000
quoted_html
string
propertyName
anything
/mail/drafts
/mail/drafts/:draft_id/send
Send draft
draft_id
string · path
subject
string · max length: 998
body_html
string
recipients
object
propertyName
anything
/mail/drafts/example/send
/mail/accounts/:account_id/signatures/:signature_id
Update signature
account_id
string · path
signature_id
string · path
name
string · min length: 1 · max length: 100
body_html
string · max length: 40000
is_default
propertyName
anything
/mail/accounts/example/signatures/example
/mail/drafts/:draft_id
Save draft
draft_id
string · path
subject
string · max length: 998
body_html
string
recipients
object
attachments
array
group_id
string · min length: 1 · max length: 64
account_id
string · min length: 1 · max length: 64
in_reply_to
string · max length: 998
references
string · max length: 8000
quoted_html
string
propertyName
anything
/mail/drafts/example
/mail/mailboxes/:mailbox_id/outbox-keys/:key_id/secret
undocumented /mail/mailboxes/:mailbox_id/outbox-keys/:key_id/secret
Replace the secret; the old one dies now. New secret shown once.
mailbox_id
string · path
key_id
string · path
/mail/mailboxes/example/outbox-keys/example/secret
/exchanges
Send mail as a hosted mailbox
Send as a hosted mailbox. authz_exchange_send already passed the slk_ (steps 1-3 of the auth order); this handler runs steps 4-6 — the outbox key must hash to a live key on an active MX mailbox in this workspace — then validates the body, applies limits and idempotency, and submits through the existing MX path (postfix :587 as the mailbox, copy in Sent).
to
array
cc
array
bcc
array
subject
string · max length: 998
html
string
text
string
from_name
string · max length: 200
reply_to
string · max length: 254 · email
attachments
array
in_reply_to
string · max length: 998
references
string · max length: 8000
propertyName
anything
/exchanges
/mail/mailboxes/:mailbox_id/outbox-keys
Mint an outbox key
Mint a named key for this shared mailbox. The secret appears in this response only; the row stores its sha256. kind is always 'shared' now (personal mailboxes have no keys) and the send path re-checks it.
mailbox_id
string · path
name
string · min length: 1 · max length: 100
expires_at
string · max length: 64
propertyName
anything
/mail/mailboxes/example/outbox-keys
/mail/mailboxes/:mailbox_id/outbox-keys/:key_id
Rename or revoke an outbox key
Rename and/or revoke a key. Revocation is soft and takes effect on the key's next send; the row stays as an audit record until deleted.
mailbox_id
string · path
key_id
string · path
name
string · min length: 1 · max length: 100
status
string
propertyName
anything
/mail/mailboxes/example/outbox-keys/example
/mail/domains/:domain_id
Set domain catch-all
Set/clear the wildcard catch-all address for a domain.
domain_id
string · path
catch_all_to
string · max length: 254
propertyName
anything
/mail/domains/example
/mail/mailboxes/:mailbox_id
Assign a mailbox to a member
Assign (or unassign, with an empty member_mrn) a provisioned mailbox to a member. Keeps the member's connected-accounts mirror in sync so it appears in their client.
mailbox_id
string · path
member_mrn
string · max length: 200
propertyName
anything
/mail/mailboxes/example
/mail/groups/:group_id/members/:member_id
Change member tier
Change an assignee's content-permission tier. Admins only — membership and tier assignment are group configuration, not a content capability.
group_id
string · path
member_id
string · path
role
string
propertyName
anything
/mail/groups/example/members/example
/mail/domains
Add a mail domain
Register a domain as PENDING and return the DNS to publish. Nothing is activated and no DNS is written on the owner's behalf — they publish the records, then verify.
domain
string · min length: 3 · max length: 253
propertyName
anything
/mail/domains
/mail/mailboxes
Provision a mailbox
local_part
string · min length: 1 · max length: 64
member_mrn
string · max length: 200
display_name
string · max length: 200
quota_mb
integer · min: 10 · max: 51200
propertyName
anything
/mail/mailboxes
/mail/mailboxes/bulk
Provision many mailboxes
Create many addresses on one verified domain at once (editable grid / CSV upload). Each row is validated and provisioned independently: a malformed local-part or an address that already exists is reported back under `skipped` (with a reason) while the rest are still created — partial success, never an all-or-nothing batch.
domain_id
string · min length: 1 · max length: 64
mailboxes
array
propertyName
anything
/mail/mailboxes/bulk
/mail/groups
Create group mailbox
name
string · min length: 1 · max length: 120
local_part
string · min length: 1 · max length: 64
domain_id
string · min length: 1 · max length: 64
aliases
array
member_mrns
array
propertyName
anything
/mail/groups
/mail/groups/:group_id/members
Add group member
group_id
string · path
member_mrn
string · min length: 1 · max length: 200
role
string
propertyName
anything
/mail/groups/example/members
/demo-requests
Request a demo
POST /demo-requests — public lead capture for "Book a demo" (no auth).
name
string · min length: 1 · max length: 120
work_email
string · min length: 1 · email
slot
string · min length: 1 · max length: 40
company
string · max length: 200
team_size
string · max length: 40
message
string · max length: 1000
timezone
string · max length: 64
website
string · max length: 200
propertyName
anything
/demo-requests
/me
undocumented /me
/me
/me/notification-preferences
undocumented /me/notification-preferences
/me/notification-preferences
/meetings/:id
undocumented /meetings/:id
id
string · path
/meetings/example
/meetings/:id/attendees/:attendee_id
undocumented /meetings/:id/attendees/:attendee_id
id
string · path
attendee_id
string · path
/meetings/example/attendees/example
/meetings
undocumented /meetings
/meetings
/meetings/:id/attendees
undocumented /meetings/:id/attendees
id
string · path
/meetings/example/attendees
/meetings/:id
Update a meeting
id
string · path
title
string · min length: 1 · max length: 300
description
string
start_datetime
string
end_datetime
string
timezone
string
is_all_day
color
string
type
string
status
string
recurrence_rule
string
visibility
string
propertyName
anything
/meetings/example
/meetings
Create a meeting
title
string · min length: 1 · max length: 300
start_datetime
string · min length: 1
end_datetime
string · min length: 1
description
string
timezone
string
is_all_day
color
string
type
string
status
string
create_call
recurrence_rule
string
visibility
string
attendees
array
external_invitees
array
propertyName
anything
/meetings
/meetings/:id/attendees
undocumented /meetings/:id/attendees
id
string · path
/meetings/example/attendees
/meetings/:id/call
undocumented /meetings/:id/call
id
string · path
/meetings/example/call
/meetings/:id/rsvp
Set your RSVP for a meeting
PUT /meetings/:id/rsvp — the authenticated caller sets their own RSVP.
id
string · path
status
propertyName
anything
/meetings/example/rsvp
/members/:member_id
undocumented /members/:member_id
DELETE /accounts/organisation/members/:member_id — Remove a member.
member_id
string · path
/members/example
/members
undocumented /members
GET /members — Search workspace members by name or email.
/members
/members/:member_id
undocumented /members/:member_id
PATCH /accounts/organisation/members/:member_id — Change platform role.
member_id
string · path
/members/example
/members
Invite member
POST /accounts/organisation/members — Invite a member.
email
string · min length: 1 · email
full_name
string · max length: 200
role
propertyName
anything
/members
/members/bulk
Bulk invite members
POST /members/bulk — Invite multiple members at once.
members
array
propertyName
anything
/members/bulk
/members/:member_id/invitations
undocumented /members/:member_id/invitations
POST /members/:member_id/invitations — Re-invite a member with a fresh token.
member_id
string · path
/members/example/invitations
/members/:member_id/password-resets
undocumented /members/:member_id/password-resets
POST /members/:member_id/password-resets — Send a 'Set Your Password' email.
member_id
string · path
/members/example/password-resets
/members/:member_id/sessions
Force logout member
POST /members/:member_id/sessions — really sign a member out of THIS workspace. This used to push a WebSocket frame and hope the browser was listening, which a closed tab, an offline client, or anyone holding the cookie in curl simply ignored. Then it rotated the profile's security stamp, which worked but was per IDENTITY: the same person signed into another workspace under the same email got kicked out of that one too, by an admin with no authority there. Since migration 079 every session has its own row tagged with the workspace it belongs to, so this revokes exactly the rows for this workspace. The socket push stays as the courtesy, not the mechanism.
member_id
string · path
action
propertyName
anything
/members/example/sessions
/messages
undocumented /messages
GET /messages — support threads list page.
/messages
/messages/:thread_id
undocumented /messages/:thread_id
GET /messages/:thread_id — thread conversation page.
thread_id
string · path
/messages/example
/chats/:id/messages/:msg_id
Edit a message
PATCH /chats/:id/messages/:msg_id — edit a message.
id
string · path
msg_id
string · path
content
string · min length: 1 · max length: 10000
propertyName
anything
/chats/example/messages/example
/calls/:id/messages
Send a chat message
id
string · path
content
string · min length: 1 · max length: 2000
propertyName
anything
/calls/example/messages
/chats/:id/messages
Send a message
POST /chats/:id/messages — send a message.
id
string · path
to
array
cc
array
bcc
array
subject
string · max length: 998
body_text
string
body_html
string
is_draft
signature_id
string · min length: 1
attachments
array
in_reply_to
string · max length: 998
references
string · max length: 8000
propertyName
anything
/chats/example/messages
/notifications/:id
undocumented /notifications/:id
Hard-delete a single notification.
id
string · path
/notifications/example
/notifications
undocumented /notifications
/notifications
/notifications/unread-count
undocumented /notifications/unread-count
/notifications/unread-count
/notifications/:id
undocumented /notifications/:id
Mark a single notification as read.
id
string · path
/notifications/example
/notifications
undocumented /notifications
Mark all notifications as read for the authenticated member.
/notifications
/o1/calls/:token/sessions
undocumented /o1/calls/:token/sessions
Guest gave up waiting or left the lobby page. Marks the participant row as 'left' and clears the waiting-guest entry for hosts.
token
string · path
/o1/calls/example/sessions
/o1/calendar/rsvp/:token
undocumented /o1/calendar/rsvp/:token
GET /o1/calendar/rsvp/:token — public one-click RSVP from an invite email. Anonymous (the /o1/ namespace skips the session); enforce_workspace injects a workspace-scoped ctx.db. A `?status=` records the response, then a confirmation page lets the invitee change it.
token
string · path
/o1/calendar/rsvp/example
/o1/calls/:token
undocumented /o1/calls/:token
Public guest lobby page at /o1/calls/:token. Unauthenticated — core.tenant.enforce_workspace injects ctx.db via the subdomain slug but does not require a session. Renders a standalone page (no shell) with a camera preview and display-name input. Invalid/expired tokens and ended calls both render the generic 'not_found' state.
token
string · path
/o1/calls/example
/o1/calls/:token/admission
undocumented /o1/calls/:token/admission
Poll endpoint. Returns one of: - {state: 'waiting'} — host hasn't decided yet - {state: 'admitted', lk_token, lk_url, lk_room_name, participant_id, call_id} - {state: 'denied'} — host declined - {state: 'not_found'} — link expired / call ended while waiting
token
string · path
/o1/calls/example/admission
/o1/calls/:token/messages
undocumented /o1/calls/:token/messages
Chat history for an in-call guest. Same call_messages space as members.
token
string · path
/o1/calls/example/messages
/o1/contacts/widget.js
undocumented /o1/contacts/widget.js
GET /o1/contacts/widget.js — the loader the customer pastes on their site. Deliberately key-agnostic: it reads ``data-key`` off its own script tag at runtime, so one cached script serves every workspace. It injects a bubble and an iframe pointed at this origin, which is why the host page needs no CORS setup and never touches our cookies.
/o1/contacts/widget.js
/o1/contacts/widget/:key
undocumented /o1/contacts/widget/:key
GET /o1/contacts/widget/:key — the iframe panel: form, then thread. ``frame-ancestors`` is the enforcement point for allowed_origins: an unlisted site can load the script but cannot frame the panel.
key
string · path
/o1/contacts/widget/example
/o1/contacts/widget/:key/conversation/messages
undocumented /o1/contacts/widget/:key/conversation/messages
GET /o1/contacts/widget/:key/conversation/messages — thread poll. Internal notes are excluded in the query, not the template: a colleague's aside must not be one rendering bug away from the visitor.
key
string · path
/o1/contacts/widget/example/conversation/messages
/o1/crm/:token
undocumented /o1/crm/:token
token
string · path
/o1/crm/example
/o1/files/s/:token
undocumented /o1/files/s/:token
GET /o1/files/s/:token — public share page (file or folder).
token
string · path
/o1/files/s/example
/o1/files/s/:token/download
undocumented /o1/files/s/:token/download
GET /o1/files/s/:token/download — count the download, redirect to R2. For folder shares ``?file_id=`` names the file, which must live inside the shared subtree. The download counter increments atomically with the max_downloads guard so the limit cannot be raced past.
token
string · path
/o1/files/s/example/download
/o1/finance/:token
undocumented /o1/finance/:token
token
string · path
/o1/finance/example
/o1/finance/:token/pdf
undocumented /o1/finance/:token/pdf
Redirect to a short-lived presigned URL for the latest stored PDF.
token
string · path
/o1/finance/example/pdf
/o1/sign/:token
undocumented /o1/sign/:token
GET /o1/sign/:token — the public signing room. Never leaks whether a document exists: unknown/expired/used tokens all render the generic not-found state. On the first open of an actionable room the recipient is marked viewed (audit + core.sign.document.viewed).
token
string · path
/o1/sign/example
/o1/sign/links/:link_token
undocumented /o1/sign/links/:link_token
GET /o1/sign/links/:link_token — the public self-serve start page: the visitor enters their own name and email; submitting clones the template into their own envelope and forwards them to its signing room.
link_token
string · path
/o1/sign/links/example
/o1/calls/:token/sessions
undocumented /o1/calls/:token/sessions
Guest posts `{display_name}` to request admission. In auto mode the response contains an LK token immediately; in lobby mode the response is `{state: 'waiting'}` and the guest polls the admission endpoint until a host admits them (or denies).
token
string · path
/o1/calls/example/sessions
/o1/calls/:token/sessions/leave
undocumented /o1/calls/:token/sessions/leave
Guest gave up waiting or left the lobby page. Marks the participant row as 'left' and clears the waiting-guest entry for hosts.
token
string · path
/o1/calls/example/sessions/leave
/o1/calls/:token/hand
undocumented /o1/calls/:token/hand
A view-only guest in a broadcast call asks to speak (or lowers their hand). Relayed to the room so hosts can promote them. Body: {raised: bool}.
token
string · path
/o1/calls/example/hand
/o1/calls/:token/reactions
undocumented /o1/calls/:token/reactions
A guest sends an emoji reaction. Relayed to the whole room (members and other guests) as an ephemeral floating reaction. Body: {emoji: str}. The emoji must be one of the allowed reactions, so the broadcast never carries arbitrary content.
token
string · path
/o1/calls/example/reactions
/o1/calls/:token/messages
undocumented /o1/calls/:token/messages
A guest posts into the shared call chat. Persisted to the same call_messages table as members and delivered to members (their WS) and other guests (the per-call guest sockets).
token
string · path
/o1/calls/example/messages
/o1/contacts/widget/:key/attest
undocumented /o1/contacts/widget/:key/attest
POST /o1/contacts/widget/:key/attest — bind this iframe to a parent site. Called from inside the panel after the parent loader postMessages its origin, or from ``document.referrer`` when Referrer-Policy stripped the navigation Referer. Only mints the cookie when the claimed parent host is on this embed's allowlist.
key
string · path
/o1/contacts/widget/example/attest
/o1/contacts/widget/:key/conversations
undocumented /o1/contacts/widget/:key/conversations
POST /o1/contacts/widget/:key/conversations — open a conversation. Name and message are required, email is optional: a visitor who will not identify themselves still gets answered, their thread simply stays guest.
key
string · path
/o1/contacts/widget/example/conversations
/o1/contacts/widget/:key/conversation/messages
undocumented /o1/contacts/widget/:key/conversation/messages
POST /o1/contacts/widget/:key/conversation/messages — visitor reply.
key
string · path
/o1/contacts/widget/example/conversation/messages
/o1/contacts/widget/:key/conversation/attachments
undocumented /o1/contacts/widget/:key/conversation/attachments
POST /o1/contacts/widget/:key/conversation/attachments A visitor sending a file. Doubly gated: the workspace must have ticked "allow uploads", and the caller must hold this conversation's visitor token, so nothing can be written until a real conversation exists. The allow-list, the byte cap and the per-conversation cap are all enforced server-side against the actual bytes received, never against a client-declared size or content type. The extension is derived from the sniffed type rather than the supplied filename, so "invoice.pdf.exe" cannot name its own destiny.
key
string · path
/o1/contacts/widget/example/conversation/attachments
/o1/contacts/widget/:key/conversation/rating
undocumented /o1/contacts/widget/:key/conversation/rating
POST /o1/contacts/widget/:key/conversation/rating — post-resolution CSAT. Only a resolved thread can be rated, and only once: the rating is the receipt for a specific resolution, not a running score.
key
string · path
/o1/contacts/widget/example/conversation/rating
/o1/crm/:token/responses
undocumented /o1/crm/:token/responses
Accept or decline the proposal. The transition runs here, server-side.
token
string · path
/o1/crm/example/responses
/o1/files/s/:token
undocumented /o1/files/s/:token
POST /o1/files/s/:token — verify the share password, set the proof cookie.
token
string · path
/o1/files/s/example
/o1/finance/:token/responses
undocumented /o1/finance/:token/responses
Quote accept/decline. Runs the same transition core as the staff PATCH, attributed to the portal link.
token
string · path
/o1/finance/example/responses
/o1/finance/:token/checkouts
undocumented /o1/finance/:token/checkouts
Start a hosted checkout with the workspace's own provider for the invoice's outstanding balance.
token
string · path
/o1/finance/example/checkouts
/o1/finance/:token/payments
undocumented /o1/finance/:token/payments
Verify pending checkouts against the provider and record the payment. Idempotent on the provider reference: re-verifying a settled checkout (or a double redirect) returns the recorded state without booking twice.
token
string · path
/o1/finance/example/payments
/o1/sign/:token/session
undocumented /o1/sign/:token/session
POST /o1/sign/:token/session — unlock + bootstrap the signing room. Verifies the access code (when required), then returns the presigned source-PDF URL, the recipient's own fields, and the branding the room renders. Consolidates the spec's separate /verification + /document steps (guests have no session to remember a prior unlock across requests).
token
string · path
/o1/sign/example/session
/o1/sign/:token/signature
undocumented /o1/sign/:token/signature
POST /o1/sign/:token/signature — capture consent + field values + drawn marks. Signature/initials marks arrive as base64 (guests can't use the session-based presign) and are uploaded server-side to Sign's private R2 prefix. Idempotent: a re-submit after signing returns the signed state rather than double-writing.
token
string · path
/o1/sign/example/signature
/o1/sign/:token/declination
undocumented /o1/sign/:token/declination
POST /o1/sign/:token/declination — a signer declines, stopping the envelope.
token
string · path
/o1/sign/example/declination
/o1/sign/links/:link_token/envelopes
undocumented /o1/sign/links/:link_token/envelopes
POST /o1/sign/links/:link_token/envelopes {name, email} — public: clone the template into a fresh envelope for this visitor and hand back their signing URL.
link_token
string · path
/o1/sign/links/example/envelopes
/onboarding/handle-check
undocumented /onboarding/handle-check
GET /onboarding/handle-check?handle=xxx — Check if a workspace handle is available.
/onboarding/handle-check
/onboarding/payments
Capture onboarding payment
POST /accounts/onboarding/payment — Add card via Flutterwave v4.
card_number
string · min length: 13 · max length: 19
expiry_month
string · min length: 1 · max length: 2
expiry_year
string · min length: 2 · max length: 4
cvv
string · min length: 3 · max length: 4
propertyName
anything
/onboarding/payments
/onboarding/steps
undocumented /onboarding/steps
POST /accounts/onboarding/skip-payment — Skip payment step.
/onboarding/steps
/onboarding/invitations
Send onboarding invites
POST /accounts/onboarding/invites — Invite collaborators.
emails
array
propertyName
anything
/onboarding/invitations
/onboarding/completions
undocumented /onboarding/completions
POST /accounts/onboarding/complete — Mark workspace as onboarded.
/onboarding/completions
/onboarding/profile
Setup onboarding profile
PUT /accounts/onboarding/profile — Update avatar and workspace theme.
avatar_url
string · max length: 2048
propertyName
anything
/onboarding/profile
/onboarding/handle
Set workspace handle
PUT /onboarding/handle — Set the workspace handle and display name.
handle
string · min length: 3 · max length: 30
name
string · min length: 1 · max length: 200
propertyName
anything
/onboarding/handle
/onboarding
undocumented /onboarding
Render the onboarding wizard. Redirect to hub if already onboarded.
/onboarding
/online
undocumented /online
List workspace members who are currently online.
/online
/finance/orders/:entry_id
Transition an order
entry_id
string · path
status
propertyName
anything
/finance/orders/example
/finance/orders
Create an order
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
tags
array
sources
array
adjustments
array
idempotency_key
string · max length: 100
propertyName
anything
/finance/orders
/finance/orders/:entry_id/fulfillments
Record a fulfillment
Record a fulfillment — auto-creates a draft invoice with selected lines.
entry_id
string · path
date
string · min length: 10
lines
array
memo
string · max length: 2000
propertyName
anything
/finance/orders/example/fulfillments
/finance/orders/:entry_id
Update a draft order
entry_id
string · path
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
tags
array
adjustments
array
dimensions
propertyName
anything
/finance/orders/example
/organisations/:org_id
Update organisation
PUT /accounts/organisation — Update org details.
org_id
string · path
name
string · min length: 1 · max length: 200
email_domain
string
industry
string
size
string
timezone
string · max length: 64
propertyName
anything
/organisations/example
/ptos
Request time off
policy_id
string · min length: 1
start_date
string · min length: 1
end_date
string · min length: 1
half_day
reason
string · max length: 1000
propertyName
anything
/ptos
/ptos/:id
Update a pending PTO
id
string · path
start_date
string · min length: 1
end_date
string · min length: 1
half_day
reason
string · max length: 1000
propertyName
anything
/ptos/example
/ptos/:id/decision
Approve or deny a PTO
Approve or deny a PTO (manager/admin).
id
string · path
decision
note
string · max length: 1000
propertyName
anything
/ptos/example/decision
/papers/trash
undocumented /papers/trash
DELETE /papers/trash — destroy every trashed document the caller manages. Scoped by the same query as the listing, so this can only ever destroy what the caller was already being shown. It never touches a colleague's trash.
/papers/trash
/papers/trash/:document_id
undocumented /papers/trash/:document_id
DELETE /papers/trash/:document_id — destroy a trashed document for good. The purge gate has already confirmed the document is in the trash and that the caller manages it (CLAUDE.md rule 18). Versions, comments and collaborator rows go with it through ON DELETE CASCADE; the grants are not foreign keys, so they are revoked explicitly.
document_id
string · path
/papers/trash/example
/papers/:document_id
undocumented /papers/:document_id
DELETE /papers/:document_id — move a document to the trash. The delete gate has already loaded the document onto ctx.authz.document (CLAUDE.md rule 18). Grants are deliberately LEFT INTACT here. This used to call revoke_all, on the reasoning that the document was gone, which quietly made the trash unimplementable: a restored document came back with no grants at all, not even its owner's, so nobody could open, edit or delete it ever again. Grants are dropped at permanent deletion instead, in api_purge_document.
document_id
string · path
/papers/example
/papers/:document_id/comments/:comment_id
undocumented /papers/:document_id/comments/:comment_id
DELETE /papers/:document_id/comments/:comment_id — delete a comment. The delete gate (authz.can_delete_comment) has already loaded the comment onto ctx.authz.comment and confirmed the caller authored it or manages the document, so there's no re-query here (CLAUDE.md rule 18).
document_id
string · path
comment_id
string · path
/papers/example/comments/example
/papers
undocumented /papers
GET /papers — list documents for the workspace.
/papers
/papers/web-images
undocumented /papers/web-images
GET /papers/web-images?q=&page= — search openly-licensed web images.
/papers/web-images
/papers/trash
undocumented /papers/trash
GET /papers/trash — documents in the trash that the caller can restore.
/papers/trash
/papers/:document_id
undocumented /papers/:document_id
GET /papers/:document_id — get a single document with content.
document_id
string · path
/papers/example
/papers/:document_id/exports/:format
undocumented /papers/:document_id/exports/:format
GET /papers/:document_id/exports/:format — download as docx, odt, or pdf. The read gate (authz.can_view_doc) has already loaded the document onto ctx.authz.document, so there's no re-query here (CLAUDE.md rule 18).
document_id
string · path
format
string · path
/papers/example/exports/example
/papers/:document_id/versions
undocumented /papers/:document_id/versions
GET /papers/:document_id/versions — list version history.
document_id
string · path
/papers/example/versions
/papers/:document_id/versions/:version_id
undocumented /papers/:document_id/versions/:version_id
GET /papers/:document_id/versions/:version_id — get a single version.
document_id
string · path
version_id
string · path
/papers/example/versions/example
/papers/:document_id/comments
undocumented /papers/:document_id/comments
GET /papers/:document_id/comments — list comments for a document.
document_id
string · path
/papers/example/comments
/papers/:document_id/presence
undocumented /papers/:document_id/presence
GET /papers/:document_id/presence — get active collaborators.
document_id
string · path
/papers/example/presence
/papers/:document_id
Update a document
PATCH /papers/:document_id — update a document, or restore it from trash. The update gate (authz.can_update_doc) has already loaded the document onto ctx.authz.document and decided what this caller may do with it, including the trashed case, so there's no re-query here (CLAUDE.md rule 18).
document_id
string · path
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
content
string
is_starred
page_mode
visibility
page_setup
object
deleted
propertyName
anything
/papers/example
/papers/:document_id/versions/:version_id
Name or rename a version
PATCH /papers/:document_id/versions/:version_id — name or rename a version.
document_id
string · path
version_id
string · path
name
string · max length: 120
propertyName
anything
/papers/example/versions/example
/papers/:document_id/comments/:comment_id
Resolve/unresolve comment
PATCH /papers/:document_id/comments/:comment_id — resolve or unresolve.
document_id
string · path
comment_id
string · path
resolved
propertyName
anything
/papers/example/comments/example
/papers
Create a document
POST /papers — create a new document.
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
content
string
propertyName
anything
/papers
/papers/imports
undocumented /papers/imports
POST /papers/imports — create a new document from an uploaded .docx/.odt.
/papers/imports
/papers/images
undocumented /papers/images
POST /papers/images — upload image bytes (From Computer / From Camera).
/papers/images
/papers/image-imports
Re-host a remote image
POST /papers/image-imports — re-host a remote image by URL (From URL Link, a Search Web pick, or a Files App pick) into the public bucket.
url
string · min length: 1 · max length: 2000
propertyName
anything
/papers/image-imports
/papers/:document_id/versions
Snapshot a named version
POST /papers/:document_id/versions — snapshot the current state as a named version. The edit gate (authz.can_edit_doc) has already loaded the document onto ctx.authz.document, so there's no re-query here (CLAUDE.md rule 18).
document_id
string · path
name
string · min length: 1 · max length: 120
propertyName
anything
/papers/example/versions
/papers/:document_id/comments
Add a comment
POST /papers/:document_id/comments — add a comment.
document_id
string · path
body
string · min length: 1 · max length: 4000
object_id
string · max length: 64
parent_id
string · max length: 64
nx
number
ny
number
propertyName
anything
/papers/example/comments
/papers/:document_id/presence
undocumented /papers/:document_id/presence
PUT /papers/:document_id/presence — update cursor position.
document_id
string · path
/papers/example/presence
/partials/workspaces
undocumented /partials/workspaces
GET /partials/workspaces — workspace list partial for dashboard tab.
/partials/workspaces
/partials/invoices
undocumented /partials/invoices
GET /partials/invoices — global invoice list partial.
/partials/invoices
/partials/threads
undocumented /partials/threads
GET /partials/threads — support threads list partial.
/partials/threads
/partials/audit
undocumented /partials/audit
GET /partials/audit — audit log partial.
/partials/audit
/partials/microns
undocumented /partials/microns
GET /partials/microns — microns list partial (MicroTable fetches the data).
/partials/microns
/partials/coupons
undocumented /partials/coupons
GET /partials/coupons — coupon list partial (admin).
/partials/coupons
/partials/demos
undocumented /partials/demos
GET /partials/demos — "Book a demo" request list partial (admin).
/partials/demos
/partials/preview-apps
undocumented /partials/preview-apps
GET /partials/preview-apps — preview apps + their early-adopter allowlists.
/partials/preview-apps
/partials/releases
undocumented /partials/releases
GET /partials/releases — version history master-detail for dashboard tab.
/partials/releases
/partials/settings/forms/new-api-key
undocumented /partials/settings/forms/new-api-key
Form drawer for creating an API key (shared #form-panel).
/partials/settings/forms/new-api-key
/partials/settings/apps
undocumented /partials/settings/apps
/partials/settings/apps
/partials/settings/account
undocumented /partials/settings/account
Profile settings — edit own name, job title, password, preferences.
/partials/settings/account
/partials/settings/account/:section
undocumented /partials/settings/account/:section
Profile settings — edit own name, job title, password, preferences.
section
string · path
/partials/settings/account/example
/partials/settings/store
undocumented /partials/settings/store
HTMX partial — app store catalog grid.
/partials/settings/store
/partials/settings/store/:slug
undocumented /partials/settings/store/:slug
HTMX partial — single app detail view with events, deps, pricing.
slug
string · path
/partials/settings/store/example
/calls/:id/participants/:member_mrn
Update participant role
id
string · path
member_mrn
string · path
role
status
can_speak
propertyName
anything
/calls/example/participants/example
/chats/:id/participants/:member_mrn
Update participant role
PATCH /chats/:id/participants/:member_mrn — change a participant's role.
id
string · path
member_mrn
string · path
role
status
can_speak
propertyName
anything
/chats/example/participants/example
/calls/:id/participants
Invite participants
id
string · path
members
array
propertyName
anything
/calls/example/participants
/chats/:id/participants
Add participants
POST /chats/:id/participants — add participants to a group.
id
string · path
members
array
history
history_days
integer · min: 1 · max: 3650
share_history
propertyName
anything
/chats/example/participants
/payment-methods/:pm_id
undocumented /payment-methods/:pm_id
DELETE /payment-methods/:pm_id — Remove a payment method.
pm_id
string · path
/payment-methods/example
/payment-methods/:pm_id
undocumented /payment-methods/:pm_id
PUT /payment-methods/:pm_id — Set default payment method.
pm_id
string · path
/payment-methods/example
/finance/payments/:payment_id
Apply allocations
Apply new allocations to an unallocated (or partially-allocated) payment.
payment_id
string · path
allocations
array
propertyName
anything
/finance/payments/example
/finance/payments
Record a payment
direction
amount
number
method
paid_at
string · min length: 10
bank_account_id
string
allocations
array
allocate_entry_id
string
allow_overpayment
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
reference
string · max length: 200
memo
string · max length: 2000
idempotency_key
string · max length: 100
propertyName
anything
/finance/payments
/finance/payments/:payment_id/reversals
Reverse a payment
payment_id
string · path
reason
string · min length: 1 · max length: 500
propertyName
anything
/finance/payments/example/reversals
/finance/fiscal-periods/:period_id
Update/close a period
period_id
string · path
name
string · min length: 1 · max length: 50
start
string · min length: 10
end
string · min length: 10
status
propertyName
anything
/finance/fiscal-periods/example
/finance/fiscal-periods
Create a fiscal period
name
string · min length: 1 · max length: 50
start
string · min length: 10
end
string · min length: 10
status
propertyName
anything
/finance/fiscal-periods
/finance/fiscal-periods/:period_id/revaluations
Run period-end FX revaluation
POST /finance/fiscal-periods/:period_id/revaluations Runs one revaluation for the period at the given ``as_of``, applying the supplied closing rates to every open foreign-currency monetary position. Posts a journal entry (``type=journal``, ``status=posted``) and schedules the reversing entry for the first day of the next period.
period_id
string · path
as_of
string · min length: 10
rates
propertyName
anything
/finance/fiscal-periods/example/revaluations
/folders/:folder_id/permissions
Update folder permission
folder_id
string · path
member_mrn
string · min length: 1
role
propertyName
anything
/folders/example/permissions
/files/:file_id/permissions
Update file permission
file_id
string · path
member_mrn
string · min length: 1
role
propertyName
anything
/files/example/permissions
/folders/:folder_id/permissions
Grant folder permissions
folder_id
string · path
members
array
propertyName
anything
/folders/example/permissions
/files/:file_id/permissions
Grant file permissions
file_id
string · path
members
array
propertyName
anything
/files/example/permissions
/pipelines/:pipeline_id
undocumented /pipelines/:pipeline_id
pipeline_id
string · path
/pipelines/example
/pipelines/:pipeline_id/stages/:stage_id
undocumented /pipelines/:pipeline_id/stages/:stage_id
pipeline_id
string · path
stage_id
string · path
/pipelines/example/stages/example
/pipelines
undocumented /pipelines
/pipelines
/pipelines/:pipeline_id
undocumented /pipelines/:pipeline_id
pipeline_id
string · path
/pipelines/example
/pipelines/:pipeline_id/stages
undocumented /pipelines/:pipeline_id/stages
pipeline_id
string · path
/pipelines/example/stages
/pipelines
Create a pipeline
name
string · min length: 1 · max length: 200
description
string · max length: 2000
stages
array
is_default
propertyName
anything
/pipelines
/pipelines/:pipeline_id/stages
Add a stage to a pipeline
pipeline_id
string · path
name
string · min length: 1 · max length: 100
key
string · min length: 1 · max length: 50
position
integer
probability
integer · min: 0 · max: 100
is_closed
is_won
playbook
string · max length: 5000
checklist_template
array
propertyName
anything
/pipelines/example/stages
/pipelines/:pipeline_id
Update a pipeline
pipeline_id
string · path
name
string · min length: 1 · max length: 200
description
string · max length: 2000
is_default
propertyName
anything
/pipelines/example
/pipelines/:pipeline_id/stages/:stage_id
Update a stage
pipeline_id
string · path
stage_id
string · path
name
string · min length: 1 · max length: 100
position
integer
probability
integer · min: 0 · max: 100
is_closed
is_won
playbook
string · max length: 5000
checklist_template
array
propertyName
anything
/pipelines/example/stages/example
/plan
undocumented /plan
GET /plan — Current plan, selected apps, region, and billing interval.
/plan
/finance/quotes/:entry_id/links
Share a quote with a customer
entry_id
string · path
recipient_email
string · max length: 320
propertyName
anything
/finance/quotes/example/links
/finance/invoices/:entry_id/links
Share an invoice with a customer
entry_id
string · path
recipient_email
string · max length: 320
propertyName
anything
/finance/invoices/example/links
/finance/credit-notes/:entry_id/links
Share a credit note with a customer
entry_id
string · path
recipient_email
string · max length: 320
propertyName
anything
/finance/credit-notes/example/links
/finance/payment-credentials/:provider
Store workspace payment keys
Store a workspace's own provider keys, encrypted at rest. The raw key is write-only: responses only ever carry the mask.
provider
string · path
secret_key
string · min length: 8 · max length: 200
public_key
string · max length: 200
enabled
propertyName
anything
/finance/payment-credentials/example
/preferences
undocumented /preferences
/preferences
/preferences
undocumented /preferences
/preferences
/presignations/:id
undocumented /presignations/:id
DELETE /presignations/:id — abandon a multipart upload so no orphaned parts linger (R2 bills incomplete parts until aborted).
id
string · path
/presignations/example
/presignations
undocumented /presignations
POST /presignations — generate a presigned R2 PUT URL. Body: {app, filename, content_type, size_bytes, context: {...}}
/presignations
/presignations/:id/confirmations
undocumented /presignations/:id/confirmations
POST /presignations/:id/confirmations — confirm upload completed. Emits ``system.{app}.upload.confirmed`` with the upload metadata + app context so the originating app can do its bookkeeping. The client-supplied fields are treated as claims, not facts: the storage key must live inside the caller's own workspace namespace, and when R2 is configured the object is HEAD-verified so the size the apps record (and quota checks trust) is what R2 actually holds, not what the client typed.
id
string · path
/presignations/example/confirmations
/presignations/:id/completions
undocumented /presignations/:id/completions
POST /presignations/:id/completions — stitch uploaded parts together. Body: {app, storage_key, r2_upload_id, parts: [{part_number, etag}]}. The client still calls the confirmation endpoint afterwards; that is where the HEAD verification and app bookkeeping happen.
id
string · path
/presignations/example/completions
/pricing
undocumented /pricing
/pricing
/privacy
undocumented /privacy
/privacy
/me/locale
Set your UI language
PUT /me/locale — save the UI language this person picked. Written to profiles, not members: the preference belongs to the individual, so it follows them into every workspace they belong to and onto every device they sign in from. A workspace never overrides it. Three places are updated together, and all three matter: * profiles.locale — the durable record, read at sign-in on a new device * the session blob — what the locale middleware reads per request * the cookie — so signing out does not drop the login page back to English, and so the marketing site agrees with the app The caller reloads afterwards. Every surface is server-rendered, so there is nothing to re-translate in place.
locale
propertyName
anything
/me/locale
/profiles/:member_id
Update profile
Update own profile (name, job title).
member_id
string · path
full_name
string · min length: 1 · max length: 200
job_title
string · max length: 200
propertyName
anything
/profiles/example
/profiles/:member_id/contact
Update contact info
PUT /profiles/:member_id/contact — update phone number and address. Writes the CURRENT WORKSPACE's copy, not the shared profile. Before migration 080 these six fields lived only on profiles, so two workspaces inviting the same email shared one row: handing your mobile to one employer published it to every other workspace you belonged to. Same reason migration 035 moved name, title and avatar.
member_id
string · path
phone_number
string · max length: 50
street
string · max length: 300
city
string · max length: 100
state
string · max length: 100
postal_code
string · max length: 20
country
string · max length: 100
propertyName
anything
/profiles/example/contact
/passwords/:member_id
Set or change password
Set or change your own password. This is also the only way to SET one, because there is no forgot-password flow: if you cannot remember it, you sign in with a mailed link and come here. So the current password is required only when one exists. Somebody who joined by link and has never had a password proves nothing beyond the live session they are already holding, and demanding a password they do not have would strand them with no way to ever get one.
member_id
string · path
new_password
string · min length: 8
current_password
string · min length: 1
propertyName
anything
/passwords/example
/workers/:worker_id/fields
Update a worker's custom field values
PATCH custom field values: {values: [{field_id, value}]}. A null/empty value clears the field. Values are validated against the definition type.
worker_id
string · path
values
array
propertyName
anything
/workers/example/fields
/workers/fields
Create a custom profile field
label
string · min length: 1 · max length: 100
type
section
string · max length: 100
options
array
required
sensitive
help_text
string · max length: 300
position
integer · min: 0 · max: 10000
propertyName
anything
/workers/fields
/workers/fields/:field_id
Update a custom profile field
field_id
string · path
label
string · min length: 1 · max length: 100
section
string · max length: 100
options
array
required
sensitive
help_text
string · max length: 300
position
integer · min: 0 · max: 10000
propertyName
anything
/workers/fields/example
/ptos/:id
undocumented /ptos/:id
Cancel a PTO (worker) or revoke (manager).
id
string · path
/ptos/example
/ptos
undocumented /ptos
/ptos
/ptos/pending
undocumented /ptos/pending
List pending PTOs the current user can approve. A user approves their direct reports (workers whose manager is them). The projection stores ``manager_id`` as a *worker* id, so we resolve the viewer's own worker id and match against it — never against the member id. Owners and admins additionally approve workers who have no manager at all (the no-manager fallback). A user never approves their own request.
/ptos/pending
/ptos/:id
undocumented /ptos/:id
id
string · path
/ptos/example
/public/*
undocumented /public/*
/public/*
/public/apps/calls/*
undocumented /public/apps/calls/*
/public/apps/calls/*
/public/apps/canvas/*
undocumented /public/apps/canvas/*
/public/apps/canvas/*
/public/apps/chat/*
undocumented /public/apps/chat/*
/public/apps/chat/*
/public/apps/contacts/*
undocumented /public/apps/contacts/*
/public/apps/contacts/*
/public/apps/crm/*
undocumented /public/apps/crm/*
/public/apps/crm/*
/public/apps/feeds/*
undocumented /public/apps/feeds/*
/public/apps/feeds/*
/public/apps/files/*
undocumented /public/apps/files/*
/public/apps/files/*
/public/apps/finance/*
undocumented /public/apps/finance/*
/public/apps/finance/*
/public/apps/growth/*
undocumented /public/apps/growth/*
/public/apps/growth/*
/public/apps/leaves/*
undocumented /public/apps/leaves/*
/public/apps/leaves/*
/public/apps/papers/*
undocumented /public/apps/papers/*
/public/apps/papers/*
/public/apps/settings/*
undocumented /public/apps/settings/*
/public/apps/settings/*
/public/apps/sign/*
undocumented /public/apps/sign/*
/public/apps/sign/*
/public/apps/slides/*
undocumented /public/apps/slides/*
/public/apps/slides/*
/public/apps/tables/*
undocumented /public/apps/tables/*
/public/apps/tables/*
/public/apps/tasks/*
undocumented /public/apps/tasks/*
/public/apps/tasks/*
/public/apps/wands/*
undocumented /public/apps/wands/*
/public/apps/wands/*
/public/apps/wiki/*
undocumented /public/apps/wiki/*
/public/apps/wiki/*
/public/apps/workers/*
undocumented /public/apps/workers/*
/public/apps/workers/*
/public/*
undocumented /public/*
/public/*
/public/*
undocumented /public/*
/public/*
/public/*
undocumented /public/*
/public/*
/public/apps/calls/*
undocumented /public/apps/calls/*
/public/apps/calls/*
/public/apps/canvas/*
undocumented /public/apps/canvas/*
/public/apps/canvas/*
/public/apps/chat/*
undocumented /public/apps/chat/*
/public/apps/chat/*
/public/apps/contacts/*
undocumented /public/apps/contacts/*
/public/apps/contacts/*
/public/apps/crm/*
undocumented /public/apps/crm/*
/public/apps/crm/*
/public/apps/feeds/*
undocumented /public/apps/feeds/*
/public/apps/feeds/*
/public/apps/files/*
undocumented /public/apps/files/*
/public/apps/files/*
/public/apps/finance/*
undocumented /public/apps/finance/*
/public/apps/finance/*
/public/apps/growth/*
undocumented /public/apps/growth/*
/public/apps/growth/*
/public/apps/leaves/*
undocumented /public/apps/leaves/*
/public/apps/leaves/*
/public/apps/papers/*
undocumented /public/apps/papers/*
/public/apps/papers/*
/public/apps/settings/*
undocumented /public/apps/settings/*
/public/apps/settings/*
/public/apps/sign/*
undocumented /public/apps/sign/*
/public/apps/sign/*
/public/apps/slides/*
undocumented /public/apps/slides/*
/public/apps/slides/*
/public/apps/tables/*
undocumented /public/apps/tables/*
/public/apps/tables/*
/public/apps/tasks/*
undocumented /public/apps/tasks/*
/public/apps/tasks/*
/public/apps/wands/*
undocumented /public/apps/wands/*
/public/apps/wands/*
/public/apps/wiki/*
undocumented /public/apps/wiki/*
/public/apps/wiki/*
/public/apps/workers/*
undocumented /public/apps/workers/*
/public/apps/workers/*
/finance/purchase-credit-notes/:entry_id
Issue/void purchase credit note
entry_id
string · path
status
propertyName
anything
/finance/purchase-credit-notes/example
/finance/purchase-credit-notes
Record a supplier credit note
date
string · min length: 10
items
array
source_entry_id
string · min length: 1
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
adjustments
array
dimensions
idempotency_key
string · max length: 100
propertyName
anything
/finance/purchase-credit-notes
/finance/purchase-credit-notes/:entry_id/allocations
Set supplier credit against a bill
entry_id
string · path
entry_id
string · min length: 1
amount
number
entry_amount
number
propertyName
anything
/finance/purchase-credit-notes/example/allocations
/finance/purchase-credit-notes/:entry_id
Update a draft purchase credit note
entry_id
string · path
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
adjustments
array
dimensions
propertyName
anything
/finance/purchase-credit-notes/example
/finance/purchase-orders/:entry_id
Transition a PO
entry_id
string · path
status
propertyName
anything
/finance/purchase-orders/example
/finance/purchase-orders
Create a purchase order
date
string · min length: 10
items
array
company_mrn
string
contact_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
tags
array
adjustments
array
idempotency_key
string · max length: 100
propertyName
anything
/finance/purchase-orders
/finance/purchase-orders/:entry_id/receipts
Record a receipt
Record a receipt against a PO — auto-creates a draft bill with the selected lines.
entry_id
string · path
date
string · min length: 10
lines
array
memo
string · max length: 2000
propertyName
anything
/finance/purchase-orders/example/receipts
/finance/purchase-orders/:entry_id
Update a draft PO
entry_id
string · path
date
string · min length: 10
items
array
company_mrn
string
contact_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
memo
string · max length: 5000
tags
array
adjustments
array
dimensions
propertyName
anything
/finance/purchase-orders/example
/finance/quotes/:entry_id
Transition a quote
entry_id
string · path
status
propertyName
anything
/finance/quotes/example
/finance/quotes
Create a quote
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
valid_until
string · min length: 10
memo
string · max length: 5000
tags
array
adjustments
array
idempotency_key
string · max length: 100
propertyName
anything
/finance/quotes
/finance/quotes/:entry_id/sends
Email a quote
entry_id
string · path
to
string · min length: 1 · max length: 500
cc
string · max length: 500
subject
string · max length: 300
message
string · max length: 5000
propertyName
anything
/finance/quotes/example/sends
/finance/quotes/:entry_id/revisions
Revise a sent quote
Revise a sent/rejected quote: supersede the original and create a new draft revision carrying the edits. With ``resend`` (and a known recipient) the revision is emailed and marked sent in one step.
entry_id
string · path
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
valid_until
string · min length: 10
memo
string · max length: 5000
tags
array
resend
to
string · max length: 500
propertyName
anything
/finance/quotes/example/revisions
/finance/quotes/:entry_id
Update a draft quote
entry_id
string · path
date
string · min length: 10
items
array
contact_mrn
string
company_mrn
string
currency
string · min length: 3 · max length: 3
exchange_rate
number
valid_until
string · min length: 10
memo
string · max length: 5000
tags
array
adjustments
array
dimensions
propertyName
anything
/finance/quotes/example
/chats/:id/messages/:msg_id/reactions
Add a reaction
POST /chats/:id/messages/:msg_id/reactions — add an emoji reaction.
id
string · path
msg_id
string · path
emoji
string · min length: 1 · max length: 32
propertyName
anything
/chats/example/messages/example/reactions
/sign/envelopes/:envelope_id/recipients/:recipient_id
Edit a recipient
PATCH /sign/envelopes/:envelope_id/recipients/:recipient_id — edit a recipient (before send).
envelope_id
string · path
recipient_id
string · path
name
string · min length: 1 · max length: 200
email
string · email
role
string · min length: 1 · max length: 100
recipient_type
signer_mrn
string
signing_order
integer
access_code
string · min length: 4 · max length: 64
propertyName
anything
/sign/envelopes/example/recipients/example
/sign/envelopes/:envelope_id/recipients
Add a recipient
POST /sign/envelopes/:envelope_id/recipients — add a recipient (member or external guest).
envelope_id
string · path
name
string · min length: 1 · max length: 200
email
string · email
role
string · min length: 1 · max length: 100
recipient_type
signer_mrn
string
signing_order
integer
access_code
string · min length: 4 · max length: 64
propertyName
anything
/sign/envelopes/example/recipients
/finance/bank-rules/:rule_id
Update a bank rule
rule_id
string · path
name
string · min length: 1 · max length: 100
match
object
action
object
propertyName
anything
/finance/bank-rules/example
/finance/bank-imports
Import a bank feed
bank_account_id
string · min length: 1
rows
array
propertyName
anything
/finance/bank-imports
/finance/bank-imports/:import_id/entries
Create an entry from a bank import
Create a bill/invoice for an unmatched bank import and reconcile the import against it in one step. The category comes from the request body or from the first matching bank rule.
import_id
string · path
account_code
string · max length: 20
description
string · max length: 500
entry_type
propertyName
anything
/finance/bank-imports/example/entries
/finance/bank-connections
Connect a bank account
code
string · min length: 1 · max length: 200
propertyName
anything
/finance/bank-connections
/finance/reconciliations
Finalise a reconciliation
bank_account_id
string · min length: 1
period_start
string · min length: 10
period_end
string · min length: 10
statement_balance
number
propertyName
anything
/finance/reconciliations
/finance/bank-rules
Create a bank rule
name
string · min length: 1 · max length: 100
match
object
action
object
propertyName
anything
/finance/bank-rules
/calls/:id/recordings/:recording_id
Abort a recording
Abandon a recording: abort the R2 multipart upload and mark it failed. Host-only.
id
string · path
recording_id
string · path
status
upload_id
string · min length: 1 · max length: 512
propertyName
anything
/calls/example/recordings/example
/calls/:id/recordings
Start a recording
id
string · path
content_type
string · max length: 100
propertyName
anything
/calls/example/recordings
/calls/:id/recordings/:recording_id
Complete a recording
Finalize a recording: assemble the uploaded parts in R2 and mark it ready. Host-only.
id
string · path
recording_id
string · path
upload_id
string · min length: 1 · max length: 512
parts
array
size_bytes
integer · min: 0
duration_seconds
integer · min: 0
propertyName
anything
/calls/example/recordings/example
/recovery-codes
undocumented /recovery-codes
/recovery-codes
/recovery-codes
undocumented /recovery-codes
/recovery-codes
/finance/recurring-entries/:recurring_id
Update recurring entry
recurring_id
string · path
name
string · min length: 1 · max length: 200
type
frequency
next_date
string · min length: 10
company_mrn
string
contact_mrn
string
items
array
auto_approve
propertyName
anything
/finance/recurring-entries/example
/finance/recurring-entries
Create recurring entry
name
string · min length: 1 · max length: 200
type
frequency
next_date
string · min length: 10
company_mrn
string
contact_mrn
string
items
array
auto_approve
propertyName
anything
/finance/recurring-entries
/reports/burndown
undocumented /reports/burndown
Return burndown + burnup chart data for a schedule (or board-wide).
/reports/burndown
/finance/requests/:request_id
Approve or decline a request
PATCH /finance/requests/:id — approve (books the artifact) or decline.
request_id
string · path
status
reason
string · max length: 1000
propertyName
anything
/finance/requests/example
/finance/requests
File an expense claim, advance, or purchase request
POST /finance/requests — any portal member files their own request.
kind
amount
number
date
string · min length: 10
description
string · min length: 1 · max length: 2000
currency
string · min length: 3 · max length: 3
category_code
string · max length: 20
vendor
string · max length: 200
needed_by
string · min length: 10
receipts
array
dimensions
propertyName
anything
/finance/requests
/finance/requests/:request_id/payments
Pay out an approved request
POST /finance/requests/:id/payments — pay out an approved request. Expenses settle the bill the approval created (outbound payment, AP → cash). Advances post a journal (Employee Advances ← cash). Purchases are paid through their PO chain, never directly.
request_id
string · path
bank_account_id
string
propertyName
anything
/finance/requests/example/payments
/finance/requests/:request_id/messages
Message on a request thread
POST /finance/requests/:id/messages — the claimant or a reviewer leaves a message on the request's thread. Visibility follows the request itself (scope deposited by the authz chain).
request_id
string · path
body
string · min length: 1 · max length: 2000
propertyName
anything
/finance/requests/example/messages
/requests/:update_id
undocumented /requests/:update_id
PUT /requests/:update_id — Approve or deny an install request via status field.
update_id
string · path
/requests/example
/robots.txt
undocumented /robots.txt
/robots.txt
/roles/:role_id
undocumented /roles/:role_id
DELETE /accounts/organisation/roles/:role_id — Delete a role.
role_id
string · path
/roles/example
/roles/:role_id/members/:member_id
undocumented /roles/:role_id/members/:member_id
DELETE /accounts/organisation/roles/:role_id/members/:member_id — Remove member from role.
role_id
string · path
member_id
string · path
/roles/example/members/example
/roles
undocumented /roles
GET /roles — List custom roles for the workspace (admin view).
/roles
/roles
Create role
POST /accounts/organisation/roles — Create a role.
name
string · min length: 1 · max length: 100
description
string · max length: 500
propertyName
anything
/roles
/roles/:role_id/members
Assign member to role
POST /accounts/organisation/roles/:role_id/members — Assign member to role.
role_id
string · path
member_id
string · min length: 1
propertyName
anything
/roles/example/members
/roles/:role_id
undocumented /roles/:role_id
PUT /accounts/organisation/roles/:role_id — Update role + permissions.
role_id
string · path
/roles/example
/roles/:role_id/default
Set role as default
Toggle whether a role is auto-assigned to new members. Body: {is_default: bool}
role_id
string · path
is_default
propertyName
anything
/roles/example/default
/rooms/:id
undocumented /rooms/:id
Permanently delete a room. Kicks all connected participants, then removes the room row (live_room_members rows cascade via FK).
id
string · path
/rooms/example
/rooms/:id/members/:member_mrn
undocumented /rooms/:id/members/:member_mrn
Remove member from room.
id
string · path
member_mrn
string · path
/rooms/example/members/example
/rooms/:id/sessions
undocumented /rooms/:id/sessions
Leave a room. Sets is_connected = FALSE.
id
string · path
/rooms/example/sessions
/rooms
undocumented /rooms
List rooms visible to the current member. Supports ?q= search and pagination.
/rooms
/rooms/:id
undocumented /rooms/:id
Get room details + full member list with connection status.
id
string · path
/rooms/example
/rooms/:id/members
undocumented /rooms/:id/members
List room members with connection/mute state.
id
string · path
/rooms/example/members
/rooms/:id
Update a room
Update room name, description, settings, type.
id
string · path
name
string · min length: 1 · max length: 50
description
string · max length: 200
type
max_participants
integer · min: 2 · max: 100
settings
object
propertyName
anything
/rooms/example
/rooms/:id/members/:member_mrn
Update room member role
Update member role (promote/demote admin).
id
string · path
member_mrn
string · path
role
propertyName
anything
/rooms/example/members/example
/rooms
Create a room
Create a new room. Creator becomes room admin.
name
string · min length: 1 · max length: 50
description
string · max length: 200
type
max_participants
integer · min: 2 · max: 100
settings
object
propertyName
anything
/rooms
/rooms/:id/members
Add room members
Add member(s) to a room.
id
string · path
members
array
propertyName
anything
/rooms/example/members
/rooms/:id/sessions
undocumented /rooms/:id/sessions
Join a room. Generates a LiveKit access token. Sets is_connected = TRUE.
id
string · path
/rooms/example/sessions
/rooms/:id/token
undocumented /rooms/:id/token
Mint a fresh LiveKit token for a room the member is already connected to. Unlike POST /rooms/:id/sessions (which runs the full join lifecycle — kicks stale participants, updates is_connected, emits events), this endpoint is a pure token refresh. Used by the client's proactive refresh timer before the current token's `exp` claim kicks in.
id
string · path
/rooms/example/token
/rooms/:id/members/:member_mrn/mute
undocumented /rooms/:id/members/:member_mrn/mute
Mute a participant (room admin only). Signals via platform WS.
id
string · path
member_mrn
string · path
/rooms/example/members/example/mute
/rooms/session-state
undocumented /rooms/session-state
PUT /rooms/session-state — Sync client-side mute state into session for restore on refresh.
/rooms/session-state
/schedules/:schedule_id
undocumented /schedules/:schedule_id
Delete a schedule. Its tasks and deliverables are kept — the schedule link is cleared via the ON DELETE SET NULL foreign key, so they fall back to having no schedule rather than being deleted.
schedule_id
string · path
/schedules/example
/schedules
undocumented /schedules
GET /schedules?board_id=...&q=... — list schedules for a board, optionally filtered by name.
/schedules
/schedules
Create a schedule
board_id
string
name
string · min length: 1 · max length: 200
start_date
string · min length: 1
end_date
string · min length: 1
goal
string · max length: 500
description
string · max length: 5000
status
propertyName
anything
/schedules
/schedules/:schedule_id
Update a schedule
Update a schedule's mutable fields.
schedule_id
string · path
name
string · min length: 1 · max length: 200
goal
string · max length: 500
description
string · max length: 5000
status
start_date
string
end_date
string
propertyName
anything
/schedules/example
/scoring/rules/:rule_id
undocumented /scoring/rules/:rule_id
rule_id
string · path
/scoring/rules/example
/scoring/rules
undocumented /scoring/rules
/scoring/rules
/scoring/rules/:rule_id
undocumented /scoring/rules/:rule_id
rule_id
string · path
/scoring/rules/example
/scoring/:entity_type/:entity_id
undocumented /scoring/:entity_type/:entity_id
Compute a score on demand. Deal scores persist on the deal and threshold events fire only on crossings (comparing against the stored score). Contact scores are computed read-only here; the daily sweep in events.py owns persistence and threshold events for contacts, because apis.py must never write the crm_party_index projection.
entity_type
string · path
entity_id
string · path
/scoring/example/example
/scoring/rules
Create a scoring rule
name
string · min length: 1 · max length: 200
entity_type
rules
array
thresholds
array
enabled
propertyName
anything
/scoring/rules
/scoring/rules/:rule_id
Update a scoring rule
rule_id
string · path
name
string · min length: 1 · max length: 200
rules
array
thresholds
array
enabled
propertyName
anything
/scoring/rules/example
/search
undocumented /search
GET /search?app=chat&q=hello&types=message — central search dispatcher.
/search
/segments/:segment_id
undocumented /segments/:segment_id
DELETE /segments/:segment_id — delete a segment.
segment_id
string · path
/segments/example
/segments/:segment_id/members/:member_id
undocumented /segments/:segment_id/members/:member_id
DELETE /segments/:segment_id/members/:member_id — remove from a static segment.
segment_id
string · path
member_id
string · path
/segments/example/members/example
/segments
undocumented /segments
GET /segments — list segments.
/segments
/segments/:segment_id
undocumented /segments/:segment_id
GET /segments/:segment_id — get segment with resolved members.
segment_id
string · path
/segments/example
/segments
Create a segment
POST /segments — create a segment (static or dynamic).
name
string · min length: 1 · max length: 100
description
string · max length: 500
type
entity_type
filter
object
members
array
propertyName
anything
/segments
/segments/:segment_id/members
Add member to segment
POST /segments/:segment_id/members — add a contact/company to a static segment.
segment_id
string · path
type
id
string · min length: 1
propertyName
anything
/segments/example/members
/segments/:segment_id
Update a segment
PUT /segments/:segment_id — update a segment (name, description, or rules).
segment_id
string · path
name
string · min length: 1 · max length: 100
description
string · max length: 500
filter
object
propertyName
anything
/segments/example
/chats/:id/settings
Update chat settings
PATCH /chats/:id/settings — per-chat settings for the caller (mute).
id
string · path
muted_until
string
propertyName
anything
/chats/example/settings
/finance/tax-rates/:tax_id
Update tax preset
tax_id
string · path
name
string · min length: 1 · max length: 100
rates
array
propertyName
anything
/finance/tax-rates/example
/finance/payment-terms/:term_id
Update payment term
term_id
string · path
name
string · min length: 1 · max length: 100
days
integer · min: 0
early_discount_rate
number
early_discount_days
integer
propertyName
anything
/finance/payment-terms/example
/finance/tax-rates
Create tax preset
name
string · min length: 1 · max length: 100
rates
array
propertyName
anything
/finance/tax-rates
/finance/payment-terms
Create payment term
name
string · min length: 1 · max length: 100
days
integer · min: 0
early_discount_rate
number
early_discount_days
integer
propertyName
anything
/finance/payment-terms
/finance/settings
Update core settings
base_currency
string · min length: 3 · max length: 3
fiscal_year_start
integer · min: 1 · max: 12
accounting_enabled
number_prefixes
object
sequential_numbers
default_accounts
object
invoice_template
object
propertyName
anything
/finance/settings
/shared
undocumented /shared
/shared
/shares/:share_id
undocumented /shares/:share_id
share_id
string · path
/shares/example
/shares
undocumented /shares
/shares
/shares/:share_id
undocumented /shares/:share_id
share_id
string · path
/shares/example
/shares/:share_id
Update a share link
share_id
string · path
password
string · min length: 4 · max length: 128
expires_at
string
max_downloads
integer
is_active
propertyName
anything
/shares/example
/shares
Create a share link
resource_type
resource_id
string · min length: 1
password
string · min length: 4 · max length: 128
expires_at
string
max_downloads
integer
propertyName
anything
/shares
/sign/envelopes/:envelope_id/documents/:document_id
undocumented /sign/envelopes/:envelope_id/documents/:document_id
DELETE /sign/envelopes/:envelope_id/documents/:document_id — remove one part. Fields sitting on the removed part's (global) pages are deleted; fields on later pages shift back by the removed page span so they stay on the pages they were placed on.
envelope_id
string · path
document_id
string · path
/sign/envelopes/example/documents/example
/sign/envelopes/:envelope_id
undocumented /sign/envelopes/:envelope_id
DELETE /sign/envelopes/:envelope_id — delete a draft/template (sent envelopes are voided, not deleted).
envelope_id
string · path
/sign/envelopes/example
/sign/templates/:envelope_id/links/:link_id
undocumented /sign/templates/:envelope_id/links/:link_id
DELETE /sign/templates/:envelope_id/links/:link_id — close a link. Soft (revoked_at): the row keeps its submission history.
envelope_id
string · path
link_id
string · path
/sign/templates/example/links/example
/sign/envelopes/:envelope_id/exports/:target
undocumented /sign/envelopes/:envelope_id/exports/:target
DELETE /sign/envelopes/:envelope_id/exports/:target — take the saved copy back out of Files. Files itself refuses to delete anything Sign owns, so this is the only way to undo a Save to Files. It has to live here: a completed envelope can never be deleted (sealed documents are voided, not removed), so without this the copy would be permanent and an accidental save unfixable.
envelope_id
string · path
target
string · path
/sign/envelopes/example/exports/example
/sign/envelopes/:envelope_id/fields/:field_id
undocumented /sign/envelopes/:envelope_id/fields/:field_id
DELETE /sign/envelopes/:envelope_id/fields/:field_id — remove a field.
envelope_id
string · path
field_id
string · path
/sign/envelopes/example/fields/example
/sign/envelopes/:envelope_id/recipients/:recipient_id
undocumented /sign/envelopes/:envelope_id/recipients/:recipient_id
DELETE /sign/envelopes/:envelope_id/recipients/:recipient_id — remove a recipient (before send).
envelope_id
string · path
recipient_id
string · path
/sign/envelopes/example/recipients/example
/sign/envelopes
undocumented /sign/envelopes
GET /sign/envelopes — list documents (non-templates by default; ?is_template=true, ?status=).
/sign/envelopes
/sign/envelopes/:envelope_id
undocumented /sign/envelopes/:envelope_id
GET /sign/envelopes/:envelope_id — envelope + its fields + recipients.
envelope_id
string · path
/sign/envelopes/example
/sign/envelopes/:envelope_id/source
undocumented /sign/envelopes/:envelope_id/source
GET /sign/envelopes/:envelope_id/source — presigned GET URLs for the source PDFs. The builder loads these into PDF.js to render pages for field placement. `documents` lists every part in signing order (a legacy single-PDF envelope synthesizes one entry); `url`/`page_count` keep the pre-multi-document shape (first part / total pages).
envelope_id
string · path
/sign/envelopes/example/source
/sign/envelopes/:envelope_id/documents
undocumented /sign/envelopes/:envelope_id/documents
GET /sign/envelopes/:envelope_id/documents — the envelope's source PDFs in order.
envelope_id
string · path
/sign/envelopes/example/documents
/sign/envelopes/:envelope_id/audit
undocumented /sign/envelopes/:envelope_id/audit
GET /sign/envelopes/:envelope_id/audit — the envelope's chronological audit trail.
envelope_id
string · path
/sign/envelopes/example/audit
/sign/envelopes/:envelope_id/values
undocumented /sign/envelopes/:envelope_id/values
GET /sign/envelopes/:envelope_id/values — what each recipient actually entered. Text/date/name/email come back as `value`; signature/initials come back as a short- lived presigned `signature_url` for the drawn PNG. The builder overlays these on a sent/completed document so the owner sees the real content, not the placeholders.
envelope_id
string · path
/sign/envelopes/example/values
/sign/envelopes/:envelope_id/document
undocumented /sign/envelopes/:envelope_id/document
GET /sign/envelopes/:envelope_id/document — presigned URL for the sealed PDF.
envelope_id
string · path
/sign/envelopes/example/document
/sign/envelopes/:envelope_id/certificate
undocumented /sign/envelopes/:envelope_id/certificate
GET /sign/envelopes/:envelope_id/certificate — presigned URL for the Certificate of Completion.
envelope_id
string · path
/sign/envelopes/example/certificate
/sign/templates
undocumented /sign/templates
GET /sign/templates — list reusable templates (sugar for ?is_template=true).
/sign/templates
/sign/templates/:envelope_id/usages
undocumented /sign/templates/:envelope_id/usages
GET /sign/templates/:envelope_id/usages: every document created from this template (one-off clones and broadcast sends), newest first, with sender and recipients attached. Visible to anyone holding a read grant on the template.
envelope_id
string · path
/sign/templates/example/usages
/sign/templates/:envelope_id/links
undocumented /sign/templates/:envelope_id/links
GET /sign/templates/:envelope_id/links — this template's self-serve links.
envelope_id
string · path
/sign/templates/example/links
/sign/signatories
undocumented /sign/signatories
GET /sign/signatories?q= : everyone ever added to a document the caller can see, aggregated by email: document count, signed/declined counts, and last activity.
/sign/signatories
/sign/signatories/:email
undocumented /sign/signatories/:email
GET /sign/signatories/:email — one signatory's profile (see _signatory_profile).
email
string · path
/sign/signatories/example
/sign/statistics
undocumented /sign/statistics
GET /sign/statistics: dashboard aggregates over the documents the caller can see (same visibility as the lists: grants, widened for auditors): status counts, monthly sent/completed volume, completion rate, median time-to-complete, pending-signature aging, top templates by usage, and recent activity.
/sign/statistics
/sign/jurisdictions
undocumented /sign/jurisdictions
GET /sign/jurisdictions — picker options + carve-out warnings (static config).
/sign/jurisdictions
/sign/settings
undocumented /sign/settings
GET /sign/settings: Sign's workspace configuration. Today that is one choice: which template a cross-app signature request is raised from. Readable by anyone who can see documents, so the Templates list can mark the chosen one even for members who may not change it.
/sign/settings
/sign/envelopes/:envelope_id/fields
undocumented /sign/envelopes/:envelope_id/fields
GET /sign/envelopes/:envelope_id/fields — list field placements.
envelope_id
string · path
/sign/envelopes/example/fields
/sign/envelopes/:envelope_id/recipients
undocumented /sign/envelopes/:envelope_id/recipients
GET /sign/envelopes/:envelope_id/recipients — list recipients + their status.
envelope_id
string · path
/sign/envelopes/example/recipients
/sign/envelopes/:envelope_id/reminders
undocumented /sign/envelopes/:envelope_id/reminders
POST /sign/envelopes/:envelope_id/reminders — remind recipients who haven't signed.
envelope_id
string · path
/sign/envelopes/example/reminders
/sign/templates/:envelope_id/broadcasts
undocumented /sign/templates/:envelope_id/broadcasts
POST /sign/templates/:envelope_id/broadcasts {rows:[{recipients:[{role,name,email}]}]} Send-to-many: clone the template once per row, bind each role to its recipient, and send every envelope. Gated by sign.envelopes.send (it IS sending). A row is used only if it has a distinct email for every role in the template; incomplete rows are skipped.
envelope_id
string · path
/sign/templates/example/broadcasts
/sign-in/:token
undocumented /sign-in/:token
GET /sign-in/:token — the landing page for a mailed link. This RENDERS ONLY. It deliberately does not redeem the token, because every mail security product worth the name (Safe Links, Proofpoint, Mimecast) fetches every URL in an inbound message before the recipient sees it. A link that signed you in on GET would be spent, or followed, by the scanner. The button below POSTs, which is what actually redeems.
token
string · path
/sign-in/example
/signup
undocumented /signup
/signup
/sitemap.xml
undocumented /sitemap.xml
/sitemap.xml
/decks/:id
Update a deck
PATCH /decks/:id. Title, content, thumbnail, or restore from trash.
id
string · path
title
string · min length: 1 · max length: 200
deck_json
object
slide_count
integer · min: 0 · max: 500
thumbnail_key
string · max length: 512
deleted
propertyName
anything
/decks/example
/decks
Create a deck
POST /decks. Create a blank deck.
title
string · min length: 1 · max length: 200
propertyName
anything
/decks
/decks/:id/assets
Register a deck image
POST /decks/:id/assets. Register an uploaded image. Gate loaded ctx.authz.deck.
id
string · path
asset_id
string · min length: 6 · max length: 64
storage_key
string · min length: 1 · max length: 512
filename
string · min length: 1 · max length: 255
content_type
string · min length: 1 · max length: 100
size_bytes
integer · min: 0
width
integer · min: 0
height
integer · min: 0
propertyName
anything
/decks/example/assets
/spellschemas
Introspect a platform API schema
Introspect a platform API endpoint's pytastic schema. POST /spellschemas with {route: "/tasks", method: "POST"} Returns UI-ready field definitions extracted from the TypedDict at runtime.
route
string · min length: 1
method
string
propertyName
anything
/spellschemas
/spell-runs/:run_id
undocumented /spell-runs/:run_id
run_id
string · path
/spell-runs/example
/spells/:spell_id
undocumented /spells/:spell_id
spell_id
string · path
/spells/example
/spells
undocumented /spells
/spells
/spells/:spell_id
undocumented /spells/:spell_id
spell_id
string · path
/spells/example
/spells/:spell_id/runs
undocumented /spells/:spell_id/runs
spell_id
string · path
/spells/example/runs
/spells
Create a spell
name
string · min length: 1 · max length: 200
description
string · max length: 2000
trigger
object
chain
array
enabled
format
source
string · max length: 100000
propertyName
anything
/spells
/spells/:spell_id/test
Test a spell (dry run)
Dry-run a spell with a sample event payload.
spell_id
string · path
payload
event_name
string
propertyName
anything
/spells/example/test
/wands/spellbook
Transform YAML <-> spell
Stateless YAML <-> spell transformer (no persistence). POST /wands/spellbook with {"source": "<yaml>"} -> {"spell": {...}} POST /wands/spellbook with {"spell": {...}} -> {"yaml": "..."} Lets the editor swap between the visual builder and the YAML view without saving. The engine still runs on stored JSON; this only reshapes in flight.
source
string · max length: 100000
spell
propertyName
anything
/wands/spellbook
/wands/schedule-previews
Check a schedule and preview its next runs
Validate a schedule and return the next few times it would fire. Always answers 200 with {valid: bool}: an author typing into the field gets a friendly message, not a stream of 422s.
text
string · min length: 1 · max length: 200
timezone
string · max length: 64
propertyName
anything
/wands/schedule-previews
/spells/:spell_id
Update a spell
spell_id
string · path
name
string · min length: 1 · max length: 200
description
string · max length: 2000
trigger
object
chain
array
enabled
format
source
string · max length: 100000
propertyName
anything
/spells/example
/suspended
undocumented /suspended
Render the subscription suspended recovery page. Shows payment methods, unpaid invoices, retry option, and delete workspace. Only accessible when subscription.status == 'suspended'.
/suspended
/tables/:table_id
undocumented /tables/:table_id
DELETE /tables/:table_id — soft-delete a table.
table_id
string · path
/tables/example
/tables/:table_id/sheets/:sheet_id
undocumented /tables/:table_id/sheets/:sheet_id
DELETE /tables/:table_id/sheets/:sheet_id — remove one sheet.
table_id
string · path
sheet_id
string · path
/tables/example/sheets/example
/tables
undocumented /tables
GET /tables — list tables for the workspace.
/tables
/tables/:table_id
undocumented /tables/:table_id
GET /tables/:table_id — get a single table with data.
table_id
string · path
/tables/example
/tables/:table_id/versions
undocumented /tables/:table_id/versions
GET /tables/:table_id/versions — list version history.
table_id
string · path
/tables/example/versions
/tables/:table_id/presence
undocumented /tables/:table_id/presence
GET /tables/:table_id/presence — get active collaborators.
table_id
string · path
/tables/example/presence
/tables/:table_id
Update a table
PATCH /tables/:table_id — update table title, icon, or data.
table_id
string · path
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
data
string
visibility
propertyName
anything
/tables/example
/tables
Create a table
POST /tables — create a new table.
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
data
string
propertyName
anything
/tables
/tables/:table_id/sheets/:sheet_id
Create or update a sheet
PUT /tables/:table_id/sheets/:sheet_id — create or update one sheet. The editor's debounced save PUTs only the sheets that actually changed, instead of PATCHing the whole workbook on every edit.
table_id
string · path
sheet_id
string · path
name
string · min length: 1 · max length: 200
position
integer · min: 0 · max: 500
doc
string
propertyName
anything
/tables/example/sheets/example
/tables/:table_id/presence
undocumented /tables/:table_id/presence
PUT /tables/:table_id/presence — update cursor position.
table_id
string · path
/tables/example/presence
/targets/:target_id
undocumented /targets/:target_id
target_id
string · path
/targets/example
/targets
undocumented /targets
/targets
/targets/leaderboard
undocumented /targets/leaderboard
/targets/leaderboard
/targets/:target_id
undocumented /targets/:target_id
target_id
string · path
/targets/example
/targets
Create a target
type
owner_mrn
string
pipeline_id
string
period
period_start
string
period_end
string
target_value
number
currency
string
propertyName
anything
/targets
/targets/:target_id
Update a target
target_id
string · path
type
owner_mrn
string
period
period_start
string
period_end
string
target_value
number
status
propertyName
anything
/targets/example
/tasks/:task_id
undocumented /tasks/:task_id
task_id
string · path
/tasks/example
/tasks
Delete tasks in bulk
Delete multiple tasks by ID.
task_ids
array
propertyName
anything
/tasks
/tasks/:task_id/links/:link_id
undocumented /tasks/:task_id/links/:link_id
task_id
string · path
link_id
string · path
/tasks/example/links/example
/tasks
undocumented /tasks
/tasks
/tasks
Create a task
title
string · min length: 1 · max length: 200
board_id
string
column_name
string · min length: 1
parent_id
string
on_board
priority
description
string · max length: 10000
topic
string
labels
array
attachments
array
assignee_mrn
string
schedule_id
string
due_date
string
size
integer · min: 1
source_mrn
string
propertyName
anything
/tasks
/tasks/completions
Mark tasks as completed
Mark multiple tasks as completed by moving them to a done column.
task_ids
array
propertyName
anything
/tasks/completions
/tasks/:task_id/links
Link two tasks
POST /tasks/:task_id/links — relate this task to another (blocks/relates/duplicates).
task_id
string · path
to_task_id
string · min length: 1
kind
propertyName
anything
/tasks/example/links
/tasks/:task_id
Update a task
task_id
string · path
title
string · min length: 1 · max length: 200
description
string · max length: 50000
column_name
string · min length: 1
assignee_mrn
string
reporter_mrn
string
reviewer_mrn
string
priority
topic
string
due_date
string
start_date
string
estimate_hours
logged_hours
wiki
string · max length: 200000
blocked_by
string
position
schedule_id
string
deliverable_id
string
parent_id
string
size
integer · min: 1
on_board
completed
labels
array
attachments
array
watchers
array
add_comment
object
propertyName
anything
/tasks/example
/sign/templates
Create a reusable template
POST /sign/templates — create a reusable template.
title
string · min length: 1 · max length: 300
subject
string · max length: 300
message
string · max length: 2000
template_id
string
signing_order_mode
jurisdiction
string · max length: 10
is_template
source_mrn
string · max length: 200
propertyName
anything
/sign/templates
/sign/templates/:envelope_id/links
Publish the template as a self-serve link
POST /sign/templates/:envelope_id/links {expires_at?, max_submissions?} — publish the template as a URL anyone can open. Single-role templates only: the visitor fills that one role; multi-party agreements go through send.
envelope_id
string · path
expires_at
string
max_submissions
integer
propertyName
anything
/sign/templates/example/links
/terms
undocumented /terms
/terms
/totps/status
undocumented /totps/status
/totps/status
/totps
undocumented /totps
/totps
/trash
undocumented /trash
/trash
/trash
undocumented /trash
/trash
/trash/restorations
Restore from trash
ids
array
propertyName
anything
/trash/restorations
/v/admin/versions/:version/notes/:note_id
undocumented /v/admin/versions/:version/notes/:note_id
DELETE /v/admin/versions/:version/notes/:note_id — remove an internal note.
version
string · path
note_id
string · path
/v/admin/versions/example/notes/example
/v/admin/coupon-redemptions/:id
undocumented /v/admin/coupon-redemptions/:id
DELETE /v/admin/coupon-redemptions/:id — unapply a redemption and subtract days.
id
string · path
/v/admin/coupon-redemptions/example
/v/admin/preview-apps/:slug/adopters/:workspace_id
undocumented /v/admin/preview-apps/:slug/adopters/:workspace_id
DELETE /v/admin/preview-apps/:slug/adopters/:workspace_id — remove from the allowlist.
slug
string · path
workspace_id
string · path
/v/admin/preview-apps/example/adopters/example
/v/admin/stats
undocumented /v/admin/stats
GET /v/admin/stats — summary stats for the admin dashboard.
/v/admin/stats
/v/admin/workspaces
undocumented /v/admin/workspaces
GET /v/admin/workspaces — list all workspaces (paginated, filterable).
/v/admin/workspaces
/v/admin/workspaces/:id
undocumented /v/admin/workspaces/:id
GET /v/admin/workspaces/:id — workspace detail.
id
string · path
/v/admin/workspaces/example
/v/admin/workspaces/:id/members
undocumented /v/admin/workspaces/:id/members
GET /v/admin/workspaces/:id/members — members of a workspace.
id
string · path
/v/admin/workspaces/example/members
/v/admin/workspaces/:id/apps
undocumented /v/admin/workspaces/:id/apps
GET /v/admin/workspaces/:id/apps — installed apps for a workspace.
id
string · path
/v/admin/workspaces/example/apps
/v/admin/workspaces/:id/invoices
undocumented /v/admin/workspaces/:id/invoices
GET /v/admin/workspaces/:id/invoices — invoices for a workspace.
id
string · path
/v/admin/workspaces/example/invoices
/v/admin/workspaces/:id/usage
undocumented /v/admin/workspaces/:id/usage
GET /v/admin/workspaces/:id/usage — current period usage meters.
id
string · path
/v/admin/workspaces/example/usage
/v/admin/settings/billing-alerts
undocumented /v/admin/settings/billing-alerts
GET /v/admin/settings/billing-alerts — operator alert recipients.
/v/admin/settings/billing-alerts
/v/admin/invoices
undocumented /v/admin/invoices
GET /v/admin/invoices — global invoice list (paginated, filterable).
/v/admin/invoices
/v/admin/threads
undocumented /v/admin/threads
GET /v/admin/threads — list all support threads.
/v/admin/threads
/v/admin/threads/:id
undocumented /v/admin/threads/:id
GET /v/admin/threads/:id — thread detail + messages.
id
string · path
/v/admin/threads/example
/v/admin/audit
undocumented /v/admin/audit
GET /v/admin/audit — audit log (paginated, filterable).
/v/admin/audit
/v/admin/profiles
undocumented /v/admin/profiles
GET /v/admin/profiles?q=... — search profiles for micron invite.
/v/admin/profiles
/v/admin/microns
undocumented /v/admin/microns
GET /v/admin/microns — list all microns (paginated, searchable).
/v/admin/microns
/v/admin/coupons
undocumented /v/admin/coupons
GET /v/admin/coupons — list coupons with optional search.
/v/admin/coupons
/v/admin/coupons/:code
undocumented /v/admin/coupons/:code
GET /v/admin/coupons/:code — coupon detail + redemption history.
code
string · path
/v/admin/coupons/example
/v/admin/demo-requests
undocumented /v/admin/demo-requests
GET /v/admin/demo-requests — list demo requests (paginated, filterable).
/v/admin/demo-requests
/v/admin/preview-apps
undocumented /v/admin/preview-apps
GET /v/admin/preview-apps — preview apps with their early-adopter allowlists.
/v/admin/preview-apps
/v/admin/preview-apps/workspace-search
undocumented /v/admin/preview-apps/workspace-search
GET /v/admin/preview-apps/workspace-search?q= — find workspaces to add.
/v/admin/preview-apps/workspace-search
/v/admin/workspaces/:id/billing
undocumented /v/admin/workspaces/:id/billing
PATCH /v/admin/workspaces/:id/billing — adjust billing controls. Region is operator-controlled: it derives from the signup country and only the Micron console may correct it (self-service switching allowed customers to pick the cheaper rate).
id
string · path
/v/admin/workspaces/example/billing
/v/admin/coupons/:code
undocumented /v/admin/coupons/:code
PATCH /v/admin/coupons/:code — flip is_active (admin revoke/restore).
code
string · path
/v/admin/coupons/example
/v/admin/demo-requests/:id
undocumented /v/admin/demo-requests/:id
PATCH /v/admin/demo-requests/:id — update a demo request's status.
id
string · path
/v/admin/demo-requests/example
/v/admin/workspaces/:id/winback-emails
undocumented /v/admin/workspaces/:id/winback-emails
POST /v/admin/workspaces/:id/winback-emails — invite a suspended workspace back. Manual, per-workspace, from the console: emails every owner/admin the win-back note with the current entry price for their region.
id
string · path
/v/admin/workspaces/example/winback-emails
/v/admin/invoices/:id/refunds
undocumented /v/admin/invoices/:id/refunds
POST /v/admin/invoices/:id/refunds {amount?, reason} — refund a paid invoice. Full refunds (no amount) mark the invoice 'refunded'; partial refunds keep it 'paid' with the action recorded in the audit log either way.
id
string · path
/v/admin/invoices/example/refunds
/v/admin/invoices/:id/charge
undocumented /v/admin/invoices/:id/charge
POST /v/admin/invoices/:id/charge — retry payment on an invoice.
id
string · path
/v/admin/invoices/example/charge
/v/admin/threads/:id/messages
undocumented /v/admin/threads/:id/messages
POST /v/admin/threads/:id/messages — micron replies to a thread.
id
string · path
/v/admin/threads/example/messages
/v/admin/microns
undocumented /v/admin/microns
POST /v/admin/microns — add a profile as micron. Owner can add admin or member. Admin can add member only.
/v/admin/microns
/v/admin/versions/:version/notes
undocumented /v/admin/versions/:version/notes
POST /v/admin/versions/:version/notes — append an internal note to a release.
version
string · path
/v/admin/versions/example/notes
/v/admin/coupons
undocumented /v/admin/coupons
POST /v/admin/coupons — create a new coupon. Owner or admin only.
/v/admin/coupons
/v/admin/preview-apps/:slug/adopters
undocumented /v/admin/preview-apps/:slug/adopters
POST /v/admin/preview-apps/:slug/adopters — add a workspace to the allowlist.
slug
string · path
/v/admin/preview-apps/example/adopters
/v/admin/workspaces/:id/subscription
undocumented /v/admin/workspaces/:id/subscription
PUT /v/admin/workspaces/:id/subscription — lock or unlock a workspace.
id
string · path
/v/admin/workspaces/example/subscription
/v/admin/settings/billing-alerts
undocumented /v/admin/settings/billing-alerts
PUT /v/admin/settings/billing-alerts — set operator alert recipients. These addresses receive an email whenever a customer charge fails or a workspace gets suspended for non-payment. Empty list turns emails off (the console invoice list remains the fallback).
/v/admin/settings/billing-alerts
/v/admin/invoices/:id
undocumented /v/admin/invoices/:id
PUT /v/admin/invoices/:id — void an invoice.
id
string · path
/v/admin/invoices/example
/v/admin/threads/:id
undocumented /v/admin/threads/:id
PUT /v/admin/threads/:id — update thread (assign, priority, status).
id
string · path
/v/admin/threads/example
/v/admin/microns/:id
undocumented /v/admin/microns/:id
PUT /v/admin/microns/:id — update a micron's role or revoke access. Owner can change any role. Admin cannot change owners or other admins.
id
string · path
/v/admin/microns/example
/verifications/resend
undocumented /verifications/resend
/verifications/resend
/verify
undocumented /verify
/verify
/views/:view_id
undocumented /views/:view_id
view_id
string · path
/views/example
/views
undocumented /views
/views
/wands/events
undocumented /wands/events
List all platform events available as flow triggers.
/wands/events
/wands/filters
undocumented /wands/filters
List all registered Jinja2 filters with descriptions.
/wands/filters
/wands/context/:spell_id/:step_index
undocumented /wands/context/:spell_id/:step_index
Get available context variables for a given step in a spell's chain.
spell_id
string · path
step_index
string · path
/wands/context/example/example
/wands/macros
undocumented /wands/macros
All macros. ?grouped=true returns them in category order with Spellbook-rendered examples (what the reference page renders).
/wands/macros
/wands/macros/:macro_name
undocumented /wands/macros/:macro_name
macro_name
string · path
/wands/macros/example
/wands/samples
undocumented /wands/samples
Recent REAL payloads captured in this workspace. With ?action=core.crm.deal.won: every stored sample for that event. Without it: the latest sample for each event seen, so the builder and the macro playground can offer a menu of real payloads to try.
/wands/samples
/wands/recipes
undocumented /wands/recipes
Curated recipe gallery, filtered to the workspace's installed apps.
/wands/recipes
/wands/stats
undocumented /wands/stats
Workspace automation dashboard payload.
/wands/stats
/webhooks/livekit-rooms
undocumented /webhooks/livekit-rooms
LiveKit sends participant events here. Update is_connected state.
/webhooks/livekit-rooms
/webhooks/livekit
undocumented /webhooks/livekit
/webhooks/livekit
/wiki/share-roles
undocumented /wiki/share-roles
GET /wiki/share-roles — roles a member may add to a page share list.
/wiki/share-roles
/wikis/:page_id
Update a wiki page
PATCH /wikis/:page_id — update page title, content, icon, etc.
page_id
string · path
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
content
string
position
integer · min: 0
parent_id
string
propertyName
anything
/wikis/example
/wikis/:page_id/comments/:comment_id
Resolve/unresolve comment
PATCH /wikis/:page_id/comments/:comment_id — resolve or unresolve.
page_id
string · path
comment_id
string · path
resolved
propertyName
anything
/wikis/example/comments/example
/wikis
Create a wiki page
POST /wikis — create a new wiki page.
title
string · min length: 1 · max length: 500
parent_id
string
icon
string · max length: 100
icon_type
content
string
propertyName
anything
/wikis
/wikis/:page_id/comments
Add a comment
POST /wikis/:page_id/comments — add a comment.
page_id
string · path
body
string · min length: 1 · max length: 4000
object_id
string · max length: 64
parent_id
string · max length: 64
nx
number
ny
number
propertyName
anything
/wikis/example/comments
/wikis/:page_id/position
Move/reorder a page
PUT /wikis/:page_id/position — move a page to a new parent/position.
page_id
string · path
parent_id
string
position
integer · min: 0
propertyName
anything
/wikis/example/position
/wikis/:page_id/access
Change page visibility and share list
PUT /wikis/:page_id/access — change visibility and share list. Requires manage-level access (authz: can_manage_page).
page_id
string · path
visibility
shares
array
propertyName
anything
/wikis/example/access
/wikis/:page_id
undocumented /wikis/:page_id
DELETE /wikis/:page_id — soft-delete a page and its descendants.
page_id
string · path
/wikis/example
/wikis/:page_id/comments/:comment_id
undocumented /wikis/:page_id/comments/:comment_id
DELETE /wikis/:page_id/comments/:comment_id — delete a comment.
page_id
string · path
comment_id
string · path
/wikis/example/comments/example
/wikis
undocumented /wikis
GET /wikis — list root-level pages. Restricted pages the caller cannot access are filtered out at query time. Owners/admins see everything (platform bypass).
/wikis
/wikis/:page_id
undocumented /wikis/:page_id
GET /wikis/:page_id — get a single page with content.
page_id
string · path
/wikis/example
/wikis/:page_id/children
undocumented /wikis/:page_id/children
GET /wikis/:page_id/children — list child pages. Filters out restricted children the caller cannot access.
page_id
string · path
/wikis/example/children
/wikis/:page_id/versions
undocumented /wikis/:page_id/versions
GET /wikis/:page_id/versions — list version history.
page_id
string · path
/wikis/example/versions
/wikis/:page_id/versions/:version_id
undocumented /wikis/:page_id/versions/:version_id
GET /wikis/:page_id/versions/:version_id — get a single version.
page_id
string · path
version_id
string · path
/wikis/example/versions/example
/wikis/:page_id/comments
undocumented /wikis/:page_id/comments
GET /wikis/:page_id/comments — list comments for a page.
page_id
string · path
/wikis/example/comments
/wikis/:page_id/presence
undocumented /wikis/:page_id/presence
GET /wikis/:page_id/presence — get active collaborators.
page_id
string · path
/wikis/example/presence
/wikis/:page_id/presence
undocumented /wikis/:page_id/presence
PUT /wikis/:page_id/presence — update cursor position.
page_id
string · path
/wikis/example/presence
/workers/:worker_id/documents/:document_id
Move or rename a worker document
Move a document between folders (and to/from root), or rename it.
worker_id
string · path
document_id
string · path
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
content
string
is_starred
page_mode
visibility
page_setup
object
deleted
propertyName
anything
/workers/example/documents/example
/workers/:worker_id/documents/folders
Create a document folder
worker_id
string · path
name
string · min length: 1 · max length: 120
propertyName
anything
/workers/example/documents/folders
/workers/:worker_id/documents
Record an uploaded worker document
Record a document the browser already uploaded to R2 (Computer source).
worker_id
string · path
title
string · min length: 1 · max length: 500
icon
string · max length: 100
icon_type
content
string
propertyName
anything
/workers/example/documents
/workers/:worker_id/notes
Add a note to a worker
worker_id
string · path
text
string · min length: 1 · max length: 5000
propertyName
anything
/workers/example/notes
/workers/:worker_id/notes/:note_id
Update a worker note
worker_id
string · path
note_id
string · path
text
string · min length: 1 · max length: 5000
propertyName
anything
/workers/example/notes/example
/workers/:worker_id/personal
Update personal details
PATCH personal details — merge provided keys; empty string clears a key.
worker_id
string · path
date_of_birth
string · max length: 10
gender
string · max length: 50
pronouns
string · max length: 50
nationality
string · max length: 100
marital_status
string · max length: 50
personal_email
string · max length: 200
personal_phone
string · max length: 50
address_line1
string · max length: 200
address_line2
string · max length: 200
city
string · max length: 100
state
string · max length: 100
postal_code
string · max length: 30
country
string · max length: 100
propertyName
anything
/workers/example/personal
/workers/:worker_id/qualifications
Update qualifications
PATCH qualifications — each provided collection replaces that collection.
worker_id
string · path
education
array
certifications
array
skills
array
languages
array
propertyName
anything
/workers/example/qualifications
/workers/:worker_id/bank-details
Update bank details
PATCH bank details — merge flat fields; identifiers list replaces whole.
worker_id
string · path
bank_name
string · max length: 150
account_name
string · max length: 150
account_number
string · max length: 50
branch_code
string · max length: 50
iban
string · max length: 50
swift_bic
string · max length: 20
currency
string · max length: 3
notes
string · max length: 500
identifiers
array
propertyName
anything
/workers/example/bank-details
/workers/:worker_id/emergency-contacts
Replace emergency contacts
PUT the full emergency contacts list (replace semantics).
worker_id
string · path
contacts
array
propertyName
anything
/workers/example/emergency-contacts
/workers/:worker_id/right-to-work
Replace right-to-work documents
PUT the full right-to-work document list (replace semantics).
worker_id
string · path
records
array
propertyName
anything
/workers/example/right-to-work
/workers/:worker_id
undocumented /workers/:worker_id
worker_id
string · path
/workers/example
/workers/fields/:field_id
undocumented /workers/fields/:field_id
field_id
string · path
/workers/fields/example
/workers/:worker_id/notes/:note_id
undocumented /workers/:worker_id/notes/:note_id
worker_id
string · path
note_id
string · path
/workers/example/notes/example
/workers/:worker_id/employment/:record_id
undocumented /workers/:worker_id/employment/:record_id
worker_id
string · path
record_id
string · path
/workers/example/employment/example
/workers/:worker_id/documents/folders/:folder_id
undocumented /workers/:worker_id/documents/folders/:folder_id
worker_id
string · path
folder_id
string · path
/workers/example/documents/folders/example
/workers/:worker_id/documents/:document_id
undocumented /workers/:worker_id/documents/:document_id
worker_id
string · path
document_id
string · path
/workers/example/documents/example
/workers
undocumented /workers
/workers
/workers/:worker_id
undocumented /workers/:worker_id
worker_id
string · path
/workers/example
/workers/locations/:location_id/members
undocumented /workers/locations/:location_id/members
Workers currently assigned to a location — powers the delete dialog count.
location_id
string · path
/workers/locations/example/members
/workers/fields
undocumented /workers/fields
/workers/fields
/workers/:worker_id/fields
undocumented /workers/:worker_id/fields
Field definitions merged with this worker's values. Sensitive-flagged fields are omitted entirely unless the caller holds workers.sensitive.*.
worker_id
string · path
/workers/example/fields
/workers/:worker_id/personal
undocumented /workers/:worker_id/personal
Personal profile bundle: personal details, emergency contacts, right to work, qualifications (all gated on workers.personal.*).
worker_id
string · path
/workers/example/personal
/workers/:worker_id/bank-details
undocumented /workers/:worker_id/bank-details
Bank details + identity numbers (gated on workers.sensitive.*).
worker_id
string · path
/workers/example/bank-details
/workers/:worker_id/notes
undocumented /workers/:worker_id/notes
worker_id
string · path
/workers/example/notes
/workers/:worker_id/compensation
undocumented /workers/:worker_id/compensation
worker_id
string · path
/workers/example/compensation
/workers/:worker_id/employment
undocumented /workers/:worker_id/employment
worker_id
string · path
/workers/example/employment
/workers/:worker_id/documents
undocumented /workers/:worker_id/documents
worker_id
string · path
/workers/example/documents
/workers/:worker_id/documents/:document_id/view
undocumented /workers/:worker_id/documents/:document_id/view
Short-lived presigned GET URL for a worker document.
worker_id
string · path
document_id
string · path
/workers/example/documents/example/view
/workers/:worker_id
Update a worker profile
worker_id
string · path
employee_id
string · max length: 50
department_id
string
manager_id
string
status
location_mrn
string · max length: 120
work_location
string · max length: 200
work_mode
expected_hours_per_day
number
work_email
string · max length: 200
work_phone
string · max length: 50
notes
string · max length: 5000
propertyName
anything
/workers/example
/workers
Create a worker profile
member_mrn
string · min length: 1
job_title
string · min length: 1 · max length: 200
hire_date
string · min length: 1
employee_id
string · max length: 50
department_id
string
manager_id
string
employment_type
status
location_mrn
string · max length: 120
work_location
string · max length: 200
work_mode
expected_hours_per_day
number
work_email
string · max length: 200
work_phone
string · max length: 50
notes
string · max length: 5000
propertyName
anything
/workers
/workers/locations/:location_id/reassignment
Reassign workers off a location
Move every worker assigned to a location to another one (or clear it). Body: {"target": "<location mrn>"} to move, or omit/empty to set to none. Called by the location delete dialog before the location is removed.
location_id
string · path
target
string
propertyName
anything
/workers/locations/example/reassignment
/workspaces/:id
Delete workspace
DELETE /workspaces/:id — permanently delete a workspace. Owner only.
id
string · path
confirmation
string · min length: 1
propertyName
anything
/workspaces/example
/workspaces/:id
undocumented /workspaces/:id
GET /workspaces/:id — workspace detail page with tabs.
id
string · path
/workspaces/example
/workspaces/:id/partials/members
undocumented /workspaces/:id/partials/members
GET /workspaces/:id/partials/members — paginated members list partial.
id
string · path
/workspaces/example/partials/members
/ws/ws
Platform WebSocket handler — authenticates via session and holds connection open.
/app/mail/ws/:draft_id/app/mail/ws/:draft_id
WS at /app/mail/ws/:draft_id — Yjs body sync (binary) + field/presence relay (JSON).
/app/calls/ws/app/calls/ws
WebSocket handler for call signaling and state updates.
/o1/calls/:token/ws/o1/calls/:token/ws
Open WebSocket for in-call guests. Guests have no workspace session, so we resolve the call from the (globally unique) link slug and scope the socket to that one call. Receive-only: chat is sent via the REST endpoint; this just delivers chat/state events the same way members get them over their WS.
/app/canvas/ws/:board_id/app/canvas/ws/:board_id
Yjs binary relay + awareness + presence for one board.
/app/chat/ws/app/chat/ws
WebSocket handler for real-time chat events.
/app/papers/ws/:document_id/app/papers/ws/:document_id
WebSocket relay for Yjs collaborative editing on a document. The socket is binary-only: y-websocket clients decode every frame as binary y-protocols messages and crash on text frames, so errors are sent as native permission-denied frames and JSON is never written here.
/app/tables/ws/:table_id/app/tables/ws/:table_id
WebSocket handler for collaborative presence on a table.
/app/wiki/ws/:page_id/app/wiki/ws/:page_id
WebSocket handler for Yjs collaborative editing on a wiki page. WS routes bypass BEFORE hooks, so auth + access are checked here. Restricted pages require share ≥ edit (same as PATCH).