LDM v3 API

Multi-tenant B2B outreach automation platform exposed as one Bearer-authenticated HTTPS surface for the web UI, MCP and A2A clients. 1,304 operations across 119 tags: companies, contacts, leads and pipelines, briefs and creatives, mailing tasks and campaigns with send-readiness dry-runs, email accounts and warm-up, three-phase deliverability probes, suppression / stop-list / marking guardrails, webhooks, billing ledger, legal documents and a public DSAR endpoint. Tenant-scoped calls carry X-Tenant-Id; 406 operations declare x-required-scope from a 79-scope catalog. Self-serve registration returns a PENDING-account ldm_* key immediately.

Operations 1304

Showing the first 250 of 1304. The full set is in the contract, and via get_provider_operations.

GET /api/notifications/push/public-key Get the tenant VAPID public key for Web Push #
POST /api/notifications/push/subscribe Register a browser Web Push subscription #
POST /api/notifications/push/unsubscribe Remove a browser Web Push subscription #
GET /api/notifications List notifications for the current user #
GET /api/notifications/unread-count Get the unread notifications badge count #
POST /api/notifications/read-all Mark all unread notifications as read #
POST /api/notifications/{id}/read Mark a notification as read #
POST /api/notifications/{id}/dismiss Dismiss a notification (hide from widget) #
POST /api/notifications/dismiss-all Dismiss all notifications for the current user #
POST /api/notifications/self-note Create an agent self-note notification #
POST /api/auth/register Register a new account (self-service). Requires termsAccepted=true (user agreement: GET /api/legal/terms). channel=web needs a password; channel=mcp/a2a/form (bootstrap from an AI #
GET /api/auth/verify-email Confirm email by the token from the signup email. Activates the account automatically (1 auto-activation per hour platform-wide; otherwise it stays PENDING for admin approval). Bro #
POST /api/auth/signup-questionnaire Issue #322 — submit the signup questionnaire for accounts that did not qualify for automatic activation (free mailbox, or the website/MX checks did not line up). Authenticated by t #
POST /api/auth/otc Exchange the one-time sign-in code from the email-verification redirect for a session (same response as /auth/login). Codes are single-use and expire in 5 minutes. #
POST /api/auth/login Authenticate a user and issue access + refresh tokens. 401 = wrong email/password; 403 = credentials are correct but the account is not ACTIVE yet (email not confirmed / awaiting a #
POST /api/auth/refresh Exchange a refresh token for a new access + refresh pair #
POST /api/auth/logout Revoke a refresh token and end the session #
POST /api/auth/forgot-password Request a password reset email (rate-limited per email and per IP) #
POST /api/auth/reset-password Reset password using a reset token #
GET /api/auth/profile Get the current authenticated user profile #
GET /api/auth/me Get current user profile (alias of /auth/profile) #
POST /api/auth/change-password Change the password of the authenticated user (current required) #
POST /api/auth/impersonate/{userId} Impersonate another user (SUPER role only) #
GET /api/api-keys List tenant API keys (raw key value hidden) #
POST /api/api-keys Create a new tenant API key. Pass `actAsCurrentUser: true` to bind the key to the calling user (required for compose/reply/forward and other user-context endpoints; sets `ownerUser #
GET /api/api-keys/whoami Check that the current Bearer credentials (API key or JWT) are valid, and learn where this key is connected before hitting a wall. No scope required — any authenticated caller pass #
GET /api/api-keys/{id}/reveal Reveal the raw value of an existing API key. Only JWT-authenticated (browser) calls are allowed — an ApiKey cannot read another key's secret. Returns { id, name, key }. #
GET /api/api-keys/scopes/structured Structured scope catalog for the API Keys UI wizard. Returns presets (AI Agent / Read-only) + grouped scope definitions with descriptions and dangerous-flag. Used by Settings → API #
PATCH /api/api-keys/{id} Upgrade an existing API key in-place: set/unset Act-as-me. Only JWT-authenticated calls are allowed (an ApiKey cannot upgrade another ApiKey). Key value is NOT changed — downstream #
DELETE /api/api-keys/{id} Permanently delete a tenant API key #
DELETE /api/api-keys/{id}/revoke Revoke (deactivate) a tenant API key without deleting it #
GET /api/webhooks List webhook endpoints #
POST /api/webhooks Create a webhook endpoint #
PATCH /api/webhooks/{id} Update a webhook endpoint #
DELETE /api/webhooks/{id} Delete a webhook endpoint #
GET /api/webhooks/{id}/deliveries List delivery history for a webhook endpoint #
POST /api/webhooks/deliveries/{id}/retry Retry a single webhook delivery #
POST /api/webhooks/{id}/retrigger Retrigger the last N deliveries for a webhook endpoint #
POST /api/users/me/accept-terms Accept legal terms for the current user #
GET /api/users List users (SUPER/MANAGER) #
POST /api/users Create a user (SUPER only) #
GET /api/users/system/stats Get system stats (SUPER only) #
POST /api/users/system/kill-process/{pid} Kill a system process by pid (SUPER only) #
POST /api/users/system/cleanup-orphans Cleanup orphan system resources (SUPER only) #
GET /api/users/{id} Get a user by id (SUPER/MANAGER) #
DELETE /api/users/{id} Delete a user with tenant cleanup: sole-member tenants + their DBs are dropped (SUPER only) #
PATCH /api/users/{id}/role Update a user role (SUPER/MANAGER) #
PATCH /api/users/{id}/status Update a user status (SUPER/MANAGER) #
PATCH /api/users/{id}/password Update a user password (SUPER only) #
PATCH /api/users/{id}/profile Update a user profile (SUPER only) #
GET /api/users/{id}/comments List admin comments on a user (SUPER/MANAGER) #
POST /api/users/{id}/comments Add an admin comment on a user (SUPER/MANAGER) #
DELETE /api/users/{id}/comments/{commentId} Delete an admin comment on a user (SUPER only) #
GET /api/companies/custom-fields List custom field definitions for the given entity (company/contact/lead) #
POST /api/companies/custom-fields Create a custom field definition #
PUT /api/companies/custom-fields/reorder Reorder custom field definitions by id array #
GET /api/companies/custom-fields/{companyId}/values Get custom field values for a company #
POST /api/companies/custom-fields/{companyId}/values Set custom field values for a company #
PUT /api/companies/custom-fields/{id} Update a custom field definition #
DELETE /api/companies/custom-fields/{id} Delete a custom field definition (requires confirm=true) #
GET /api/companies/duplicates/fields List fields available for duplicate-scan matching #
POST /api/companies/duplicates/scan Scan companies for duplicates by configured fields #
POST /api/companies/duplicates/merge Merge duplicate company records #
POST /api/companies/duplicates/delete Delete duplicate company records identified by scan #
POST /api/companies/duplicates/move-to-list Move duplicate companies into a target list #
GET /api/companies/stats Get company statistics, optionally scoped to a list #
GET /api/companies List companies with pagination, search, and filters #
POST /api/companies Create a new company. Note: `email` is NOT a Company field — emails live on linked contacts as Channels. Use POST /api/contacts to create the contact, then POST /api/contacts/:id/c #
GET /api/companies/duplicates Find duplicate companies in the workspace. Groups are ordered by reliability: same_inn (strong) first, then same_domain (strong), then same_name (weak — different legal entities sh #
GET /api/companies/{id} Get a single company by ID #
PATCH /api/companies/{id} Update an existing company #
DELETE /api/companies/{id} Soft-delete a company #
GET /api/companies/{id}/timeline Get a paginated timeline of events for a company #
POST /api/companies/bulk Enqueue a bulk action on multiple companies (async) #
GET /api/companies/bulk/{jobId} Get the status of a bulk company job #
DELETE /api/companies/bulk/{jobId} Cancel an in-progress bulk company job #
GET /api/companies/export/columns List exportable column definitions for companies #
POST /api/companies/export Export companies to a downloadable file #
POST /api/companies/merge Merge multiple companies into one keeper record #
POST /api/companies/import/google-sheets Fetch rows from a Google Sheets URL for import. Returns { headers, rows, suggestedMapping, unmapped } (#1058): suggestedMapping proposes a column -> field guess (incl. cf:/cus #
POST /api/companies/import/preview Preview a companies import with proposed mapping #
POST /api/companies/import/start Start a companies import. Body: { rows: object[], mapping: {csvColumn -> field}, options }. Mappable fields: name (required), domain, inn, industry, size, country, city, address, s #
POST /api/companies/import/combined Combined companies + contacts import. mapping fields: company (name, domain, inn, industry, size, country, city, address, state, phone, website, source), custom fields cf: → c #
POST /api/companies/{id}/restore Restore a soft-deleted company #
DELETE /api/companies/{id}/purge PERMANENTLY delete a trashed company (requires isDeleted). Irreversible. #
DELETE /api/companies/import/rollback/{batchId} Roll back a company import batch by ID #
PATCH /api/companies/{id}/freeze Freeze a company (set status FROZEN). Blocks campaign sending (#369) #
PATCH /api/companies/{id}/unfreeze Unfreeze a company (set status ACTIVE). Does NOT resume already-skipped rows (#369) #
GET /api/rpa/v1/readiness Read scoped queue and campaign metadata without claiming, preparing or authorizing sending; follow pagination for a complete snapshot #
POST /api/rpa/v1/heartbeat Service heartbeat; include the complete task lease identity to extend a live CLAIMED/STARTED/CONTROL_REPORTED/REAL_READY task by 60 minutes. Stop at the last acknowledged expiresAt #
POST /api/rpa/v1/claim Poll preparation: task:null while validating; placement-gated tasks begin CONTROL-only and receive REAL only after server evidence. Deduplicate by idempotencyKey. #
POST /api/rpa/v1/start Revalidate canonical send gates for the claimed operationId; send only when sendEnabled=true. CONTROL and REAL use different operation idempotency keys on the same task. #
POST /api/rpa/v1/current Read the same task and lease after a CONTROL report or server placement poll; never creates a second claim. #
POST /api/rpa/v1/renew Extend this worker’s live CLAIMED/STARTED/CONTROL_REPORTED/REAL_READY lease by 60 minutes; never revive an expired or terminal task #
POST /api/rpa/v1/refresh Refresh HTTPS attachment links and scoped relay context without changing canonical envelope bytes #
POST /api/rpa/v1/report Report one immutable CONTROL or REAL operation. Gated tasks must echo operationId, taskVersion and contentFingerprint; legacy three-field reports remain for one-step tasks. #
POST /api/rpa/v1/profile-release Optional terminal-task browser-close acknowledgement. CONTROL/placement/REAL continuation never releases the profile. Without this acknowledgement legacy reports remain valid and o #
POST /api/rpa/v1/return Return an execution known not to have sent. Keeps the same task, retries through canonical gates within its attempt budget. #
POST /api/rpa/v1/reconciliation Read this worker’s unresolved tasks, up to 20 per authorized target. Never permission to resend. Resolve items then read again. #
POST /api/rpa/v1/reconcile Resolve an uncertain execution using positive sent evidence or retained executor proof of no send. Not a blind retry or a lease renewal. #
POST /api/rpa/v1/error Report a deduplicated execution error; obey the returned action, never replay sending after an uncertain outcome #
POST /api/rpa/v1/placement Attach late seed-copy placement evidence; never evidence of recipient inbox placement #
GET /api/rpa/v1/attachments/{token}/{filename} Download a lease-bound signed attachment with its original filename; legacy token-only URLs remain supported #
GET /api/rpa/v1/attachments/{token} Download a lease-bound signed attachment with its original filename; legacy token-only URLs remain supported #
GET /api/suppression List suppressed emails #
POST /api/suppression Add an email to the suppression list #
POST /api/suppression/bulk Bulk-add emails to the suppression list #
POST /api/suppression/check Check a batch of emails against the suppression list #
DELETE /api/suppression/{email} Remove an email from the suppression list #
GET /api/suppression/domains List suppressed domains #
POST /api/suppression/domains Add a domain to the suppression list #
DELETE /api/suppression/domains/{domain} Remove a domain from the suppression list #
GET /api/stop-lists List stop list entries (user scope) #
POST /api/stop-lists Add a stop list entry (user scope) #
GET /api/stop-lists/stats Get stop list statistics (user scope) #
POST /api/stop-lists/bulk Bulk-add stop list entries (user scope) #
DELETE /api/stop-lists/{id} Remove a stop list entry (user scope) #
POST /api/stop-lists/check Check a batch of emails against the stop list #
GET /api/stop-lists/global List global stop list entries (SUPER only) #
POST /api/stop-lists/global Add a global stop list entry (SUPER only) #
GET /api/stop-lists/global/stats Get global stop list statistics (SUPER only) #
POST /api/stop-lists/global/bulk Bulk-add global stop list entries (SUPER only) #
DELETE /api/stop-lists/global/{id} Remove a global stop list entry (SUPER only) #
GET /api/reports List tenant reports (paginated) + storage quota #
POST /api/reports Create a report from base64 content (agent/MCP path) #
GET /api/reports/limits Reports storage limits and current usage #
POST /api/reports/upload Upload a report file (multipart, UI path) #
POST /api/reports/from-export/{exportJobId} Register a completed export job as a report (idempotent) #
GET /api/reports/{id} Get one report #
PATCH /api/reports/{id} Update report title/description #
DELETE /api/reports/{id} Delete a report (file + record) #
POST /api/reports/{id}/publish Publish: open a direct public download link (no auth!) #
POST /api/reports/{id}/unpublish Unpublish: close the public link (token kept — re-publish restores the same url) #
POST /api/reports/{id}/rotate-token Rotate the public token — old link dies immediately #
GET /api/reports/{id}/download Download the report file (authorized) #
GET /api/mail-agent/status Get the mail agent connection status and stats #
GET /api/mail-agent/settings Get current mail agent settings #
POST /api/mail-agent/settings Toggle the mail agent enabled flag #
POST /api/mail-agent/token/regenerate Regenerate the mail agent auth token #
POST /api/mail-agent/stats/reset Reset mail agent statistics counters #
POST /api/mail-agent/disconnect Disconnect the mail agent session #
GET /api/mail-agent/download/windows Download the Windows mail agent bundle with token pre-configured #
GET /api/mail-agent/qr Get an SVG QR code for pairing the Android mail agent #
GET /api/mail-agent/update/check Check for the latest mail agent version (public) #
POST /api/ai/generate Generate AI completion via configured provider #
GET /api/ai/balance Get balance for current or specified AI provider #
GET /api/ai/balances Get balances for all configured AI providers #
GET /api/ai/usage Get AI usage statistics for the given window (days) #
GET /api/ai/logs Get recent AI usage logs #
GET /api/ai/providers List available AI providers with status #
GET /api/ai/models List available AI models per provider (dynamic) #
POST /api/ai/check-balance Check AI balance against threshold (cron/monitoring hook) #
GET /api/oauth/connect Public OAuth connect page for anti-detect browser flow #
GET /api/oauth/connect/{accountId} Public OAuth consent redirect for a specific account #
GET /api/oauth/auth-url/{accountId} Get the OAuth consent URL for an email account #
GET /api/oauth/callback OAuth provider callback endpoint (public, used by provider redirect) #
GET /api/oauth/{accountId}/status Get OAuth connection status for an account #
POST /api/oauth/{accountId}/revoke Revoke OAuth tokens for an account #
POST /api/oauth/{accountId}/refresh Manually refresh the OAuth access token for an account #
GET /api/creatives/{id}/rules Get the creative rules document #
PATCH /api/creatives/{id}/rules Patch the creative rules document #
GET /api/creatives/{id}/rules/schema Get the JSON Schema for creative rules #
GET /api/creatives/{id}/rules/context Get supporting context used to evaluate creative rules #
GET /api/creatives/{id}/rules/history Get audit history of creative rule changes #
GET /api/creatives/{id}/bootstrap Get unified creative bootstrap snapshot for page render #
PATCH /api/creatives/{id}/meta Update creative meta fields (non-rule) #
GET /api/creatives/{id}/rules-sub List available autopilot sub-resource keys #
GET /api/creatives/{id}/rules/{sub} Get an autopilot sub-resource rules document #
PATCH /api/creatives/{id}/rules/{sub} Patch an autopilot sub-resource rules document #
GET /api/creatives/{id}/rules/{sub}/schema Get the JSON Schema for an autopilot sub-resource #
GET /api/creatives/{id}/rules/{sub}/history Get audit history for an autopilot sub-resource #
GET /api/discovery Get agent discovery document with resources and endpoints #
GET /api/contract Get the agent contract version and core principles #
POST /api/nalog-id/lookup Look up Russian tax/company data (Nalog) by company info #
GET /api/nalog-id/test Debug/test endpoint for Nalog lookup via query parameters #
GET /api/mail-transport/stats Transport-usage breakdown from mail_outbox.sent_via. Useful for spotting unused or broken transports (e.g. relay=0 implies the option can be disabled). #
POST /api/verify Verify a single email address synchronously #
POST /api/verify/batch Verify a batch of email addresses synchronously #
GET /api/custom-fields List custom field definitions, optionally filtered by entity #
POST /api/custom-fields Create a custom field definition #
GET /api/custom-fields/inventory Read-only report: divergence between JSONB and table storage #
PATCH /api/custom-fields/{id} Update a custom field definition #
DELETE /api/custom-fields/{id} Delete a custom field definition #
POST /api/custom-fields/reorder Reorder custom field definitions #
GET /api/custom-fields/values/{entity}/{entityId} Get all custom field values for an entity instance #
POST /api/custom-fields/values/{entity}/{entityId} Set a custom field value for an entity instance #
POST /api/custom-fields/params/{entity}/{entityId} Legacy bulk set of params as key-value pairs #
GET /api/custom-fields/params/{entity}/{entityId} Legacy get of params as flat key-value object #
GET /api/contacts/stats Get contact statistics, optionally scoped to a list #
GET /api/contacts/duplicates Find duplicate contacts across the workspace #
GET /api/contacts List contacts with pagination, search, and filters #
POST /api/contacts Create a new contact. Note: `email`/`phone` are NOT direct Contact fields — they live as Channels. After creating the contact, attach the email/phone via POST /api/contacts/:id/cha #
GET /api/contacts/{id} Get a single contact by ID #
PATCH /api/contacts/{id} Update an existing contact #
DELETE /api/contacts/{id} Soft-delete a contact #
GET /api/contacts/{id}/timeline Get a paginated timeline of events for a contact #
POST /api/contacts/bulk Bulk action on contacts (async, BullMQ). Pass either contactIds[] OR selectAll:true (the server resolves contacts by the search/emailValidStatus/dig* filter). Actions: delete | add #
GET /api/contacts/bulk/{jobId} Get the status of a bulk contact job #
DELETE /api/contacts/bulk/{jobId} Cancel an in-progress bulk contact job #
POST /api/contacts/export Export contacts to a downloadable file #
POST /api/contacts/import/preview Preview a contacts import with proposed mapping #
POST /api/contacts/import/start Start a contacts import job #
POST /api/contacts/{id}/restore Restore a soft-deleted contact #
DELETE /api/contacts/{id}/purge PERMANENTLY delete a trashed contact (requires isDeleted). Irreversible. #
POST /api/contacts/merge Merge multiple contacts into one keeper record #
POST /api/contacts/{id}/dig Manually trigger DIG email enrichment for a contact #
GET /api/contacts/{id}/duplicates Check for duplicates of a specific contact #
POST /api/contacts/{id}/channels Add a communication channel to a contact #
PATCH /api/contacts/{contactId}/channels/{channelId} Update a contact channel #
DELETE /api/contacts/{contactId}/channels/{channelId} Delete a contact channel #
DELETE /api/contacts/import/rollback/{batchId} Roll back a contact import batch by ID #
GET /api/contacts/duplicates/by-email Find contacts that share duplicate email addresses #
GET /api/pipelines List all pipelines #
POST /api/pipelines Create a new pipeline #
GET /api/pipelines/automation-logs Get global automation logs across pipelines #
GET /api/pipelines/{id} Get a single pipeline by ID #
PATCH /api/pipelines/{id} Update an existing pipeline #
DELETE /api/pipelines/{id} Delete a pipeline #
POST /api/pipelines/{id}/stages Create a new stage in a pipeline #
PATCH /api/pipelines/{pipelineId}/stages/reorder Reorder pipeline stages #
PATCH /api/pipelines/{pipelineId}/stages/{stageId} Update a pipeline stage #
DELETE /api/pipelines/{pipelineId}/stages/{stageId} Delete a pipeline stage #
GET /api/pipelines/stages/{stageId}/automations List automations attached to a stage #
POST /api/pipelines/stages/{stageId}/automations Create an automation on a stage #
PATCH /api/pipelines/automations/{automationId} Update a stage automation #
DELETE /api/pipelines/automations/{automationId} Delete a stage automation #
GET /api/pipelines/automations/{automationId}/logs Get execution logs for an automation #
GET /api/pipelines/{id}/stats Get stats and conversion metrics for a pipeline #
POST /api/pipelines/{id}/migrate-legacy-stages Migrate legacy denormalized stage JSON into PipelineStage rows #
GET /api/leads List leads with pagination, search, and pipeline/stage filters #
POST /api/leads Create a new lead #
GET /api/leads/stats Get lead statistics, optionally scoped to a pipeline #
GET /api/leads/kanban/{pipelineId} Get the kanban board for a pipeline #
GET /api/leads/kanban/{pipelineId}/stage/{stageId} Load more leads for a single kanban stage #
GET /api/leads/stages/{pipelineId} List stages of a pipeline (for lead filters) #
GET /api/leads/duplicates Find duplicate leads across the workspace (by title/contact/company within a pipeline) #
GET /api/leads/{id} Get a single lead by ID #
PATCH /api/leads/{id} Update an existing lead #
DELETE /api/leads/{id} Soft-delete a lead #
GET /api/leads/{id}/duplicates Check for duplicates of a specific lead #
GET /api/leads/{id}/dossier Get the full dossier (company + contact + activity) for a lead #
GET /api/leads/{id}/interest Get the AI interest classification for a lead #
PATCH /api/leads/{id}/interest Manually set the interest status of a lead #
GET /api/leads/interest/breakdown Get the breakdown of leads by interest status #
GET /api/leads/{id}/deal Get the deal projection (amount/probability/weighted) for a lead #
PATCH /api/leads/{id}/deal Update deal fields (amount/currency/probability/close date) #
GET /api/leads/deal/forecast Compute the weighted-amount forecast across leads in scope #
POST /api/leads/{id}/move Move a lead to a different stage (and optionally pipeline) #
POST /api/leads/bulk Enqueue a bulk action on multiple leads (async) #
GET /api/leads/bulk/{jobId} Get the status of a bulk lead job #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/ldm-v3-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

live-direct-marketing-online-ldm-v3-openapi.json Raw ↑
{"openapi":"3.0.0","paths":{"/api/notifications/push/public-key":{"get":{"operationId":"NotificationsController_pushPublicKey","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get the tenant VAPID public key for Web Push","tags":["Notifications"],"x-required-scope":["notifications:read"]}},"/api/notifications/push/subscribe":{"post":{"operationId":"NotificationsController_pushSubscribe","parameters":[{"name":"user-agent","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscribeDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Register a browser Web Push subscription","tags":["Notifications"],"x-required-scope":["notifications:write"]}},"/api/notifications/push/unsubscribe":{"post":{"operationId":"NotificationsController_pushUnsubscribe","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushUnsubscribeDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Remove a browser Web Push subscription","tags":["Notifications"],"x-required-scope":["notifications:write"]}},"/api/notifications":{"get":{"operationId":"NotificationsController_findAll","parameters":[{"name":"dismissed","required":true,"in":"query","schema":{"type":"string"}},{"name":"type","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"string"}},{"name":"pageSize","required":true,"in":"query","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List notifications for the current user","tags":["Notifications"]}},"/api/notifications/unread-count":{"get":{"operationId":"NotificationsController_unreadCount","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get the unread notifications badge count","tags":["Notifications"],"x-required-scope":["notifications:read"]}},"/api/notifications/read-all":{"post":{"operationId":"NotificationsController_readAll","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Mark all unread notifications as read","tags":["Notifications"],"x-required-scope":["notifications:write"]}},"/api/notifications/{id}/read":{"post":{"operationId":"NotificationsController_markRead","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Mark a notification as read","tags":["Notifications"]}},"/api/notifications/{id}/dismiss":{"post":{"operationId":"NotificationsController_dismiss","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Dismiss a notification (hide from widget)","tags":["Notifications"]}},"/api/notifications/dismiss-all":{"post":{"operationId":"NotificationsController_dismissAll","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Dismiss all notifications for the current user","tags":["Notifications"],"x-required-scope":["notifications:write"]}},"/api/notifications/self-note":{"post":{"operationId":"NotificationsController_createSelfNote","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSelfNoteDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Create an agent self-note notification","tags":["Notifications"],"x-required-scope":["notifications:write"]}},"/api/auth/register":{"post":{"operationId":"AuthController_register","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Register a new account (self-service). Requires termsAccepted=true (user agreement: GET /api/legal/terms). channel=web needs a password; channel=mcp/a2a/form (bootstrap from an AI agent) makes the password optional and returns the key as flat api_key/scope/quota fields (agent signup is rate-limited per IP). Creates User+Tenant with status=PENDING and emails a confirmation link (valid 48h) to the address. After the email is confirmed the account auto-activates — at most 1 auto-activation per hour platform-wide; beyond that it stays PENDING until admin approval (the admin is notified by email at every step). Self-signup workspaces have a 50MB database quota: over quota, POST/PUT/PATCH return 403 while reads and DELETE keep working. The auto-issued ldm_* key has SAFE_AGENT_SCOPES (read-all + safe drafts; no email:send / mailing:write) — mint a wider key in Settings → API Keys after activation.","tags":["Authentication"]}},"/api/auth/verify-email":{"get":{"operationId":"AuthController_verifyEmail","parameters":[{"name":"token","required":true,"in":"query","schema":{"type":"string"}},{"name":"format","required":true,"in":"query","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Confirm email by the token from the signup email. Activates the account automatically (1 auto-activation per hour platform-wide; otherwise it stays PENDING for admin approval). Browsers are redirected to the login page with the result; API clients get JSON when ?format=json.","tags":["Authentication"]}},"/api/auth/signup-questionnaire":{"post":{"operationId":"AuthController_submitQuestionnaire","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupQuestionnaireDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Issue #322 — submit the signup questionnaire for accounts that did not qualify for automatic activation (free mailbox, or the website/MX checks did not line up). Authenticated by the signup_token from the verify-email redirect, not by an API key — the key issued at /auth/register stays inert until the account is ACTIVE. Calling this endpoint runs the automatic checks immediately (does the company domain resolve, does it answer over HTTP, does it match the contact mailbox) and saves the answers plus those results on the tenant record; it does NOT activate the account itself. The admin is emailed and approves the workspace as a separate, manual step (#1189: no ETA endpoint for that step). Until approval the account stays PENDING (read-only, cannot send email). Re-submitting overwrites the previous answers.","tags":["Authentication"]}},"/api/auth/otc":{"post":{"operationId":"AuthController_exchangeOtc","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Exchange the one-time sign-in code from the email-verification redirect for a session (same response as /auth/login). Codes are single-use and expire in 5 minutes.","tags":["Authentication"]}},"/api/auth/login":{"post":{"operationId":"AuthController_login","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Authenticate a user and issue access + refresh tokens. 401 = wrong email/password; 403 = credentials are correct but the account is not ACTIVE yet (email not confirmed / awaiting admin approval / blocked) — the error message says which.","tags":["Authentication"]}},"/api/auth/refresh":{"post":{"operationId":"AuthController_refresh","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Exchange a refresh token for a new access + refresh pair","tags":["Authentication"]}},"/api/auth/logout":{"post":{"operationId":"AuthController_logout","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Revoke a refresh token and end the session","tags":["Authentication"]}},"/api/auth/forgot-password":{"post":{"operationId":"AuthController_forgotPassword","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Request a password reset email (rate-limited per email and per IP)","tags":["Authentication"]}},"/api/auth/reset-password":{"post":{"operationId":"AuthController_resetPassword","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Reset password using a reset token","tags":["Authentication"]}},"/api/auth/profile":{"get":{"operationId":"AuthController_getProfile","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get the current authenticated user profile","tags":["Authentication"]}},"/api/auth/me":{"get":{"operationId":"AuthController_getMe","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get current user profile (alias of /auth/profile)","tags":["Authentication"]}},"/api/auth/change-password":{"post":{"operationId":"AuthController_changePassword","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Change the password of the authenticated user (current required)","tags":["Authentication"]}},"/api/auth/impersonate/{userId}":{"post":{"operationId":"AuthController_impersonate","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Impersonate another user (SUPER role only)","tags":["Authentication"]}},"/api/api-keys":{"get":{"operationId":"ApiKeysController_list","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List tenant API keys (raw key value hidden)","tags":["API Keys (tenant-scoped)"]},"post":{"operationId":"ApiKeysController_create","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Create a new tenant API key. Pass `actAsCurrentUser: true` to bind the key to the calling user (required for compose/reply/forward and other user-context endpoints; sets `ownerUserId`). Optional `scopes` array gates which surfaces the key can hit; default `[\"*\"]`.","tags":["API Keys (tenant-scoped)"]}},"/api/api-keys/whoami":{"get":{"operationId":"ApiKeysController_whoami","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Check that the current Bearer credentials (API key or JWT) are valid, and learn where this key is connected before hitting a wall. No scope required — any authenticated caller passes. Used by the MCP gateway to reject bad keys before building an MCP session, instead of after the first tool call. Beyond the original `{ ok, tenantId, scopes, authMode }`, also returns `baseUrl` (scheme+host the request actually arrived on, honoring x-forwarded-proto/x-forwarded-host behind the nginx edge), `apiPrefix` (the mandatory path prefix, taken from the same constant main.ts uses for setGlobalPrefix), and `closedCapabilityClasses` (LEGACY_CAPABILITIES id-prefix groups where NOT ONE operation is reachable with this key's granted scopes).","tags":["API Keys (tenant-scoped)"]}},"/api/api-keys/{id}/reveal":{"get":{"operationId":"ApiKeysController_reveal","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Reveal the raw value of an existing API key. Only JWT-authenticated (browser) calls are allowed — an ApiKey cannot read another key's secret. Returns { id, name, key }.","tags":["API Keys (tenant-scoped)"]}},"/api/api-keys/scopes/structured":{"get":{"operationId":"ApiKeysController_structuredScopes","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Structured scope catalog for the API Keys UI wizard. Returns presets (AI Agent / Read-only) + grouped scope definitions with descriptions and dangerous-flag. Used by Settings → API Keys to render the scope picker.","tags":["API Keys (tenant-scoped)"],"x-required-scope":["keys:read"]}},"/api/api-keys/{id}":{"patch":{"operationId":"ApiKeysController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Upgrade an existing API key in-place: set/unset Act-as-me. Only JWT-authenticated calls are allowed (an ApiKey cannot upgrade another ApiKey). Key value is NOT changed — downstream clients keep working without re-configuration.","tags":["API Keys (tenant-scoped)"]},"delete":{"operationId":"ApiKeysController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Permanently delete a tenant API key","tags":["API Keys (tenant-scoped)"]}},"/api/api-keys/{id}/revoke":{"delete":{"operationId":"ApiKeysController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Revoke (deactivate) a tenant API key without deleting it","tags":["API Keys (tenant-scoped)"]}},"/api/webhooks":{"get":{"operationId":"WebhooksController_list","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List webhook endpoints","tags":["Webhooks"]},"post":{"operationId":"WebhooksController_create","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Create a webhook endpoint","tags":["Webhooks"]}},"/api/webhooks/{id}":{"patch":{"operationId":"WebhooksController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Update a webhook endpoint","tags":["Webhooks"]},"delete":{"operationId":"WebhooksController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Delete a webhook endpoint","tags":["Webhooks"]}},"/api/webhooks/{id}/deliveries":{"get":{"operationId":"WebhooksController_deliveries","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"status","required":true,"in":"query","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List delivery history for a webhook endpoint","tags":["Webhooks"]}},"/api/webhooks/deliveries/{id}/retry":{"post":{"operationId":"WebhooksController_retry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Retry a single webhook delivery","tags":["Webhooks"]}},"/api/webhooks/{id}/retrigger":{"post":{"operationId":"WebhooksController_retrigger","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Retrigger the last N deliveries for a webhook endpoint","tags":["Webhooks"]}},"/api/users/me/accept-terms":{"post":{"operationId":"UsersController_acceptTerms","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Accept legal terms for the current user","tags":["Users"],"x-required-scope":["users:write"]}},"/api/users":{"get":{"operationId":"UsersController_findAll","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"pageSize","required":true,"in":"query","schema":{"type":"number"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List users (SUPER/MANAGER)","tags":["Users"]},"post":{"operationId":"UsersController_createUser","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Create a user (SUPER only)","tags":["Users"]}},"/api/users/system/stats":{"get":{"operationId":"UsersController_systemStats","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get system stats (SUPER only)","tags":["Users"],"x-required-scope":["users:read"]}},"/api/users/system/kill-process/{pid}":{"post":{"operationId":"UsersController_killProcess","parameters":[{"name":"pid","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Kill a system process by pid (SUPER only)","tags":["Users"]}},"/api/users/system/cleanup-orphans":{"post":{"operationId":"UsersController_cleanupOrphans","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Cleanup orphan system resources (SUPER only)","tags":["Users"],"x-required-scope":["users:write"]}},"/api/users/{id}":{"get":{"operationId":"UsersController_findById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get a user by id (SUPER/MANAGER)","tags":["Users"]},"delete":{"operationId":"UsersController_deleteUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Delete a user with tenant cleanup: sole-member tenants + their DBs are dropped (SUPER only)","tags":["Users"]}},"/api/users/{id}/role":{"patch":{"operationId":"UsersController_updateRole","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleDto"}}}},"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Update a user role (SUPER/MANAGER)","tags":["Users"]}},"/api/users/{id}/status":{"patch":{"operationId":"UsersController_updateStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Update a user status (SUPER/MANAGER)","tags":["Users"]}},"/api/users/{id}/password":{"patch":{"operationId":"UsersController_updatePassword","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePasswordDto"}}}},"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Update a user password (SUPER only)","tags":["Users"]}},"/api/users/{id}/profile":{"patch":{"operationId":"UsersController_updateProfile","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Update a user profile (SUPER only)","tags":["Users"]}},"/api/users/{id}/comments":{"get":{"operationId":"UsersController_listComments","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List admin comments on a user (SUPER/MANAGER)","tags":["Users"]},"post":{"operationId":"UsersController_addComment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCommentDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Add an admin comment on a user (SUPER/MANAGER)","tags":["Users"]}},"/api/users/{id}/comments/{commentId}":{"delete":{"operationId":"UsersController_deleteComment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"commentId","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Delete an admin comment on a user (SUPER only)","tags":["Users"]}},"/api/companies/custom-fields":{"get":{"operationId":"CompanyCustomFieldController_getDefinitions","parameters":[{"name":"entity","required":true,"in":"query","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"List custom field definitions for the given entity (company/contact/lead)","tags":["Companies / Custom Fields"]},"post":{"operationId":"CompanyCustomFieldController_createDefinition","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomFieldDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Create a custom field definition","tags":["Companies / Custom Fields"]}},"/api/companies/custom-fields/reorder":{"put":{"operationId":"CompanyCustomFieldController_reorder","parameters":[{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Reorder custom field definitions by id array","tags":["Companies / Custom Fields"],"x-required-scope":["crm:write"]}},"/api/companies/custom-fields/{companyId}/values":{"get":{"operationId":"CompanyCustomFieldController_getValues","parameters":[{"name":"companyId","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"responses":{"200":{"description":""}},"security":[{"jwt":[]}],"summary":"Get custom field values for a company","tags":["Companies / Custom Fields"]},"post":{"operationId":"CompanyCustomFieldController_setValues","parameters":[{"name":"companyId","required":true,"in":"path","schema":{"type":"string"}},{"name":"X-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Tenant UUID — required for all tenant-scoped endpoints"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetValuesDto"}}}},"responses":{"201":{"description":""}},"security":[{"jwt":[]}],"summary":"Set custom field values for a company","tags":["Companies / Custom Fields"]}},"/api/companies/custom-fields/{id}":{"put":{"operationId":"CompanyCustomFieldController_updateDefinition","parameters":[{"name":"id","required":true,"in":"

# --- truncated at 32 KB (823 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/live-direct-marketing-online/refs/heads/main/openapi/live-direct-marketing-online-ldm-v3-openapi.json