LDM.delivery
Email delivery API for AI agents. Pay only for delivered inbox messages.
AgentCard object, but omits optional fields an agent may expect.
/.well-known/agent.json, the
pre-0.3 location, rather than the current /.well-known/agent-card.json. Clients written
against A2A 1.0.0 will not find it.
An A2A client finds this agent by fetching the well-known path on the provider's own host. That is what makes an agent card different from every other agent artifact in this catalog: it is provider-published by construction — it cannot be derived, generated, or reconstructed on a provider's behalf.
List notifications for the current user notifications.list
List notifications for the current user — GET /api/notifications (scope notifications:read)
notificationsnotificationsCreate an agent self-note notification notifications.self-note
Create an agent self-note notification — POST /api/notifications/self-note (scope notifications:write)
notificationsnotificationsList tenant API keys (raw key value hidden) keys.list
List tenant API keys (raw key value hidden) — GET /api/api-keys (scope keys:read)
keyskeysCreate 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 `["*"]`. keys.create
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)
keyskeysCheck 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). me
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
mePermanently delete a tenant API key keys.revoke
Permanently delete a tenant API key — DELETE /api/api-keys/{id} (scope keys:write)
keyskeysList webhook endpoints webhooks.list
List webhook endpoints — GET /api/webhooks (scope webhooks:read)
webhookswebhooksCreate a webhook endpoint webhooks.create
Create a webhook endpoint — POST /api/webhooks (scope webhooks:write)
webhookswebhooksList delivery history for a webhook endpoint webhooks.deliveries
List delivery history for a webhook endpoint — GET /api/webhooks/{id}/deliveries (scope webhooks:read)
webhookswebhooksRetry a single webhook delivery webhooks.retry
Retry a single webhook delivery — POST /api/webhooks/deliveries/{id}/retry (scope webhooks:write)
webhookswebhooksList users (SUPER/MANAGER) users.list
List users (SUPER/MANAGER) — GET /api/users (scope users:read)
usersusersCreate a user (SUPER only) users.create
Create a user (SUPER only) — POST /api/users (scope users:write)
usersusersList companies with pagination, search, and filters companies.list
List companies with pagination, search, and filters — GET /api/companies (scope crm:read)
companiescrmCreate 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. companies.create
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)
companiescrmSoft-delete a company companies.delete
Soft-delete a company — DELETE /api/companies/{id} (scope companies:write)
companiescompaniesRestore a soft-deleted company companies.restore
Restore a soft-deleted company — POST /api/companies/{id}/restore (scope companies:write)
companiescompaniesRoll back a company import batch by ID companies.import_rollback
Roll back a company import batch by ID — DELETE /api/companies/import/rollback/{batchId} (scope companies:write)
companiescompaniesList suppressed emails suppression.list
List suppressed emails — GET /api/suppression (scope suppression:read)
suppressionsuppressionAdd an email to the suppression list suppression.add
Add an email to the suppression list — POST /api/suppression (scope suppression:write)
suppressionsuppressionCheck a batch of emails against the suppression list suppression.check
Check a batch of emails against the suppression list — POST /api/suppression/check (scope suppression:read)
suppressionsuppressionRemove an email from the suppression list suppression.remove
Remove an email from the suppression list — DELETE /api/suppression/{email} (scope suppression:write)
suppressionsuppressionList stop list entries (user scope) stoplist.list
List stop list entries (user scope) — GET /api/stop-lists (scope stoplist:read)
stopliststoplistAdd a stop list entry (user scope) stoplist.add
Add a stop list entry (user scope) — POST /api/stop-lists (scope stoplist:write)
stopliststoplistRemove a stop list entry (user scope) stoplist.remove
Remove a stop list entry (user scope) — DELETE /api/stop-lists/{id} (scope stoplist:write)
stopliststoplistCheck a batch of emails against the stop list stoplist.check
Check a batch of emails against the stop list — POST /api/stop-lists/check (scope stoplist:read)
stopliststoplistList tenant reports (paginated) + storage quota reports.list
List tenant reports (paginated) + storage quota — GET /api/reports (scope reports:read)
reportsreportsCreate a report from base64 content (agent/MCP path) reports.create
Create a report from base64 content (agent/MCP path) — POST /api/reports (scope reports:write)
reportsreportsRegister a completed export job as a report (idempotent) reports.from_export
Register a completed export job as a report (idempotent) — POST /api/reports/from-export/{exportJobId} (scope reports:write)
reportsreportsPublish: open a direct public download link (no auth!) reports.publish
Publish: open a direct public download link (no auth!) — POST /api/reports/{id}/publish (scope reports:write)
reportsreportsUnpublish: close the public link (token kept — re-publish restores the same url) reports.unpublish
Unpublish: close the public link (token kept — re-publish restores the same url) — POST /api/reports/{id}/unpublish (scope reports:write)
reportsreportsDownload the report file (authorized) reports.download
Download the report file (authorized) — GET /api/reports/{id}/download (scope reports:read)
reportsreportsGet the mail agent connection status and stats agent.status
Get the mail agent connection status and stats — GET /api/mail-agent/status (scope agent:read)
agentagentGet current mail agent settings agent.settings.get
Get current mail agent settings — GET /api/mail-agent/settings (scope agent:read)
agentagentToggle the mail agent enabled flag agent.settings.toggle
Toggle the mail agent enabled flag — POST /api/mail-agent/settings (scope agent:write)
agentagentRegenerate the mail agent auth token agent.token.regenerate
Regenerate the mail agent auth token — POST /api/mail-agent/token/regenerate (scope agent:write)
agentagentDisconnect the mail agent session agent.disconnect
Disconnect the mail agent session — POST /api/mail-agent/disconnect (scope agent:write)
agentagentGenerate AI completion via configured provider ai.generate
Generate AI completion via configured provider — POST /api/ai/generate (scope ai:write)
aiaiList available AI providers with status ai.providers
List available AI providers with status — GET /api/ai/providers (scope ai:read)
aiaiVerify a batch of email addresses synchronously email-verification.verify-batch
Verify a batch of email addresses synchronously — POST /api/verify/batch (scope email:send)
email-verificationemailList custom field definitions, optionally filtered by entity customfields.list
List custom field definitions, optionally filtered by entity — GET /api/custom-fields (scope customfields:read)
customfieldscustomfieldsCreate a custom field definition customfields.create
Create a custom field definition — POST /api/custom-fields (scope customfields:write)
customfieldscustomfieldsList contacts with pagination, search, and filters contacts.list
List contacts with pagination, search, and filters — GET /api/contacts (scope crm:read)
contactscrmCreate 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. contacts.create
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)
contactscrmSoft-delete a contact contacts.delete
Soft-delete a contact — DELETE /api/contacts/{id} (scope contacts:write)
contactscontactsRestore a soft-deleted contact contacts.restore
Restore a soft-deleted contact — POST /api/contacts/{id}/restore (scope contacts:write)
contactscontactsRoll back a contact import batch by ID contacts.import_rollback
Roll back a contact import batch by ID — DELETE /api/contacts/import/rollback/{batchId} (scope contacts:write)
contactscontactsList all pipelines pipelines.list
List all pipelines — GET /api/pipelines (scope pipelines:read)
pipelinespipelinesCreate a new pipeline pipelines.create
Create a new pipeline — POST /api/pipelines (scope pipelines:write)
pipelinespipelinesList leads with pagination, search, and pipeline/stage filters leads.list
List leads with pagination, search, and pipeline/stage filters — GET /api/leads (scope leads:read)
leadsleadsCreate a new lead leads.create
Create a new lead — POST /api/leads (scope leads:write)
leadsleadsGet lead statistics, optionally scoped to a pipeline leads.stats
Get lead statistics, optionally scoped to a pipeline — GET /api/leads/stats (scope leads:read)
leadsleadsGet the kanban board for a pipeline leads.kanban
Get the kanban board for a pipeline — GET /api/leads/kanban/{pipelineId} (scope leads:read)
leadsleadsUpdate an existing lead leads.update
Update an existing lead — PATCH /api/leads/{id} (scope leads:write)
leadsleadsMove a lead to a different stage (and optionally pipeline) leads.move
Move a lead to a different stage (and optionally pipeline) — POST /api/leads/{id}/move (scope leads:write)
leadsleadsExport leads to a downloadable file leads.export
Export leads to a downloadable file — POST /api/leads/export (scope leads:write)
leadsleadsStart a leads import job leads.import
Start a leads import job — POST /api/leads/import/start (scope leads:write)
leadsleadsList all tags in the workspace tags.list
List all tags in the workspace — GET /api/tags (scope tags:read)
tagstagsCreate a new tag tags.create
Create a new tag — POST /api/tags (scope tags:write)
tagstagsList all contact lists for the tenant contact-lists.list
List all contact lists for the tenant — GET /api/contact-lists (scope crm:read)
contact-listscrmList all company lists for the tenant company-lists.list
List all company lists for the tenant — GET /api/company-lists (scope crm:read)
company-listscrmGet the full workspace settings document settings.get
Get the full workspace settings document — GET /api/settings (scope settings:read)
settingssettingsUpdate workspace metadata (name, currency, language) settings.update
Update workspace metadata (name, currency, language) — PATCH /api/settings/workspace (scope settings:write)
settingssettingsGet bo.nalog.gov.ru integration state: enabled, our rate limit, requests today, last error integrations.bo_nalog_get
Get bo.nalog.gov.ru integration state: enabled, our rate limit, requests today, last error — GET /api/settings/integrations/bo-nalog (scope settings:read)
integrationssettingsUpdate bo.nalog.gov.ru integration: enable/disable, requests-per-minute cap integrations.bo_nalog_update
Update bo.nalog.gov.ru integration: enable/disable, requests-per-minute cap — PATCH /api/settings/integrations/bo-nalog (scope settings:write)
integrationssettingsGet DaData integration configuration integrations.dadata_get
Get DaData integration configuration — GET /api/settings/integrations/dadata (scope settings:read)
integrationssettingsUpdate DaData integration configuration integrations.dadata_update
Update DaData integration configuration — PATCH /api/settings/integrations/dadata (scope settings:write)
integrationssettingsReset the DaData daily request counter integrations.dadata_reset_counter
Reset the DaData daily request counter — POST /api/settings/integrations/dadata/reset-counter (scope settings:write)
integrationssettingsGet Inbox Check integration configuration integrations.inbox_check_get
Get Inbox Check integration configuration — GET /api/settings/integrations/inbox-check (scope settings:read)
integrationssettingsUpdate Inbox Check integration configuration integrations.inbox_check_update
Update Inbox Check integration configuration — PATCH /api/settings/integrations/inbox-check (scope settings:write)
integrationssettingsTest the Inbox Check connection integrations.inbox_check_test
Test the Inbox Check connection — POST /api/settings/integrations/inbox-check/test (scope settings:write)
integrationssettingsGet Smartlead integration configuration integrations.smartlead_get
Get Smartlead integration configuration — GET /api/settings/integrations/smartlead (scope settings:read)
integrationssettingsUpdate Smartlead integration configuration integrations.smartlead_update
Update Smartlead integration configuration — PATCH /api/settings/integrations/smartlead (scope settings:write)
integrationssettingsTest the Smartlead connection integrations.smartlead_test
Test the Smartlead connection — POST /api/settings/integrations/smartlead/test (scope settings:write)
integrationssettingsSmartlead placement matrix — mailbox × provider (#1040) integrations.smartlead_placement_matrix
Smartlead placement matrix — mailbox × provider (#1040) — GET /api/settings/integrations/smartlead/placement-matrix (scope settings:read)
integrationssettingsSmartlead placement history for one mailbox × provider cell (#1040) integrations.smartlead_placement_history
Smartlead placement history for one mailbox × provider cell (#1040) — GET /api/settings/integrations/smartlead/placement-history (scope settings:read)
integrationssettingsList dialogs with filters (channel, status, folder, etc.) dialogs.list
List dialogs with filters (channel, status, folder, etc.) — GET /api/dialogs (scope dialogs:read)
dialogsdialogsRead safe, paginated history for one durable outbox task dialogs.outbox_history
Read safe, paginated history for one durable outbox task — GET /api/dialogs/outbox/{id}/history (scope dialogs:read)
dialogsdialogsGet a single dialog by ID messages.get
Get a single dialog by ID — GET /api/dialogs/{id} (scope dialogs:read)
messagesdialogsReply 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) dialogs.reply
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)
dialogsdialogsCompose 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) dialogs.compose
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)
dialogsdialogsGet current user settings user-settings.get
Get current user settings — GET /api/user-settings (scope settings:read)
user-settingssettingsGet 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 mailing.overview
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)
mailingmailingList campaigns awaiting admin approval (cross-tenant for SUPER) mailing.pending
List campaigns awaiting admin approval (cross-tenant for SUPER) — GET /api/mailing/pending-approvals (scope mailing:read)
mailingmailingApprove a pending mailing campaign (admin) mailing.approve
Approve a pending mailing campaign (admin) — POST /api/mailing/{taskId}/approve (scope mailing:write)
mailingmailingGet browser queue stats and fair-share view admin.browser-queue
Get browser queue stats and fair-share view — GET /api/admin/browser-queue (scope admin:read)
adminadminPause the browser queue admin.browser-queue.pause
Pause the browser queue — POST /api/admin/browser-queue/pause (scope admin:write)
adminadminImport images from a source attachment into tenant storage files.images.import
Import images from a source attachment into tenant storage — POST /api/files/images/import (scope files:write)
filesfilesUpload an image for creatives (max 5 MB) files.upload
Upload an image for creatives (max 5 MB) — POST /api/files/upload (scope files:write)
filesfilesList uploaded creative images for the tenant files.images
List uploaded creative images for the tenant — GET /api/files/images (scope files:read)
filesfilesDelete a tenant-scoped creative image files.delete_image
Delete a tenant-scoped creative image — DELETE /api/files/images/{filename} (scope files:write)
filesfilesList tenant assets files.assets
List tenant assets — GET /api/files/assets (scope files:read)
filesfilesDelete a tenant asset files.delete_asset
Delete a tenant asset — DELETE /api/files/assets/{filename} (scope files:write)
filesfilesList file attachments for a contact, company or lead files.list
List file attachments for a contact, company or lead — GET /api/files (scope files:read)
filesfilesDelete a file attachment record files.delete
Delete a file attachment record — DELETE /api/files/{id} (scope files:write)
filesfilesList tasks with pagination and status/method filters tasks.list
List tasks with pagination and status/method filters — GET /api/tasks (scope tasks:read)
taskstasksCreate 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). tasks.create
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)
taskstasksDelete a task tasks.delete
Delete a task — DELETE /api/tasks/{id} (scope tasks:write)
taskstasksList errors encountered during a task run tasks.errors
List errors encountered during a task run — GET /api/tasks/{id}/errors (scope tasks:read)
taskstasksStart (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). tasks.start
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)
taskstasksList pipeline steps configured on a task tasks.steps.list
List pipeline steps configured on a task — GET /api/tasks/{id}/steps (scope tasks:read)
taskstasksAdd 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). tasks.steps.add
tasks.steps.addAdd 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_
Reorder pipeline steps in a task tasks.steps.reorder
Reorder pipeline steps in a task — PUT /api/tasks/{id}/steps/reorder (scope tasks:write)
taskstasksUpdate a single pipeline step tasks.steps.update
Update a single pipeline step — PATCH /api/tasks/{id}/steps/{stepId} (scope tasks:write)
taskstasksDelete a pipeline step from a task tasks.steps.remove
Delete a pipeline step from a task — DELETE /api/tasks/{id}/steps/{stepId} (scope tasks:write)
taskstasksList 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). tasks.scoring-results
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)
taskstasksGet aggregate scoring statistics for a task tasks.scoring-stats
Get aggregate scoring statistics for a task — GET /api/tasks/{id}/scoring-stats (scope tasks:read)
taskstasks#975: paginated step journal for a single scoring card (requested/success/fail/error/interrupted/resumed_after_restart, seq by time) tasks.scoring-step-events
#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)
taskstasksGet the cron scheduling settings for a task tasks.cron.get
Get the cron scheduling settings for a task — GET /api/tasks/{id}/cron (scope tasks:read)
taskstasksUpdate the cron scheduling settings for a task tasks.cron.update
Update the cron scheduling settings for a task — PATCH /api/tasks/{id}/cron (scope tasks:write)
taskstasksManually trigger a task cron run tasks.cron.trigger
Manually trigger a task cron run — POST /api/tasks/{id}/cron/trigger (scope tasks:write)
taskstasksList creatives with pagination and search creatives.list
List creatives with pagination and search — GET /api/creatives (scope creatives:read)
creativescreativesCreate a new creative creatives.create
Create a new creative — POST /api/creatives (scope creatives:write)
creativescreativesGet the PDF generation queue status creatives.pdf-status
Get the PDF generation queue status — GET /api/creatives/pdf-status (scope creatives:read)
creativescreativesList available template variables creatives.variables.available
List available template variables — GET /api/creatives/variables/available (scope creatives:read)
creativescreativesGet a single creative by ID creatives.get
Get a single creative by ID — GET /api/creatives/{id} (scope creatives:read)
creativescreativesUpdate a creative creatives.update
Update a creative — PATCH /api/creatives/{id} (scope creatives:write)
creativescreativesCanonical brief intake email and localized help for customer materials linked to this creative creatives.brief-intake
Canonical brief intake email and localized help for customer materials linked to this creative — GET /api/creatives/{id}/brief-intake (scope creatives:read)
creativescreativesRender a preview of a creative for a sample contact creatives.preview
Render a preview of a creative for a sample contact — POST /api/creatives/{id}/preview (scope creatives:write)
creativescreativesGet template variables used in a creative creatives.variables
Get template variables used in a creative — GET /api/creatives/{id}/variables (scope creatives:read)
creativescreativesList test sends of a creative creatives.test-sends
List test sends of a creative — GET /api/creatives/{id}/test-sends (scope creatives:read)
creativescreativesSend 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). creatives.test-send
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)
creativescreativesGet the status of an asynchronous PDF generation creatives.pdf-generations.get
Get the status of an asynchronous PDF generation — GET /api/creatives/{id}/pdf-generations/{generationId} (scope creatives:read)
creativescreativesGenerate a PDF from a creative creatives.generate-pdf
Generate a PDF from a creative — POST /api/creatives/{id}/generate-pdf (scope creatives:write)
creativescreativesExisting Brief intake address by briefId/briefUrl; omit both only before a Brief exists for workspace unassigned intake (#755) briefs.intake
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)
briefsbriefsList system intake messages for MCP/UI (#750) briefs.intake.items.list
List system intake messages for MCP/UI (#750) — GET /api/briefs/intake/items (scope briefs:read)
briefsbriefsRead one lossless system intake item with provenance, attachments and work log (#750) briefs.intake.items.get
Read one lossless system intake item with provenance, attachments and work log (#750) — GET /api/briefs/intake/items/{itemId} (scope briefs:read)
briefsbriefsTransition an intake item to IN_REVIEW, IGNORED or REJECTED with an audited reason (#750) briefs.intake.items.transition
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)
briefsbriefsLink an intake item/files to a Brief idempotently (#750) briefs.intake.items.link
Link an intake item/files to a Brief idempotently (#750) — POST /api/briefs/intake/items/{itemId}/link (scope briefs:write)
briefsbriefsAppend an agent work-log event with intake provenance (#750) briefs.intake.items.log
Append an agent work-log event with intake provenance (#750) — POST /api/briefs/intake/items/{itemId}/log (scope briefs:write)
briefsbriefsList briefs with pagination, search and active/deleted filters briefs.list
List briefs with pagination, search and active/deleted filters — GET /api/briefs (scope briefs:read)
briefsbriefsCreate a new brief briefs.create
Create a new brief — POST /api/briefs (scope briefs:write)
briefsbriefsRead one Brief attachment as bounded source-backed text/structure/image pages; imageRef yields a real MCP image block (#768) briefs.attachment.content
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)
briefsbriefsUpdate 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 briefs.update-content
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)
briefsbriefsOperation-level SDR expert flow: intake provenance → live schema → gaps → recommendations → save/validate briefs.expert
Operation-level SDR expert flow: intake provenance → live schema → gaps → recommendations → save/validate — GET /api/briefs/{id}/expert (scope briefs:read)
briefsbriefsDecline a Russian full name (FIO) by grammatical case names.decline
Decline a Russian full name (FIO) by grammatical case — POST /api/names/decline (scope utils:read)
namesutilsList email accounts with filters and pagination accounts.list
List email accounts with filters and pagination — GET /api/email-accounts (scope accounts:read)
accountsaccountsCreate 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). accounts.create
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)
accountsaccountsGet IMAP orchestrator dashboard stats imap.stats
Get IMAP orchestrator dashboard stats — GET /api/imap-orchestrator/stats (scope imap:read)
imapimapGet lossless mail sync cursor, staging and quarantine health imap.sync-health
Get lossless mail sync cursor, staging and quarantine health — GET /api/imap-orchestrator/sync-health (scope imap:read)
imapimapRetry a failed durable inbound message, or force a re-fetch of an exhausted quarantine row imap.retry-staged
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)
imapimapAuto-heal stuck GAS accounts and IMAP locks for the current tenant imap.heal
Auto-heal stuck GAS accounts and IMAP locks for the current tenant — POST /api/imap-orchestrator/heal (scope imap:write)
imapimapTrigger an IMAP fetch for every active account in the tenant imap.fetch-all
Trigger an IMAP fetch for every active account in the tenant — POST /api/imap-orchestrator/fetch-all (scope imap:write)
imapimapGet the latest N IMAP job log entries for monitoring imap.tech-log
Get the latest N IMAP job log entries for monitoring — GET /api/imap-orchestrator/tech-log (scope imap:read)
imapimapList all inbound rules inbound-rules.list
List all inbound rules — GET /api/inbound-rules (scope rules:read)
inbound-rulesrulesCreate a new inbound rule inbound-rules.create
Create a new inbound rule — POST /api/inbound-rules (scope rules:write)
inbound-rulesrulesManually re-run linker for a specific dialog linker.relink
Manually re-run linker for a specific dialog — POST /api/dialog-linker/relink/{dialogId} (scope linker:write)
linkerlinkerGet linker statistics by status linker.stats
Get linker statistics by status — GET /api/dialog-linker/stats (scope linker:read)
linkerlinkerGet all linker logs (admin tech log) linker.logs
Get all linker logs (admin tech log) — GET /api/dialog-linker/logs (scope linker:read)
linkerlinkerList saved views for an entity for the current user views.list
List saved views for an entity for the current user — GET /api/saved-views (scope views:read)
viewsviewsCreate a saved view views.create
Create a saved view — POST /api/saved-views (scope views:write)
viewsviewsList activities filtered by lead/contact/company/type activities.list
List activities filtered by lead/contact/company/type — GET /api/activities (scope activities:read)
activitiesactivitiesCreate an activity (call/task/note) linked to a lead/contact/company activities.create
Create an activity (call/task/note) linked to a lead/contact/company — POST /api/activities (scope activities:write)
activitiesactivitiesGet stats for all BullMQ queues admin.queues
Get stats for all BullMQ queues — GET /api/admin/queues (scope admin:read)
adminadminPause a BullMQ queue admin.queue.pause
Pause a BullMQ queue — POST /api/admin/queues/{name}/pause (scope admin:write)
adminadminList all tenants with metadata admin.tenants
List all tenants with metadata — GET /api/admin/tenants (scope admin:read)
adminadminToggle LDM AI for a tenant admin.tenant.ldm-ai
Toggle LDM AI for a tenant — PATCH /api/admin/tenants/{dbName}/ldm-ai (scope admin:write)
adminadminUpdate mail transport config for a tenant admin.tenant.transport
Update mail transport config for a tenant — PATCH /api/admin/tenants/{dbName}/transport (scope admin:write)
adminadminGet i18n translations bundle admin.i18n
Get i18n translations bundle — GET /api/admin/i18n (scope admin:read)
adminadminList memory files admin.memory.list
List memory files — GET /api/admin/memory (scope admin:read)
adminadminGet security overview dashboard admin.security.overview
Get security overview dashboard — GET /api/admin/security/overview (scope admin:read)
adminadmincampaigns test task create campaigns.test_task.create
POST /api/campaigns/{id}/test-task (scope campaigns:write)
campaignscampaignscampaigns test task status campaigns.test_task.status
GET /api/campaigns/{id}/test-task/{taskId} (scope campaigns:read)
campaignscampaignsSingle 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. campaigns.operational_status
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)
campaignscampaignsPaginated durable delivery-task history for a campaign campaigns.task_history
Paginated durable delivery-task history for a campaign — GET /api/campaigns/{id}/task-history (scope campaigns:read)
campaignscampaignsSubmit 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. campaigns.submit_rendered_emails
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)
campaignscampaignsStart 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. campaigns.preparations.start
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)
campaignscampaignsRead a tenant-bound preparation operation. Completed result has the same fields as prepare; failed contains a safe error code/message. This endpoint never sends. campaigns.preparations.status
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)
campaignscampaignsResolve recommended send time without scheduling; AI fallback uses normal usage logging and billing best-send-time.calc
Resolve recommended send time without scheduling; AI fallback uses normal usage logging and billing — POST /api/best-send-time (scope mailing:read)
best-send-timemailingResume snapshot (read-only): tenant context core, own recent notifications and self-notes, plus an honest next_step resume
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)
resumeagent#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. site-enrichment.detect-forms
#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)
site-enrichmentsite-enrichment#903/#889 enqueue the canonical site-crawl task (durable, DB is the source of truth) site-enrichment.tasks.create
#903/#889 enqueue the canonical site-crawl task (durable, DB is the source of truth) — POST /api/site-enrichment/tasks (scope site-enrichment:write)
site-enrichmentsite-enrichment#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) site-enrichment.tasks.list
#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)
site-enrichmentsite-enrichment#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) site-enrichment.tasks.preview
#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)
site-enrichmentsite-enrichmentStatus/counters of a site-crawl task site-enrichment.tasks.get
Status/counters of a site-crawl task — GET /api/site-enrichment/tasks/{id} (scope site-enrichment:read)
site-enrichmentsite-enrichment#903 task transition log, read from the DB, cursor=last received seq site-enrichment.tasks.events
#903 task transition log, read from the DB, cursor=last received seq — GET /api/site-enrichment/tasks/{id}/events (scope site-enrichment:read)
site-enrichmentsite-enrichment#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). site-enrichment.tasks.events.add
#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)
site-enrichmentsite-enrichment#949 summary of failure reasons (for a clickable filter above the journal) site-enrichment.tasks.reason-summary
#949 summary of failure reasons (for a clickable filter above the journal) — GET /api/site-enrichment/tasks/{id}/reason-summary (scope site-enrichment:read)
site-enrichmentsite-enrichment#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. site-enrichment.tasks.stats
#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)
site-enrichmentsite-enrichment#952/#969 crawl task items: paginated, with a filter by outcome (status=OK|DOWN|NO_SITE|EMPTY|CAPTCHA) and/or reason code (reasonCode) site-enrichment.tasks.items
#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)
site-enrichmentsite-enrichment#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 site-enrichment.tasks.raw
#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)
site-enrichmentsite-enrichmentCancel a site-crawl task (durable — status in the DB, visible to any process) site-enrichment.tasks.cancel
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)
site-enrichmentsite-enrichment#952 pause a crawl task (durable, non-terminal — resumed via .../resume) site-enrichment.tasks.pause
#952 pause a crawl task (durable, non-terminal — resumed via .../resume) — POST /api/site-enrichment/tasks/{id}/pause (scope site-enrichment:write)
site-enrichmentsite-enrichment#952 resume a paused crawl task site-enrichment.tasks.resume
#952 resume a paused crawl task — POST /api/site-enrichment/tasks/{id}/resume (scope site-enrichment:write)
site-enrichmentsite-enrichmentRetry still-not-OK companies of a terminal task (FAILED/PARTIAL/CANCELLED) site-enrichment.tasks.retry
Retry still-not-OK companies of a terminal task (FAILED/PARTIAL/CANCELLED) — POST /api/site-enrichment/tasks/{id}/retry (scope site-enrichment:write)
site-enrichmentsite-enrichment#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. site-enrichment.backlog.list
#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)
site-enrichmentsite-enrichment#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. site-enrichment.backlog.requeue
#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)
site-enrichmentsite-enrichment#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. site-enrichment.backlog-down.list
#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)
site-enrichmentsite-enrichment#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. site-enrichment.backlog-down.requeue
#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)
site-enrichmentsite-enrichmentList all marking patterns marking.patterns.list
List all marking patterns — GET /api/marking/patterns (scope marking:read)
markingmarkingCreate a new marking pattern marking.patterns.create
Create a new marking pattern — POST /api/marking/patterns (scope marking:write)
markingmarkingClassify a message against the marking patterns marking.classify
Classify a message against the marking patterns — POST /api/marking/classify (scope marking:read)
markingmarkingList all email provider configurations provider-configs.list
List all email provider configurations — GET /api/provider-configs (scope settings:read)
provider-configssettingsUpdate the terms of service text (SUPER only) legal.update
Update the terms of service text (SUPER only) — PUT /api/legal/terms (scope legal:write)
legallegalList all legal documents (SUPER only) legal.list
List all legal documents (SUPER only) — GET /api/legal (scope legal:read)
legallegalTilda form webhook (disabled — requires authorization, see #193) connectors.tilda.webhook
Tilda form webhook (disabled — requires authorization, see #193) — POST /api/connectors/tilda/webhook (scope connectors:write)
connectorsconnectorsNormalize Russian full name via DaData API connectors.dadata
Normalize Russian full name via DaData API — GET /api/connectors/dadata/name (scope connectors:read)
connectorsconnectorsAccount 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. billing.get_balance
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)
billingbillingBalance 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. billing.list_charges
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)
billingbillingCreate a share link for an entity share.create
Create a share link for an entity — POST /api/share-links (scope share:write)
shareshareList share links for an entity share.list
List share links for an entity — GET /api/share-links (scope share:read)
shareshareList exportable columns and groups for an entity exports.columns
List exportable columns and groups for an entity — GET /api/exports/columns (scope exports:read)
exportsexportsCreate an export job exports.create
Create an export job — POST /api/exports (scope exports:write)
exportsexportsList my export jobs exports.list
List my export jobs — GET /api/exports (scope exports:read)
exportsexportsDownload a completed export file exports.download
Download a completed export file — GET /api/exports/{id}/download (scope exports:read)
exportsexportsRead 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. me.calls
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)
meagentList ICP tasks with pagination and status filter icp.tasks.list
List ICP tasks with pagination and status filter — GET /api/icp-tasks (scope icp:read)
icpicpCreate a new ICP task icp.tasks.create
Create a new ICP task — POST /api/icp-tasks (scope icp:write)
icpicp#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) icp.scrape.preview
#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)
icpicp#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. icp.scrape.status
#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)
icpicp#835 cancel a site-crawl task icp.scrape.cancel
#835 cancel a site-crawl task — POST /api/icp-tasks/companies/scrape/{taskId}/cancel (scope icp:write)
icpicpGet an ICP task by id icp.tasks.get
Get an ICP task by id — GET /api/icp-tasks/{id} (scope icp:read)
icpicpUpdate an ICP task icp.tasks.update
Update an ICP task — PATCH /api/icp-tasks/{id} (scope icp:write)
icpicpPreview the ACTUAL scoring prompt for this task (brief-driven / custom / default) icp.tasks.scoring-prompt
Preview the ACTUAL scoring prompt for this task (brief-driven / custom / default) — GET /api/icp-tasks/{id}/scoring-prompt (scope icp:read)
icpicp#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. icp.scrape.start
#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)
icpicp#952 pause a crawl task (alias of .../pause on the canonical site-enrichment) icp.scrape.pause
#952 pause a crawl task (alias of .../pause on the canonical site-enrichment) — POST /api/icp-tasks/companies/scrape/{taskId}/pause (scope icp:write)
icpicp#952 resume a paused crawl task (alias of .../resume on the canonical site-enrichment) icp.scrape.resume
#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)
icpicp#952 crawl task items with a filter by outcome/reason code (alias of .../items on the canonical site-enrichment) icp.scrape.items
#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)
icpicpGet statistics for an ICP task icp.tasks.stats
Get statistics for an ICP task — GET /api/icp-tasks/{id}/statistics (scope icp:read)
icpicpList items belonging to an ICP task icp.tasks.items
List items belonging to an ICP task — GET /api/icp-tasks/{id}/items (scope icp:read)
icpicpLinkedIn integration status (toggle, defaults) linkedin.integration
LinkedIn integration status (toggle, defaults) — GET /api/linkedin/integration (scope linkedin:read)
linkedinlinkedinEnable/disable the module, kill-switch, defaults linkedin.integration.update
Enable/disable the module, kill-switch, defaults — PATCH /api/linkedin/integration (scope linkedin:write)
linkedinlinkedinList of LinkedIn accounts (without cookies) linkedin.accounts
List of LinkedIn accounts (without cookies) — GET /api/linkedin/accounts (scope linkedin:read)
linkedinlinkedinRevoke session (erase cookies) linkedin.account.disconnect
Revoke session (erase cookies) — POST /api/linkedin/accounts/{id}/disconnect (scope linkedin:write)
linkedinlinkedinList of campaigns linkedin.campaigns
List of campaigns — GET /api/linkedin/campaigns (scope linkedin:read)
linkedinlinkedinCreate a campaign linkedin.campaign.create
Create a campaign — POST /api/linkedin/campaigns (scope linkedin:write)
linkedinlinkedinPour leads into a campaign linkedin.campaign.leads
Pour leads into a campaign — POST /api/linkedin/campaigns/{id}/leads (scope linkedin:write)
linkedinlinkedinList of scenarios linkedin.scenarios
List of scenarios — GET /api/linkedin/scenarios (scope linkedin:read)
linkedinlinkedinDashboard: funnel + acceptance/reply-rate linkedin.stats
Dashboard: funnel + acceptance/reply-rate — GET /api/linkedin/stats (scope linkedin:read)
linkedinlinkedinList all Phantom browser profiles admin.phantom.profiles
List all Phantom browser profiles — GET /api/phantom-browser/profiles (scope admin:read)
adminadminLaunch a profile on the user's Phantom desktop client admin.phantom.launch
Launch a profile on the user's Phantom desktop client — POST /api/phantom-browser/profiles/{id}/launch (scope admin:write)
adminadminList available import templates import.templates
List available import templates — GET /api/import/templates (scope import:read)
importimportCreate a new import task import.tasks.create
Create a new import task — POST /api/import/tasks (scope import:write)
importimportImport 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. import.from_url
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)
importimportGet an import task by id import.tasks.get
Get an import task by id — GET /api/import/tasks/{id} (scope import:read)
importimportCancel an in-progress import task import.tasks.cancel
Cancel an in-progress import task — POST /api/import/tasks/{id}/cancel (scope import:write)
importimportList IANA timezones with cities, country, offset utils.timezones
List IANA timezones with cities, country, offset — GET /api/utils/timezones (scope utils:read)
utilsutilsLook up timezone by city or country utils.tz-lookup
Look up timezone by city or country — POST /api/utils/timezone-lookup (scope utils:read)
utilsutils2026-09-19 from https://api.live-direct-marketing.online/.well-known/agent.json,
HTTP 200. The body was saved verbatim and is the sole source for
everything on this page — no field is inferred.
View the captured card.
Providers change what they serve; if this card has moved or changed shape,
the provider profile carries the
current state as of the last build.
Work with this as data
Every agent card here is available over the APIs.io API and to AI agents over MCP. A2A Agent Cards is not yet its own endpoint on the v1 API. Reach it through catalog search and the tag graph, or the MCP server.