Skip to main content

API Reference

Base URL: https://api.h.work (prod) / https://api.h852.work (staging)

Auth: Authorization: Bearer <jwt> on all protected endpoints unless noted.

Global rate limit: 100 req/min per IP. Auth endpoints: 10 req/min.

โš ๏ธ Frontend โ‰  API surface. The /ops/* prefix exists on the frontend (Next.js, under frontend/src/app/ops/), but most ops surfaces on the API are still served from /am/orgs/*, /superadmin/*, or /admin/*. The real /ops/* API routes today are the Tavus function-call admin under /ops/tavus/function-calls (renamed from /ops/personas/function-calls via #1031 โ€” old paths return 308 redirects for ~30 days) and the legacy tombstone POST /ops/orgs/:orgId/ragflow-provision, which returns a compatibility response. Server-side redirects from /am/* and /superadmin/* to /ops/* apply to frontend routes only; the underlying API paths have not moved. Tracked: #247.

Auth column legend: JWT = JwtAuthGuard only ยท SA = superadmin ยท AM = account_manager+ ยท Expert = expert+ ยท OrgAdmin/OrgMember/OrgOwner = OrgRolesGuard role ยท Token = onboarding/invite token ยท Agent = AgentTokenGuard HMAC.


Healthโ€‹

Source: health.controller.ts, common/metrics.controller.ts.

MethodPathAuthDescription
GET/healthNoneLiveness probe
GET/readyNoneReadiness probe (DB + agent connectivity)
GET/metricsNetwork policyPrometheus metrics (internal only)

Authโ€‹

Source: auth/auth.controller.ts.

MethodPathAuthDescription
POST/auth/registerNoneSelf-service: create org + first admin user
POST/auth/loginNoneReturns JWT with userId, email, platformRole, orgMemberships
POST/auth/demo-loginNoneDemo backdoor (DEMO_MODE=true only)
POST/auth/orgsSACreate org with admin user
POST/auth/accept-invite/:tokenNoneAccept invite + set password โ†’ JWT
POST/orgs/:orgId/invitesOrgAdminInvite user by email
DELETE/orgs/:orgId/members/:userIdOrgAdminRemove user from org
GET/orgs/:orgIdOrgMemberOrg details
GET/orgs/:orgId/membersOrgMemberList org members

Password Resetโ€‹

MethodPathAuthDescription
POST/auth/request-password-resetNoneSend password-reset email
POST/auth/reset-passwordNoneComplete password reset with token

2FAโ€‹

MethodPathAuthDescription
POST/auth/2fa/setupJWTGenerate TOTP secret + QR code URI
POST/auth/2fa/verifyJWTVerify TOTP code and enable 2FA

Superadmin Auth Toolsโ€‹

MethodPathAuthDescription
POST/auth/bootstrap-superadminNone (once)Promote first user if no superadmin exists
GET/admin/users/:idSAFetch any user by id
PATCH/admin/users/:idSAUpdate arbitrary user fields
PATCH/admin/users/:id/roleSAUpdate platformRole
PATCH/admin/users/:id/passwordSAReset password

OTP & Invite Flowโ€‹

MethodPathAuthDescription
GET/invites/validateNoneValidate invite token
POST/auth/send-invite-otpNoneSend email OTP
POST/auth/verify-invite-otpNoneVerify OTP โ†’ create/activate account
POST/auth/request-otpNoneGeneric OTP request
POST/auth/verify-otpNoneGeneric OTP verify

Conversationsโ€‹

Source: conversations/conversations.controller.ts. Rate limit: 100 req/min per PRD ยง14.

MethodPathAuthDescription
POST/conversationsJWTCreate conversation
GET/conversationsJWTList conversations (filter: orgId)
GET/conversations/searchJWTFull-text search (q, orgId, limit, offset)
GET/conversations/:idJWTFetch conversation + messages (paginated)
POST/conversations/:id/messagesJWTSend message
POST/conversations/:id/messages/streamJWTStream agent response as SSE
PATCH/conversations/:id/statusExpertUpdate conversation status
PATCH/conversations/:id/assignExpertReassign Specialist on a conversation
POST/conversations/:id/assign-agentJWTTrigger agentic-mode re-assignment
GET/conversations/:id/assignment-historyExpertAppend-only assignment audit (#363)

Internal Agent Thread (HP staff only)โ€‹

These power the Expert/AM "ask the agent" side panel and are guarded by PlatformRolesGuard.

MethodPathAuthDescription
GET/conversations/:id/agent-threadStaffFetch internal agent-thread for conversation
POST/conversations/:id/agent-thread/messagesStaffSend message to internal agent thread
POST/conversations/:id/agent-thread/messages/streamStaffSSE stream from internal agent thread

Expert Queueโ€‹

Source: expert-queue/expert-queue.controller.ts. All routes require PlatformRolesGuard (expert, account_manager, or superadmin unless noted).

MethodPathAuthDescription
GET/expert-queueExpertList queue items (filter: status, orgId)
GET/expert-queue/:idExpertFetch single queue item
PATCH/expert-queue/:idExpertUpdate queue item (generic patch)
PATCH/expert-queue/:id/statusExpertUpdate status (4-state: pending/awaiting_client/resolved/snoozed; widened by #1985)
POST/expert-queue/:id/suggestExpertGet fresh AI suggestion for item
POST/expert-queue/:id/respondExpertSend response (approve/edit/write own)
POST/expert-queue/:id/resolveExpertResolve with satisfaction score
POST/expert-queue/:id/deferExpertDefer item by X hours
POST/expert-queue/:id/add-noteExpertAdd internal note
POST/expert-queue/:id/correctionsExpertSubmit correction for learning loop
POST/expert-queue/:id/drafts/:draftId/releaseExpertPer-draft release (Expert hands a single draft off the queue) โ€” #1878 / PR #1966
POST/expert-queue/:id/drafts/:draftId/discardExpertPer-draft discard (Expert drops a single draft) โ€” #1878 / PR #1966
POST/expert-queue/admin/resurface-snoozedSAForce-resurface all snoozed items
GET/expert/orgsExpertGet Expert's available orgs
GET/expert/orgs/:orgId/assignable-expertsExpertList experts assignable on this org

Per-thread Slack queue items (#1877)โ€‹

Slack channel queue items are keyed by (conversation_id, slack_thread_ts) so each Slack thread becomes its own queue item rather than collapsing onto the parent conversation. The standard /expert-queue/* endpoints above accept these items transparently; the additional thread key is exposed on the response payload as slackThreadTs.


Agent Statusโ€‹

Source: agents/agent-status.controller.ts.

MethodPathAuthDescription
GET/agent/statusStaffLiveness/health of agent service

Onboardingโ€‹

Source: onboarding/onboarding.controller.ts. All onboarding endpoints use a token (from the invitation email) instead of JWT auth.

Client-Facing (Phase 2 Wizard)โ€‹

MethodPathAuthDescription
POST/onboarding/:token/verify-emailTokenSend OTP to admin email
POST/onboarding/:token/confirm-otpTokenVerify OTP โ†’ session JWT
POST/onboarding/:token/profileTokenSave name, title, phone
GET/onboarding/:token/orgTokenOrg details for wizard
GET/onboarding/:token/specialistTokenAssigned Specialist card
POST/onboarding/:token/confirm-slugTokenFinalize and reserve slug
POST/onboarding/:token/invite-membersTokenInvite multiple Client Members
POST/onboarding/:token/completeTokenFinalize onboarding (Step 2.6)
POST/onboarding/:token/business-contextTokenSubmit business context
GET/onboarding/:token/whitelistTokenList email whitelist entries
POST/onboarding/:token/whitelistTokenAdd entry to whitelist
DELETE/onboarding/:token/whitelist/:idTokenRemove whitelist entry

Public Slug / Invite Endpointsโ€‹

Sources: auth.controller.ts, organizations.controller.ts.

MethodPathAuthDescription
GET/orgs/slug-checkNoneReal-time slug availability check
GET/api/slugs/:slug/resolveNoneResolve slug โ†’ org info
GET/invitations/:token/validateNoneValidate invite token, return org slug
GET/client/trial-infoJWTTrial countdown for client portal

Organizations โ€” Account Manager / Superadminโ€‹

Source: organizations/organizations.controller.ts.

API contract: the AM portal is still served from /am/orgs/* on the API even though the frontend now lives at /ops/clients/*. See the banner at the top of this file (#247).

Core AM org routesโ€‹

MethodPathAuthDescription
GET/am/orgsAMList AM's assigned orgs
GET/am/orgs/:orgIdAMOrg detail
PATCH/am/orgs/:orgIdAMUpdate company info
GET/am/orgs/:orgId/phase0-statusAMPhase 0 validation checklist
POST/am/orgs/:orgId/inviteAMSend client invitation (Phase 0 gate check)
POST/am/orgs/:orgId/invite/resendAMResend invitation (fresh 7-day token)
DELETE/am/orgs/:orgId/inviteAMRevoke invitation
POST/am/orgs/:orgId/finish-setupAMMark AM setup complete
POST/am/orgs/:orgId/deactivateAMDeactivate org (AM-side)
GET/orgs/:orgId/auditAM/SAPer-org audit log

Specialists (AM catalog + per-org assignment)โ€‹

MethodPathAuthDescription
GET/am/specialistsAMList available specialists
GET/am/specialists/:idAMSpecialist detail
GET/am/orgs/:orgId/specialistsAMSpecialists assigned to org
POST/am/orgs/:orgId/specialistAMAssign Specialist to org
PATCH/am/orgs/:orgId/specialist-assignments/:assignmentIdAMUpdate assignment (threshold, primary)
GET/am/orgs/:orgId/specialist-assignments/:assignmentId/rate-historyAMHourly-rate history for assignment
DELETE/am/orgs/:orgId/specialistAMRemove all Specialists from org
DELETE/am/orgs/:orgId/specialist/:specialistIdAMRemove one Specialist from org

Expert โ†” Org Assignmentโ€‹

/organizations/:orgId/experts is the canonical surface; /am/orgs/:orgId/experts is the legacy surface still served by the controller.

MethodPathAuthDescription
GET/organizations/:orgId/expertsOrgAdminList experts for org
POST/organizations/:orgId/expertsOrgAdminAssign expert to org
DELETE/organizations/:orgId/experts/:expertIdOrgAdminRemove expert from org
GET/am/orgs/:orgId/expertsAMList experts (legacy)
POST/am/orgs/:orgId/expertsAMAssign expert (legacy)
DELETE/am/orgs/:orgId/experts/:expertIdAMRemove expert (legacy)
GET/am/expertsAMGlobal expert directory

Specialist Change Requestsโ€‹

MethodPathAuthDescription
POST/orgs/:orgId/specialist-change-requestsOrgAdminClient requests different Specialist
GET/orgs/:orgId/specialist-change-requestsAMAM views pending requests
PATCH/orgs/:orgId/specialist-change-requests/:idAMAM fulfills or declines request

Org Ownership / Trialโ€‹

MethodPathAuthDescription
POST/orgs/:orgId/transfer-ownershipOrgOwnerTransfer org ownership

Superadmin Org Endpointsโ€‹

MethodPathAuthDescription
POST/organizationsSACreate org
POST/orgsSACreate org (legacy alias of /organizations)
GET/superadmin/orgsSAList all orgs
GET/superadmin/orgs/:orgId/invite-tokenSAGet current invite token
DELETE/superadmin/orgs/:orgIdSAPermanently delete org
GET/expertsSAList all experts
POST/ops/orgs/:orgId/ragflow-provisionSARemoved provisioning path; returns a compatibility tombstone because Haystack has no per-org provisioning step
POST/admin/orgs/:orgId/rebrandSARebrand org (name/slug)
POST/admin/orgs/:orgId/deactivateSADeactivate org (SA-side)

Note: /ops/orgs/:orgId/ragflow-provision retains the legacy ragflow-provision path during the P3-1 migration; it will be renamed in a follow-up.


Client Portal Helpersโ€‹

Source: organizations/organizations.controller.ts.

MethodPathAuthDescription
GET/client/contextJWTFull client portal context
GET/client/specialistsJWTClient's assigned Specialists
GET/client/org-infoJWTOrg info for client portal

Admin (per-org + platform ops)โ€‹

Source: admin/admin.controller.ts.

MethodPathAuthDescription
GET/admin/membersSA / OrgAdmin / AMList members
GET/admin/internal-staffSAList HP internal staff
POST/admin/members/inviteSA / OrgAdminInvite member
PATCH/admin/members/:id/roleSA / OrgAdminChange member role
DELETE/admin/members/:idSA / OrgAdminRemove member
DELETE/admin/invites/:idSA / OrgAdminRevoke a pending invite
POST/admin/invites/:id/resendSA / OrgAdminResend a pending invite
GET/admin/billingSA / OrgAdminOrg billing status
GET/admin/quotaSA / OrgAdminOrg quota usage
GET/admin/usersSASearch users globally
POST/admin/impersonate/:userIdSAStart impersonation session
POST/admin/impersonate/am/:userIdSAStart silent AM impersonation
DELETE/admin/impersonateSAEnd impersonation session
POST/admin/orgs/:orgId/restoreSARestore archived stale org
GET/admin/test/latest-otpSATest-only: fetch most recent OTP
GET/admin/orgs/:orgId/invite-tokenSA / AMRead current invite token
POST/admin/backfill-subjectsSABackfill auth subjects (one-shot)

Admin ยท Specialists Catalogโ€‹

Source: admin/admin-specialists.controller.ts.

MethodPathAuthDescription
GET/admin/specialistsSAList Specialist catalog
POST/admin/specialistsSACreate catalog Specialist
PATCH/admin/specialists/:idSAUpdate catalog Specialist
DELETE/admin/specialists/:idSADelete catalog Specialist
GET/admin/specialists/exportSAExport catalog JSON
POST/admin/specialists/push-to-r2SAPublish live DB state to R2 manifest
POST/admin/specialists/seed-catalogSASeed catalog from manifest

Admin ยท Experts (SuperAdmin fast-path)โ€‹

Source: admin/admin-experts.controller.ts (#1221, closes #1208).

MethodPathAuthDescription
POST/admin/expertsSADirect Expert creation (bypasses waitlist/lead flow)

Admin ยท Marketing Leadsโ€‹

Source: admin/admin-marketing-leads.controller.ts.

MethodPathAuthDescription
GET/admin/marketing/leads/companiesSAList company leads
GET/admin/marketing/leads/companies/:idSACompany lead detail
PATCH/admin/marketing/leads/companies/:id/statusSAUpdate company lead status
GET/admin/marketing/leads/expertsSAList expert applications
GET/admin/marketing/leads/experts/:idSAExpert application detail
PATCH/admin/marketing/leads/experts/:id/statusSAUpdate expert app status
POST/admin/marketing/leads/experts/:id/promoteSAPromote waitlisted Expert to active (#1200, closes #1084)
POST/admin/marketing/leads/experts/:id/declineSADecline Expert application (#1200, closes #1084)

Admin ยท DLQโ€‹

Source: channels/dlq-admin.controller.ts. Prefix /admin/dlq. See DLQ Admin feature + DLQ Handling runbook.

MethodPathAuthDescription
GET/admin/dlqSAList dead-letter entries (filter status/channel/org)
GET/admin/dlq/statsSADLQ aggregate stats (count by status + pending)
POST/admin/dlq/drainSADrain entries (mark drained, no redelivery)
POST/admin/dlq/replaySAReplay entries (reset dead/drained โ†’ queued)

Admin ยท WhatsApp Poolโ€‹

Source: admin/whatsapp-admin.controller.ts. Prefix /admin/whatsapp/pool.

MethodPathAuthDescription
GET/admin/whatsapp/poolSAList pool numbers
GET/admin/whatsapp/pool/healthSAPool health
POST/admin/whatsapp/poolSAAdd number to pool
PATCH/admin/whatsapp/pool/:idSAUpdate pool number
POST/admin/whatsapp/pool/:id/assign/:specialistIdSAAssign number to a Specialist
POST/admin/whatsapp/pool/:id/retireSARetire number
POST/admin/whatsapp/pool/:id/unassignSAUnassign number from Specialist

Admin ยท Integrations Catalogโ€‹

Source: admin/integrations-catalog/integrations-catalog.controller.ts.

MethodPathAuthDescription
GET/v1/admin/integrations/catalogSAList supported integrations

Email Whitelistโ€‹

Source: organizations/organizations.controller.ts. Same underlying data, two surfaces.

AM-sideโ€‹

MethodPathAuthDescription
GET/am/orgs/:orgId/email-whitelistAMList email whitelist
POST/am/orgs/:orgId/email-whitelistAMAdd to whitelist
DELETE/am/orgs/:orgId/email-whitelist/:idAMRemove from whitelist

Client-sideโ€‹

MethodPathAuthDescription
GET/client/orgs/:orgId/email-whitelistOrgMemberList email whitelist
POST/client/orgs/:orgId/email-whitelistOrgAdminAdd to whitelist
DELETE/client/orgs/:orgId/email-whitelist/:idOrgAdminRemove from whitelist

Auto-Reply Configurationโ€‹

Source: organizations/organizations.controller.ts.

MethodPathAuthDescription
GET/orgs/:orgId/auto-reply-configSA/AM/ExpertGet auto-reply configuration
PATCH/orgs/:orgId/auto-reply-configSA/AMUpdate auto-reply configuration

Expert Access (ADR-007, canonical)โ€‹

Source: expert-access/expert-access.controller.ts. Prefix /orgs/:orgId/expert-access. All routes require superadmin or account_manager.

MethodPathAuthDescription
POST/orgs/:orgId/expert-accessSA/AMCreate access grant (scope=org or specialist)
GET/orgs/:orgId/expert-accessSA/AMList access grants for org
DELETE/orgs/:orgId/expert-access/:grantIdSA/AMRevoke a single grant
DELETE/orgs/:orgId/expert-access/expert/:expertIdSA/AMRevoke all grants for an expert on this org

Channelsโ€‹

Inbound Webhooksโ€‹

Sources: channels/slack/slack.controller.ts (Slack inbound, post-#1212 SlackModule refactor), channels/channels.controller.ts (Email, WhatsApp, Teams, WeChat), channels/telegram/telegram.controller.ts.

MethodPathAuthDescription
POST/channels/slack/eventsSlack HMAC-SHA256ยนSlack Events API webhook
POST/channels/email/inboundNone (Cloudflare)Cloudflare Email Routing inbound webhook
POST/channels/whatsapp/inboundTwilio HMAC-SHA1WhatsApp inbound
POST/channels/whatsapp/statusTwilio HMAC-SHA1WhatsApp delivery status callback
POST/channels/teams/webhookBot FrameworkTeams inbound webhook
POST/channels/teams/messagesBot FrameworkTeams proactive-message endpoint
GET/channels/wechat/webhookNoneWeChat verification challenge
POST/channels/wechat/webhookWeChat signatureWeChat inbound
POST/channels/telegram/webhookHMAC-SHA256Telegram Bot API updates

ยน Slack signing_secret is resolved per-org from integration_credentials (BLK-004 / #1219); the SLACK_SIGNING_SECRET env var is a dev-only fallback and disallowed in production.

Channel Adminโ€‹

Source: channels/channel-admin.controller.ts. Prefix /orgs/:orgId/channels.

MethodPathAuthDescription
GET/orgs/:orgId/channels/statusOrgAdminHealth status for all channels
GET/orgs/:orgId/channels/webhook-urlsOrgAdminWebhook URLs to paste into dashboards
GET/orgs/:orgId/channels/slack/manifestOrgAdminSlack app manifest suggester (#1034)

Channel Mediaโ€‹

Source: channels/channel-media.controller.ts.

MethodPathAuthDescription
GET/messages/:id/attachments/:idxStaffStream message attachment (signed)

WhatsApp ยท per-orgโ€‹

Source: channels/whatsapp/whatsapp-org.controller.ts. Prefix /orgs/:orgId/whatsapp/whitelist.

MethodPathAuthDescription
GET/orgs/:orgId/whatsapp/whitelistOrgAdminList whitelist numbers
POST/orgs/:orgId/whatsapp/whitelistOrgAdminAdd number to whitelist
DELETE/orgs/:orgId/whatsapp/whitelist/:idOrgAdminRemove from whitelist

WhatsApp ยท pairing (user-side)โ€‹

Source: channels/whatsapp/whatsapp-pairing.controller.ts. Prefix /whatsapp.

MethodPathAuthDescription
POST/whatsapp/pairing-codeJWTGenerate pairing code
GET/whatsapp/linked-numbersJWTList linked numbers for current user
DELETE/whatsapp/linked-numbers/:idJWTUnlink a number

Integration Credentialsโ€‹

Source: integrations/credentials/credentials.controller.ts. Two controllers in one file.

Per-org generic credentials (/orgs/:orgId/integrations)โ€‹

MethodPathAuthDescription
POST/orgs/:orgId/integrationsOrgAdminCreate/upsert channel credentials
GET/orgs/:orgId/integrationsOrgAdminList integrations (values masked)
DELETE/orgs/:orgId/integrations/:idOrgAdminDelete integration
POST/orgs/:orgId/integrations/:id/testOrgAdminTest connection

Nango (/v1/integrations)โ€‹

MethodPathAuthDescription
POST/v1/integrations/nango/sessionOrgAdminCreate Nango connect session
POST/v1/integrations/credentials/nango/confirmOrgAdminConfirm Nango credentials

Billingโ€‹

Sources: billing/interface/client-billing.controller.ts, billing/interface/ops-billing.controller.ts, billing/interface/billing-webhook.controller.ts.

Status (2026-06-04): Lago is the active billing rail โ€” self-hosted Lago (Railway for dev; AWS for staging + prod โ€” AWS bring-up tracked in #1287). Legacy Stripe/RequestFinance plan-tier endpoints (/billing/subscriptions, /billing/checkout-session, /billing/webhooks/stripe, /billing/webhooks/request-finance) were removed in #1016 (Phase 7, 2026-05-28). The Lago provider adapter shipped in #1069; dual-strategy pricing (plan_per_rate default for free-tier Lago, plan_overrides for premium) shipped in #1105; client + ops surfaces via #1155 (#1165 was closed-unmerged and superseded by #1155); #1217 renamed the launch-checklist row from "Orb" โ†’ "Lago". See docs/superpowers/specs/2026-05-26-billing-provider-leveraged-design.md.

Client billing (/client/billing)โ€‹

MethodPathAuthDescription
GET/client/billing/summaryOrgMemberCurrent subscription summary for the org
GET/client/billing/portal-urlOrgAdminOne-shot Lago portal URL for self-service

Ops billing (/ops/billing)โ€‹

MethodPathAuthDescription
GET/ops/billingSA/AMList all orgs + subscription state
POST/ops/billing/sync-customer/:orgIdSAReconcile Lago customer for an org
GET/ops/billing/customer/:orgIdSA/AMLago customer detail for an org
POST/ops/billing/subscriptions/:assignmentId/retry-syncSARetry Lago subscription sync for a stuck OSA

Lago webhooksโ€‹

MethodPathAuthDescription
POST/billing/webhooks/lagoLago signatureLago webhook intake

LlmCostRollupService (#1151) rolls up messages.cost_cents pivoted on osa_id into the per-OSA billing record.


Agentic Tasksโ€‹

Source: agentic/agentic.controller.ts. Prefix /agentic.

Status (2026-05-25): The HTTP surface below is unchanged, but execution has been superseded by the RIG runtime control plane (#696). The legacy Python /v1/tasks* runtime was removed; backing for /agentic/tasks/* now flows through the RIG run authority (runs, events, approvals/input, tool/model/sandbox/artifact gateways). See docs/architecture/RIG_HARD_CUT_RUNTIME_PORT_PLAN.md.

MethodPathAuthDescription
POST/agentic/tasksJWTCreate agentic task with step plan
GET/agentic/tasksJWTList tasks by org
GET/agentic/tasks/:idJWTGet task + full plan
POST/agentic/tasks/:id/steps/:stepId/approveJWTApprove a step
POST/agentic/tasks/:id/steps/:stepId/rejectJWTReject step with feedback

Agents (per-org)โ€‹

Source: agents/agents.controller.ts. Prefix /orgs/:orgId/agents.

MethodPathAuthDescription
GET/orgs/:orgId/agentsJWTList org agents (filter: role)
POST/orgs/:orgId/agentsJWTCreate agent for org
DELETE/orgs/:orgId/agents/:idJWTRemove agent

Toolsโ€‹

Source: tools/tools.controller.ts.

MethodPathAuthDescription
POST/tools/executeโ€”Removed 2026-05-25 (#696 โ€” RIG hard-cut). Returns HTTP 410. Tool execution flows through the runtime tool gateway / POST /v1/agent-api/tools/:toolName (Agent surface).
GET/orgs/:orgId/tool-permissionsJWTList enabled tools
PUT/orgs/:orgId/tool-permissions/:toolNameJWTEnable/disable tool with optional config

Analyticsโ€‹

Source: analytics/analytics.controller.ts.

MethodPathAuthDescription
GET/analytics/summaryStaffAggregate analytics (superadmin: all orgs; org: scoped)

Audit Logโ€‹

Sources: audit/audit-log.controller.ts, organizations/organizations.controller.ts.

MethodPathAuthDescription
GET/audit-logJWTPaginated audit log (filter: from, to, entity_type, limit, cursor)
GET/orgs/:orgId/auditAM/SAPer-org audit (see Organizations section)

Learningโ€‹

Source: learning/learning.controller.ts.

MethodPathAuthDescription
POST/expert-queue/:id/correctionsExpertSubmit correction (alias used by Expert UI)
POST/correctionsNone*Agent service submits correction (* gated by agent-service auth header)
GET/learning/correctionsStaffList corrections (filter: role)
GET/learning/corrections/statsStaffAggregated correction stats by type
GET/learning/corrections/exportSAExport corrections CSV
GET/learning/corrections/stats/by-orgSAStats grouped by org

Usersโ€‹

Source: users/users.controller.ts. Prefix /users.

MethodPathAuthDescription
GET/users/meJWTCurrent user profile
PATCH/users/meJWTUpdate own profile
POST/users/:id/hp-verifyJWTHumanity Protocol credential verification (stub)

Uploadโ€‹

Source: upload/upload.controller.ts. Prefix /upload.

MethodPathAuthDescription
POST/uploadJWTUpload file to R2
GET/upload/signed-url/*keyJWTGet signed URL for file

Knowledge Baseโ€‹

Sources: kb/kb-documents.controller.ts (prefix /kb), kb/kb-retrieval.controller.ts (prefix /kb, Agent-only), kb/kb.controller.ts (prefix /api/kb). The /api/kb/* surface is the pre-#817 controller; document CRUD has migrated to /kb/*, but #1526 extended /api/kb/* with a new search endpoint used by the Expert workspace KB panel, so /api/kb/* is not wholesale retired.

MethodPathAuthDescription
POST/kbJWTRegister a document (metadata)
GET/kbJWTList KB documents for the org
GET/kb/:idJWTGet document detail
POST/kb/uploadJWTUpload document file (multipart) โ€” #817
GET/kb/:id/access-urlJWTSigned access URL for a stored document โ€” #823
GET/kb/retrievalAgentVector retrieval for Agent runtime โ€” #819
GET/api/kb/searchJWTKB search for Expert workspace KB panel โ€” #1526

Internal-only audit logging (used by Agent + runtime):

MethodPathAuthDescription
POST/audit/logAgentAppend agent-driven audit entry

Notificationsโ€‹

Source: notifications/notifications.controller.ts (#915). Prefix /notifications. Pipeline overview: features/notifications.md.

MethodPathAuthDescription
POST/notificationsJWTCreate an AppNotification (internal/system callers โ€” see note)
GET/notifications?limit=&offset=JWTList the caller's notifications, newest first (limit default 50, clamped 1โ€“200; offset default 0)
PATCH/notifications/:id/readJWTMark notification as read (ownership-checked; idempotent)
  • POST body (CreateNotificationDto): userId (uuid, recipient), type (string), message (string), title?, meta? (object). Currently JwtAuthGuard-only; a PlatformRolesGuard tier is a tracked #170 follow-up, so treat POST as internal-caller-only.
  • GET resolves the recipient from the JWT (never a query param); a request whose token has no user id 401s rather than returning an unfiltered list (#915).
  • markRead returns 403 if the notification belongs to another user, 404 if it doesn't exist. There is no unread-count endpoint โ€” the badge is derived client-side from readAt === null.
  • Response/Socket.io payload shape (NotificationDto, identical on both surfaces): { id, userId, type, message, title, meta, readAt, createdAt }.

Socket.io (/notifications namespace)โ€‹

Real-time delivery runs alongside REST (#915). Namespace /notifications; JWT supplied via the Socket.io auth object, ?token=, or Authorization: Bearer. On connect the socket joins user:<userId> (always), org:<orgId> (non-client roles), and experts (expert/superadmin); conversation:<id> is joined on demand via the join_conversation event (ACL-checked, paired with leave_conversation). Redis-backed adapter fans events across pods when REDIS_URL is set.

EventDirectionRoomNotes
notification:newserver โ†’ clientuser:<userId>In-app AppNotification delivery (payload = NotificationDto)
expert_queue_item_addedserver โ†’ clientexpertsQueue surface
queue_item_resolvedserver โ†’ clientexperts, conversation:<id>Queue surface
queue_item_status_updatedserver โ†’ clientexpertsQueue surface โ€” generic status change (defer/awaiting_client/โ€ฆ)
queue_item_updatedserver โ†’ clientexperts (+ conversation:<id> conversation_status_changed)Queue surface โ€” non-terminal transition (pending/awaiting_client/snoozed), row stays visible (#388)
conversation_status_changedserver โ†’ clientconversation:<id>Conversation surface
agent_message_sentserver โ†’ clientorg:<id>, conversation:<id>, expertsConversation surface
user_message_receivedserver โ†’ clientorg:<id>, conversation:<id>, expertsConversation surface
workspace_message_addedserver โ†’ clientexpertsConversation surface โ€” Expert-workspace internal note
join_conversation / leave_conversationclient โ†’ serverโ€”Subscribe/unsubscribe a conversation:<id> room

Schedulerโ€‹

Source: scheduler/scheduler.controller.ts. Prefix /scheduler. All routes require superadmin.

MethodPathAuthDescription
GET/scheduler/jobsSAList scheduled jobs
POST/scheduler/jobs/:jobName/triggerSATrigger job immediately
DELETE/scheduler/jobs/:jobKeySADelete scheduled job
GET/scheduler/healthSAScheduler health

Marketing (public)โ€‹

Source: marketing/marketing.controller.ts. Prefix /marketing. All routes are public.

MethodPathAuthDescription
POST/marketing/companies/leadNoneSubmit company lead
POST/marketing/experts/applicationNoneSubmit expert application
GET/marketing/specialistsNoneList public Specialists
GET/marketing/specialists/:slugNonePublic Specialist profile

Public Widget (embeddable chat)โ€‹

Source: public/widget-session.controller.ts. Prefix /public/widget. Unauthenticated entry point that mints a short-lived visitor JWT for the embeddable chat widget (@humanwork/chat-widget). See features/embeddable-chat-widget.md and integrations/embed.md.

MethodPathAuthDescription
OPTIONS/public/widget/sessionNoneCORS preflight (Access-Control-Allow-Origin: *), 204
POST/public/widget/sessionNone, 30/minMint a 24h visitor JWT for { orgSlug, visitorId? } โ†’ { token, expiresAt, visitorId }
  • orgSlug is required; an unknown slug returns 404. visitorId is optional โ€” when omitted (or not a UUID it can normalize) the server generates one; a malformed visitorId returns 400.
  • The minted token carries role: "client" / platformRole: "client", widgetVisitorId, and a single-org orgMemberships entry. TTL = 24h (#2925).
  • After holding the token the widget reuses the standard Conversations API above as a client-role caller (GET/POST /conversations, GET /conversations/:id, POST /conversations/:id/messages); responses are masked by ClientConversationViewInterceptor (Expert identity stripped, role: "expert" โ†’ "agent"). Realtime arrives over the /notifications Socket.IO namespace (agent_message_sent, agent_typing).

Environment Profilesโ€‹

Source: environment-profiles/environment-profiles.controller.ts. Prefix /environment-profiles.

MethodPathAuthDescription
GET/environment-profiles/:idJWTGet environment profile
GET/environment-profiles/by-assignment/:assignmentIdJWTGet profile by specialist-assignment id
PATCH/environment-profiles/:idJWTUpdate profile (draft fields)
POST/environment-profiles/:id/approveJWTApprove profile

Meetings (Onboarding videos / Tavus)โ€‹

Source: meetings/meetings.controller.ts.

MethodPathAuthDescription
POST/assignments/:assignmentId/onboarding/startJWTStart onboarding video session
POST/assignments/:assignmentId/meetingsJWTCreate a meeting for assignment
GET/assignments/:assignmentId/meetingsJWTList meetings for assignment
POST/assignments/:assignmentId/meetings/:meetingId/startJWTStart a specific meeting
GET/meetings/:idJWTGet meeting detail

Tavus Replicas + Webhooksโ€‹

Source: tavus/tavus.controller.ts.

MethodPathAuthDescription
GET/tavus/replicasStaffList Tavus replicas
POST/tavus/webhooks/function-callTavus signatureTavus function-call webhook
POST/tavus/webhooks/transcript-readyTavus signatureTavus transcript-ready webhook

Tavus Function-Call Definitions (admin)โ€‹

Source: tavus/tavus-function-definitions.controller.ts. Prefix /ops/tavus/function-calls since #1031 (renamed from /ops/personas/function-calls; legacy controller tavus-function-definitions-legacy.controller.ts serves 308 redirects for ~30 days). One of the rare real /ops/* API surfaces.

MethodPathAuthDescription
GET/ops/tavus/function-callsStaffList function-call definitions
GET/ops/tavus/function-calls/:idStaffGet definition
POST/ops/tavus/function-callsStaffCreate definition
PATCH/ops/tavus/function-calls/:idStaffUpdate definition
POST/ops/tavus/function-calls/:name/versionsStaffCreate new version of named definition
DELETE/ops/tavus/function-calls/:idStaffDelete definition

Agent API (Agent Service โ†’ Control Plane)โ€‹

These routes are called by the Python agent service and are guarded by AgentTokenGuard (HMAC of AGENT_API_SHARED_SECRET). Not for human/UI clients.

Source: agent-api/agent-api.controller.ts, agent-events/agent-events.controller.ts, agent-runtime/internal-runtime-config.controller.ts.

MethodPathAuthDescription
GET/v1/agent-api/conversations/:conversationId/messagesAgentFetch conversation history
GET/v1/agent-api/contextAgentFetch org/specialist context
GET/v1/agent-api/toolsAgentList available tools for org/specialist
POST/v1/agent-api/tools/:toolNameAgentExecute a tool
POST/v1/agent-api/token/refreshAgentRefresh agent service token
POST/v1/agent-api/eventsAgentStream agent execution events
GET/v1/internal/org/:slug/runtime-configAgentPer-org agent runtime config

Recently Removed / Audit Notesโ€‹

The following endpoints have been documented in past versions of this reference but do not exist in the current controllers (verified 2026-05-25 against api/src/**/*.controller.ts).

PathStatus
GET /orgs/:orgId/quotaRemoved โ€” quota is exposed via /admin/quota.
POST /expert-queue/:id/reassignRemoved 2026-05-03 โ€” expert-pool model deleted; replaced by expert_access (ADR-007).
GET /expert/pools, POST /pools, GET /expert/pools/:id/membersRemoved 2026-05-03 โ€” expert-pool model deleted.
org_experts table writesDeprecated 2026-05-22 (ADR-007); reads still served via /am/orgs/:orgId/experts for back-compat through #540.
POST /tools/executeRemoved 2026-05-25 (#696, RIG hard-cut). Returns HTTP 410. Use the runtime tool gateway / POST /v1/agent-api/tools/:toolName.
POST /v1/tasks and /v1/tasks/* (Agent surface)Removed 2026-05-25 (#696). Agent endpoints return HTTP 410 with LEGACY_TASK_AUTHORITY_REMOVED. The Platform /agentic/tasks/* surface remains but is now RIG-backed.
POST /billing/subscriptions, GET /billing/subscriptions[/:orgId], DELETE /billing/subscriptions/:orgId, POST /billing/checkout-session, POST /billing/webhooks, POST /billing/webhooks/stripe, POST /billing/webhooks/request-financeRemoved 2026-05-28 (#1016, Phase 7). Legacy fixed-plan Stripe + RequestFinance rail killed; Lago is canonical (#1069/#1105/#1155 โ€” #1165 was closed-unmerged, superseded by #1155). See Billing section above.

Methodologyโ€‹

This file was audited end-to-end against the controller decorators on 2026-05-25 (closes #247). The procedure was:

  1. Enumerate every *.controller.ts under api/src/.
  2. For each file, extract @Controller(...) prefix and every @Get/@Post/@Put/@Patch/@Delete decorator together with @PlatformRoles / @OrgRoles / @UseGuards.
  3. Cross-check the resulting (method, fully-qualified path, auth) triples against this document, in both directions.
  4. Drop fictional entries, correct wrong methods/paths, add missing real endpoints, and note removed routes above.

@MessagePattern queue handlers and Socket.io gateway events are intentionally excluded โ€” this file documents HTTP only.


Last updated: 2026-06-01 โ€” Pass-2 docs audit sweep: KB/Notifications/Lago sections refreshed; /tools/execute + Stripe legacy + /v1/tasks* moved to Recently Removed; Slack source path updated for #1212; Slack signing_secret per-org footnote (#1219); SuperAdmin Expert fast-path and waitlist promote/decline endpoints added; Slack manifest endpoint added. Underlying full controller audit: 2026-05-25 (#247). If you add, rename, or remove a controller route, update this file in the same PR.