{"protocolVersion":"0.3.0","version":"0.1.0","name":"LDM.delivery","description":"Email delivery API for AI agents. Pay only for delivered inbox messages.","url":"https://api.live-direct-marketing.online/a2a","provider":{"organization":"Live Direct Marketing","url":"https://live-direct-marketing.online"},"capabilities":{"streaming":true,"pushNotifications":true,"stateTransitionHistory":false},"defaultInputModes":["text/plain","application/json"],"defaultOutputModes":["text/plain","application/json"],"skills":[{"id":"notifications.list","name":"List notifications for the current user","description":"List notifications for the current user — GET /api/notifications (scope notifications:read)","tags":["notifications","notifications"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"notifications.self-note","name":"Create an agent self-note notification","description":"Create an agent self-note notification — POST /api/notifications/self-note (scope notifications:write)","tags":["notifications","notifications"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"keys.list","name":"List tenant API keys (raw key value hidden)","description":"List tenant API keys (raw key value hidden) — GET /api/api-keys (scope keys:read)","tags":["keys","keys"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"keys.create","name":"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 `[\"*\"]`.","description":"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 `[\"*\"]`. — POST /api/api-keys (scope keys:write)","tags":["keys","keys"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"me","name":"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).","description":"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). — GET /api/api-keys/whoami","tags":["me"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"keys.revoke","name":"Permanently delete a tenant API key","description":"Permanently delete a tenant API key — DELETE /api/api-keys/{id} (scope keys:write)","tags":["keys","keys"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"webhooks.list","name":"List webhook endpoints","description":"List webhook endpoints — GET /api/webhooks (scope webhooks:read)","tags":["webhooks","webhooks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"webhooks.create","name":"Create a webhook endpoint","description":"Create a webhook endpoint — POST /api/webhooks (scope webhooks:write)","tags":["webhooks","webhooks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"webhooks.deliveries","name":"List delivery history for a webhook endpoint","description":"List delivery history for a webhook endpoint — GET /api/webhooks/{id}/deliveries (scope webhooks:read)","tags":["webhooks","webhooks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"webhooks.retry","name":"Retry a single webhook delivery","description":"Retry a single webhook delivery — POST /api/webhooks/deliveries/{id}/retry (scope webhooks:write)","tags":["webhooks","webhooks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"users.list","name":"List users (SUPER/MANAGER)","description":"List users (SUPER/MANAGER) — GET /api/users (scope users:read)","tags":["users","users"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"users.create","name":"Create a user (SUPER only)","description":"Create a user (SUPER only) — POST /api/users (scope users:write)","tags":["users","users"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"companies.list","name":"List companies with pagination, search, and filters","description":"List companies with pagination, search, and filters — GET /api/companies (scope crm:read)","tags":["companies","crm"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"companies.create","name":"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/channels { type: \"EMAIL\", value } to attach an email channel. Passing `email` in this body returns 400.","description":"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/channels { type: \"EMAIL\", value } to attach an email channel. Passing `email` in this body returns 400. — POST /api/companies (scope crm:write)","tags":["companies","crm"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"companies.delete","name":"Soft-delete a company","description":"Soft-delete a company — DELETE /api/companies/{id} (scope companies:write)","tags":["companies","companies"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"companies.restore","name":"Restore a soft-deleted company","description":"Restore a soft-deleted company — POST /api/companies/{id}/restore (scope companies:write)","tags":["companies","companies"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"companies.import_rollback","name":"Roll back a company import batch by ID","description":"Roll back a company import batch by ID — DELETE /api/companies/import/rollback/{batchId} (scope companies:write)","tags":["companies","companies"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"suppression.list","name":"List suppressed emails","description":"List suppressed emails — GET /api/suppression (scope suppression:read)","tags":["suppression","suppression"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"suppression.add","name":"Add an email to the suppression list","description":"Add an email to the suppression list — POST /api/suppression (scope suppression:write)","tags":["suppression","suppression"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"suppression.check","name":"Check a batch of emails against the suppression list","description":"Check a batch of emails against the suppression list — POST /api/suppression/check (scope suppression:read)","tags":["suppression","suppression"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"suppression.remove","name":"Remove an email from the suppression list","description":"Remove an email from the suppression list — DELETE /api/suppression/{email} (scope suppression:write)","tags":["suppression","suppression"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"stoplist.list","name":"List stop list entries (user scope)","description":"List stop list entries (user scope) — GET /api/stop-lists (scope stoplist:read)","tags":["stoplist","stoplist"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"stoplist.add","name":"Add a stop list entry (user scope)","description":"Add a stop list entry (user scope) — POST /api/stop-lists (scope stoplist:write)","tags":["stoplist","stoplist"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"stoplist.remove","name":"Remove a stop list entry (user scope)","description":"Remove a stop list entry (user scope) — DELETE /api/stop-lists/{id} (scope stoplist:write)","tags":["stoplist","stoplist"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"stoplist.check","name":"Check a batch of emails against the stop list","description":"Check a batch of emails against the stop list — POST /api/stop-lists/check (scope stoplist:read)","tags":["stoplist","stoplist"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"reports.list","name":"List tenant reports (paginated) + storage quota","description":"List tenant reports (paginated) + storage quota — GET /api/reports (scope reports:read)","tags":["reports","reports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"reports.create","name":"Create a report from base64 content (agent/MCP path)","description":"Create a report from base64 content (agent/MCP path) — POST /api/reports (scope reports:write)","tags":["reports","reports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"reports.from_export","name":"Register a completed export job as a report (idempotent)","description":"Register a completed export job as a report (idempotent) — POST /api/reports/from-export/{exportJobId} (scope reports:write)","tags":["reports","reports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"reports.publish","name":"Publish: open a direct public download link (no auth!)","description":"Publish: open a direct public download link (no auth!) — POST /api/reports/{id}/publish (scope reports:write)","tags":["reports","reports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"reports.unpublish","name":"Unpublish: close the public link (token kept — re-publish restores the same url)","description":"Unpublish: close the public link (token kept — re-publish restores the same url) — POST /api/reports/{id}/unpublish (scope reports:write)","tags":["reports","reports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"reports.download","name":"Download the report file (authorized)","description":"Download the report file (authorized) — GET /api/reports/{id}/download (scope reports:read)","tags":["reports","reports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"agent.status","name":"Get the mail agent connection status and stats","description":"Get the mail agent connection status and stats — GET /api/mail-agent/status (scope agent:read)","tags":["agent","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"agent.settings.get","name":"Get current mail agent settings","description":"Get current mail agent settings — GET /api/mail-agent/settings (scope agent:read)","tags":["agent","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"agent.settings.toggle","name":"Toggle the mail agent enabled flag","description":"Toggle the mail agent enabled flag — POST /api/mail-agent/settings (scope agent:write)","tags":["agent","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"agent.token.regenerate","name":"Regenerate the mail agent auth token","description":"Regenerate the mail agent auth token — POST /api/mail-agent/token/regenerate (scope agent:write)","tags":["agent","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"agent.disconnect","name":"Disconnect the mail agent session","description":"Disconnect the mail agent session — POST /api/mail-agent/disconnect (scope agent:write)","tags":["agent","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"ai.generate","name":"Generate AI completion via configured provider","description":"Generate AI completion via configured provider — POST /api/ai/generate (scope ai:write)","tags":["ai","ai"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"ai.providers","name":"List available AI providers with status","description":"List available AI providers with status — GET /api/ai/providers (scope ai:read)","tags":["ai","ai"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"email-verification.verify-batch","name":"Verify a batch of email addresses synchronously","description":"Verify a batch of email addresses synchronously — POST /api/verify/batch (scope email:send)","tags":["email-verification","email"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"customfields.list","name":"List custom field definitions, optionally filtered by entity","description":"List custom field definitions, optionally filtered by entity — GET /api/custom-fields (scope customfields:read)","tags":["customfields","customfields"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"customfields.create","name":"Create a custom field definition","description":"Create a custom field definition — POST /api/custom-fields (scope customfields:write)","tags":["customfields","customfields"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"contacts.list","name":"List contacts with pagination, search, and filters","description":"List contacts with pagination, search, and filters — GET /api/contacts (scope crm:read)","tags":["contacts","crm"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"contacts.create","name":"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/channels { type: \"EMAIL\" | \"PHONE\", value }. Passing `email`/`phone` in this body returns 400.","description":"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/channels { type: \"EMAIL\" | \"PHONE\", value }. Passing `email`/`phone` in this body returns 400. — POST /api/contacts (scope crm:write)","tags":["contacts","crm"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"contacts.delete","name":"Soft-delete a contact","description":"Soft-delete a contact — DELETE /api/contacts/{id} (scope contacts:write)","tags":["contacts","contacts"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"contacts.restore","name":"Restore a soft-deleted contact","description":"Restore a soft-deleted contact — POST /api/contacts/{id}/restore (scope contacts:write)","tags":["contacts","contacts"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"contacts.import_rollback","name":"Roll back a contact import batch by ID","description":"Roll back a contact import batch by ID — DELETE /api/contacts/import/rollback/{batchId} (scope contacts:write)","tags":["contacts","contacts"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"pipelines.list","name":"List all pipelines","description":"List all pipelines — GET /api/pipelines (scope pipelines:read)","tags":["pipelines","pipelines"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"pipelines.create","name":"Create a new pipeline","description":"Create a new pipeline — POST /api/pipelines (scope pipelines:write)","tags":["pipelines","pipelines"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.list","name":"List leads with pagination, search, and pipeline/stage filters","description":"List leads with pagination, search, and pipeline/stage filters — GET /api/leads (scope leads:read)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.create","name":"Create a new lead","description":"Create a new lead — POST /api/leads (scope leads:write)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.stats","name":"Get lead statistics, optionally scoped to a pipeline","description":"Get lead statistics, optionally scoped to a pipeline — GET /api/leads/stats (scope leads:read)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.kanban","name":"Get the kanban board for a pipeline","description":"Get the kanban board for a pipeline — GET /api/leads/kanban/{pipelineId} (scope leads:read)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.update","name":"Update an existing lead","description":"Update an existing lead — PATCH /api/leads/{id} (scope leads:write)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.move","name":"Move a lead to a different stage (and optionally pipeline)","description":"Move a lead to a different stage (and optionally pipeline) — POST /api/leads/{id}/move (scope leads:write)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.export","name":"Export leads to a downloadable file","description":"Export leads to a downloadable file — POST /api/leads/export (scope leads:write)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"leads.import","name":"Start a leads import job","description":"Start a leads import job — POST /api/leads/import/start (scope leads:write)","tags":["leads","leads"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tags.list","name":"List all tags in the workspace","description":"List all tags in the workspace — GET /api/tags (scope tags:read)","tags":["tags","tags"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tags.create","name":"Create a new tag","description":"Create a new tag — POST /api/tags (scope tags:write)","tags":["tags","tags"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"contact-lists.list","name":"List all contact lists for the tenant","description":"List all contact lists for the tenant — GET /api/contact-lists (scope crm:read)","tags":["contact-lists","crm"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"company-lists.list","name":"List all company lists for the tenant","description":"List all company lists for the tenant — GET /api/company-lists (scope crm:read)","tags":["company-lists","crm"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"settings.get","name":"Get the full workspace settings document","description":"Get the full workspace settings document — GET /api/settings (scope settings:read)","tags":["settings","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"settings.update","name":"Update workspace metadata (name, currency, language)","description":"Update workspace metadata (name, currency, language) — PATCH /api/settings/workspace (scope settings:write)","tags":["settings","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.bo_nalog_get","name":"Get bo.nalog.gov.ru integration state: enabled, our rate limit, requests today, last error","description":"Get bo.nalog.gov.ru integration state: enabled, our rate limit, requests today, last error — GET /api/settings/integrations/bo-nalog (scope settings:read)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.bo_nalog_update","name":"Update bo.nalog.gov.ru integration: enable/disable, requests-per-minute cap","description":"Update bo.nalog.gov.ru integration: enable/disable, requests-per-minute cap — PATCH /api/settings/integrations/bo-nalog (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.dadata_get","name":"Get DaData integration configuration","description":"Get DaData integration configuration — GET /api/settings/integrations/dadata (scope settings:read)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.dadata_update","name":"Update DaData integration configuration","description":"Update DaData integration configuration — PATCH /api/settings/integrations/dadata (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.dadata_reset_counter","name":"Reset the DaData daily request counter","description":"Reset the DaData daily request counter — POST /api/settings/integrations/dadata/reset-counter (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.inbox_check_get","name":"Get Inbox Check integration configuration","description":"Get Inbox Check integration configuration — GET /api/settings/integrations/inbox-check (scope settings:read)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.inbox_check_update","name":"Update Inbox Check integration configuration","description":"Update Inbox Check integration configuration — PATCH /api/settings/integrations/inbox-check (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.inbox_check_test","name":"Test the Inbox Check connection","description":"Test the Inbox Check connection — POST /api/settings/integrations/inbox-check/test (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.smartlead_get","name":"Get Smartlead integration configuration","description":"Get Smartlead integration configuration — GET /api/settings/integrations/smartlead (scope settings:read)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.smartlead_update","name":"Update Smartlead integration configuration","description":"Update Smartlead integration configuration — PATCH /api/settings/integrations/smartlead (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.smartlead_test","name":"Test the Smartlead connection","description":"Test the Smartlead connection — POST /api/settings/integrations/smartlead/test (scope settings:write)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.smartlead_placement_matrix","name":"Smartlead placement matrix — mailbox × provider (#1040)","description":"Smartlead placement matrix — mailbox × provider (#1040) — GET /api/settings/integrations/smartlead/placement-matrix (scope settings:read)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"integrations.smartlead_placement_history","name":"Smartlead placement history for one mailbox × provider cell (#1040)","description":"Smartlead placement history for one mailbox × provider cell (#1040) — GET /api/settings/integrations/smartlead/placement-history (scope settings:read)","tags":["integrations","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"dialogs.list","name":"List dialogs with filters (channel, status, folder, etc.)","description":"List dialogs with filters (channel, status, folder, etc.) — GET /api/dialogs (scope dialogs:read)","tags":["dialogs","dialogs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"dialogs.outbox_history","name":"Read safe, paginated history for one durable outbox task","description":"Read safe, paginated history for one durable outbox task — GET /api/dialogs/outbox/{id}/history (scope dialogs:read)","tags":["dialogs","dialogs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"messages.get","name":"Get a single dialog by ID","description":"Get a single dialog by ID — GET /api/dialogs/{id} (scope dialogs:read)","tags":["messages","dialogs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"dialogs.reply","name":"Reply to a dialog (optionally send via SMTP with attachments). Attachments can be passed inline as `attachmentsJson: [{ filename, contentBase64, contentType }]` (base64-encoded, JSON body) or as multipart files. (#175 — parity with /compose)","description":"Reply to a dialog (optionally send via SMTP with attachments). Attachments can be passed inline as `attachmentsJson: [{ filename, contentBase64, contentType }]` (base64-encoded, JSON body) or as multipart files. (#175 — parity with /compose) — POST /api/dialogs/{id}/reply (scope dialogs:write)","tags":["dialogs","dialogs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"dialogs.compose","name":"Compose and send a new outbound email. Provide exactly one sender binding: `accountId` (a fixed relay) OR `accountListId` (a virtual-relay pool — the live relay is chosen from the pool at dispatch time, #40). Attachments are inline only: `attachmentsJson: [{ filename, contentBase64, contentType }]` (base64-encoded). No multipart upload on this endpoint — use `:id/reply` or `:id/forward` for that. (#3 Block 3 — inline attachments)","description":"Compose and send a new outbound email. Provide exactly one sender binding: `accountId` (a fixed relay) OR `accountListId` (a virtual-relay pool — the live relay is chosen from the pool at dispatch time, #40). Attachments are inline only: `attachmentsJson: [{ filename, contentBase64, contentType }]` (base64-encoded). No multipart upload on this endpoint — use `:id/reply` or `:id/forward` for that. (#3 Block 3 — inline attachments) — POST /api/dialogs/compose (scope dialogs:write)","tags":["dialogs","dialogs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"user-settings.get","name":"Get current user settings","description":"Get current user settings — GET /api/user-settings (scope settings:read)","tags":["user-settings","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"mailing.overview","name":"Get a global overview of all mailing campaigns (admin dashboard) — merges legacy mailing tasks AND the campaign conveyor (#539); each row is tagged source: legacy | campaign","description":"Get a global overview of all mailing campaigns (admin dashboard) — merges legacy mailing tasks AND the campaign conveyor (#539); each row is tagged source: legacy | campaign — GET /api/mailing/overview (scope mailing:read)","tags":["mailing","mailing"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"mailing.pending","name":"List campaigns awaiting admin approval (cross-tenant for SUPER)","description":"List campaigns awaiting admin approval (cross-tenant for SUPER) — GET /api/mailing/pending-approvals (scope mailing:read)","tags":["mailing","mailing"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"mailing.approve","name":"Approve a pending mailing campaign (admin)","description":"Approve a pending mailing campaign (admin) — POST /api/mailing/{taskId}/approve (scope mailing:write)","tags":["mailing","mailing"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.browser-queue","name":"Get browser queue stats and fair-share view","description":"Get browser queue stats and fair-share view — GET /api/admin/browser-queue (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.browser-queue.pause","name":"Pause the browser queue","description":"Pause the browser queue — POST /api/admin/browser-queue/pause (scope admin:write)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.images.import","name":"Import images from a source attachment into tenant storage","description":"Import images from a source attachment into tenant storage — POST /api/files/images/import (scope files:write)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.upload","name":"Upload an image for creatives (max 5 MB)","description":"Upload an image for creatives (max 5 MB) — POST /api/files/upload (scope files:write)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.images","name":"List uploaded creative images for the tenant","description":"List uploaded creative images for the tenant — GET /api/files/images (scope files:read)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.delete_image","name":"Delete a tenant-scoped creative image","description":"Delete a tenant-scoped creative image — DELETE /api/files/images/{filename} (scope files:write)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.assets","name":"List tenant assets","description":"List tenant assets — GET /api/files/assets (scope files:read)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.delete_asset","name":"Delete a tenant asset","description":"Delete a tenant asset — DELETE /api/files/assets/{filename} (scope files:write)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.list","name":"List file attachments for a contact, company or lead","description":"List file attachments for a contact, company or lead — GET /api/files (scope files:read)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"files.delete","name":"Delete a file attachment record","description":"Delete a file attachment record — DELETE /api/files/{id} (scope files:write)","tags":["files","files"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.list","name":"List tasks with pagination and status/method filters","description":"List tasks with pagination and status/method filters — GET /api/tasks (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.create","name":"Create a task. SITE SCORING (lead gen): methodId=22 + methodName=\"scoring\" + companyListId (items are populated from the company list on start) → POST /tasks/:id/steps (SITE_AVAILABILITY, then AI_CONTENT) → POST /tasks/:id/start. Other methodId values: 11=email validation, 14=ICP review, 15=DIG, 12=mailing (legacy — prefer /campaigns).","description":"Create a task. SITE SCORING (lead gen): methodId=22 + methodName=\"scoring\" + companyListId (items are populated from the company list on start) → POST /tasks/:id/steps (SITE_AVAILABILITY, then AI_CONTENT) → POST /tasks/:id/start. Other methodId values: 11=email validation, 14=ICP review, 15=DIG, 12=mailing (legacy — prefer /campaigns). — POST /api/tasks (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.delete","name":"Delete a task","description":"Delete a task — DELETE /api/tasks/{id} (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.errors","name":"List errors encountered during a task run","description":"List errors encountered during a task run — GET /api/tasks/{id}/errors (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.start","name":"Start (or resume) a task. If items are empty, they are populated from the task's contactListId/companyListId. Progress: GET /tasks/:id (processedItems/totalItems); for scoring: GET /tasks/:id/scoring-stats and /tasks/:id/scoring-results?status=ACTIVE (score, companyType, contacts found on the site).","description":"Start (or resume) a task. If items are empty, they are populated from the task's contactListId/companyListId. Progress: GET /tasks/:id (processedItems/totalItems); for scoring: GET /tasks/:id/scoring-stats and /tasks/:id/scoring-results?status=ACTIVE (score, companyType, contacts found on the site). — POST /api/tasks/{id}/start (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.steps.list","name":"List pipeline steps configured on a task","description":"List pipeline steps configured on a task — GET /api/tasks/{id}/steps (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.steps.add","name":"Add a pipeline step to a task. Types: SITE_AVAILABILITY, AI_CONTENT, KEYWORDS, EMAIL_EXTRACT, PHONE_EXTRACT, SOCIAL_LINKS, TECH_DETECT, GEO_FILTER, NALOG_LOOKUP, AI_CARD_FIELD, and others. For AI_CONTENT: config.messages=[{role:system,...},{role:user,...}] with placeholders {-Variable.page_text-}/{-Variable.domain-}, config.min_score (success when score>=min_score). For AI_CARD_FIELD (#1035, requires item.contactId; or item.companyId when config.targetEntity=COMPANY — a company with no single contact is covered too): config.promptTemplate with the resolver's canonical variables ({{firstName}}, {company.name}, ccf_...), config.targetEntity=CONTACT|COMPANY|LEAD (LEAD requires item.contactId — TaskItem does not store leadId, the target becomes that contact's single lead; 0 leads → no_lead, more than one → ambiguous_lead, the step does not guess), config.targetFieldId=id of an existing CustomFieldDefinition, config.fallback — writes the result to that custom field WITHOUT hitting the site; a repeat on an already-computed entity×field pair does not invoke AI again (dedup by non-empty field value). Routing: onSuccess/onFail/onError = CONTINUE|STOP|MOVE_TO_LIST (+onSuccessTarget=list id)|DELETE. Typical scoring: step 1 SITE_AVAILABILITY (onFail=STOP), step 2 AI_CONTENT (onSuccess=MOVE_TO_LIST into the target list).","description":"Add a pipeline step to a task. Types: SITE_AVAILABILITY, AI_CONTENT, KEYWORDS, EMAIL_EXTRACT, PHONE_EXTRACT, SOCIAL_LINKS, TECH_DETECT, GEO_FILTER, NALOG_LOOKUP, AI_CARD_FIELD, and others. For AI_CONTENT: config.messages=[{role:system,...},{role:user,...}] with placeholders {-Variable.page_text-}/{-Variable.domain-}, config.min_score (success when score>=min_score). For AI_CARD_FIELD (#1035, requires item.contactId; or item.companyId when config.targetEntity=COMPANY — a company with no single contact is covered too): config.promptTemplate with the resolver's canonical variables ({{firstName}}, {company.name}, ccf_...), config.targetEntity=CONTACT|COMPANY|LEAD (LEAD requires item.contactId — TaskItem does not store leadId, the target becomes that contact's single lead; 0 leads → no_lead, more than one → ambiguous_lead, the step does not guess), config.targetFieldId=id of an existing CustomFieldDefinition, config.fallback — writes the result to that custom field WITHOUT hitting the site; a repeat on an already-computed entity×field pair does not invoke AI again (dedup by non-empty field value). Routing: onSuccess/onFail/onError = CONTINUE|STOP|MOVE_TO_LIST (+onSuccessTarget=list id)|DELETE. Typical scoring: step 1 SITE_AVAILABILITY (onFail=STOP), step 2 AI_CONTENT (onSuccess=MOVE_TO_LIST into the target list). — POST /api/tasks/{id}/steps (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.steps.reorder","name":"Reorder pipeline steps in a task","description":"Reorder pipeline steps in a task — PUT /api/tasks/{id}/steps/reorder (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.steps.update","name":"Update a single pipeline step","description":"Update a single pipeline step — PATCH /api/tasks/{id}/steps/{stepId} (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.steps.remove","name":"Delete a pipeline step from a task","description":"Delete a pipeline step from a task — DELETE /api/tasks/{id}/steps/{stepId} (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.scoring-results","name":"List scoring results for a task with pagination. contradictory=true narrows to results whose stepResults carry a contradiction flag (data.contradictoryFields non-empty on any step) — same detection as POST :id/scoring-results/retry contradictoryOnly (#1113).","description":"List scoring results for a task with pagination. contradictory=true narrows to results whose stepResults carry a contradiction flag (data.contradictoryFields non-empty on any step) — same detection as POST :id/scoring-results/retry contradictoryOnly (#1113). — GET /api/tasks/{id}/scoring-results (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.scoring-stats","name":"Get aggregate scoring statistics for a task","description":"Get aggregate scoring statistics for a task — GET /api/tasks/{id}/scoring-stats (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.scoring-step-events","name":"#975: paginated step journal for a single scoring card (requested/success/fail/error/interrupted/resumed_after_restart, seq by time)","description":"#975: paginated step journal for a single scoring card (requested/success/fail/error/interrupted/resumed_after_restart, seq by time) — GET /api/tasks/{id}/scoring-results/{resultId}/events (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.cron.get","name":"Get the cron scheduling settings for a task","description":"Get the cron scheduling settings for a task — GET /api/tasks/{id}/cron (scope tasks:read)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.cron.update","name":"Update the cron scheduling settings for a task","description":"Update the cron scheduling settings for a task — PATCH /api/tasks/{id}/cron (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"tasks.cron.trigger","name":"Manually trigger a task cron run","description":"Manually trigger a task cron run — POST /api/tasks/{id}/cron/trigger (scope tasks:write)","tags":["tasks","tasks"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.list","name":"List creatives with pagination and search","description":"List creatives with pagination and search — GET /api/creatives (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.create","name":"Create a new creative","description":"Create a new creative — POST /api/creatives (scope creatives:write)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.pdf-status","name":"Get the PDF generation queue status","description":"Get the PDF generation queue status — GET /api/creatives/pdf-status (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.variables.available","name":"List available template variables","description":"List available template variables — GET /api/creatives/variables/available (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.get","name":"Get a single creative by ID","description":"Get a single creative by ID — GET /api/creatives/{id} (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.update","name":"Update a creative","description":"Update a creative — PATCH /api/creatives/{id} (scope creatives:write)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.brief-intake","name":"Canonical brief intake email and localized help for customer materials linked to this creative","description":"Canonical brief intake email and localized help for customer materials linked to this creative — GET /api/creatives/{id}/brief-intake (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.preview","name":"Render a preview of a creative for a sample contact","description":"Render a preview of a creative for a sample contact — POST /api/creatives/{id}/preview (scope creatives:write)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.variables","name":"Get template variables used in a creative","description":"Get template variables used in a creative — GET /api/creatives/{id}/variables (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.test-sends","name":"List test sends of a creative","description":"List test sends of a creative — GET /api/creatives/{id}/test-sends (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.test-send","name":"Send a test copy of this creative. sender=\"account\" (default, unchanged behaviour) needs a connected email account: pass accountId AND toEmail. sender=\"platform\" needs NO connected account and NO toEmail at all — omit toEmail and it sends from the LDM platform mailbox (same transport as signup email) straight to the address the TENANT OWNER registered with; this is the intended zero-config call. If you DO pass toEmail with sender=\"platform\" it must equal that same registration address exactly or the call is refused (not an open relay, #801) — passing any other address never sends anywhere else, it just fails closed. Use \"platform\" the moment a creative exists, before any mailbox is connected, to see the rendered email + attachment land for real. Rate-limited to 5 platform sends/hour per tenant. The response carries a disclaimer: placement via the platform mailbox says NOTHING about the client's own sending domain reputation — it only proves the creative renders and the attachment attaches; re-test with sender=\"account\" before trusting placement for a real campaign. Zero connected accounts AND no sender given → the 400 body lists BOTH ways forward (connect one, or use sender=\"platform\" with no toEmail).","description":"Send a test copy of this creative. sender=\"account\" (default, unchanged behaviour) needs a connected email account: pass accountId AND toEmail. sender=\"platform\" needs NO connected account and NO toEmail at all — omit toEmail and it sends from the LDM platform mailbox (same transport as signup email) straight to the address the TENANT OWNER registered with; this is the intended zero-config call. If you DO pass toEmail with sender=\"platform\" it must equal that same registration address exactly or the call is refused (not an open relay, #801) — passing any other address never sends anywhere else, it just fails closed. Use \"platform\" the moment a creative exists, before any mailbox is connected, to see the rendered email + attachment land for real. Rate-limited to 5 platform sends/hour per tenant. The response carries a disclaimer: placement via the platform mailbox says NOTHING about the client's own sending domain reputation — it only proves the creative renders and the attachment attaches; re-test with sender=\"account\" before trusting placement for a real campaign. Zero connected accounts AND no sender given → the 400 body lists BOTH ways forward (connect one, or use sender=\"platform\" with no toEmail). — POST /api/creatives/{id}/test-send (scope creatives:write)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.pdf-generations.get","name":"Get the status of an asynchronous PDF generation","description":"Get the status of an asynchronous PDF generation — GET /api/creatives/{id}/pdf-generations/{generationId} (scope creatives:read)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"creatives.generate-pdf","name":"Generate a PDF from a creative","description":"Generate a PDF from a creative — POST /api/creatives/{id}/generate-pdf (scope creatives:write)","tags":["creatives","creatives"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.intake","name":"Existing Brief intake address by briefId/briefUrl; omit both only before a Brief exists for workspace unassigned intake (#755)","description":"Existing Brief intake address by briefId/briefUrl; omit both only before a Brief exists for workspace unassigned intake (#755) — GET /api/briefs/intake (scope briefs:read)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.intake.items.list","name":"List system intake messages for MCP/UI (#750)","description":"List system intake messages for MCP/UI (#750) — GET /api/briefs/intake/items (scope briefs:read)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.intake.items.get","name":"Read one lossless system intake item with provenance, attachments and work log (#750)","description":"Read one lossless system intake item with provenance, attachments and work log (#750) — GET /api/briefs/intake/items/{itemId} (scope briefs:read)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.intake.items.transition","name":"Transition an intake item to IN_REVIEW, IGNORED or REJECTED with an audited reason (#750)","description":"Transition an intake item to IN_REVIEW, IGNORED or REJECTED with an audited reason (#750) — PATCH /api/briefs/intake/items/{itemId}/status (scope briefs:write)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.intake.items.link","name":"Link an intake item/files to a Brief idempotently (#750)","description":"Link an intake item/files to a Brief idempotently (#750) — POST /api/briefs/intake/items/{itemId}/link (scope briefs:write)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.intake.items.log","name":"Append an agent work-log event with intake provenance (#750)","description":"Append an agent work-log event with intake provenance (#750) — POST /api/briefs/intake/items/{itemId}/log (scope briefs:write)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.list","name":"List briefs with pagination, search and active/deleted filters","description":"List briefs with pagination, search and active/deleted filters — GET /api/briefs (scope briefs:read)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.create","name":"Create a new brief","description":"Create a new brief — POST /api/briefs (scope briefs:write)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.attachment.content","name":"Read one Brief attachment as bounded source-backed text/structure/image pages; imageRef yields a real MCP image block (#768)","description":"Read one Brief attachment as bounded source-backed text/structure/image pages; imageRef yields a real MCP image block (#768) — GET /api/briefs/{id}/attachments/content (scope briefs:read)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.update-content","name":"Update brief content body (JSON-merge patch). personas[]/examples[] merge by item id when every item has a stable id -- give a NEW item a UUID id and keep reusing it, or the whole array is replaced (legacy behavior, unsafe under concurrent edits, #782); customFields[] has no id yet and always replaces whole","description":"Update brief content body (JSON-merge patch). personas[]/examples[] merge by item id when every item has a stable id -- give a NEW item a UUID id and keep reusing it, or the whole array is replaced (legacy behavior, unsafe under concurrent edits, #782); customFields[] has no id yet and always replaces whole — PATCH /api/briefs/{id}/content (scope briefs:write)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"briefs.expert","name":"Operation-level SDR expert flow: intake provenance → live schema → gaps → recommendations → save/validate","description":"Operation-level SDR expert flow: intake provenance → live schema → gaps → recommendations → save/validate — GET /api/briefs/{id}/expert (scope briefs:read)","tags":["briefs","briefs"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"names.decline","name":"Decline a Russian full name (FIO) by grammatical case","description":"Decline a Russian full name (FIO) by grammatical case — POST /api/names/decline (scope utils:read)","tags":["names","utils"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"accounts.list","name":"List email accounts with filters and pagination","description":"List email accounts with filters and pagination — GET /api/email-accounts (scope accounts:read)","tags":["accounts","accounts"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"accounts.create","name":"Create a new email account. Lookup is advisory and client-invoked: POST does not auto-detect transport. Call GET /email-accounts/lookup first for the email address, then pass the returned SMTP/IMAP/service fields explicitly. Override host/port/credentials for custom domains. The legacy `provider` field is normalized to the `service` enum (no separate column).","description":"Create a new email account. Lookup is advisory and client-invoked: POST does not auto-detect transport. Call GET /email-accounts/lookup first for the email address, then pass the returned SMTP/IMAP/service fields explicitly. Override host/port/credentials for custom domains. The legacy `provider` field is normalized to the `service` enum (no separate column). — POST /api/email-accounts (scope accounts:write)","tags":["accounts","accounts"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"imap.stats","name":"Get IMAP orchestrator dashboard stats","description":"Get IMAP orchestrator dashboard stats — GET /api/imap-orchestrator/stats (scope imap:read)","tags":["imap","imap"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"imap.sync-health","name":"Get lossless mail sync cursor, staging and quarantine health","description":"Get lossless mail sync cursor, staging and quarantine health — GET /api/imap-orchestrator/sync-health (scope imap:read)","tags":["imap","imap"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"imap.retry-staged","name":"Retry a failed durable inbound message, or force a re-fetch of an exhausted quarantine row","description":"Retry a failed durable inbound message, or force a re-fetch of an exhausted quarantine row — POST /api/imap-orchestrator/sync-health/{id}/retry (scope imap:write)","tags":["imap","imap"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"imap.heal","name":"Auto-heal stuck GAS accounts and IMAP locks for the current tenant","description":"Auto-heal stuck GAS accounts and IMAP locks for the current tenant — POST /api/imap-orchestrator/heal (scope imap:write)","tags":["imap","imap"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"imap.fetch-all","name":"Trigger an IMAP fetch for every active account in the tenant","description":"Trigger an IMAP fetch for every active account in the tenant — POST /api/imap-orchestrator/fetch-all (scope imap:write)","tags":["imap","imap"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"imap.tech-log","name":"Get the latest N IMAP job log entries for monitoring","description":"Get the latest N IMAP job log entries for monitoring — GET /api/imap-orchestrator/tech-log (scope imap:read)","tags":["imap","imap"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"inbound-rules.list","name":"List all inbound rules","description":"List all inbound rules — GET /api/inbound-rules (scope rules:read)","tags":["inbound-rules","rules"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"inbound-rules.create","name":"Create a new inbound rule","description":"Create a new inbound rule — POST /api/inbound-rules (scope rules:write)","tags":["inbound-rules","rules"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linker.relink","name":"Manually re-run linker for a specific dialog","description":"Manually re-run linker for a specific dialog — POST /api/dialog-linker/relink/{dialogId} (scope linker:write)","tags":["linker","linker"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linker.stats","name":"Get linker statistics by status","description":"Get linker statistics by status — GET /api/dialog-linker/stats (scope linker:read)","tags":["linker","linker"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linker.logs","name":"Get all linker logs (admin tech log)","description":"Get all linker logs (admin tech log) — GET /api/dialog-linker/logs (scope linker:read)","tags":["linker","linker"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"views.list","name":"List saved views for an entity for the current user","description":"List saved views for an entity for the current user — GET /api/saved-views (scope views:read)","tags":["views","views"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"views.create","name":"Create a saved view","description":"Create a saved view — POST /api/saved-views (scope views:write)","tags":["views","views"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"activities.list","name":"List activities filtered by lead/contact/company/type","description":"List activities filtered by lead/contact/company/type — GET /api/activities (scope activities:read)","tags":["activities","activities"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"activities.create","name":"Create an activity (call/task/note) linked to a lead/contact/company","description":"Create an activity (call/task/note) linked to a lead/contact/company — POST /api/activities (scope activities:write)","tags":["activities","activities"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.queues","name":"Get stats for all BullMQ queues","description":"Get stats for all BullMQ queues — GET /api/admin/queues (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.queue.pause","name":"Pause a BullMQ queue","description":"Pause a BullMQ queue — POST /api/admin/queues/{name}/pause (scope admin:write)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.tenants","name":"List all tenants with metadata","description":"List all tenants with metadata — GET /api/admin/tenants (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.tenant.ldm-ai","name":"Toggle LDM AI for a tenant","description":"Toggle LDM AI for a tenant — PATCH /api/admin/tenants/{dbName}/ldm-ai (scope admin:write)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.tenant.transport","name":"Update mail transport config for a tenant","description":"Update mail transport config for a tenant — PATCH /api/admin/tenants/{dbName}/transport (scope admin:write)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.i18n","name":"Get i18n translations bundle","description":"Get i18n translations bundle — GET /api/admin/i18n (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.memory.list","name":"List memory files","description":"List memory files — GET /api/admin/memory (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.security.overview","name":"Get security overview dashboard","description":"Get security overview dashboard — GET /api/admin/security/overview (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.test_task.create","name":"campaigns test task create","description":"POST /api/campaigns/{id}/test-task (scope campaigns:write)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.test_task.status","name":"campaigns test task status","description":"GET /api/campaigns/{id}/test-task/{taskId} (scope campaigns:read)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.operational_status","name":"Single source of truth for \"what is happening with this campaign right now\". Returns lifecycleStatus (DRAFT|ACTIVE|PAUSED|DONE|ERROR|AUDIT_BLOCKED) SEPARATELY from operationalState (RUNNING|WAITING|DEGRADED|BLOCKED|COMPLETED): an ACTIVE campaign that sends nothing is the exact defect this endpoint exists for, so never report \"active\" without the operational qualifier. primaryBlocker is picked by a documented priority table and carries code, since, retryAt, recoverable, suggestedAction and docsKey; `legitimateWait` marks a normal wait (closed send window, future schedule) rather than a stop. `lastProgressAt` is the last REAL hand-off to transport, not the last campaign event. `nextActions[]` lists machine-readable moves — the endpoint never promises to fix anything by itself. UI, notifications and MCP all read this same computation; send-readiness returns the same state plus the full gate dump.","description":"Single source of truth for \"what is happening with this campaign right now\". Returns lifecycleStatus (DRAFT|ACTIVE|PAUSED|DONE|ERROR|AUDIT_BLOCKED) SEPARATELY from operationalState (RUNNING|WAITING|DEGRADED|BLOCKED|COMPLETED): an ACTIVE campaign that sends nothing is the exact defect this endpoint exists for, so never report \"active\" without the operational qualifier. primaryBlocker is picked by a documented priority table and carries code, since, retryAt, recoverable, suggestedAction and docsKey; `legitimateWait` marks a normal wait (closed send window, future schedule) rather than a stop. `lastProgressAt` is the last REAL hand-off to transport, not the last campaign event. `nextActions[]` lists machine-readable moves — the endpoint never promises to fix anything by itself. UI, notifications and MCP all read this same computation; send-readiness returns the same state plus the full gate dump. — GET /api/campaigns/{id}/operational-status (scope campaigns:read)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.task_history","name":"Paginated durable delivery-task history for a campaign","description":"Paginated durable delivery-task history for a campaign — GET /api/campaigns/{id}/task-history (scope campaigns:read)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.submit_rendered_emails","name":"Submit self-rendered (BYOC) email content for SCREENED recipients: [{recipientId, subject, bodyHtml, bodyText?}], batch <=100, bodyHtml <=256KB. Submission is free; the content goes through a mandatory paid audit (audit/audit_failed operations), rejection reasons are coarse categories in auditCategories. Limit of 5 audit iterations per recipient; the campaign is blocked (AUDIT_BLOCKED) on systematic rejections.","description":"Submit self-rendered (BYOC) email content for SCREENED recipients: [{recipientId, subject, bodyHtml, bodyText?}], batch <=100, bodyHtml <=256KB. Submission is free; the content goes through a mandatory paid audit (audit/audit_failed operations), rejection reasons are coarse categories in auditCategories. Limit of 5 audit iterations per recipient; the campaign is blocked (AUDIT_BLOCKED) on systematic rejections. — POST /api/campaigns/{id}/recipients/content (scope campaigns:write)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.preparations.start","name":"Start or join a durable bounded preparation operation (no sending). Poll statusUrl; accepted means queued, not completed. Preferred over synchronous prepare for AI and personal PDFs.","description":"Start or join a durable bounded preparation operation (no sending). Poll statusUrl; accepted means queued, not completed. Preferred over synchronous prepare for AI and personal PDFs. — POST /api/campaigns/{id}/preparations (scope campaigns:write)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"campaigns.preparations.status","name":"Read a tenant-bound preparation operation. Completed result has the same fields as prepare; failed contains a safe error code/message. This endpoint never sends.","description":"Read a tenant-bound preparation operation. Completed result has the same fields as prepare; failed contains a safe error code/message. This endpoint never sends. — GET /api/campaigns/{id}/preparations/{generationId} (scope campaigns:read)","tags":["campaigns","campaigns"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"best-send-time.calc","name":"Resolve recommended send time without scheduling; AI fallback uses normal usage logging and billing","description":"Resolve recommended send time without scheduling; AI fallback uses normal usage logging and billing — POST /api/best-send-time (scope mailing:read)","tags":["best-send-time","mailing"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"resume","name":"Resume snapshot (read-only): tenant context core, own recent notifications and self-notes, plus an honest next_step","description":"Resume snapshot (read-only): tenant context core, own recent notifications and self-notes, plus an honest next_step — GET /api/v1/agent-guide/resume (scope agent:read)","tags":["resume","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.detect-forms","name":"#968 detect forms on a page from HTML: hasForm — whether any form is present at all; hasContactForm — a CONTACT-US form (excluding search/login/subscribe/catalog filter); forms[] — submit address (absolute if pageUrl is supplied), method, kind (contact|search|login|subscribe|catalog_filter|other), confidence (0..1), and reasons[] — a human-readable basis for the decision.","description":"#968 detect forms on a page from HTML: hasForm — whether any form is present at all; hasContactForm — a CONTACT-US form (excluding search/login/subscribe/catalog filter); forms[] — submit address (absolute if pageUrl is supplied), method, kind (contact|search|login|subscribe|catalog_filter|other), confidence (0..1), and reasons[] — a human-readable basis for the decision. — POST /api/site-enrichment/detect-forms (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.create","name":"#903/#889 enqueue the canonical site-crawl task (durable, DB is the source of truth)","description":"#903/#889 enqueue the canonical site-crawl task (durable, DB is the source of truth) — POST /api/site-enrichment/tasks (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.list","name":"#953 list of site-crawl tasks: both linked to a scoring task (scoringTaskId) and unlinked (owned=false — e.g. launched via MCP without a task)","description":"#953 list of site-crawl tasks: both linked to a scoring task (scoringTaskId) and unlinked (owned=false — e.g. launched via MCP without a task) — GET /api/site-enrichment/tasks (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.preview","name":"#955 preview list coverage WITHOUT starting a crawl: how many cards are in the list, how many have the domain field filled, how many unique domains among them — plus coverage of ALL eligible fields at once (website/domain/URL custom fields)","description":"#955 preview list coverage WITHOUT starting a crawl: how many cards are in the list, how many have the domain field filled, how many unique domains among them — plus coverage of ALL eligible fields at once (website/domain/URL custom fields) — GET /api/site-enrichment/tasks/preview (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.get","name":"Status/counters of a site-crawl task","description":"Status/counters of a site-crawl task — GET /api/site-enrichment/tasks/{id} (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.events","name":"#903 task transition log, read from the DB, cursor=last received seq","description":"#903 task transition log, read from the DB, cursor=last received seq — GET /api/site-enrichment/tasks/{id}/events (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.events.add","name":"#1144 atom B: an agent note into the task journal (kind=agent_note, author taken from the request key/JWT, NOT from the body). Written through the SINGLE existing journal writer (SiteEnrichmentService.appendEvent) — there is no second one. Does NOT touch the task's updatedAt/status/processed/counters and does not count towards MAX_RESUME_ATTEMPTS: an observer note must not affect the observed thing (otherwise it would delay the watchdog's staleness pickup). The body is ONLY {text}; the system kind cannot be supplied from outside (forbidNonWhitelisted → 400 before the controller, see CreateAgentNoteDto).","description":"#1144 atom B: an agent note into the task journal (kind=agent_note, author taken from the request key/JWT, NOT from the body). Written through the SINGLE existing journal writer (SiteEnrichmentService.appendEvent) — there is no second one. Does NOT touch the task's updatedAt/status/processed/counters and does not count towards MAX_RESUME_ATTEMPTS: an observer note must not affect the observed thing (otherwise it would delay the watchdog's staleness pickup). The body is ONLY {text}; the system kind cannot be supplied from outside (forbidNonWhitelisted → 400 before the controller, see CreateAgentNoteDto). — POST /api/site-enrichment/tasks/{id}/events (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.reason-summary","name":"#949 summary of failure reasons (for a clickable filter above the journal)","description":"#949 summary of failure reasons (for a clickable filter above the journal) — GET /api/site-enrichment/tasks/{id}/reason-summary (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.stats","name":"#957/#969 unified task statistics read from durable rows: funnel (cards AND domains counted separately, including sourceTotal/visitsSaved from dedup), collected data (substrate-writer receipt — emails/phones/socials/text/native fields, per-map and total), acquisition method, pace/forecast state by domain (plus elapsedSeconds/cardsPerHour/etaAt), breakdown by reason (byReason), breakdown by outcome (byStatus: OK/DOWN/NO_SITE/EMPTY/CAPTCHA) and actual homepage HTTP codes (byHttpStatus, httpStatus:null — no response), launch (launch parameters echoed back — listId/listName/domainField/visitPages/timeoutMs/maxAttempts/mode/surface/startedBy), and links (direct URLs to the scoring-task card and this task's journal) — WITHOUT the full result list (use tasks/:id/items for paginated inspection). The same method serves the legacy alias GET /icp-tasks/companies/scrape/:taskId (stats key) — the only route that actually reaches MCP.","description":"#957/#969 unified task statistics read from durable rows: funnel (cards AND domains counted separately, including sourceTotal/visitsSaved from dedup), collected data (substrate-writer receipt — emails/phones/socials/text/native fields, per-map and total), acquisition method, pace/forecast state by domain (plus elapsedSeconds/cardsPerHour/etaAt), breakdown by reason (byReason), breakdown by outcome (byStatus: OK/DOWN/NO_SITE/EMPTY/CAPTCHA) and actual homepage HTTP codes (byHttpStatus, httpStatus:null — no response), launch (launch parameters echoed back — listId/listName/domainField/visitPages/timeoutMs/maxAttempts/mode/surface/startedBy), and links (direct URLs to the scoring-task card and this task's journal) — WITHOUT the full result list (use tasks/:id/items for paginated inspection). The same method serves the legacy alias GET /icp-tasks/companies/scrape/:taskId (stats key) — the only route that actually reaches MCP. — GET /api/site-enrichment/tasks/{id}/stats (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.items","name":"#952/#969 crawl task items: paginated, with a filter by outcome (status=OK|DOWN|NO_SITE|EMPTY|CAPTCHA) and/or reason code (reasonCode)","description":"#952/#969 crawl task items: paginated, with a filter by outcome (status=OK|DOWN|NO_SITE|EMPTY|CAPTCHA) and/or reason code (reasonCode) — GET /api/site-enrichment/tasks/{id}/items (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.raw","name":"#965 diagnostic snapshot of the RAW visited page text(s) for ONE company (homepage + \"Contacts\", BEFORE contact extraction) — TTL 12h, only while diagnostic mode is on; an empty data is legitimate, not an error","description":"#965 diagnostic snapshot of the RAW visited page text(s) for ONE company (homepage + \"Contacts\", BEFORE contact extraction) — TTL 12h, only while diagnostic mode is on; an empty data is legitimate, not an error — GET /api/site-enrichment/tasks/{id}/raw (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.cancel","name":"Cancel a site-crawl task (durable — status in the DB, visible to any process)","description":"Cancel a site-crawl task (durable — status in the DB, visible to any process) — POST /api/site-enrichment/tasks/{id}/cancel (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.pause","name":"#952 pause a crawl task (durable, non-terminal — resumed via .../resume)","description":"#952 pause a crawl task (durable, non-terminal — resumed via .../resume) — POST /api/site-enrichment/tasks/{id}/pause (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.resume","name":"#952 resume a paused crawl task","description":"#952 resume a paused crawl task — POST /api/site-enrichment/tasks/{id}/resume (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.tasks.retry","name":"Retry still-not-OK companies of a terminal task (FAILED/PARTIAL/CANCELLED)","description":"Retry still-not-OK companies of a terminal task (FAILED/PARTIAL/CANCELLED) — POST /api/site-enrichment/tasks/{id}/retry (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.backlog.list","name":"#969 backfill: count and ids of tenant cards where customFields.site_status='ok' but a real crawl HTTP code was never recorded (customFields.site_status_http is empty). The condition is live (the same as the migration itself), NOT the write-once flag site_needs_recrawl_969 — a card that has already actually been recrawled drops out of the list by itself, with no separate cleanup step. Not retroactive code guessing.","description":"#969 backfill: count and ids of tenant cards where customFields.site_status='ok' but a real crawl HTTP code was never recorded (customFields.site_status_http is empty). The condition is live (the same as the migration itself), NOT the write-once flag site_needs_recrawl_969 — a card that has already actually been recrawled drops out of the list by itself, with no separate cleanup step. Not retroactive code guessing. — GET /api/site-enrichment/backlog/stale-http-status (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.backlog.requeue","name":"#969 backfill: a controlled BATCH re-crawl of flagged cards (batchSize, defaults to 50, cap 200) — via the same create()/run() as a normal task enqueue; not a separate crawl engine.","description":"#969 backfill: a controlled BATCH re-crawl of flagged cards (batchSize, defaults to 50, cap 200) — via the same create()/run() as a normal task enqueue; not a separate crawl engine. — POST /api/site-enrichment/backlog/stale-http-status/requeue (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.backlog-down.list","name":"#1126: count and ids of tenant cards where customFields.site_status='down' AND customFields.site_last_reason is one of a NARROW list of transient failures of OUR OWN infrastructure (currently only 'wait_timeout'), AND customFields.site_status_http is empty (navigation never reached a response). NOT cards with dns_error/tls_error/conn_refused — those are responses FROM THE WORLD about the site, not a failure of our attempt, and are deliberately excluded (see SiteEnrichmentService.TRANSIENT_DOWN_REASONS). The condition is live — a card that has already actually been recrawled drops out of the list by itself.","description":"#1126: count and ids of tenant cards where customFields.site_status='down' AND customFields.site_last_reason is one of a NARROW list of transient failures of OUR OWN infrastructure (currently only 'wait_timeout'), AND customFields.site_status_http is empty (navigation never reached a response). NOT cards with dns_error/tls_error/conn_refused — those are responses FROM THE WORLD about the site, not a failure of our attempt, and are deliberately excluded (see SiteEnrichmentService.TRANSIENT_DOWN_REASONS). The condition is live — a card that has already actually been recrawled drops out of the list by itself. — GET /api/site-enrichment/backlog/down-wait-timeout (scope site-enrichment:read)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"site-enrichment.backlog-down.requeue","name":"#1126: a controlled BATCH re-crawl of cards from backlog/down-wait-timeout (batchSize, defaults to 50, cap 200) — via the same create()/run() as a normal task enqueue; not a separate crawl engine, only a real crawl changes a card's status.","description":"#1126: a controlled BATCH re-crawl of cards from backlog/down-wait-timeout (batchSize, defaults to 50, cap 200) — via the same create()/run() as a normal task enqueue; not a separate crawl engine, only a real crawl changes a card's status. — POST /api/site-enrichment/backlog/down-wait-timeout/requeue (scope site-enrichment:write)","tags":["site-enrichment","site-enrichment"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"marking.patterns.list","name":"List all marking patterns","description":"List all marking patterns — GET /api/marking/patterns (scope marking:read)","tags":["marking","marking"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"marking.patterns.create","name":"Create a new marking pattern","description":"Create a new marking pattern — POST /api/marking/patterns (scope marking:write)","tags":["marking","marking"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"marking.classify","name":"Classify a message against the marking patterns","description":"Classify a message against the marking patterns — POST /api/marking/classify (scope marking:read)","tags":["marking","marking"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"provider-configs.list","name":"List all email provider configurations","description":"List all email provider configurations — GET /api/provider-configs (scope settings:read)","tags":["provider-configs","settings"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"legal.update","name":"Update the terms of service text (SUPER only)","description":"Update the terms of service text (SUPER only) — PUT /api/legal/terms (scope legal:write)","tags":["legal","legal"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"legal.list","name":"List all legal documents (SUPER only)","description":"List all legal documents (SUPER only) — GET /api/legal (scope legal:read)","tags":["legal","legal"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"connectors.tilda.webhook","name":"Tilda form webhook (disabled — requires authorization, see #193)","description":"Tilda form webhook (disabled — requires authorization, see #193) — POST /api/connectors/tilda/webhook (scope connectors:write)","tags":["connectors","connectors"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"connectors.dadata","name":"Normalize Russian full name via DaData API","description":"Normalize Russian full name via DaData API — GET /api/connectors/dadata/name (scope connectors:read)","tags":["connectors","connectors"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"billing.get_balance","name":"Account balance (USD) + operation prices (platform_render/audit/audit_failed/send) + topUpUrl. Top-up is only via the personal account; every paid response contains a _billing { operation, cost, balance_after } block.","description":"Account balance (USD) + operation prices (platform_render/audit/audit_failed/send) + topUpUrl. Top-up is only via the personal account; every paid response contains a _billing { operation, cost, balance_after } block. — GET /api/billing/balance (scope billing:read)","tags":["billing","billing"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"billing.list_charges","name":"Balance movement journal (billing_ledger): entryType (CHARGE|CREDIT|ADJUSTMENT|REFUND), operation, cost, balance_after, campaignId/recipientId. Also shows background cron-pipeline charges that are absent from HTTP responses. Filters: campaignId, entryType.","description":"Balance movement journal (billing_ledger): entryType (CHARGE|CREDIT|ADJUSTMENT|REFUND), operation, cost, balance_after, campaignId/recipientId. Also shows background cron-pipeline charges that are absent from HTTP responses. Filters: campaignId, entryType. — GET /api/billing/ledger (scope billing:read)","tags":["billing","billing"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"share.create","name":"Create a share link for an entity","description":"Create a share link for an entity — POST /api/share-links (scope share:write)","tags":["share","share"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"share.list","name":"List share links for an entity","description":"List share links for an entity — GET /api/share-links (scope share:read)","tags":["share","share"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"exports.columns","name":"List exportable columns and groups for an entity","description":"List exportable columns and groups for an entity — GET /api/exports/columns (scope exports:read)","tags":["exports","exports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"exports.create","name":"Create an export job","description":"Create an export job — POST /api/exports (scope exports:write)","tags":["exports","exports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"exports.list","name":"List my export jobs","description":"List my export jobs — GET /api/exports (scope exports:read)","tags":["exports","exports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"exports.download","name":"Download a completed export file","description":"Download a completed export file — GET /api/exports/{id}/download (scope exports:read)","tags":["exports","exports"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"me.calls","name":"Read your own API/MCP call journal — time, MCP tool name, method, path, HTTP status, duration, error, resourceId (object a create call produced), costUsd (mirrors _billing.cost) and correlationId. Scoped to your own tenant; foreign tenantId cannot be requested. #1212: the SDK's own /api-keys/whoami preflight before every tool call is hidden by default — pass includeInternal=true to see it.","description":"Read your own API/MCP call journal — time, MCP tool name, method, path, HTTP status, duration, error, resourceId (object a create call produced), costUsd (mirrors _billing.cost) and correlationId. Scoped to your own tenant; foreign tenantId cannot be requested. #1212: the SDK's own /api-keys/whoami preflight before every tool call is hidden by default — pass includeInternal=true to see it. — GET /api/me/api-monitor/calls (scope agent:read)","tags":["me","agent"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.list","name":"List ICP tasks with pagination and status filter","description":"List ICP tasks with pagination and status filter — GET /api/icp-tasks (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.create","name":"Create a new ICP task","description":"Create a new ICP task — POST /api/icp-tasks (scope icp:write)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.preview","name":"#955 preview list coverage WITHOUT starting a crawl: how many cards, how many have the domain field filled, how many unique domains among them (alias of .../preview on the canonical site-enrichment)","description":"#955 preview list coverage WITHOUT starting a crawl: how many cards, how many have the domain field filled, how many unique domains among them (alias of .../preview on the canonical site-enrichment) — GET /api/icp-tasks/companies/scrape/preview (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.status","name":"#835 status and progress of a site-crawl task. #957 (fix): includeResults=false removes the results field from the response — on large tasks (thousands of cards) the full result list stops fitting in the response and gets in the way of working with the task via MCP; by default results is returned (the old contract), an explicit includeResults=false returns only aggregates (total/processed/ok/down/noSite). To page through the results themselves — GET .../companies/scrape/:taskId/items or the canonical .../site-enrichment/tasks/:id/items. #957 (continued): the response NOW carries a stats key — the same enriched statistics byte-for-byte as the canonical GET .../site-enrichment/tasks/:id/stats (cards AND domains funnel counted separately, breakdown of collected data by field, pace/forecast, launch parameters echoed back — listId/listName/domainField/visitPages/timeoutMs/maxAttempts/mode/surface/startedBy, direct links to the scoring-task card and this same task's journal); this is a legacy route (ldm_icp_scrape_status) that remains available. The canonical ldm_site_enrichment_tasks_* tools exist in the client catalog but may return 403 insufficient_scope. The legacy alias stays available for clients that lack scope for the new tools.","description":"#835 status and progress of a site-crawl task. #957 (fix): includeResults=false removes the results field from the response — on large tasks (thousands of cards) the full result list stops fitting in the response and gets in the way of working with the task via MCP; by default results is returned (the old contract), an explicit includeResults=false returns only aggregates (total/processed/ok/down/noSite). To page through the results themselves — GET .../companies/scrape/:taskId/items or the canonical .../site-enrichment/tasks/:id/items. #957 (continued): the response NOW carries a stats key — the same enriched statistics byte-for-byte as the canonical GET .../site-enrichment/tasks/:id/stats (cards AND domains funnel counted separately, breakdown of collected data by field, pace/forecast, launch parameters echoed back — listId/listName/domainField/visitPages/timeoutMs/maxAttempts/mode/surface/startedBy, direct links to the scoring-task card and this same task's journal); this is a legacy route (ldm_icp_scrape_status) that remains available. The canonical ldm_site_enrichment_tasks_* tools exist in the client catalog but may return 403 insufficient_scope. The legacy alias stays available for clients that lack scope for the new tools. — GET /api/icp-tasks/companies/scrape/{taskId} (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.cancel","name":"#835 cancel a site-crawl task","description":"#835 cancel a site-crawl task — POST /api/icp-tasks/companies/scrape/{taskId}/cancel (scope icp:write)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.get","name":"Get an ICP task by id","description":"Get an ICP task by id — GET /api/icp-tasks/{id} (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.update","name":"Update an ICP task","description":"Update an ICP task — PATCH /api/icp-tasks/{id} (scope icp:write)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.scoring-prompt","name":"Preview the ACTUAL scoring prompt for this task (brief-driven / custom / default)","description":"Preview the ACTUAL scoring prompt for this task (brief-driven / custom / default) — GET /api/icp-tasks/{id}/scoring-prompt (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.start","name":"#298/#835 server-side crawl fetcher: enqueued in the background, the response is a taskId immediately. Input is companyIds OR listId (#955, the whole list with no 500-item cap on the request body — SiteEnrichmentService resolves it in full); with an explicit limit, the first limit are taken into work (defaults to 50 for companyIds input), how many were actually enqueued is visible in the queued field.","description":"#298/#835 server-side crawl fetcher: enqueued in the background, the response is a taskId immediately. Input is companyIds OR listId (#955, the whole list with no 500-item cap on the request body — SiteEnrichmentService resolves it in full); with an explicit limit, the first limit are taken into work (defaults to 50 for companyIds input), how many were actually enqueued is visible in the queued field. — POST /api/icp-tasks/companies/scrape (scope icp:write)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.pause","name":"#952 pause a crawl task (alias of .../pause on the canonical site-enrichment)","description":"#952 pause a crawl task (alias of .../pause on the canonical site-enrichment) — POST /api/icp-tasks/companies/scrape/{taskId}/pause (scope icp:write)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.resume","name":"#952 resume a paused crawl task (alias of .../resume on the canonical site-enrichment)","description":"#952 resume a paused crawl task (alias of .../resume on the canonical site-enrichment) — POST /api/icp-tasks/companies/scrape/{taskId}/resume (scope icp:write)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.scrape.items","name":"#952 crawl task items with a filter by outcome/reason code (alias of .../items on the canonical site-enrichment)","description":"#952 crawl task items with a filter by outcome/reason code (alias of .../items on the canonical site-enrichment) — GET /api/icp-tasks/companies/scrape/{taskId}/items (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.stats","name":"Get statistics for an ICP task","description":"Get statistics for an ICP task — GET /api/icp-tasks/{id}/statistics (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"icp.tasks.items","name":"List items belonging to an ICP task","description":"List items belonging to an ICP task — GET /api/icp-tasks/{id}/items (scope icp:read)","tags":["icp","icp"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.integration","name":"LinkedIn integration status (toggle, defaults)","description":"LinkedIn integration status (toggle, defaults) — GET /api/linkedin/integration (scope linkedin:read)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.integration.update","name":"Enable/disable the module, kill-switch, defaults","description":"Enable/disable the module, kill-switch, defaults — PATCH /api/linkedin/integration (scope linkedin:write)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.accounts","name":"List of LinkedIn accounts (without cookies)","description":"List of LinkedIn accounts (without cookies) — GET /api/linkedin/accounts (scope linkedin:read)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.account.disconnect","name":"Revoke session (erase cookies)","description":"Revoke session (erase cookies) — POST /api/linkedin/accounts/{id}/disconnect (scope linkedin:write)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.campaigns","name":"List of campaigns","description":"List of campaigns — GET /api/linkedin/campaigns (scope linkedin:read)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.campaign.create","name":"Create a campaign","description":"Create a campaign — POST /api/linkedin/campaigns (scope linkedin:write)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.campaign.leads","name":"Pour leads into a campaign","description":"Pour leads into a campaign — POST /api/linkedin/campaigns/{id}/leads (scope linkedin:write)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.scenarios","name":"List of scenarios","description":"List of scenarios — GET /api/linkedin/scenarios (scope linkedin:read)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"linkedin.stats","name":"Dashboard: funnel + acceptance/reply-rate","description":"Dashboard: funnel + acceptance/reply-rate — GET /api/linkedin/stats (scope linkedin:read)","tags":["linkedin","linkedin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.phantom.profiles","name":"List all Phantom browser profiles","description":"List all Phantom browser profiles — GET /api/phantom-browser/profiles (scope admin:read)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"admin.phantom.launch","name":"Launch a profile on the user's Phantom desktop client","description":"Launch a profile on the user's Phantom desktop client — POST /api/phantom-browser/profiles/{id}/launch (scope admin:write)","tags":["admin","admin"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"import.templates","name":"List available import templates","description":"List available import templates — GET /api/import/templates (scope import:read)","tags":["import","import"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"import.tasks.create","name":"Create a new import task","description":"Create a new import task — POST /api/import/tasks (scope import:write)","tags":["import","import"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"import.from_url","name":"Import a list from a link (Google Sheets or a direct .csv/.xlsx URL) — the \"link -> file\" link, does not start the import itself (#805). Response includes suggestedMapping/unmapped (#1058): a proposed column -> field mapping (from the detected template when one matched, or a header-name heuristic otherwise) with a sample value per column, plus the columns nobody could confidently guess.","description":"Import a list from a link (Google Sheets or a direct .csv/.xlsx URL) — the \"link -> file\" link, does not start the import itself (#805). Response includes suggestedMapping/unmapped (#1058): a proposed column -> field mapping (from the detected template when one matched, or a header-name heuristic otherwise) with a sample value per column, plus the columns nobody could confidently guess. — POST /api/import/from-url (scope import:write)","tags":["import","import"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"import.tasks.get","name":"Get an import task by id","description":"Get an import task by id — GET /api/import/tasks/{id} (scope import:read)","tags":["import","import"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"import.tasks.cancel","name":"Cancel an in-progress import task","description":"Cancel an in-progress import task — POST /api/import/tasks/{id}/cancel (scope import:write)","tags":["import","import"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"utils.timezones","name":"List IANA timezones with cities, country, offset","description":"List IANA timezones with cities, country, offset — GET /api/utils/timezones (scope utils:read)","tags":["utils","utils"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"utils.tz-lookup","name":"Look up timezone by city or country","description":"Look up timezone by city or country — POST /api/utils/timezone-lookup (scope utils:read)","tags":["utils","utils"],"inputModes":["application/json"],"outputModes":["application/json"]}],"skills_total":1270,"skills_note":"Showing 237 curated capabilities of 1270 total. Add ?full=1 to this URL for the complete catalog.","securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"ldm_*","description":"LDM API key (tenant-scoped). Self-serve: POST /api/auth/register (MCP: ldm_terms → ldm_register). Already have an account? Manage keys in CRM Settings → API Keys."}},"security":[{"bearer":[]}],"signup":{"endpoint":"POST /api/auth/register","body":{"email":"string, required","termsAccepted":"boolean, required — must be true (agreement text: GET /api/legal/terms)","channel":"web | mcp | a2a | form, optional — mcp/a2a/form skip the password requirement","org":"string, optional","use_case":"string, optional","firstName":"string, optional"},"note":"Creates a PENDING account + tenant, emails a confirmation link (valid 48h), and — for channel=mcp/a2a/form — returns an ldm_* key immediately with read + safe-draft scopes (no email:send until the owner expands scopes post-activation). Rate-limited per IP. Already have an account? CRM Settings → API Keys mints a wider key directly."},"contact":{"billing":"welcome@live-direct-marketing.online","support":"welcome@live-direct-marketing.online"},"scopes":["email:send","crm:read","crm:write","dialogs:read","dialogs:write","accounts:read","accounts:write","tasks:read","tasks:write","tasks:create","briefs:read","briefs:write","creatives:read","creatives:write","notifications:read","notifications:write","settings:read","settings:write","ai:read","ai:write","customfields:read","customfields:write","tags:read","tags:write","views:read","views:write","pipelines:read","pipelines:write","rules:read","rules:write","mailing:read","mailing:write","users:read","users:write","keys:read","keys:write","share:read","share:write","legal:read","legal:write","admin:read","admin:write","events:read","events:write","agent:read","agent:write","imap:read","imap:write","suppression:read","suppression:write","stoplist:read","stoplist:write","marking:read","marking:write","linker:read","linker:write","exports:read","exports:write","reports:read","reports:write","import:read","import:write","activities:read","activities:write","webhooks:read","webhooks:write","connectors:read","connectors:write","files:read","files:write","icp:read","icp:write","site-enrichment:read","site-enrichment:write","leads:read","leads:write","utils:read","a2a:read","a2a:write"]}