Embed LeadTracker AI in your voice AI and automation stack.
Read live availability, create native bookings, synchronize CRM leads and inbound conversations, submit User Journey forms, and retain attribution, reminders, meeting links, and Telegram notifications in one system.
https://leadtrackerai.com/api/v1 Download OpenAPI 3.1Use the Developer API from Vapi, Retell, Bland, n8n, Zapier code steps, or your own backend. Do not expose API keys in browser code or a client-side voice widget.
Authentication
Create an API key from LeadTracker AI app → Developer API. Keys are workspace-scoped, shown once, and use explicit permissions.
Workspace isolation
A key never accepts a workspace ID from the request. Its workspace is resolved from the credential.
Least privilege
Choose narrowly scoped scheduling, CRM, conversation, call, recording, script, voicemail, analytics, or workflow permissions for each integration.
Operational control
Set an expiry, inspect last use, rotate safely, and revoke a compromised key immediately.
curl https://leadtrackerai.com/api/v1/scheduling/brands \
-H "Authorization: Bearer lt_live_..."
X-API-Key: lt_live_...
Idempotency-Key header for every mutation. Booking reschedule/cancel and form funnel events enforce replay-safe idempotency; duplicate keys replay the original result. Call-queue preview retries retain their preview_token and complete audience response. One-time credentials such as webhook signing secrets are redacted on replay.402 quota_exceeded.GET /capabilities reports the CRM, scheduling, forms, projects, team chat, meetings, documents, and webhooks domains as available; the communications, calls/telephony, meeting artifacts (recordings, transcripts, AI summaries), marketing, growth/SEO, and AI domains report subscription_required, and calling any of their operations returns 402 subscription_required until the workspace is on a paid plan. MCP tools follow /capabilities: the LeadTracker MCP server registers tools only for domains marked available, so an MCP host attached to a Free workspace sees the CRM, scheduling, forms, projects, team chat, meetings, documents, and webhook tool set. Meetings are Free because a meeting is a conference on the host's OWN connected calendar: listing, creating, updating and cancelling meetings, and a Google Meet link or a Microsoft Teams link from a Microsoft 365 work or school calendar with Teams enabled, cost the platform nothing (conference_provider and conference_status on the booking or meeting; an awaiting_connection status returns connect_options naming the provider to authorize). A Microsoft account that can sync Outlook events but cannot host Teams returns provider_error with a clear account-capability message. The operations that reach a paid provider are the exception and return 402 subscription_required on Free: an explicit location_type: leadtracker_video, POST /meetings/{id}/join-token, POST /meetings/{id}/end, send-notes, and the recording/transcript/summary/action-item reads. Count caps on Free (2,500 CRM records, 3 seats, 2 event types, 300 bookings/mo, 2 active forms, 20 documents first sent for signing per UTC month, 1 API key) return 402 quota_exceeded for new records or resources, including POST /scheduling/bookings past the monthly cap. Existing CRM records remain readable and editable. Inbound form submissions are the one exception: POST /forms/{brand}/submissions is never refused for volume on any plan; at the CRM record cap the submission is stored and marked for upgrade without creating another lead.GET /api/v1/openapi.json is public because the specification contains no credentials. /meta, /whoami, and /capabilities require a valid API key and report only safe contract, identity, and entitlement metadata.POST /scheduling/connections/{provider}/authorize creates durable, expiring state bound to the workspace, provider, client, redirect, nonce, and PKCE-S256 verifier. The callback accepts the provider's standard state and code redirect parameters; nonce proof comes from the cryptographically verified Google/Microsoft OIDC ID token, never from a client-supplied query nonce. The callback consumes state once; GET /scheduling/authorizations/{id} exposes status without state, verifier, provider credentials, or raw URLs. Disabled effects return deterministic simulation results.SDKs and MCP
The JavaScript/TypeScript and Python SDKs are generated from the canonical OpenAPI document. They stay thin: authentication, request construction, safe retries, cursor pagination, job polling, approval status, request IDs, and structured errors are ergonomic client helpers; tenancy, scopes, entitlements, plans, and policy remain server-owned.
npm install @leadtracker/developer-api
python -m pip install leadtracker-developer-api
import { LeadTrackerClient } from '@leadtracker/developer-api';
const api = new LeadTrackerClient({
baseUrl: process.env.LEADTRACKER_API_BASE_URL ?? 'https://leadtrackerai.com/api/v1',
bearerToken: process.env.LEADTRACKER_API_TOKEN,
});
for await (const lead of api.paginate('developer_crm_leads_list', {
query: { limit: 50 },
})) {
console.log(lead.id);
}
operation_id to POST /approval-requests, then poll the returned request until an external human approval before executing. waitForJob/wait_for_job only poll public job status; waitForApproval/wait_for_approval never approves or bypasses a human decision.MCP setup and authority
The MCP adapter is a separate HTTPS client over /api/v1. Configure a short-lived delegated token or least-privilege service credential in the MCP host; never give it a database connection, session cookie, platform-wide credential, or internal route access.
{
"leadtracker": {
"baseUrl": "https://leadtrackerai.com/api/v1",
"tokenEnv": "LEADTRACKER_MCP_TOKEN",
"scopes": ["leads:read", "jobs:read"]
}
}
MCP tools are derived from the same x-mcp metadata and capability checks as the public API. Workspace tenancy, scope checks, entitlement gates, idempotency, If-Match, exact plan hashes, approvals, audit, and redaction still run on every request. Human approval ceremonies and OAuth callbacks remain outside direct MCP exposure; MCP may observe status but cannot self-approve.
Remote MCP server (hosted)
The same adapter is hosted at https://leadtrackerai.com/mcp over Streamable HTTP, so ChatGPT developer mode and claude.ai / Claude Desktop custom connectors need nothing installed. One MCP session is one transport bound to exactly one caller credential; the hosted process holds no platform credential and reaches no database. Set MCP_REMOTE_ENABLED=0 to take the endpoint offline.
The endpoint is OAuth-protected and self-describing: an unauthenticated request returns 401 with WWW-Authenticate: Bearer resource_metadata="https://leadtrackerai.com/.well-known/oauth-protected-resource/mcp". Clients read /.well-known/oauth-protected-resource/mcp (RFC 9728) and /.well-known/oauth-authorization-server (RFC 8414), register themselves with POST /api/v1/oauth/register (RFC 7591), and complete authorization code + PKCE S256. The RFC 8707 resource indicator is honoured, so a token minted for another resource is rejected at /mcp; authorization responses carry iss; access tokens live 60 minutes and refresh tokens rotate with reuse detection. Registration is open by design, so it is rate limited per source address and capped globally at 200 new dynamic clients per rolling day. A client that names no scope receives the default connector set only — CRM, scheduling, meetings, projects, chat, forms and tasks read+write plus users:read, approvals:read, and approvals:request. Those approval scopes let a connector request and read a human approval; they never let it decide one. Analytics, audit, webhook management, bulk/archive and workspace or user writes must be requested explicitly and always appear on the consent screen. Existing grants are never widened silently, so remove and add an older default connector again to create a fresh registration with this corrected default set.
A human always approves in the browser. An unauthenticated /authorize redirects to /login?next= and back, then to a consent screen naming the client, the workspace, and every requested permission grouped by domain. The screen may narrow the grant but never widen it, and the grant is revocable under Settings → Developer.
Server URL: https://leadtrackerai.com/mcp Auth: OAuth (dynamic registration — leave client id and secret blank) ChatGPT: Settings → Connectors → Advanced → Developer mode → Create Claude: Settings → Connectors → Add custom connector Cursor: local stdio (see the MCP host configuration above)
A token that acts as a person never exceeds that person's role. Access tokens from authorization code + PKCE (every hosted connector) are bound to one workspace member, and on every request their scopes are intersected with that member's role — including tokens issued before a role changed. Owners and admins keep every granted scope. Managers keep everything except the admin control planes (developer:credentials:admin, developer:webhooks:write, billing:write, users:write, workspace:write, domains:write, integrations:write, phone_numbers:manage, invoices:write, payments:write, commissions:approve). Setters, closers, full-cycle closers and any other role are limited to leads:read, leads:write, deals:read, deals:write, tasks:read, tasks:write, scheduling:read, scheduling:write, meetings:read, meetings:write, calls:read, tags:read, custom_fields:read, pipelines:read, users:read, teams:read, notifications:read, notifications:write, chat:read, chat:write, roleplay:read and roleplay:execute; token introspection and the MCP tool list report the clamped set.
Within those scopes a rep-delegated token sees exactly the records its person sees in the app, and a hidden record answers 404: leads the person created or is assigned to (plus the unassigned pool for setters and full-cycle closers); deals they own (closer) or set (setter); tasks assigned to them; bookings they host or whose lead they can see; meetings they host or are invited to; calls they made or on leads they can see; and only visible smart-list members, lead/deal tags and custom fields. POST /leads/upsert and POST /scheduling/bookings return 409 lead_exists_outside_scope instead of changing another teammate's lead; leads created through the token are owned by the person. Call queues, prospect packs, signal-to-lead conversion and duplicate review return 403 role_denied. Service accounts and workspace API keys can only be created by owners and admins and remain workspace-wide integrations.
Because several hundred tools degrade a model's tool selection, a hosted session lists the essentials profile by default: 203 tools covering leads, deals, pipelines, tasks, scheduling, meetings, forms, projects, chat, smart lists, custom fields, tags, analytics, users, teams, webhooks, and workspace reads. Local stdio keeps the full 791. The consent screen picks the profile and can narrow it to a subset of domains, and the choice is stored on the access token; stdio uses LEADTRACKER_MCP_PROFILE and LEADTRACKER_MCP_DOMAINS. A profile controls tool visibility only; it cannot add OAuth permissions. Profile filtering never grants anything — a tool is listed only when the credential's scopes, the workspace's entitlements, and the profile all allow it, and leadtracker://capabilities reports the exact reason for every omission, including the per-domain paid_only_operations a zero-cost subscription cannot call.
Tools carry MCP annotations so a host can decide what to confirm: readOnlyHint on reads, destructiveHint on archive/delete/cancel/disable, idempotentHint on If-Match updates, and openWorldHint: false everywhere. Booking creation, rescheduling, and cancellation are R2 plan-first actions. The default connector scopes include approval read/request, so the connector can create and check the approval request without “Allow all”; the person in LeadTracker makes the approval decision. An R2 request may be approved by the same person who made it, while R3 requires a different admin and the approval_request_id they granted for that exact plan.
Appointments, consultations, and discovery calls must use the native leadtracker_scheduling_* tools. The generic calendar-entry create tool only adds an internal workspace block: it does not create an attendee booking or send confirmation, reschedule, or cancellation emails. For a workspace with one booking brand, clients omit brand_id and the server selects that brand automatically; configured: null in capabilities means configuration was not evaluated, not that the booking brand is missing.
CRM companies, duplicate review, stage rules and durable jobs
The /crm routes use delegated user credentials and the same record visibility as the application. Service accounts cannot impersonate a member. Mutations require an Idempotency-Key; versioned writes include the opened numeric version.
Owners and admins can review exact-identity duplicate groups with owner_id or normalized identity filters. Preview is capped at 100 groups and returns has_more; narrow or resolve the displayed groups. Reviewed merge requires both opened revisions and a reason, preserves originals in the audit snapshot, transfers associations atomically, and never auto-merges candidates.
Companies support versioned edits and contact associations. Deal stakeholder links authorize the contact and deal separately. Managers can configure stage requirements and approve a specific deal revision. Database rules enforce entry and exit requirements across writers. Task completion creates one recurring successor atomically.
Audience preparation freezes ordered membership, and export preparation also freezes values. Confirm the prepared count before execution. Queued work supports checkpoints, cancellation, per-record errors, and protected downloads expiring after 24 hours. Audiences are capped at 100,000 records; the cap is enforced without partial results.
Working context requires leads:read, tasks:read, deals:read, communications:read and finance:read. Stakeholder and recurring-task creation also require leads:read. Audience actions require leads:bulk, plus tags:write, leads:archive or leads:write for the chosen mutation.
Durable CSV imports use POST /crm/imports, then POST /crm/imports/{id}/start with the exact expected_count. Active owners, admins and managers can validate up to 100,000 rows in a 10 MB file. Row outcomes, validated column mappings, validation errors, reviewed field choices and committed checkpoints are retained for seven days. Import GET/list responses include the current member's saved mappings for reuse. The paginated rows endpoint can collect a complete live CSV error/review report; it is not limited to the displayed page. Cancel and resume preserve completed rows. Duplicate policies are skip, update non-identity fields, or manual review; ambiguous and archived contacts always require review. Custom mappings and reviewed custom updates also require custom_fields:write.
Stage filters retain literal field semantics. Pipeline context is a separate view_context setting; saved views store it as view_state.stage_tab. Calendar-relative filters use the requested timezone and exclusive interval ends.
Canonical operation inventory
Saved Deals and Tasks queues have asynchronous CSV exports with up to 100,000 exact ordered records and selected columns. Native UI and delegated API use the same workspace, role, filter and saved-view checks. Export preparation freezes membership and values; 200-row checkpoints support cancellation and resume without repeated output. Money exports include currency. Artifacts expire after 24 hours and downloads reauthorize membership, view access and every captured record. Owner, admin or manager membership is required. Create through POST /crm/deals/exports or POST /crm/tasks/exports, then inspect, cancel, resume or download through /crm/entity-exports/{id}. Status/download also require leads:bulk and the corresponding deals:read or tasks:read scope. Mutations require an Idempotency-Key; service credentials cannot impersonate a user.
Platform support uses support:read and support:write on every plan. Cases remain limited to the requesting user or service credential; public articles exclude operator notes. Mutations require Idempotency-Key and return durable acceptance with an honest sync state. See the support contract. The authenticated v1 surface contains 774 operations. It includes native scheduling, CRM records and relationships, durable jobs, communications, documents, workflows, finance and governed integrations. This inventory matches the downloadable OpenAPI contract.
The MCP projection exposes 833 tools: 769 direct public-operation tools plus 63 target-specific immutable plan tools. Provider actions retain their reviewed plan and approval contracts. Account-bound CRM operations require delegated user authorization and cannot impersonate workspace members.
/support/cases/{uid}/diagnosticssupport:write; see support contract/support/cases/{uid}/attachmentssupport:read; see support contract/support/cases/{uid}/attachments/{attachmentUid}support:read; see support contract/support/cases/{uid}/attachmentssupport:write; see support contract/support/identity/linksupport:write; see support contract/support/statussupport:read or support:write; see contract/support/casessupport:read or support:write; see contract/support/casessupport:read or support:write; see contract/support/cases/{uid}support:read or support:write; see contract/support/cases/{uid}/messagessupport:read or support:write; see contract/support/cases/{uid}/handoffsupport:read or support:write; see contract/support/cases/{uid}/feedbacksupport:read or support:write; see contract/support/knowledgesupport:read or support:write; see contract/support/knowledge/{articleId}support:read or support:write; see contract/crm/duplicatesleads:read; owner/admin review/crm/leads/mergeleads:write; versioned reviewed merge/crm/deals/exportsdeals:read; manager export/crm/tasks/exportstasks:read; manager export/crm/entity-exportsleads:bulk/crm/entity-exports/{id}leads:bulk + entity read/crm/entity-exports/{id}/cancelleads:bulk + entity read/crm/entity-exports/{id}/resumeleads:bulk + entity read/crm/entity-exports/{id}/downloadleads:bulk + entity read; binary CSV/crm/metricsanalytics:read + leads:read + deals:read/crm/metrics/recordsBounded milestone drill-through/crm/companies/{id}/archiveleads:write/crm/companies/{id}/restoreleads:write/crm/companies/{id}/contacts/{leadId}leads:write/crm/companies/{id}/reconciliationleads:read/crm/deals/{id}/stakeholders/{leadId}deals:write/crm/importsValidate a durable CSV import
GET/crm/importsList recent imports
GET/crm/imports/{id}Read import progress
POST/crm/imports/{id}/startConfirm or resume pending rows
POST/crm/imports/{id}/cancelCancel at a committed checkpoint
GET/crm/imports/{id}/rowsPage through errors and duplicate decisions
POST/crm/imports/{id}/rows/{ordinal}/resolveConfirm reviewed contact fields
/crm/task-alertstasks:read/crm/task-alerts/{id}tasks:write/crm/companiesleads:read/crm/companiesleads:write/crm/companies/{id}leads:read/crm/companies/{id}leads:write/crm/companies/{id}/contactsleads:write/crm/leads/{id}/workspaceleads:read/crm/deals/{id}/stakeholdersdeals:read/crm/deals/{id}/stakeholdersdeals:write/crm/stages/{id}/policypipelines:read/crm/stages/{id}/policypipelines:write/crm/deals/{id}/stage-approvalsdeals:write/crm/deals/{id}/next-actiondeals:write/crm/task-templatestasks:read/crm/task-templatestasks:write/crm/task-templates/{id}/taskstasks:write/crm/tasks/{id}/stop-recurrencetasks:write/crm/audiencesleads:bulk/crm/audiences/{id}leads:bulk/crm/audiences/{id}/jobsleads:bulk/crm/jobsleads:bulk/crm/jobs/{id}leads:bulk/crm/jobs/{id}/failuresleads:bulk/crm/jobs/{id}/cancelleads:bulk/crm/jobs/{id}/downloadleads:bulk + leads:read/crm/pipelines/{id}/configurationpipelines:write/metaauthenticated/whoamiauthenticated/capabilitiesauthenticated/operation-planstarget scope · R1 · immutable MCP plan/scheduling/brandsscheduling:read/scheduling/event-typesscheduling:read/scheduling/availabilityscheduling:read/scheduling/bookingsscheduling:read/scheduling/bookings/{uid}scheduling:read/scheduling/bookingsscheduling:write · R2 · Idempotency-Key/scheduling/bookings/{uid}/reschedulescheduling:write · R2 · Idempotency-Key/scheduling/bookings/{uid}/cancelscheduling:write · R2 · Idempotency-Key/scheduling/calendarsscheduling:read · R0 · cursor/scheduling/calendarsscheduling:configure · R1 · Idempotency-Key/scheduling/calendars/{id}scheduling:read · R0/scheduling/calendars/{id}scheduling:configure · R1 · If-Match/scheduling/calendars/{id}/archivescheduling:configure · R1 · If-Match/scheduling/event-typesscheduling:configure · R1 · Idempotency-Key/scheduling/event-types/{id}scheduling:read · R0/scheduling/event-types/{id}scheduling:configure · R1 · If-Match/scheduling/event-types/{id}scheduling:configure · R1 · If-Match/scheduling/event-types/{id}/remindersscheduling:read · R0/scheduling/event-types/{id}/remindersscheduling:configure · R1 · If-Match/scheduling/precall-sequencesscheduling:read · R0/scheduling/precall-sequencesscheduling:configure · R1 · Idempotency-Key/scheduling/precall-sequences/{id}scheduling:read · R0/scheduling/precall-sequences/{id}scheduling:configure · R1 · If-Match/scheduling/precall-sequences/{id}/archivescheduling:configure · R1 · If-Match/scheduling/precall-sequences/{id}/event-typesscheduling:configure · R1 · If-Match/scheduling/precall-sequences/{id}/assetsscheduling:configure · R1 · multipart · Idempotency-Key/scheduling/precall-sequences/{id}/assets/{asset_id}scheduling:configure · R1 · If-Match/scheduling/calendars/{id}/availability-rulesscheduling:read · R0/scheduling/calendars/{id}/availability-rulesscheduling:configure · R1 · If-Match/scheduling/calendars/{id}/exceptionsscheduling:read · R0/scheduling/calendars/{id}/exceptionsscheduling:configure · R1 · Idempotency-Key/scheduling/calendars/{id}/exceptions/{exception_id}scheduling:configure · R1 · If-Match/scheduling/calendars/{id}/exceptions/{exception_id}scheduling:configure · R1 · If-Match/scheduling/time-offscheduling:read · R0/scheduling/time-offscheduling:configure · R1 · Idempotency-Key/scheduling/time-off/{id}scheduling:configure · R1 · If-Match/scheduling/time-off/{id}scheduling:configure · R1 · If-Match/scheduling/routing-poolsscheduling:read · R0 · single page/scheduling/routing-poolsscheduling:configure · R1 · Idempotency-Key/scheduling/routing-pools/{id}scheduling:read · R0/scheduling/routing-pools/{id}scheduling:configure · R1 · If-Match/scheduling/routing-pools/{id}/membersscheduling:configure · R1 · If-Match/scheduling/connectionsscheduling:connections · R0/scheduling/connections/{provider}/authorizescheduling:connections · R1 · Idempotency-Key/scheduling/connections/{provider}/callbackpublic state/PKCE/OIDC-ID-token callback · MCP hidden/scheduling/authorizations/{id}scheduling:connections · R0 · status only/scheduling/connections/{id}/syncscheduling:connections · R2 · 202 · Idempotency-Key/scheduling/connections/{id}/calendars/{calendar_id}scheduling:connections · R1 · If-Match/scheduling/connections/{id}/disconnect/planscheduling:connections · R2 · Idempotency-Key/scheduling/connections/{id}/disconnectscheduling:connections · R3 · If-Match/scheduling/holdsscheduling:write · R1 · Idempotency-Key/scheduling/bookings/{uid}/attendancescheduling:write · R1 · If-Match/scheduling/bookings/{uid}/refresh-conferencescheduling:write · R1 · Idempotency-Key/scheduling/bookings/{uid}/guestsscheduling:write · R1 · Idempotency-Key/scheduling/bookings/{uid}/guestsscheduling:read · R0/scheduling/booking-links/mescheduling:read · R0 · the token's own person only/scheduling/booking-links/mescheduling:write · R1 · Idempotency-Key · the token's own person only/leads/searchleads:read/leadsleads:read/leads/queryleads:read/leads/{id}leads:read/leads/{id}/taskstasks:read · R0 · cursor/leads/{id}/researchleads:write · R2 · 202 · Idempotency-Key/leads/{id}/enrichmentleads:write · R2 · 202 · Idempotency-Key/leads/bulkleads:bulk · R1 · 202 · Idempotency-Key/leadsleads:write/leads/upsertleads:write/leads/importsleads:bulk · R1 · 202 · Idempotency-Key/leads/imports/{job_id}leads:bulk · R0/leads/imports/{import_id}/commitleads:bulk · R1 · 202 · Idempotency-Key/leads/exportsanalytics:export · R1 · 202 · Idempotency-Key/leads/exports/{artifact_id}analytics:export · R0 · expires/leads/exports/{artifact_id}/downloadanalytics:export · R0 · audited/leads/{id}leads:write/leads/{id}/archiveleads:archive/leads/{id}/restoreleads:archive/leads/{id}/notesleads:read/leads/{id}/notesleads:write/leads/{id}/notes/{note_id}leads:write/leads/{id}/notes/{note_id}leads:write/leads/{id}/activitiesleads:read/leads/{id}/activitiesleads:write/conversations/inboundconversations:write/conversations/inbound-callsconversations:write/conversationsconversations:read · R0 · cursor/conversations/{id}conversations:read · R0/conversations/{id}/assignconversations:write · R1 · Idempotency-Key/conversations/{id}/closeconversations:write · R1 · Idempotency-Key/conversations/{id}/reopenconversations:write · R1 · Idempotency-Key/conversations/{id}/messagesconversations:read · R0 · cursor/conversations/{id}/send-eligibilityconversations:send · R0/conversations/{id}/messagesconversations:send · R2 · 202 · Idempotency-Key/conversations/{id}/messages/scheduleconversations:send · R2 · 202 · Idempotency-Key/conversations/{id}/messages/{message_id}/replyconversations:send · R2 · 202 · Idempotency-Key/suppression/statusconversations:read · R0/suppression/requestsconversations:write · R1 · Idempotency-Key/callscalls:read · R0 · cursor/callscalls:start · R2 · 201/202 · Idempotency-Key/calls/{id}calls:read · R0/calls/{id}/statuscalls:read · R0/calls/{id}/statuscalls:control · R2 · Idempotency-Key/calls/{id}/dtmfcalls:control · R2 · Idempotency-Key/calls/{id}/hangupcalls:control · R2 · Idempotency-Key/calls/{id}/dispositioncalls:control · R1 · Idempotency-Key/calls/{id}/retrycalls:start · R2 · 201/202 · Idempotency-Key/calls/{id}/recordingrecordings:read · R0 · signed expiry/calls/{id}/transcriptrecordings:read · R0 · signed expiry/calls/{id}/summarycalls:read · R0 · signed expiry/scheduled-callscalls:read · R0 · cursor/scheduled-callscalls:start · R1 · Idempotency-Key/scheduled-calls/{id}calls:start · R1 · If-Match · Idempotency-Key/scheduled-calls/{id}/completecalls:control · R1 · Idempotency-Key/scheduled-calls/{id}/snoozecalls:control · R1 · Idempotency-Key/scheduled-calls/{id}/skipcalls:control · R1 · Idempotency-Key/call-queuescalls:read · R0 · cursor/call-queuescalls:start · R1 · Idempotency-Key/call-queues/previewcalls:read · R0 · Idempotency-Key/call-queues/{id}calls:read · R0/call-queues/{id}/start-nextcalls:start · R2 · 202 · Idempotency-Key/call-queues/{id}/pausecalls:control · R1 · If-Match · Idempotency-Key/call-queues/{id}/resumecalls:control · R1 · If-Match · Idempotency-Key/scriptsscripts:read · R0 · cursor/scriptsscripts:write · R1 · Idempotency-Key/scripts/{id}scripts:read · R0/scripts/{id}scripts:write · R1 · If-Match · Idempotency-Key/scripts/{id}/publishscripts:write · R1 · Idempotency-Key/scripts/{id}/archivescripts:write · R1 · Idempotency-Key/scripts/{id}/clonescripts:write · R1 · Idempotency-Key/scripts/{id}/versionsscripts:read · R0 · cursor/scripts/{id}/assignmentsscripts:read · R0/scripts/{id}/assignscripts:write · R1 · Idempotency-Key/voicemailsvoicemails:read · R0 · cursor/voicemailsvoicemails:write · R1 · 201/202 · Idempotency-Key/voicemails/{id}voicemails:read · R0/voicemails/{id}voicemails:write · R1 · If-Match · Idempotency-Key/voicemails/previewvoicemails:write · R2 · 200/202 · Idempotency-Key/voicemails/{id}/previewvoicemails:read · R0 · Idempotency-Key/voicemails/{id}/set-defaultvoicemails:write · R1 · Idempotency-Key/voicemails/{id}/archivevoicemails:write · R1 · Idempotency-Key/voicemails/{id}/versionsvoicemails:read · R0 · cursor/campaignscampaigns:read · R0 · cursor/campaignscampaigns:write · R1 · Idempotency-Key/campaigns/{id}campaigns:read · R0/campaigns/{id}campaigns:write · R1 · If-Match · Idempotency-Key/campaigns/{id}/archivecampaigns:write · R1 · If-Match · Idempotency-Key/campaigns/{id}/stepscampaigns:read · R0/campaigns/{id}/stepscampaigns:write · R1 · If-Match · Idempotency-Key/campaigns/{id}/validatecampaigns:write · R1 · Idempotency-Key/campaigns/{id}/activatecampaigns:execute · R2 · If-Match · Idempotency-Key/campaigns/{id}/pausecampaigns:execute · R2 · If-Match · Idempotency-Key/campaigns/{id}/resumecampaigns:execute · R2 · If-Match · Idempotency-Key/campaigns/{id}/launch/plancampaigns:execute · R2 · plan · Idempotency-Key/campaigns/{id}/launchcampaigns:execute · R3 · approved · 202 · Idempotency-Key/campaigns/{id}/enrollmentscampaigns:execute · R2 · 202 · Idempotency-Key/campaigns/{id}/enrollmentscampaigns:read · R0 · cursor/campaigns/{id}/enrollments/{enrollment_id}/pausecampaigns:execute · R2 · If-Match · Idempotency-Key/campaigns/{id}/enrollments/{enrollment_id}/resumecampaigns:execute · R2 · If-Match · Idempotency-Key/campaigns/{id}/enrollments/{enrollment_id}/removecampaigns:execute · R2 · If-Match · Idempotency-Key/campaigns/{id}/analyticsanalytics:read · R0/workflowsworkflows:read · R0 · cursor/workflowsworkflows:write · R1 · Idempotency-Key/workflows/{id}workflows:read · R0/workflows/{id}workflows:write · R1 · If-Match · Idempotency-Key/workflows/{id}/cloneworkflows:write · R1 · Idempotency-Key/workflows/{id}/archiveworkflows:write · R1 · If-Match · Idempotency-Key/workflows/{id}/nodesworkflows:write · R1 · If-Match · Idempotency-Key/workflows/{id}/validateworkflows:write · R0 · Idempotency-Key/workflows/{id}/activate/planworkflows:execute · R2 · plan · Idempotency-Key/workflows/{id}/activateworkflows:execute · R2 · If-Match · Idempotency-Key/workflows/{id}/deactivate/planworkflows:execute · R2 · plan · Idempotency-Key/workflows/{id}/deactivateworkflows:execute · R2 · If-Match · Idempotency-Key/workflows/{id}/trigger/planworkflows:trigger · R2 · plan · Idempotency-Key/workflows/{id}/triggerworkflows:trigger · R2 · 202 · Idempotency-KeyDry-run previews follow the configured condition branches and return step output. Message previews perform read-only consent, opt-out and recipient-local sending-hour checks; blocked messages report eligible: false and a reason code. Passing consent does not promise delivery: provider availability and usage allowance are checked at execution. Simulations never call providers, mutate CRM records or persist waits. Retrying a simulation keeps it simulated. Native scheduled executions heartbeat their claim; a lost lease becomes a failed run requiring step review and delivery reconciliation before replay.
/workflows/{id}/test-runworkflows:execute · R2 · simulated · 202 · Idempotency-Key/workflows/{id}/runsworkflows:read · R0 · cursor/workflow-runs/{id}workflows:read · R0/workflow-runs/{id}/stepsworkflows:read · R0 · cursor/workflow-runs/{id}/cancelworkflows:execute · R2 · Idempotency-Key/workflow-runs/{id}/retryworkflows:execute · R2 · lineage · 202 · Idempotency-Key/meetingsmeetings:read · R0 · cursor/meetingsmeetings:write · R1 · 201 · Idempotency-Key/meetings/{id}meetings:read · R0/meetings/{id}meetings:write · R1 · If-Match · Idempotency-Key/meetings/{id}/cancelmeetings:write · R2 · policy · If-Match/meetings/{id}/inviteesmeetings:read · R0 · single page/meetings/{id}/inviteesmeetings:write · R2 · external timezone required · Idempotency-Key/meetings/{id}/invitees/{invitee_id}meetings:write · R2 · Idempotency-Key/meetings/{id}/join-tokenmeetings:write · R1 · short-lived grant/meetings/{id}/endmeetings:write · R2 · artifacts · If-Match/meetings/{id}/recordingsmeeting_artifacts:read · R0/meetings/{id}/transcriptmeeting_artifacts:read · R0/meetings/{id}/summarymeeting_artifacts:read · R0/meetings/{id}/action-itemsmeeting_artifacts:read · R0/meetings/{id}/send-notes/eligibilitymeetings:write · R0 · policy check/meetings/{id}/send-notes/planmeetings:write · R2 · plan · Idempotency-Key/meetings/{id}/send-notesmeetings:write · R2 · 202 · Idempotency-Key/meetings/{id}/refresh-conferencemeetings:write · R1 · Idempotency-Key/performance/leaderboardanalytics:read · R0 · single page/performance/reps/{user_id}analytics:read · R0/coaching/templatescoaching:read · R0/coaching/templatescoaching:write · R1 · Idempotency-Key/coaching/templates/{id}coaching:write · R1 · If-Match · Idempotency-Key/coaching/sessionscoaching:read · R0 · cursor/coaching/sessionscoaching:write · R1 · Idempotency-Key/coaching/sessions/{id}coaching:read · R0/coaching/sessions/{id}/startcoaching:write · R1 · If-Match · Idempotency-Key/coaching/sessions/{id}/completecoaching:write · R1 · If-Match · Idempotency-Key/coaching/sessions/{id}/ai-insightscoaching:write · R2 · 202 · Idempotency-Key/closer-assist/sessionscoaching:read · R0 · cursor/closer-assist/sessions/{id}coaching:read · R0/roleplay/nichesroleplay:read · R0/roleplay/certificationsroleplay:read · R0/roleplay/certifications/{mode}/startroleplay:execute · R1 · If-Match · Idempotency-Key/roleplay/certifications/{mode}/completeroleplay:execute · R1 · If-Match · Idempotency-Key/roleplay/sessionsroleplay:execute · R2 · simulated/202 · Idempotency-Key/roleplay/sessionsroleplay:read · R0 · cursor/roleplay/sessions/{id}roleplay:read · R0/roleplay/sessions/{id}/messagesroleplay:execute · R2 · simulated/202 · Idempotency-Key/roleplay/sessions/{id}/endroleplay:execute · R2 · If-Match · Idempotency-Key/roleplay/sessions/{id}/scoreroleplay:read · R0/roleplay/sessions/{id}/scoreroleplay:execute · R2 · Idempotency-Key/supervisor/presencecoaching:read · R0 · owner/admin/supervisor/agents/{user_id}coaching:read · R0 · owner/admin/supervisor/agents/{user_id}/monitorcoaching:write · R2 · 202 · Idempotency-Key/supervisor/agents/{user_id}/monitor/endcoaching:write · R2 · Idempotency-Key/projectsprojects:read · R0 · offset/projectsprojects:write · R1 · Idempotency-Key/projects/{id}projects:read · R0 · project member/projects/{id}projects:write · R1 · admin · If-Match · Idempotency-Key/projects/{id}/archiveprojects:write · R1 · admin · If-Match · Idempotency-Key/projects/{id}/restoreprojects:write · R1 · admin · If-Match · Idempotency-Key/projects/{id}/membersprojects:read · R0 · member/projects/{id}/membersprojects:write · R1 · admin · If-Match · Idempotency-Key/projects/{id}/membersprojects:write · R1 · Idempotency-Key/projects/{id}/members/{user_id}projects:write · R1 · If-Match · Idempotency-Key/projects/{id}/members/{user_id}projects:write · R1 · Idempotency-Key/projects/{id}/columnsprojects:read · R0 · member/projects/{id}/columnsprojects:write · R1 · admin · Idempotency-Key/projects/{id}/columns/{column_id}projects:write · R1 · admin · If-Match · Idempotency-Key/projects/{id}/columns/{column_id}/archiveprojects:write · R1 · Idempotency-Key/projects/{id}/columns/reorderprojects:write · R1 · admin · If-Match · Idempotency-Key/projects/{id}/tasksprojects:read · R0 · offset/projects/{id}/tasksprojects:write · R1 · Idempotency-Key/projects/{id}/tasks/{task_id}projects:read · R0 · member/projects/{id}/tasks/{task_id}projects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/moveprojects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/archiveprojects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/assigneesprojects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/labelsprojects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/checklistprojects:write · R1 · Idempotency-Key/projects/{id}/tasks/{task_id}/checklist/{item_id}projects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/checklist/{item_id}projects:write · R1 · If-Match · Idempotency-Key/projects/{id}/tasks/{task_id}/commentsprojects:read · R0 · member/projects/{id}/tasks/{task_id}/commentsprojects:write · R1 · Idempotency-Key/projects/{id}/tasks/{task_id}/restoreprojects:write · R1 · Idempotency-Key/projects/{id}/labelsprojects:write · R1 · Idempotency-Key/projects/{id}/labels/{label_id}projects:write · R1 · Idempotency-Key/projects/{id}/labels/{label_id}projects:write · R1 · Idempotency-Key/projects/{id}/inviteprojects:write · R1 · Idempotency-Key/projects/my-tasksprojects:read · R0/projects/summaryprojects:read · R0/files/uploadsfiles:write · R1 · validated private intent · Idempotency-Key/files/{id}files:read · R0 · tenant-owned metadata/files/{id}/downloadfiles:read · R0 · resource-bound expiry/files/{id}/archivefiles:write · R1 · If-Match · Idempotency-Key/chat/userschat:read · R0/chat/roomschat:read · R0/chat/channelschat:write · R1 · admin · Idempotency-Key/chat/channels/{id}chat:read · R0 · room access/chat/channels/{id}chat:write · R1 · admin · If-Match · Idempotency-Key/chat/channels/{id}/archivechat:write · R1 · admin · If-Match · Idempotency-Key/chat/channels/{id}/memberschat:read · R0 · room access/chat/channels/{id}/memberschat:write · R1 · admin · Idempotency-Key/chat/channels/{id}/memberschat:write · R1 · Idempotency-Key/chat/channels/{id}/members/{user_id}chat:write · R1 · Idempotency-Key/chat/dmschat:write · R1 · human actor · Idempotency-Key/chat/rooms/{id}/messageschat:read · R0 · room access · cursor/chat/rooms/{id}/messageschat:write · R1 · client UUID · Idempotency-Key/chat/messages/{id}chat:write · R1 · authorship · If-Match · Idempotency-Key/chat/messages/{id}chat:write · R1 · authorship/admin · If-Match · Idempotency-Key/chat/messages/{id}/reactionschat:write · R1 · Idempotency-Key/chat/rooms/{id}/readchat:write · R1 · Idempotency-Key/chat/attachmentschat:write · R1 · Idempotency-Key/invoicesfinance:read · R0 · cursor/invoicesinvoices:write · R1 · draft · Idempotency-Key/invoices/{id}finance:read · R0/invoices/{id}invoices:write · R1 · If-Match · Idempotency-Key/invoices/{id}/issue/planinvoices:write · R2 · exact plan · Idempotency-Key/invoices/{id}/issueinvoices:write · R2 · approved plan · If-Match · Idempotency-Key/invoices/{id}/void/planinvoices:write · R3 · exact plan · Idempotency-Key/invoices/{id}/voidinvoices:write · R3 · approved plan · If-Match · Idempotency-Key/paymentsfinance:read · R0 · cursor/payments/{id}finance:read · R0/payments/record/planpayments:write · R2 · exact tenant payment plan · Idempotency-Key/paymentspayments:write · R2 · hosted/tokenized · Idempotency-Key/payments/{id}/refund/planpayments:write · R3 · exact plan · Idempotency-Key/payments/{id}/refundpayments:write · R3 · approved plan · If-Match · Idempotency-Key/subscriptionsfinance:read · R0 · cursor/subscriptions/{id}finance:read · R0/documentsfinance:read · R0 · cursor/documentsdocuments:write · R1 · draft · Idempotency-Key/documents/{id}finance:read · R0/documents/{id}/send/plandocuments:write · R2 · exact plan · Idempotency-Key/documents/{id}/senddocuments:write · R2 · approved plan · If-Match · Idempotency-Key/legal-template-catalogfinance:read · R0/legal-template-catalog/{id}finance:read · R0/legal-clausesfinance:read · R0/legal-clausesdocuments:write · R1 · Idempotency-Key/legal-clauses/{id}finance:read · R0/legal-clauses/{id}/versionsfinance:read · R0/legal-clauses/{id}/versionsdocuments:write · R1 · Idempotency-Key/legal-clauses/{id}/approvedocuments:write · R1 · Idempotency-Key/legal-clauses/{id}/usagefinance:read · R0/document-drafts/importdocuments:write · R1 · PDF/DOC/DOCX upload · Idempotency-Key/document-draftsdocuments:write · R0/document-drafts/{id}documents:write · R0/document-drafts/{id}documents:write · R1 · If-Match · Idempotency-Key/native-documents/{id}/edit-copydocuments:write · R1 · creates a new editable draft; the original and its evidence remain unchanged/document-drafts/{id}/sourcedocuments:write · R0 · canonical PDF/document-drafts/{id}/retry-conversiondocuments:write · R1 · Idempotency-Key/document-drafts/{id}/senddocuments:write · R1 · Idempotency-Key/document-content-blocksfinance:read · R0/document-content-blocksdocuments:write · R1 · Idempotency-Key/document-content-blocks/{id}documents:write · R1 · Idempotency-Key/document-commentsfinance:read · R0/document-commentsdocuments:write · R1 · Idempotency-Key/document-comments/{id}documents:write · R1 · Idempotency-Key/document-templatesfinance:read · R0/document-templatesdocuments:write · R1 · Idempotency-Key/document-templates/{id}finance:read · R0/document-templates/{id}documents:write · R1 · If-Match · Idempotency-Key/document-templates/{id}/previewfinance:read · R0/document-templates/{id}/versionsfinance:read · R0/document-templates/{id}/versionsdocuments:write · R1 · Idempotency-Key/document-templates/{id}/versions/{versionId}/pdf-layoutdocuments:write · R0 · MCP/document-templates/{id}/versions/{versionId}/source-pdfdocuments:write · R0 · private PDF bytes/document-templates/{id}/versions/{versionId}/preview-pdfdocuments:write · R0 · PDF bytes · MCP resourceVisual PDF versions use visible-page normalized coordinates and bind every source to its immutable template version. Supply expected_base_version_id and expected_base_content_hash when saving a layout; stale tabs receive 409 template_version_conflict. The source and preview endpoints return sanitized application/pdf bytes with private, no-store caching. MCP reads those bytes through authorized resources. Positioned variables overlay the PDF page and do not edit printed source text.
/document-templates/{id}/submit-reviewdocuments:write · R1 · Idempotency-Key/document-templates/{id}/approvedocuments:write · R1 · Idempotency-Key/document-templates/{id}/archivedocuments:write · R1 · Idempotency-KeyPrivate personnel contacts and agreements require an active delegated owner/admin user with documents:write. Service accounts cannot access them. They stay outside the sales CRM; private agreement identity is excluded from general document reads and sales webhooks. Profiles support actual work country/state, legal address, start date and commission-only or optional base pay. Standalone worker agreements require no earlier contract; employee/contractor templates must match the saved type. Preview/send check the saved contact version and approved template version/hash; recipient details cannot be overridden.
/private-contactsdocuments:write · delegated owner/admin/private-contactsdocuments:write · delegated owner/admin · Idempotency-Key/private-contacts/{id}documents:write · delegated owner/admin/private-contacts/{id}documents:write · delegated owner/admin · Idempotency-Key/private-contacts/{id}/documentsdocuments:write · delegated owner/admin/private-contacts/{id}/preview-pdfdocuments:write · delegated owner/admin/private-contacts/{id}/senddocuments:write · delegated owner/admin · Idempotency-Key/native-documentsfinance:read · R0/native-documentsdocuments:write · R1 · Idempotency-Key/native-documents/{id}finance:read · R0/native-documents/{id}/statusfinance:read · R0/native-documents/{id}/senddocuments:write · R1 · Idempotency-Key/native-documents/{id}/resenddocuments:write · R1 · Idempotency-Key/native-documents/{id}/voiddocuments:write · R1 · Idempotency-Key/native-documents/{id}/eventsfinance:read · R0/native-documents/{id}/evidencefinance:read · R0/native-documents/{id}/downloadfinance:read · R0/native-documents/{id}/retry-onboardingdocuments:write · R1 · Idempotency-Key/native-documents/{id}/billingfinance:read · R0/native-documents/{id}/billing/changesdocuments:write · R1 · Idempotency-Key/native-documents/{id}/billing/chargesdocuments:write · R1 · Idempotency-Key/native-documents/{id}/billing/charges/{charge_id}/issuedocuments:write · R1 · Idempotency-Key/native-documents/{id}/billing/charges/{charge_id}/mark-paiddocuments:write · R1 · Idempotency-Key/native-documents/{id}/billing/charges/{charge_id}/voiddocuments:write · R1 · Idempotency-Key/payment-settingsfinance:read · R0/payment-settingsdocuments:write · R1 · Idempotency-KeyFree document allowance: 20 documents per workspace per UTC calendar month, counted once when first sent, including all signers. Drafts and resends consume no extra slot; voiding does not refund a sent document. The legacy quota key signaturesPerMonth measures documents. A twenty-first send returns HTTP 402 with signature_quota_exceeded and used, limit, requested: 1, and reset_at details. For signing operations request documents:write; template and sent-document reads use finance:read. These scopes are not part of the default OAuth consent set. finance:read also grants invoice, payment and subscription reads; request it only when those broader reads are acceptable for the integration.
POST /native-documents accepts payment_method values stripe, bank_transfer, and none for billable workspace-sale agreements; an unknown explicit value returns 422 invalid_payment_method. Stripe creates a hosted invoice after all signatures; the other methods leave collection outside LeadTracker or skip payment. Signer-visible approved text, including proposal covers, is checked at send time. Stripe invoice or payment-link terms outside verified conditional wording return 422 template_payment_terms_conflict for a non-Stripe send. An imported PDF sent without Stripe requires source_terms_confirmed: true; without confirmation it returns 422 pdf_payment_terms_unverifiable. Standalone PDF, DOC and DOCX drafts use /document-drafts and collect signatures without a deal, Stripe connection or invoice. Their send request must confirm the displayed terms. Agreement lists include the recorded payment method. LeadTracker product-sale invoice requirements remain enforced.
Payment schedules. POST /native-documents supports every pricing model: a one-off amount (amount_setup), a recurring amount (amount_recurring, or the monthly amount_mrr) billed every week, month, quarter or year (billing_interval), or both. recurring_payments bills a fixed number of payments (an instalment plan) and Stripe ends the subscription after the last one; omit it to bill until cancelled. payment_due_days (1–90) sets each invoice's due date. line_items (description, unit amount, quantity, type one_time or recurring) itemise the price so every line appears on the Stripe invoice. currency defaults to the deal's currency; any two-decimal currency is accepted unless the template restricts it. The frozen schedule is printed on the agreement and available to templates as {{payment_schedule}}, {{billing_interval_label}}, {{amount_recurring}}, {{recurring_payments}}, {{amount_total_contract}} and {{line_items_text}}; {{amount_mrr}} is always the monthly value. Deals and MRR reporting record the monthly equivalent. Errors: invalid_billing_interval, invalid_recurring_payments, invalid_payment_due_days, invalid_line_items, line_items_total_mismatch, pricing_model_mismatch, currency_not_allowed, currency_not_supported.
Deposits, delayed starts, discounts and tax. one_time_plan splits the one-off price into payments on signing, on a date, or at a milestone (percent or amount each; they must add up exactly). recurring_start_date (or recurring_start_days) starts recurring billing later; recurring_payments: "term" bills exactly enough payments for contract_term_months; discount_percent with discount_applies_to bills the net price. Workspace defaults, tax (none, automatic — Stripe Tax calculates tax on each invoice from the client's billing details — or one fixed_rate), the tax ID printed on agreements and invoices, bank-transfer instructions and reminder cadence live in GET/PATCH /payment-settings.
After signing. GET /native-documents/{id}/billing returns the billing in force: schedule, state (paid, paused, cancelled, failed-payment dunning), upcoming charges, scheduled charges, payments, change history and the client's self-service billing link. POST …/billing/changes changes a live agreement (change_price, change_payments, pause, resume, cancel) in Stripe or, for bank transfer, for every invoice from now on — price, payment-count and cancel changes require customer_consent_confirmed: true. POST …/billing/charges adds a one-off charge; …/charges/{charge_id}/issue invoices a milestone or dated charge now, …/mark-paid records a bank-transfer payment (the first one marks the agreement paid and wins the deal), and …/void cancels an un-invoiced charge. Bank-transfer agreements get every invoice and reminder emailed automatically; Stripe-billed clients whose payment fails are emailed a link to update their card.
Every plan can brand the document itself: brand_key selects the workspace brand whose name, logo and colours appear on the signing page and the signed PDF. The envelope is paid — on the Free plan LeadTracker AI delivers the document on the sender's behalf ("<sender> via LeadTracker AI", replies to the sender) on the standard signing domain, and the signing page names the sender and offers a “Report this document” link; paid plans use the brand's verified signing domain and sending address. An omitted title defaults to the approved template's title followed by the client company, e.g. Non-Disclosure Agreement - Acme LLC. The client signer must enter their position when signing; it is printed under their name in the signature block.
/documents/{id}/evidencefinance:read · R0/documents/{id}/native-signing-linkdocuments:write · R1 · Idempotency-Key/deals/{deal_id}/documentsdocuments:read · R0/commissionscommissions:read · R0 · cursor/commissions/{id}commissions:read · R0/commissions/{id}commissions:write · R1 · If-Match · Idempotency-Key/commissions/{id}/approve/plancommissions:approve · R3 · exact plan/commissions/{id}/approvecommissions:approve · R3 · separate approver · Idempotency-Key/commissions/{id}/mark-paid/plancommissions:approve · R3 · exact plan/commissions/{id}/mark-paidcommissions:approve · R3 · separate approver · Idempotency-Key/commissions/bulk-mark-paid/plancommissions:approve · R3 · exact set/total plan/commissions/bulk-mark-paidcommissions:approve · R3 · separate approver · Idempotency-Key/phone-numbersphone_numbers:read · R0 · cursor/phone-numbers/{id}phone_numbers:read · R0/phone-numbers/searchphone_numbers:manage · R0 · provider read/phone-numbers/purchases/planphone_numbers:manage · R3 · plan/phone-numbers/purchasesphone_numbers:manage · R3 · approved · Idempotency-Key/phone-numbers/{id}/health-checkphone_numbers:manage · R2 · provider read/phone-numbers/{id}/health-historyphone_numbers:read · R0 · cursor/phone-numbers/local-presence-policyphone_numbers:read · R0/phone-numbers/local-presence-policyphone_numbers:manage · R2 · If-Match · Idempotency-Key/phone-numbers/{id}/replacement/planphone_numbers:manage · R3 · plan/phone-numbers/{id}/replacementphone_numbers:manage · R3 · approved · If-Match/phone-numbers/{id}/retire/planphone_numbers:manage · R3 · plan/phone-numbers/{id}/retirephone_numbers:manage · R3 · approved · If-Match/phone-numbers/{id}/quarantine/planphone_numbers:manage · R2 · plan/phone-numbers/{id}/quarantinephone_numbers:manage · R2 · If-Match · Idempotency-Key/receptionist/agentsreceptionist:read · R0 · cursor/receptionist/agentsreceptionist:write · R1 · Idempotency-Key/receptionist/agents/{id}receptionist:read · R0/receptionist/agents/{id}receptionist:write · R1 · If-Match · Idempotency-Key/receptionist/agents/{id}/activatereceptionist:write · R2 · If-Match/receptionist/agents/{id}/deactivatereceptionist:write · R2 · If-Match/receptionist/agents/{id}/config-versionsreceptionist:read · R0/receptionist/routesreceptionist:read · R0 · cursor/receptionist/routes/{phone_number_id}receptionist:write · R2 · If-Match · Idempotency-Key/receptionist/knowledge-sourcesreceptionist:read · R0 · cursor/receptionist/knowledge-sourcesreceptionist:write · R1 · Idempotency-Key/receptionist/knowledge-sources/{id}receptionist:read · R0/receptionist/knowledge-sources/{id}receptionist:write · R1 · If-Match · Idempotency-Key/receptionist/knowledge-sources/{id}/approvereceptionist:write · R2 · If-Match · Idempotency-Key/receptionist/agents/{id}/knowledgereceptionist:write · R1 · If-Match · Idempotency-Key/receptionist/sessionsreceptionist:read · R0 · cursor/receptionist/sessions/{id}receptionist:read · R0/receptionist/sessions/{id}/transcriptrecordings:read · R0/receptionist/sessions/{id}/handoffreceptionist:write · R2 · policy/usage gate/receptionist/analyticsanalytics:read · R0/formsforms:read · R0 · cursor/formsforms:write · R1 · Idempotency-Key/forms/{brand}forms:read/forms/{brand}forms:write · R1 · If-Match · Idempotency-Key/forms/{brand}/publishforms:write · R1 · If-Match · Idempotency-Key/forms/{brand}/unpublishforms:write · R1 · If-Match · Idempotency-Key/forms/{brand}/archiveforms:write · R1 · If-Match · Idempotency-Key/forms/{brand}/cloneforms:write · R1 · Idempotency-Key/forms/{brand}/serving-areaforms:write · R1 · Idempotency-Key · If-Match/forms/{brand}/revisionsforms:read · R0 · cursor/forms/{brand}/revisions/{revision_id}forms:read · R0/forms/{brand}/submissionsforms:submissions:read · R0 · cursor/forms/{brand}/submissions/{id}forms:submissions:read · R0/forms/{brand}/submissions/{id}/reviewforms:write · R1 · Idempotency-Key/forms/{brand}/analyticsanalytics:read · R0/forms/{brand}/eventsforms:submit · R1 · 204 · Idempotency-Key/forms/{brand}/submissionsforms:submit/public-linksforms:read · R0 · cursor/public-links/{id}forms:write · R1 · If-Match · Idempotency-Key/analytics/application-funnelanalytics:read/analytics/dashboardanalytics:read · R0/analytics/funnelanalytics:read · R0/analytics/sourcesanalytics:read · R0 · cursor/analytics/velocityanalytics:read · R0 · cursor/analytics/attributionanalytics:read · R0 · cursor/analytics/cohortsanalytics:read · R0 · cursor/analytics/paid-performancemarketing:read · R0 · cursor/analytics/creativesmarketing:read · R0 · cursor/analytics/unit-economicsmarketing:read · R0 · cursor/analytics/data-qualityanalytics:read · R0 · cursor/analytics/attendanceanalytics:read · R0 · cursor/analytics/leaderboardanalytics:read · R0 · cursor/analytics/exportsanalytics:export · R1 · 202 · Idempotency-Key/tracking/eventsforms:submit · R1 · 200/201 · Idempotency-Key/tracking/conversion-eventsforms:submit · R1 · 200/201 · Idempotency-Key/commerce/eventsforms:submit · R1 · 200/201 · Idempotency-Key/tracking/events/{event_id}analytics:read · R0/marketing/connectionsintegrations:read · R0 · cursor/marketing/connections/{provider}/authorizeintegrations:write · R1 · hosted OAuth · Idempotency-Key/marketing/connections/{provider}/callbackintegrations:write · R1 · state/PKCE/nonce-bound callback/marketing/authorizations/{id}integrations:read · R0 · redacted status/marketing/connections/{id}integrations:read · R0 · redacted/marketing/connections/{id}/syncforms:submit · R2 · queued/simulated · Idempotency-Key/marketing/connections/{id}/disconnect/planintegrations:write · R3 · exact plan · Idempotency-Key/marketing/connections/{id}/disconnectintegrations:write · R3 · approved/simulated · Idempotency-Key/marketing/goal-mappingsmarketing:read · R0 · cursor/marketing/goal-mappings/{provider}forms:submit · R1 · Idempotency-Key/marketing/consent-policiesmarketing:read · R0 · cursor/marketing/consent-policies/{brand_id}forms:submit · R2 · Idempotency-Key/marketing/tracking-gateway/{brand_id}marketing:read · R0/marketing/tracking-gateway/{brand_id}marketing:configure · R2 · plan-first · Idempotency-Key/marketing/tracking-block-rulesmarketing:read · R0 · cursor/marketing/tracking-block-rulesmarketing:configure · R1 · Idempotency-Key/marketing/tracking-block-rules/{id}marketing:configure · R1 · Idempotency-Key/marketing/recommendationsmarketing:read · R0 · cursor/marketing/recommendations/{id}marketing:read · R0/marketing/recommendations/{id}/reviewforms:submit · R1 · Idempotency-Key/marketing/recommendations/{id}/execute/planmarketing:execute · R2 · quality/plan gate/marketing/recommendations/{id}/executemarketing:execute · R2 · queued/simulated · Idempotency-Key/marketing/actions/{id}/rollback/planmarketing:execute · R3 · prior-state plan/marketing/actions/{id}/rollbackmarketing:execute · R3 · approved/simulated · Idempotency-Key/marketing/actionsmarketing:read · R0 · cursor/marketing/forecastsmarketing:read · R0 · freshness warnings · cursor/marketing/forecastsforms:submit · R2 · queued/simulated · Idempotency-Key/marketing/identity/unresolvedmarketing:read · R0 · cursor/marketing/identity/correctionsforms:submit · R1 · redacted · Idempotency-Key/growth/stategrowth:read · R0 · entitlement/growth/brandsgrowth:read · R0 · cursor/growth/brandsgrowth:write · R1 · Idempotency-Key/growth/brands/{id}growth:read · R0/growth/brands/{id}growth:write · R1 · If-Match/growth/brands/{id}/keyword-plannergrowth:read · R0/growth/brands/{id}/keyword-planner/accountsseo:configure · R0/growth/brands/{id}/keyword-plannerseo:configure · R1 · If-Match/growth/brands/{id}/assetsgrowth:write · R1 · bounded upload/growth/brands/{id}/assets/{role}growth:write · R1 · If-Match/growth/brands/{id}/topicsgrowth:read · R0 · cursor/growth/brands/{id}/topicsgrowth:write · R1 · Idempotency-Key/growth/brands/{id}/topics/suggestgrowth:generate · R2 · queued/simulated/growth/postsgrowth:read · R0 · cursor/growth/posts/generategrowth:generate · R2 · queued/simulated/growth/posts/{id}growth:read · R0/growth/posts/{id}growth:write · R1 · If-Match/growth/posts/{id}/enhancegrowth:generate · R2 · queued/simulated/growth/posts/{id}/approvegrowth:write · R1 · editorial only/growth/posts/{id}/rejectgrowth:write · R1 · editorial only/growth/posts/{id}/publish/plangrowth:publish · R3 · exact plan/growth/posts/{id}/publishgrowth:publish · R3 · approved/simulated/growth/posts/{id}/unpublish/plangrowth:publish · R2 · exact plan/growth/posts/{id}/unpublishgrowth:publish · R2 · approved/simulated/growth/metricsgrowth:read · R0/growth/brands/{id}/pipeline-healthgrowth:read · R0/growth/brands/{id}/index-healthseo:read · R0/growth/brands/{id}/niche-coverageseo:read · R0/growth/brands/{id}/cta-experimentsgrowth:read · R0/growth/brands/{id}/ai-visibilityseo:read · R0 · versioned evidence/growth/brands/{id}/backlinksseo:read · R0 · cursor/growth/brands/{id}/backlinks/{backlinkId}/reviewgrowth:write · R1 · If-Match/seo/connectionsseo:read · R0 · cursor/seo/connections/google/authorizeseo:configure · R1 · hosted OAuth/seo/connections/google/callbackseo:configure · R1 · state/PKCE/nonce-bound callback/seo/authorizations/{id}seo:read · R0 · redacted status/seo/connections/{id}/syncseo:configure · R2 · queued/simulated/seo/opportunitiesseo:read · R0 · cursor/seo/recommendationsseo:read · R0 · cursor/seo/google-updatesseo:read · R0/seo/recommendations/{id}/reviewseo:configure · R1 · If-Match/signalssignals:read · R0 · cursor/signals/{id}signals:read · R0/signals/{id}/convert-to-leadleads:write · R1 · idempotent conversion/prospect-packsleads:read · R0 · cursor/prospect-packs/requests/planleads:bulk · R3 · exact criteria/cost plan/prospect-packs/requestsleads:bulk · R3 · approved · queued/simulated/prospect-packs/requests/{id}leads:read · R0 · job state/usersusers:read · R0 · cursor/users/invitations/planusers:write · R1 · exact team_ids plan + approval/users/invitationsusers:write · R1 · 202 · Idempotency-Key/users/{id}users:read · R0/users/{id}users:write · R1 · If-Match · Idempotency-Key/users/{id}/disable/planusers:write · R3 · exact ownership/workload plan/users/{id}/disableusers:write · R3 · approved plan/users/{id}/enableusers:write · R1 · If-Match · Idempotency-Key/users/meusers:write · R1 · Idempotency-Key/teamsteams:read · R0 · cursor/teamsteams:write · R1 · Idempotency-Key/teams/{id}teams:read · R0/teams/{id}teams:write · R1 · If-Match · Idempotency-Key/teams/{id}/membersteams:write · R1 · tenant membership/teams/{id}/membersteams:write · R1 · Idempotency-Key/teams/{id}/members/{user_id}teams:write · R1 · Idempotency-Key/teams/{id}/archive/planteams:write · R1 · workload plan + approval/teams/{id}/archiveteams:write · R1 · workload/If-Match/workspaceworkspace:read · R0/workspaceworkspace:write · R1 · If-Match · Idempotency-Key/workspace/brandingworkspace:read · R0/workspace/brandingworkspace:write · R1 · allowlisted HTTPS logo/workspace/notification-policiesworkspace:read · R0 · typed/workspace/notification-policiesworkspace:write · R1 · typed destinations · If-Match or version · Idempotency-Key/workspace/usageworkspace:read · R0/workspace/entitlementsworkspace:read · R0/workspacesworkspace:read · agency-owned cursor/workspaces/planworkspace:write · R3 · exact plan/workspacesworkspace:write · R3 · approved/simulated/workspaces/{id}workspace:read · R0 · owned relationship/workspaces/{id}workspace:write · R1 · If-Match/workspaces/{id}/suspend/planworkspace:write · R3 · exact plan/workspaces/{id}/suspendworkspace:write · R3 · approved/simulated/domainsdomains:read · R0 · cursor/domainsdomains:write · R1 · Idempotency-Key/domains/{id}domains:read · R0/domains/{id}/verifydomains:write · R2 · 202 · Idempotency-Key/domains/{id}/remove/plandomains:write · R3 · exact plan/domains/{id}/removedomains:write · R3 · approved plan · 202/integrationsintegrations:read · R0 · opaque cursor · max 100/integrations/{provider}integrations:read · R0/integrations/{provider}/authorizeintegrations:write · R1 · server-bound OAuth state/integrations/{provider}/authorize/completeintegrations:write · R1 · bounded/redacted completion/integrations/{provider}/authorize/statusintegrations:read · R0 · redacted status/integrations/{provider}/syncintegrations:write · R2 · 202 · Idempotency-Key/integrations/{provider}/disconnect/planintegrations:write · R3 · exact plan/integrations/{provider}/disconnectintegrations:write · R3 · approved plan · 202/onboarding/stateworkspace:read · R0 · independent email_domains_cursor/integrations_cursor · max 100/onboarding/business-profileworkspace:write · R1 · If-Match/onboarding/texting-registrationworkspace:write · R3 · carrier plan/job/onboarding/texting-registrationworkspace:read · R0/onboarding/email-domainsdomains:write · R1 · Idempotency-Key/onboarding/email-domains/{id}/verifydomains:write · R2 · 202 · Idempotency-Key/settingsworkspace:read · R0 · typed/redacted/settingsworkspace:write · R1 · If-Match/billing/statebilling:read · R0/billing/usagebilling:read · R0 · minor units/billing/plansbilling:read · R0 · Free plan and upgrade links/billing/plan-changes/previewbilling:write · R3 · downgrade to Free only · Idempotency-Key/billing/plan-changesbilling:write · R3 · approved provider/simulation · 200 · Idempotency-Key/billing/topups/previewbilling:write · R3 · exact plan · Idempotency-Key/billing/topupsbilling:write · R3 · approved provider/simulation · 200 · Idempotency-Key/billing/portal-sessionsbilling:write · R1 · provider-hosted URL · Idempotency-Key/webhook-endpointsdeveloper:webhooks:read/webhook-endpointsdeveloper:webhooks:write/webhook-endpoints/{endpoint_id}developer:webhooks:read/webhook-endpoints/{endpoint_id}developer:webhooks:write/webhook-endpoints/{endpoint_id}developer:webhooks:write · R3 · policy · Idempotency-Key + If-Match/webhook-endpoints/{endpoint_id}/rotate-secretdeveloper:webhooks:write/webhook-endpoints/{endpoint_id}/deliveriesdeveloper:webhooks:read/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}developer:webhooks:read/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/retrydeveloper:webhooks:write/workflows/{workflowId}/triggerworkflows:trigger/jobsdomain read scope/jobs/{job_id}domain read scope/jobs/{job_id}/canceloriginating execute scope/approval-requestsapprovals:read/approval-requestsapprovals:request/approval-requests/{approval_request_id}approvals:read/approval-requests/{approval_request_id}/cancelapprovals:request/audit-eventsaudit:read/audit-events/{audit_event_id}audit:read/developer/scopesdeveloper:credentials:admin/service-accountsdeveloper:credentials:admin/service-accountsdeveloper:credentials:admin/service-accounts/{service_account_id}developer:credentials:admin/service-accounts/{service_account_id}developer:credentials:admin/service-accounts/{service_account_id}/rotatedeveloper:credentials:admin/service-accounts/{service_account_id}/disabledeveloper:credentials:admin/service-accounts/{service_account_id}/enabledeveloper:credentials:admin/service-accounts/{service_account_id}/credentialsdeveloper:credentials:admin/service-accounts/{service_account_id}/credentialsdeveloper:credentials:admin/service-accounts/{service_account_id}/credentials/{credential_id}developer:credentials:admin/tagstags:read/tagstags:write · R1 · Idempotency-Key/tags/{tag_id}tags:read/tags/{tag_id}tags:write · R1 · If-Match/tags/{tag_id}/archivetags:write · R1 · If-Match/leads/{lead_id}/tagstags:read/leads/{lead_id}/tagstags:write · R1 · Idempotency-Key/deals/{deal_id}/tagstags:read/deals/{deal_id}/tagstags:write · R1 · Idempotency-Key/custom-fieldscustom_fields:read/custom-fieldscustom_fields:write · R1 · Idempotency-Key/custom-fields/{field_id}custom_fields:read/custom-fields/{field_id}custom_fields:write · R1 · If-Match/custom-fields/{field_id}/archivecustom_fields:write · R1 · If-Match/leads/{lead_id}/custom-fieldscustom_fields:read/leads/{lead_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key/leads/deduplicateleads:write · R2 · Idempotency-Key/leads/notes/bulk-deleteleads:write · R1 · Idempotency-Key/leads/idsleads:read · R0 · Idempotency-Key/leads/pipelineleads:read · R0/leads/import/jsonleads:bulk · R1 · Idempotency-Key/leads/import/templateleads:bulk · R0/deals/{deal_id}/custom-fieldscustom_fields:read/deals/{deal_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key/smart-lists/filter-schemasmart_lists:read/smart-listssmart_lists:read · cursor/smart-listssmart_lists:write · R1 · Idempotency-Key/smart-lists/previewsmart_lists:write · R0 · Idempotency-Key/smart-lists/{id}smart_lists:read/smart-lists/{id}smart_lists:write · R1 · If-Match/smart-lists/{id}smart_lists:write · R1 · If-Match/smart-lists/{id}/leadsleads:read · cursor/pipelinespipelines:read/pipelinespipelines:write · R1 · Idempotency-Key/pipelines/{id}pipelines:read/pipelines/{id}pipelines:write · R1 · If-Match/pipelines/{id}/archivepipelines:write · R1 · If-Match/pipelines/{id}/stagespipelines:write · R1 · Idempotency-Key/pipelines/{id}/stages/{stage_id}pipelines:write · R1 · If-Match/pipelines/{id}/stages/{stage_id}/archivepipelines:write · R1 · If-Match/pipelines/{id}/stages/reorderpipelines:write · R1 · If-Match/dealsdeals:read · R0 · cursor/dealsdeals:write · R1 · Idempotency-Key/deals/{id}deals:read · R0/deals/{id}deals:write · R1 · If-Match/deals/{id}/movedeals:write · R1 · If-Match/deals/{id}/wondeals:write · R1 · If-Match/deals/{id}/lostdeals:write · R1 · If-Match/deals/{id}/reopendeals:write · R1 · If-Match/deals/{id}/archivedeals:archive · R1 · If-Match/deals/{id}/restoredeals:archive · R1 · If-Match/deals/{id}/activitiesdeals:read · R0 · cursor/deals/{id}/activitiesdeals:write · R1 · Idempotency-Key/deals/filter-schemadeals:read · R0/deals/querydeals:read · R0 · cursor · Idempotency-Key/pipelines/{id}/boarddeals:read · R0 · single page/pipelines/{id}/forecastanalytics:read · R0/taskstasks:read · R0 · cursor/taskstasks:write · R1 · Idempotency-Key/tasks/{id}tasks:read · R0/tasks/{id}tasks:write · R1 · If-Match/tasks/{id}/completetasks:write · R1 · If-Match/tasks/{id}/reopentasks:write · R1 · If-Match/tasks/{id}/archivetasks:write · R1 · If-Match/tasks/{id}tasks:write · R1 · If-Match/tasks/querytasks:read · R0 · Idempotency-Key/tasks/filter-schematasks:read · R0/task-summarytasks:read · R0/calendar/entriestasks:read · R0 · cursor/calendar/entries/{id}tasks:read · R0/calendar/entriestasks:write · R1 · Idempotency-Key/calendar/entries/{id}tasks:write · R1 · If-Match/calendar/entries/{id}tasks:write · R1 · If-Match/calendar/bootstraptasks:read · R0/calendar/feedtasks:read · R0/notifications/mentionsnotifications:read · R0/notifications/mentions/{id}/readnotifications:write · R1 · Idempotency-Key/notifications/mentions/read-allnotifications:write · R1 · Idempotency-Key/webhook-eventsdeveloper:webhooks:read · R0/saved-viewssaved_views:read · R0/saved-views/{id}saved_views:read · R0/saved-viewssaved_views:write · R1 · Idempotency-Key/saved-views/{id}saved_views:write · R1 · Idempotency-Key/saved-views/{id}saved_views:write · R1 · Idempotency-Key/saved-views/{id}/defaultsaved_views:write · R1 · Idempotency-Key/saved-views/reordersaved_views:write · R1 · Idempotency-KeyCalls and voice assets
Calls are workspace-scoped durable intents. A start request persists its operation and job before any Telnyx request, then applies DNC, international, caller-ID, usage, and human/policy gates. When external effects are disabled, the same request returns a deterministic simulation and never contacts a provider.
Recording, transcript, and summary reads require their dedicated scopes. Recordings are exposed only through resource-bound signed access with a bounded expiry; raw provider URLs and storage keys are never returned. Expired or mismatched grants fail closed.
/callsHuman or exactly approved policy context
GET/calls/{id}/recordingSigned, resource-bound recording access
POST/scripts/{id}/publishImmutable script version lifecycle
POST/voicemails/previewQueued or deterministic TTS preview
calls:read, calls:start, and calls:control; artifacts use recordings:read; script and voicemail assets use their matching scripts:* and voicemails:* scopes. Mutations require replay-safe Idempotency-Key headers.Call queues and supervisor floor
Call queues persist ordered lead work in the workspace and use the same call policy gates as direct dialing. Queue start creates durable operation/job intent before a provider request; external-effects-disabled environments return deterministic simulations. For filter-based or smart-list-based queues, use the two-step preview flow: POST /call-queues/preview returns the exact audience count (max 200 leads) and an HMAC-signed preview token; pass that token to POST /call-queues to create the queue without re-resolving the audience. Preview takes calls:read and requires exactly one of smart_list_id or filter. If the audience changed between preview and create, POST /call-queues fails with 409 count_mismatch rather than dialling a different set of people than the one you approved; preview again to get a fresh token.
Queue pause/resume requires the current If-Match version. Supervisor presence and monitor sessions are owner/admin-only; monitoring requires explicit consent, a short-lived resource-bound token, and replay-safe start/end mutations.
/call-queuesCursor-paginated queue list
POST/call-queues/previewPreview audience size and mint preview token
POST/call-queuesCreate queue from lead_ids or preview_token
POST/call-queues/{id}/start-nextPolicy-bound next-call job or simulation
POST/call-queues/{id}/pauseVersion-checked queue pause
GET/supervisor/presenceOwner/admin live-floor presence
POST/supervisor/agents/{user_id}/monitorConsent-bound monitor session
calls:read, calls:start, and calls:control; supervisor reads and monitor controls use coaching:read/coaching:write. Every mutation requires Idempotency-Key; no raw provider URL, storage key, or monitor credential is returned. POST /call-queues now accepts criteria.smart_list_id via the preview flow: call POST /call-queues/preview with smart_list_id or filter, then pass the returned preview_token to create.Phone numbers and AI receptionist
Phone inventory and receptionist configuration are workspace-owned resources. Phone purchases, replacements, and retirement are two-step R3 operations: create a server-side plan, then execute only the exact approved plan. Health checks, DNC/plan/usage gates, and disabled-effects simulation are enforced by the same service boundary used by the app.
Receptionist routes accept only phone numbers, calendars, event types, and knowledge sources owned by the authenticated workspace. Transcript reads require recordings:read; handoffs require paid-plan and AI-minute allowance checks and are simulated when external effects are disabled.
/phone-numbersPhone inventory and health
POST/phone-numbers/purchases/planPlan before provider mutation
POST/receptionist/agents/{id}/activateValidate and activate an agent
PUT/receptionist/routes/{phone_number_id}Assign a tenant-owned inbound route
phone_numbers:read/phone_numbers:manage for inventory and lifecycle; receptionist:read/receptionist:write for agents, routes, knowledge, and sessions; recordings:read for receptionist transcripts. Every write is replay-safe and returns only public resource/job references.Campaigns
Campaign definitions use the same typed steps, merge-field validation, suppression rules, audience compliance checks, usage gates, and trusted worker path as the application. Create a launch plan before execution: the server binds the exact audience, resource versions, projected usage/spend, and plan hash to an expiring operation.
Launch accepts only the server-issued operation reference and exact plan context. Thresholds create an approval request; modified campaign steps, versions, audience, or spend invalidate the plan. The API queues a durable job and disabled-effects mode deterministically simulates worker effects without contacting a provider.
/campaignsList tenant-owned definitions
POST/campaigns/{id}/launch/planPreview suppressions, usage, spend, and exact hashes
POST/campaigns/{id}/launchQueue the exact approved plan
GET/campaigns/{id}/analyticsRead aggregate delivery and outcome metrics
campaigns:read for definitions, steps, and enrollments; analytics:read for campaign analytics; campaigns:write for definition changes; and campaigns:execute for activation, audience enrollment, pause/resume, and launch. Every mutation requires Idempotency-Key; versioned changes also require If-Match.Meetings, coaching, and roleplay
Meetings are workspace-owned resources with explicit host/participant visibility. Create and control them through meetings:write; read scoped recording, transcript, summary, and action-item projections through meeting_artifacts:read. Join grants are one-way, audience-bound, hashed at rest, and expire within the server's short TTL.
POST /meetings requires title and starts_at (ISO-8601 with offset); duration_minutes (default 30), description, timezone, brand, meeting_type, host_user_id (defaults to the caller), location_type, invitees and metadata are optional. The legacy names scheduled_at and organizer_id are still accepted; sending both spellings with different values returns 400 invalid_request. Timestamps in meeting, invitee, artifact and roleplay responses are ISO-8601 strings. A rep-delegated token lists only meetings its person hosts or is invited to.
Meeting endings, note delivery, AI coaching insights, and synthetic roleplay create durable job/event intent before any provider work. With external effects disabled, jobs and responses are deterministic simulations and no provider or raw storage URL is exposed.
/meetingsHost/participant-safe meeting intent
POST/meetings/{id}/join-tokenShort-lived host/participant grant
GET/meetings/{id}/summaryArtifact-scope redacted summary
POST/meetings/{id}/send-notes/planEligibility, usage, and recipient-bound plan
POST/coaching/sessions/{id}/ai-insightsPaid-plan and usage-gated AI job
POST/roleplay/sessionsParticipant-bound synthetic simulation
meetings:read/meetings:write; artifacts use meeting_artifacts:read; performance uses analytics:read; coaching uses coaching:read/coaching:write; and synthetic practice uses roleplay:read/roleplay:execute. Every mutation is replay-safe; If-Match is required for versioned state transitions.Projects and private files
Projects expose tenant-owned boards, columns, tasks, checklists, comments, and membership. A held workspace scope is necessary but not sufficient: reads require project membership, while project writes and membership changes additionally require project-admin role checks.
File upload intents validate plain names, allowlisted MIME types, a 10 MiB maximum, checksums, and project/task ownership. File responses contain public metadata only; storage keys and provider credentials never cross the API boundary.
/projectsOffset-paginated workspace boards
PUT/projects/{id}/membersProject-admin membership replacement
POST/projects/{id}/tasksTask/checklist/comment lifecycle
POST/files/uploadsValidated private upload intent
GET/files/{id}/downloadShort-lived actor/resource-bound URL
projects:read/projects:write for boards and tasks, and files:read/files:write for file metadata and lifecycle. Mutations require Idempotency-Key; versioned writes require If-Match. Download grants expire and cannot be replayed across workspaces, file versions, or actors.Team chat
Team chat exposes workspace channels, direct messages, reactions, and read markers through the same credential and live-workspace gates as the rest of the Developer API. Room membership and message authorship remain additional authorization checks after workspace scope.
Human messages identify the authenticated workspace user. Service-account messages identify the credential actor and display name; request bodies cannot supply a human sender or impersonate another actor.
/chat/roomsList visible channels and DMs
POST/chat/channelsAdmin-only channel creation
POST/chat/rooms/{id}/messagesRetry-safe message send
PATCH/chat/messages/{id}Authorship-bound edit
POST/chat/messages/{id}/reactionsToggle an allowed reaction
chat:read for users, rooms, members, and message reads; use chat:write for channel, DM, message, reaction, and read-marker mutations. Every write requires Idempotency-Key; channel/message edits and deletes also require If-Match. Message sends require a caller-stable client_message_id, and attachment references must be actor-owned uploaded references with an allowlisted MIME type and size.Finance core
Finance core exposes tenant-owned invoices, payments, customer subscriptions, and document lifecycles. Amounts are always integer minor units paired with an exact ISO-4217 currency; floating-point money is never accepted.
Raw card and bank-account details are rejected before policy or persistence. Payment recording accepts only an existing tokenized method or opaque provider/hosted reference, and public responses omit hashes, tokens, provider metadata, and storage keys.
/invoicesSigned-cursor minor-unit invoices
POST/invoices/{id}/issue/planExact recipient/amount/version plan
POST/invoices/{id}/voidApproved R3 plan with If-Match
POST/paymentsHosted/tokenized authoritative record
POST/documents/{id}/sendApproved send plan and simulated provider job
finance:read; drafts use invoices:write or documents:write; payment records and refunds use payments:write. Every mutation requires Idempotency-Key. Issue, void, refund, and send executions require the exact server-generated plan, approval/policy context, and current If-Match version. When external effects are disabled, provider work is a deterministic simulation and no provider URL or raw storage key is returned.Commissions
Commission entries are tenant-owned calculations represented in integer minor units and exact ISO-4217 currencies. Corrections and payout controls never accept raw card or bank data.
Corrections are owner/admin-only and require If-Match. Approval and mark-paid plans bind the workspace, entry IDs, versions, calculation hashes, total, and currency. Execution requires a separate approver; stale plans and approval mismatches fail closed.
/commissionsCursor-paginated commission entries
PATCH/commissions/{id}Owner/admin correction with If-Match
POST/commissions/{id}/approve/planExact R3 approval plan
POST/commissions/bulk-mark-paid/planExact set/total mark-paid plan
POST/commissions/bulk-mark-paidSeparate-approver simulated execution
commissions:read for reads, commissions:write for corrections, and commissions:approve for R3 plans/execution. Every mutation requires Idempotency-Key. Disabled effects return deterministic simulated jobs/events and never expose provider URLs, storage keys, card data, or bank data.Tasks and personal/team calendars
CRM tasks remain backed by lead_tasks; project work is a separate resource. Assignments are checked against active human workspace membership, while service accounts remain creator identities only.
Send Idempotency-Key on every mutation and the current ETag as If-Match on updates, state changes, and deletes. Task collections and calendar entry lists return opaque cursors.
Bounded CRM imports and exports
Move CRM data through bounded, tenant-safe jobs. Imports accept only CSV or TSV files with explicit allowlisted mappings; exports select an explicit public lead projection and produce an expiring artifact.
Import validation returns a five-row preview and field-level errors in a 202 job response. Commit is a separate replay-safe job and resolves ownership from the authenticated actor or active workspace owner/admin; callers cannot supply a user ID.
/leads/importsUpload, validate, and preview
GET/leads/imports/{job_id}Read validation state
POST/leads/imports/{import_id}/commitQueue the validated commit
POST/leads/exportsQueue a CSV export
GET/leads/exports/{artifact_id}Inspect artifact metadata
GET/leads/exports/{artifact_id}/downloadAudit an artifact download
/leads/importsleads:bulk · R1 · 202Send multipart/form-data with a required file and optional JSON mappings object. Files are limited to 10 MiB, 64 columns, and 1000 data rows. Unknown headers, destinations, duplicate headers, and duplicate mappings fail closed. Each row needs contact_name or company_name, and contact_email or phone_number. POST /leads/import/json takes the same mappings (plus an optional source) for up to 500 JSON rows.
| Field | Type | Contract |
|---|---|---|
| file required | CSV/TSV | UTF-8 upload; raw bytes are parsed and not retained by the public response. |
| mappings | JSON object | Source header to a field from GET /leads/import/template such as contact_email or contact_name. phone_line_type takes mobile, mobile_ported, voip, voip_mobile, landline, tollfree or unknown (normalised like the in-app importer, so unrecognised values are stored as unknown); imported leads with mobile or mobile_ported appear under the Wireless verified filter. custom:<definition_id> fills an active contact custom field from GET /custom-fields?scope=contact, using the same cell rules as the in-app importer (numbers as decimals, multi-select as ;-separated options). Custom-field targets also require the custom_fields:write scope, at validation and at commit. |
| Idempotency-Key required | header | 8–200 URL-safe characters; replay returns the original 202 response. |
curl https://leadtrackerai.com/api/v1/leads/imports \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Idempotency-Key: crm-import-20260815-01" \ -F "file=@leads.csv;type=text/csv" \ -F 'mappings={"email":"contact_email","name":"contact_name","Line type":"phone_line_type","Priority":"custom:12"}'
{
"data": {
"job_id": "job_01JIMPORT",
"status": "succeeded",
"resource_type": "lead_import",
"resource_id": "imp_01JIMPORT",
"simulated": true,
"import": { "counts": { "rows": 1, "valid": 1 } }
}
}invalid_file, unsupported_media_type, unknown_field, duplicate_header, duplicate_mapping, missing_name, missing_identity, invalid_email, invalid_phone, invalid_stage, invalid_custom_field_value, and bounded row/file limit errors are returned with safe details. A mapping to an unknown, archived or deal-scope custom field is 400 unknown_field./leads/imports/{import_id}/commitleads:bulk · R1 · 202Send an empty JSON object with a new Idempotency-Key to queue the commit. The worker uses workspace-qualified email/phone duplicate checks and tenant RLS. Imported leads follow the normal assignment rules: the workspace setter pool round-robin picks each setter (as for POST /leads without an assignee), closers are assigned at booking, and the acting user is recorded as the creator. A second request with the same key replays the original job envelope; a different payload with that key returns 409 idempotency_key_reused.
/leads/exportsanalytics:export · R1 · 202Provide 1–1000 explicit lead IDs and 1–32 fields from the public projection. The query is always workspace-qualified. Only bounded CSV is supported; generated files are capped at 8 MiB and stored as expiring artifact metadata.
curl https://leadtrackerai.com/api/v1/leads/exports \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Idempotency-Key: crm-export-20260815-01" \ -H "Content-Type: application/json" \ -d '{"lead_ids":[2194],"fields":["id","name","email","company"],"format":"csv"}'
{
"data": {
"job_id": "job_01JEXPORT",
"status": "queued",
"resource_id": "art_01JEXPORT",
"artifact": { "status": "pending", "download_url": null }
}
}workspace_id, credential data, internal provider columns, storage keys, raw URLs, or an unbounded Excel buffer./leads/exports/{artifact_id}analytics:export · R0Inspect status, projection, row and byte counts, checksum, simulated mode, download count, and expiry. The artifact is workspace-scoped and returns 410 artifact_expired after expiry.
/leads/exports/{artifact_id}/downloadanalytics:export · R0 · auditedThe download request is authenticated, workspace-qualified, expiry-checked, and audit-recorded. It returns explicit artifact metadata while the bounded artifact worker handles storage delivery; pending artifacts return 409 resource_not_ready.
Booking brands
Single-brand workspaces are configured automatically. Each workspace exposes its own tenant-configured brands and routes person-less bookings through that brand's Calendar Round Robin; the API does not use a fixed list of product brands.
When exactly one active brand owns the event type, LeadTracker selects it automatically and brand_id may be omitted. Multi-brand workspaces must send the intended numeric brand_id from GET /scheduling/brands.
/scheduling/brandsList booking brand IDs and allowed event types
GET/scheduling/event-typesInspect event types and their brands
GET/scheduling/availabilityCheck the chosen brand and event type
POST/scheduling/bookingsCreate under that exact brand
/scheduling/brandsscheduling:readReturns only active booking brands owned by the API key's workspace. identifier is the human-readable slug shown in the app; id is the numeric value to send as brand_id.
curl https://leadtrackerai.com/api/v1/scheduling/brands \
-H "Authorization: Bearer $LEADTRACKER_API_KEY"{
"data": [{
"id": 17,
"identifier": "acme-consulting",
"name": "Acme Consulting",
"event_type_ids": [42],
"routing_mode": "round_robin",
"active_calendar_count": 2
}]
}Event types
Fetch the booking types available in the authenticated workspace. Every event type includes its allowed brand records; use a matching brand.id and event type ID when retrieving availability or creating a booking.
/scheduling/brandsInspect the resolved booking brand
GET/scheduling/event-typesList active event types
GET/scheduling/availabilityRead live availability
POST/scheduling/bookingsCreate a booking
/scheduling/event-typesscheduling:readReturns active event types and their scheduling constraints.
curl https://leadtrackerai.com/api/v1/scheduling/event-types \
-H "Authorization: Bearer $LEADTRACKER_API_KEY"{
"data": [{
"id": 42,
"title": "Discovery Call",
"duration_minutes": 30,
"timezone": "America/New_York",
"booking_window_days": 14,
"brands": [{
"id": 17,
"identifier": "acme-consulting",
"name": "Acme Consulting"
}]
}]
}Availability
Slots are returned as UTC ISO 8601 timestamps. Convert them to the caller's local time in your voice experience, then pass the selected UTC start time when booking.
/scheduling/availabilityscheduling:read| Query parameter | Type | Description |
|---|---|---|
| brand_id | integer | Optional when the event type has exactly one active brand. Required when more than one brand is possible. |
| event_type_id required | integer | An ID returned by the event types endpoint. |
| start_date required | YYYY-MM-DD | First calendar date to inspect. |
| end_date required | YYYY-MM-DD | Last calendar date to inspect. Ranges may be up to 31 days. |
| routing_key | string | A stable call/conversation ID (8-200 URL-safe characters). Reuse it when creating the booking so availability and booking stay on the same round-robin calendar. If omitted, the response generates one that you must reuse. |
| closer_user_id | integer | Optional known LeadTracker user. If that active closer belongs to the brand pool, they remain pinned instead of consuming a round-robin turn. |
curl "https://leadtrackerai.com/api/v1/scheduling/availability?brand_id=17&event_type_id=42&start_date=2026-08-17&end_date=2026-08-21&routing_key=vapi-call-6d9f08b2" \ -H "Authorization: Bearer $LEADTRACKER_API_KEY"
{
"data": {
"event_type_id": 42,
"routed_event_type_id": 81,
"brand_id": 17,
"brand": { "id": 17, "identifier": "acme-consulting", "name": "Acme Consulting" },
"routing_mode": "round_robin",
"routing_key": "vapi-call-6d9f08b2",
"timezone": "America/New_York",
"slots": [{
"start": "2026-08-17T14:00:00.000Z",
"end": "2026-08-17T14:30:00.000Z"
}]
}
}Create a booking
LeadTracker AI validates the brand/event-type pair, creates a CRM lead or links an exact existing identity, performs a final conflict check, creates the correctly branded native meeting room, writes the connected calendar event, starts reminder delivery, and sends the normal Telegram booking notification. Identity matching is scoped to the API key’s workspace: the same email or phone may exist independently in another workspace. Create-style booking intake never edits an existing lead’s contact, location, or timezone; conflicting identity details return 409 lead_identity_conflict, while unresolved legacy collisions return 409 ambiguous_lead_identity.
/scheduling/bookingsscheduling:write| Body field | Type | Description |
|---|---|---|
| brand_id | integer | Optional when the event type has exactly one active brand. For multi-brand workspaces, reuse the explicit value sent to availability. |
| event_type_id required | integer | The active LeadTracker AI event type. |
| routing_key | string | The exact key used for availability. When booking directly without an availability lookup, omit it and the Idempotency-Key becomes the round-robin key. |
| closer_user_id | integer | Optional known closer override. Otherwise an existing active lead closer is preserved, then the brand round robin is used. |
| start required | ISO 8601 UTC | The exact slot start returned by availability. |
| attendee.name required | string | Prospect name. |
| attendee.email or attendee.phone required | string | At least one contact method. Phone is recommended for SMS reminders. |
| attendee.timezone required | Canonical IANA timezone | For example America/Chicago or Asia/Dubai. Fixed aliases such as EST and numeric offsets are rejected. |
| source | string | Your integration label, such as vapi or retell. |
| external_reference | string | Your call, conversation, or booking identifier for reconciliation. |
| metadata | object | Optional integration context, stored with the booking. Maximum 16 KB. |
curl -X POST https://leadtrackerai.com/api/v1/scheduling/bookings \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Idempotency-Key: vapi-call-6d9f08b2" \ -H "Content-Type: application/json" \ -d '{ "brand_id": 17, "event_type_id": 42, "routing_key": "vapi-call-6d9f08b2", "start": "2026-08-17T14:00:00.000Z", "attendee": { "name": "Avery Chen", "email": "avery@northstar.example", "phone": "+15125550123", "timezone": "America/Chicago", "company": "Northstar Health", "location": "Austin, TX" }, "source": "vapi", "external_reference": "call_01J123", "metadata": { "agent": "inbound-sales" } }'
{
"data": {
"id": "ltbk_9c7bd1...",
"status": "scheduled",
"brand_id": 17,
"brand": { "id": 17, "identifier": "acme-consulting", "name": "Acme Consulting" },
"routing_mode": "round_robin",
"routing_key": "vapi-call-6d9f08b2",
"start": "2026-08-17T14:00:00.000Z",
"end": "2026-08-17T14:30:00.000Z",
"meeting_url": "https://leadtrackerai.com/meet/...",
"lead_id": 2194
},
"duplicate": false,
"lead_created": true
}The customer confirmation is sent to attendee.email. A separate internal message labelled “Organizer notification” is sent to the exact connected calendar account (falling back to the host's login email only when needed). Seeing prospect details in the organizer message does not mean the customer confirmation was sent to the organizer. Replying to the organizer message goes to the attendee; replying to the customer confirmation goes to the organizer.
routing_key and Idempotency-Key. Availability and booking then stay pinned to one native calendar, and a replay returns 200 with duplicate: true instead of advancing the pool or creating another appointment.List bookings
Use the collection endpoint to reconcile bookings created by the API or the LeadTracker AI app. Results are always limited to the authenticated API key’s workspace and can be narrowed by attendee email, status, or the legacy from/to date filters.
/scheduling/bookingsscheduling:read| Query field | Type | Description |
|---|---|---|
| Exact attendee email filter. | ||
| status | string | Booking status filter, such as scheduled or cancelled. |
| from | string | Lower date/time bound in the existing scheduler filter format. |
| to | string | Upper date/time bound in the existing scheduler filter format. |
curl "https://leadtrackerai.com/api/v1/scheduling/bookings?status=scheduled" \
-H "Authorization: Bearer $LEADTRACKER_API_KEY"{
"data": [{
"id": "ltbk_9c7bd1...",
"status": "scheduled",
"brand_id": 17,
"event_type_id": 42,
"start": "2026-08-17T14:00:00.000Z",
"end": "2026-08-17T14:30:00.000Z",
"attendee": { "name": "Avery Chen", "email": "avery@example.com" }
}]
}Read a booking
/scheduling/bookings/{booking_id}scheduling:readUse the LeadTracker AI booking ID returned when an appointment is created. The record is only accessible within the API key's workspace.
curl https://leadtrackerai.com/api/v1/scheduling/bookings/ltbk_9c7bd1... \
-H "Authorization: Bearer $LEADTRACKER_API_KEY"Reschedule a booking
/scheduling/bookings/{booking_id}/reschedulescheduling:writeLeadTracker AI validates the requested slot again, updates the connected calendar event and native meeting, and re-evaluates reminder delivery.
{
"start": "2026-07-16T16:00:00.000Z",
"reason": "Caller requested a later time"
}Cancel a booking
/scheduling/bookings/{booking_id}/cancelscheduling:writeCancelling removes the provider event when connected, stops pending reminders, clears the active appointment from the CRM lead, and retains the booking history.
{
"reason": "Prospect cancelled during the call"
}Leads
Use the CRM endpoints to identify a caller, create or update a contact, and add durable notes or activities. Email and phone identity checks are workspace-scoped, so two workspaces can independently own the same details; a conflicting email/phone pair in one workspace fails closed for review. They expose a deliberately small CRM-safe field set: no deletion, assignment, campaign enrollment, billing, or bulk export operations are available.
pending_dm, setter, closer, closed, dormant. WRITE operations (create, update, upsert, import) accept only the three user-settable stages: pending_dm, setter, closer. The application writes closed and dormant internally via scoring and lifecycle rules (server/routes/scoring.js). This asymmetry prevents external integrations from bypassing internal stage transitions while allowing filters and reporting to see all stages./leads?filter=...&sort=...List leads with optional structured filter and sort/leads/queryQuery leads with structured filter document/leads/search?q=... | email=... | phone=...Find a specific lead/leads/{lead_id}Read one lead/leads | /leads/upsertCreate or match a lead/leads/{lead_id}Update CRM-safe fields/leads/{lead_id}/notes | /activitiesAdd CRM history/leads/search intentionally keeps its q/email/phone contract and does not accept filter documents. POST /leads/query is a read, but like /smart-lists/preview it is idempotency-keyed: send an Idempotency-Key header (or an idempotency_key body field) and repeating the same key replays the exact page you already received with Idempotent-Replayed: true. The request body must be a JSON object; unknown body fields are rejected with unknown_field, and a serialized filter over 8192 bytes returns 413 filter_too_large./leads/queryleads:readQuery workspace leads using a structured filter document (all/any/not groups, relationship predicates, search grammar, relative dates), multi-field sort, and deterministic cursor pagination. The filter document is validated against GET /smart-lists/filter-schema (version 2).
Filter document: Supports up to 60 filter rules, depth 3 nesting, all/any/not logic. NULL-safe negation: neq uses IS DISTINCT FROM, not_in adds OR IS NULL. Maximum filter document size 16KB.
Relationship fields: tags, custom:<definition_id>, calls, calls.last_at, tasks, tasks.next_due, notes, appointment, appointment.at.
Virtual fields: contact_type, safe_email, verified_mobile, verified_owner, wireless_verified.
Three different "verified" questions — do not conflate them. verified_owner means the lead's owner name was verified. verified_mobile is a provenance test on source (Lucy Verified Mobile%). wireless_verified is about the phone line: it is true when phone_line_type is mobile or mobile_ported, i.e. a carrier lookup put the number on a mobile network. It says nothing about who owns the number, and voip_mobile is deliberately excluded — a VoIP-allocated number reporting a mobile network is a softphone or a forwarding line, not a carrier handset. Leads that were never checked have a null phone_line_type and are returned by wireless_verified = false.
Search grammar: field='search', operator='matches', value='query string with -negation "phrases" prefix:filters'. Prefixes: name:, email:, phone:, company:, domain:, tag:, source:.
Sort: Up to 3 sort fields. NULLS LAST applied server-side. Final tiebreaker is always (id ASC).
Errors: invalid_filter, filter_too_large, invalid_sort, invalid_cursor, unknown_field.
curl -X POST https://leadtrackerai.com/api/v1/leads/query \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "version": 2, "all": [ { "field": "stage", "operator": "in", "value": ["setter", "closer"] }, { "field": "lead_score", "operator": "gte", "value": 70 }, { "any": [ { "field": "tags", "operator": "has_any", "value": [5, 12] }, { "field": "created_at", "operator": "in_last", "value": { "n": 7, "unit": "days" } } ] }, { "not": { "field": "contact_email", "operator": "contains", "value": "gmail.com" } } ] }, "sort": [ { "field": "lead_score", "dir": "desc" }, { "field": "created_at", "dir": "desc" } ], "limit": 100 }'
curl -X POST https://leadtrackerai.com/api/v1/leads/query \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "version": 2, "all": [ { "field": "search", "operator": "matches", "value": "acme -gmail \"jane doe\" tag:vip" } ] } }'
/leads?filter=...&sort=...leads:readGET /leads now accepts optional filter (JSON-encoded LeadFilterDocument, URL-encoded, max 8192 bytes) and sort (comma-separated field:dir pairs, e.g. lead_score:desc,contact_name:asc, max 3 fields) query parameters. For complex filters or request body convenience, use POST /leads/query instead.
The two request styles are mutually exclusive: when filter or sort is present, the legacy q, email, phone and stage parameters are rejected with 400 invalid_request (express them as filter rules) instead of being silently ignored, and any other unknown parameter returns 400 unknown_field. status and include_archived work in both styles and merge with the filter document: archived leads are excluded unless include_archived=true or status=archived, and each row carries its real status, archived_at and version, so the version stays usable as an If-Match precondition. Cursors are signed and bound to the workspace, route, resolved sort order and normalized filter, so replaying a cursor under a different filter or sort returns 400 invalid_cursor.
curl "https://leadtrackerai.com/api/v1/leads?sort=lead_score:desc&limit=50" \
-H "Authorization: Bearer $LEADTRACKER_API_KEY"/leads/upsertleads:writeProvide an email or phone to match an existing record. Every lead mutation requires Idempotency-Key.
curl -X POST https://leadtrackerai.com/api/v1/leads/upsert \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Idempotency-Key: voice-call-01JABC" \ -H "Content-Type: application/json" \ -d '{ "name": "Avery Chen", "email": "avery@northstar.example", "phone": "+15125550123", "company": "Northstar Health", "timezone": "America/Chicago", "source": "retell", "attribution": { "utm_source": "partner" } }'
Tags and custom fields
CRM taxonomy is workspace-scoped and uses the same API-key or delegated OAuth boundary as leads. Reads require a tags:read or custom_fields:read scope; mutations require the matching write scope, an Idempotency-Key, and If-Match on versioned definition updates and archives.
/tagstags:read · R0 · cursor/tagstags:write · R1 · Idempotency-Key/tags/{tag_id}tags:read · R0/tags/{tag_id}tags:write · R1 · Idempotency-Key + If-Match/tags/{tag_id}/archivetags:write · R1 · Idempotency-Key + If-Match/leads/{lead_id}/tagstags:read · R0/leads/{lead_id}/tagstags:write · R1 · Idempotency-Key/deals/{deal_id}/tagstags:read · R0/deals/{deal_id}/tagstags:write · R1 · Idempotency-Key/custom-fieldscustom_fields:read · R0 · cursor/custom-fieldscustom_fields:write · R1 · Idempotency-Key/custom-fields/{field_id}custom_fields:read · R0/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key + If-Match/custom-fields/{field_id}/archivecustom_fields:write · R1 · Idempotency-Key + If-Match/leads/{lead_id}/custom-fieldscustom_fields:read · R0/leads/{lead_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key/deals/{deal_id}/custom-fieldscustom_fields:read · R0/deals/{deal_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key| Contract | Exact behavior | Error taxonomy |
|---|---|---|
| Reads | R0, no idempotency header; list endpoints use opaque cursor pagination. | invalid_api_key, invalid_access_token, insufficient_scope, resource_access_denied, invalid_request, invalid_cursor, resource_not_found, rate_limited |
| Mutations | R1, required Idempotency-Key; create replays return 201 and updates return 200. Versioned writes require current If-Match. | invalid_request, unknown_field, idempotency_key_required, invalid_idempotency_key, idempotency_key_reused, approval_pending, resource_archived, resource_in_use, precondition_required, version_conflict, idempotency_unavailable |
| Tenant safety | Lead and deal IDs are checked against the credential workspace before reads or writes; foreign records are concealed as not found. | resource_not_found is never a cross-workspace disclosure. |
curl -X PUT https://leadtrackerai.com/api/v1/leads/2194/tags \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: lead-tags-01JABC" \ -H "Content-Type: application/json" \ -d '{"tag_ids":[12,19]}'
curl -X POST https://leadtrackerai.com/api/v1/custom-fields \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: field-01JABC" \ -H "Content-Type: application/json" \ -d '{"scope":"contact","key":"plan","label":"Plan","type":"select","options":["starter","team"]}'
Smart lists
Smart lists are saved, bounded lead filters. The filter schema is read-only metadata; creation, preview, update, and archive use smart_lists:write, R1/R0 as shown, and replay-safe idempotency. The lead projection requires leads:read.
Filter schema version 2 adds categories, value_kind, relationship fields (tags, custom fields, calls, tasks, notes, appointment), virtual fields (contact_type, safe_email, verified_mobile, verified_owner, wireless_verified), and search rule grammar to the GET /smart-lists/filter-schema response. Filters use the same validator and SQL compilation as the UI saved views and POST /leads/query.
niche is the one governed, user-facing Business category slug (for example dental or real-estate). Its picker options are assembled for the credential's current workspace: the default catalog plus that workspace's active additions. Manual CRM entry and lead enrichment create categories through the same workspace-bound resource; a category created in one workspace is never copied into another. industry is retained only as raw source evidence and for existing saved filters, not as a second user-facing category. Use Business category equality for a category spanning vendor labels such as Dentist and Dentistry. A document's top-level all conditions are ANDed with its any group. The same document semantics apply to the CRM, API, SDKs and MCP tools. Enrichment uses specific row industry evidence before a conflicting batch category, preserves valid specialist categories under broad industries, and leaves existing populated CRM classifications for evidence-based review and repair.
SmartList schema extensions: kind ('segment' | 'view', default 'segment'), sort (array of {field, dir}, max 3), view_state ({columns, hidden, density, page_size}, max 8KB, validated against shared column registry). Saved views support column layout persistence, density, and custom ordering.
/smart-lists/filter-schemasmart_lists:read · R0 · schema v2/smart-listssmart_lists:read · R0 · cursor/smart-listssmart_lists:write · R1 · Idempotency-Key/smart-lists/previewsmart_lists:write · R0 · Idempotency-Key/smart-lists/{id}smart_lists:read · R0/smart-lists/{id}smart_lists:write · R1 · Idempotency-Key + If-Match/smart-lists/{id}smart_lists:write · R1 · Idempotency-Key + If-Match/smart-lists/{id}/leadsleads:read · R0 · cursorinvalid_filter, invalid_cursor, resource_not_found, or smart_list_not_found; mutations additionally return duplicate_smart_list, role_denied, precondition_required, version_conflict, idempotency_key_reused, or idempotency_unavailable. All routes also use the shared authentication, scope, tenant, and rate-limit taxonomy.curl -X POST https://leadtrackerai.com/api/v1/smart-lists/preview \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: preview-01JABC" \ -H "Content-Type: application/json" \ -d '{"filters":{"match":"all","rules":[{"field":"stage","operator":"eq","value":"setter"}]}}'
Pipelines and stages
Pipeline configuration is workspace-scoped and admin-role guarded in addition to the pipelines:read/pipelines:write scope. Every mutation is R1, requires Idempotency-Key, and stage/pipeline updates, archives, and reorders require If-Match.
/pipelinespipelines:read · R0/pipelinespipelines:write · R1 · Idempotency-Key/pipelines/{id}pipelines:read · R0/pipelines/{id}pipelines:write · R1 · Idempotency-Key + If-Match/pipelines/{id}/archivepipelines:write · R1 · Idempotency-Key + If-Match/pipelines/{id}/stagespipelines:write · R1 · Idempotency-Key/pipelines/{id}/stages/{stage_id}pipelines:write · R1 · Idempotency-Key + If-Match/pipelines/{id}/stages/{stage_id}/archivepipelines:write · R1 · Idempotency-Key + If-Match/pipelines/{id}/stages/reorderpipelines:write · R1 · Idempotency-Key + If-Matchpipeline_not_found, stage_not_found, insufficient_role, resource_archived, resource_in_use, precondition_required, version_conflict, idempotency_key_reused, and idempotency_unavailable, plus shared authentication, scope, request, and rate-limit errors.curl -X POST https://leadtrackerai.com/api/v1/pipelines/7/stages \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: stage-01JABC" \ -H "Content-Type: application/json" \ -d '{"name":"Qualified","position":2,"color":"#22d3ee"}'
Deals and forecast
Deals are workspace-scoped pipeline records linked to a lead. Read operations require deals:read (or analytics:read for forecast); create, update, transition, and activity writes require deals:write; archive and restore additionally require deals:archive. All deal mutations are R1, require a stable Idempotency-Key, and versioned writes require the current If-Match value.
/dealsdeals:read · R0 · cursor/dealsdeals:write · R1 · Idempotency-Key/deals/{id}deals:read · R0/deals/{id}deals:write · R1 · If-Match/deals/{id}/movedeals:write · R1 · If-Match/deals/{id}/wondeals:write · R1 · If-Match/deals/{id}/lostdeals:write · R1 · If-Match/deals/{id}/reopendeals:write · R1 · If-Match/deals/{id}/archivedeals:archive · R1 · If-Match/deals/{id}/restoredeals:archive · R1 · If-Match/deals/{id}/activitiesdeals:read · R0 · cursor/deals/{id}/activitiesdeals:write · R1 · Idempotency-Key/pipelines/{id}/boarddeals:read · R0 · single page/pipelines/{id}/forecastanalytics:read · R0value.amount_minor as a non-negative integer and value.currency as an uppercase three-letter ISO-4217 code. Inputs may use value.amount_minor or a decimal string in amount, never a floating-point value. Decimal precision follows the currency: USD uses two places, JPY uses zero, and currencies such as BHD, JOD, and KWD use three. Forecast totals remain integer minor units and are never calculated through binary floating point.GET /pipelines/{id}/forecast defaults to the current month in the workspace's IANA timezone. Use from, to, include_overdue, and the existing structured filter query to select the scope. The legacy timezone parameter remains accepted for compatibility but cannot override the workspace timezone. Open deals produce separate weighted MRR, setup, and explicit TCV measures; won actuals use closed_at; currencies remain separate. The response reports missing expected dates, overdue rows, missing close attribution, missing values, and whether multiple currencies are present.| Contract | Exact behavior | Errors |
|---|---|---|
| Transitions | Only open deals can move, become won, or become lost. Only won or lost deals can reopen, and reopen requires an active open destination stage. Archive and restore are separate admin-role guarded actions. | invalid_state_transition, resource_archived, resource_not_archived, stage_not_found, insufficient_role |
| Concurrency | Send the ETag returned by a deal read in If-Match for every versioned mutation. A stale or missing version is rejected before the write. | precondition_required, version_conflict |
| Outcomes | Marking a deal won records the authoritative deal_won marketing event once per deal version. It does not charge a card, create an invoice, or imply payment. | deal_not_found, lead_not_found, pipeline_not_found |
| Replay safety | Reuse of an idempotency key replays the original response only when the canonical request hash matches; in-progress and unavailable reservations fail closed. | idempotency_key_required, invalid_idempotency_key, idempotency_key_reused, idempotency_in_progress, idempotency_unavailable |
deal.created, deal.updated, deal.stage_changed, deal.won, deal.lost, deal.archived, deal.restored, and deal.activity.created. Events retain the credential's unified actor context and remain workspace-scoped.curl -X POST https://leadtrackerai.com/api/v1/deals \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: deal-01JABC" \ -H "Content-Type: application/json" \ -d '{ "lead_id": 2194, "pipeline_id": 7, "stage_id": 31, "name": "Northstar annual plan", "amount": "12500.00", "currency": "USD" }'
curl -X POST https://leadtrackerai.com/api/v1/deals/884/move \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: deal-move-01JABC" \ -H "If-Match: \"deal-884-v3\"" \ -H "Content-Type: application/json" \ -d '{"stage_id":32,"position":0}'
Conversations and compliant messaging
Read tenant-owned conversations and messages, explain send eligibility, and queue outbound SMS, WhatsApp, and email messages from a conversation. Recipient addresses are resolved only from the conversation lead; arbitrary recipients, sender IDs, provider IDs, and provider credentials are not accepted.
/conversationsList workspace conversations (cursor)/conversations/{id}Read one safe conversation projection/conversations/{id}/messagesList messages and delivery state (cursor)/conversations/{id}/send-eligibilityExplain DNC, opt-out, quiet-hours, entitlement, and usage checks/conversations/{id}/messagesQueue an outbound message — Idempotency-Key/conversations/{id}/messages/scheduleSchedule an outbound message — Idempotency-Key/conversations/{id}/messages/{message_id}/replyReply to an inbound message — Idempotency-Key/suppression/statusRead masked suppression state/suppression/requestsRecord a workspace suppression request — Idempotency-Key/conversations/inboundStore an inbound channel message/conversations/inbound-callsStore an inbound call transcript or outcome/conversations/{id}/messagesconversations:send · R2 · 202Send only body and, when needed, a conversation-matching channel, subject, or scheduled_at. The API atomically records the message intent, audit/event record, idempotency result, generic job, and tenant-owned outbox item. With external effects disabled, the response is a deterministic simulated queue and no provider call occurs.
curl -X POST https://leadtrackerai.com/api/v1/conversations/300/messages \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: conversation-message-01JABC" \ -H "Content-Type: application/json" \ -d '{"channel":"sms","body":"Confirmed for Tuesday at 10:00."}'
{
"data": {
"status": "queued",
"simulated": true,
"outbox_id": "mout_01JABC"
},
"request_id": "req_01JABC"
}suppressed message with no provider job or outbox row. Duplicate idempotency keys replay the original result without charging usage twice./conversations/inbound-callsconversations:writeSupply lead_id, lead_email, or lead_phone, plus an external call ID and at least one of transcript, summary, disposition, or outcome. STOP requests are routed through LeadTracker AI's normal suppression handling.
User Journey forms
Manage tenant-owned User Journey definitions through draft, immutable revision, publish, unpublish, clone, and archive lifecycle operations. Public links are updated with the same workspace and event-type ownership checks, while archived forms and submissions remain retained.
Submission reads are explicitly PII-safe: request only the projections your integration needs, use cursor pagination for exports, and keep the API key on a trusted server.
{brand} is your workspace's own brand slug — one per public booking/application page you've set up (find yours on the Applications dashboard's User Journey Forms page, or in each page's live URL). Any brand slug your workspace owns works here; it isn't limited to any fixed list.
Every form read returns a serving_area object (configured, enabled, fit_countries, version, etag, updated_at). When it is enabled and an applicant answers from a country outside fit_countries, that submission is still captured in full and still visible in the workspace, but it comes back marked for review, no call is offered automatically, and it is left out of the submission KPI — the form is never blocked or hidden. The rule is skipped whenever it is disabled, the list is empty, or the applicant's country cannot be resolved, and configured: false means the journey has no rule at all. The list is editable both by an authenticated operator in User Journey Forms → Serving area and through PUT /forms/{brand}/serving-area (forms:write), which replaces the list wholesale and requires If-Match with the serving_area.etag you just read — it versions separately from the form, because saving a list creates no form revision. Enabling with an empty list is refused with fit_countries_required rather than stored, since it would flag every applicant. A successful write emits form.serving_area.updated. Server-to-server submissions through POST /forms/{brand}/submissions are not evaluated against it, because the calling socket's country is your application host, not the applicant's.
/formsList owned forms (cursor)/formsCreate a draft form — forms:write/forms/{brand}Fetch the saved form definition/forms/{brand}Save a versioned draft — If-Match/forms/{brand}/publishPublish a draft — If-Match/forms/{brand}/unpublishUnpublish without deleting submissions/forms/{brand}/archiveArchive while retaining history/forms/{brand}/cloneClone into a new tenant-owned brand/forms/{brand}/serving-areaReplace the serving-area country list — If-Match/forms/{brand}/revisionsList immutable revisions (cursor)/forms/{brand}/revisions/{revision_id}Read one immutable revision/forms/{brand}/submissionsList explicit PII-safe submissions (cursor)/forms/{brand}/submissions/{id}Read one explicit PII-safe submission, with its review decision/forms/{brand}/submissions/{id}/reviewVerify as a real prospect or confirm fake — appended, never rewritten/forms/{brand}/analyticsRead aggregate funnel analytics/forms/{brand}/eventsAppend a funnel event · Idempotency-Key · 204 replay/forms/{brand}/submissionsValidate and submit a completed form/public-linksList owned public links (cursor)/public-links/{id}Update link routing — If-Match/forms/acme/submissionsforms:submitThe submission is checked against the saved form definition. Send contact data, answers, a canonical IANA timezone, attribution, and a stable session ID. location remains accepted only for legacy compatibility; when timezone is absent, a recognized legacy location or North-American phone area code may be inferred into the canonical timezone field. New integrations should send timezone and omit location. New leads follow the existing Telegram notification route; retries replay safely. If email or phone already belongs to a different lead identity, the submission is rejected with 409 lead_identity_conflict; if a legacy disputed identity has more than one active match, it returns 409 ambiguous_lead_identity for review and leaves the CRM records unchanged.
lt_live_ key in a browser embed. Use LeadTracker AI's public hosted journey for client-side pages.Hosted links and custom domains
Every workspace gets stable hosted URLs for its public journey, and a workspace with an active custom link domain serves all of them on its own hostname — the API shapes below tell you which URL to publish.
/r/{slug}Stable CTA redirect — normalizes attribution, then lands on the journey. Safe to hardcode behind a website button./formVanity entry on a custom link domain only — serves the domain’s journey in place; the visitor’s address bar stays on /form. Append ?demo=1 for test mode./schedule/{slug}The rendered journey itself. Append ?demo=1 for the zero-write test mode.serialized CTA payloadsreferenceWherever the platform serializes a public CTA (the wizard state, journey form responses), it returns liveUrl ({base}/r/{slug}), testUrl (demo mode), and formUrl — the vanity {base}/form link, present only when the workspace has an active custom link domain. Publish formUrl when it exists, else liveUrl.
app.yourdomain.com). Once active, application forms, booking pages, video rooms, and recording links are all generated on that hostname. Attribution query parameters (utm_*, seo_source, landing_page) are read by the journey on whichever entry path is used — /form and /r/{slug} both carry them through. The REST API base URL is unaffected — always call https://leadtrackerai.com/api/v1.Analytics, attribution, and tracking
Read aggregate funnel, source, velocity, cohort, paid-media, creative, unit-economics, attendance, leaderboard, and data-quality metrics without exposing contact details, answers, session identifiers, provider payloads, or raw query strings. The same surface preserves the existing application funnel contract while adding attribution and event ingestion.
/analytics/application-funnel?days=30&brand=acmeanalytics:readdays accepts 7 through 90. brand is optional and, when given, must be one of your workspace's own registered brand slugs (omit it to aggregate across all of them). The response contains totals, daily trend data, attribution rows, and abandonment points only. Server-verified test, automation, and unusable-contact submissions remain available for audit but are excluded from prospect totals.
/analytics/dashboardanalytics:read · aggregate summary/analytics/funnelanalytics:read · aggregate stages/analytics/sourcesanalytics:read · cursor/analytics/velocityanalytics:read · cursor/analytics/attributionanalytics:read · model + currency basis · cursor/analytics/cohortsanalytics:read · model + currency basis · cursor/analytics/paid-performancemarketing:read · cursor/analytics/creativesmarketing:read · cursor/analytics/unit-economicsmarketing:read · cursor/analytics/data-qualityanalytics:read · freshness/coverage · cursor/analytics/attendanceanalytics:read · cursor/analytics/leaderboardanalytics:read · cursor/analytics/exportsanalytics:export · queued/202 · Idempotency-Key/tracking/eventsforms:submit · deduplicated · Idempotency-Key/tracking/conversion-eventsforms:submit · authoritative outcomes stay server-side/commerce/eventsforms:submit · minor-unit currency · Idempotency-Key/tracking/events/{event_id}analytics:read · workspace-scoped projectionamount_minor plus uppercase ISO-4217 currency. Mixed currencies require an explicit workspace-rate basis and may return currency_basis_required. Data-quality responses surface freshness and coverage warnings rather than silently presenting stale or incomplete inputs.analytics:export plus Idempotency-Key. With external effects disabled, export and tracking operations remain deterministic local intents; no provider URL, storage key, or raw credential is returned.Marketing connections and governed actions
The marketing surface connects workspace-owned provider integrations, goal mappings, consent policy, recommendations, forecasts, and identity resolution. Every operation is workspace-scoped, audited, idempotent, and protected by its exact integrations or marketing scope.
Authorization uses provider-hosted OAuth where supported. Request bodies reject access tokens, refresh tokens, client secrets, passwords, and credential objects; connection projections and audit summaries redact provider secrets and storage keys.
/marketing/connectionsList redacted provider connections
POST/marketing/connections/{provider}/authorizeStart hosted OAuth authorization
GET/marketing/connections/{provider}/callbackComplete state/PKCE/nonce-bound OAuth
GET/marketing/authorizations/{id}Read redacted authorization status
POST/marketing/connections/{id}/syncQueue a sync job or disabled-effects simulation
POST/marketing/connections/{id}/disconnect/planBind exact connection state before disconnect
POST/marketing/recommendations/{id}/execute/planRecheck freshness, coverage, and policy
POST/marketing/recommendations/{id}/executeExecute exact approved plan
POST/marketing/actions/{id}/rollback/planBind exact prior provider state
POST/marketing/actions/{id}/rollbackExecute exact rollback or simulation
GET/marketing/forecastsRead forecast projections and warnings
POST/marketing/forecastsQueue a forecast job
POST/marketing/identity/correctionsRecord a redacted identity correction
Idempotency-Key; retrying a completed request replays its original response.Growth Engine and SEO/GEO
Growth Engine brands, topics, posts, editorial decisions, quality gates, and SEO/GEO reporting are tenant-scoped and entitlement-gated. The surface contains 38 operations and never projects provider credentials, raw OAuth tokens, storage keys, or provider URLs.
POST /growth/posts/{id}/approve changes editorial state only. Publishing and unpublishing require growth:publish, a fresh exact plan, matching operation and plan hashes, approval context, and If-Match; quality, evidence, build, index, and semantic gates still run at execution.
/growth/brandsList entitled tenant brands
POST/growth/posts/generateQueue metered generation or deterministic simulation
POST/growth/posts/{id}/approveEditorial transition without publish side effects
POST/growth/posts/{id}/publish/planBuild exact quality-gated publish plan
POST/growth/posts/{id}/publishExecute approved plan or disabled-effects simulation
GET/growth/brands/{id}/index-healthRead freshness and index health
GET/growth/brands/{id}/ai-visibilityRead complete panels with consulted-versus-cited source lineage and no false zeros
POST/seo/connections/google/authorizeStart server-owned OAuth with PKCE
GET/seo/connections/google/callbackComplete state/PKCE/nonce-bound OAuth
GET/seo/authorizations/{id}Read redacted authorization status
POST/seo/connections/{id}/syncQueue an SEO sync job or simulation
GET/seo/opportunitiesRead bounded opportunities with cursor pagination
GET/seo/recommendationsRead bounded recommendations
seo:configure only for approved configuration actions and eligible subscription verification. An unavailable billing or provider configuration check cannot enable an external action.High-intent Signals and Prospect Packs
Signals and Prospect Packs add seven workspace-scoped operations for reading high-intent signals, converting a signal into a CRM lead exactly once, and requesting bounded prospect data through typed criteria.
Signal reads and conversion always bind the authenticated workspace; foreign signals are concealed. Conversion is replay-safe and derives the lead only from the server-owned signal identity. Prospect-pack plans bind the exact criteria, count, pricing version, usage allowance, entitlement snapshot, and plan hash before any provider work.
/signalsCursor-paginated high-intent signals
POST/signals/{id}/convert-to-leadIdempotent signal-to-lead conversion
POST/prospect-packs/requests/planExact R3 criteria and cost plan
POST/prospect-packs/requestsApproved durable request or deterministic simulation
GET/prospect-packs/requests/{id}Request, pack, and job state
leads:bulk; paid entitlement and usage checks fail closed when unavailable; external effects disabled returns deterministic simulation state without provider URLs or raw payloads.Users, teams, workspace, and agency subaccounts
The Phase 9 control plane adds 30 tenant-safe operations for workspace membership, team tenancy, profile and branding settings, typed notification policies, usage and entitlements, and an agency parent’s explicitly owned subaccounts.
Ordinary workspace credentials cannot select a workspace or team outside their authenticated tenant. Every user, team, policy, and workspace lookup is tenant-bound; cross-workspace identifiers are concealed as not found and membership replacement verifies every user belongs to the same workspace.
/usersCursor-paginated tenant users
POST/users/invitations/planExact role/team invitation plan · R2 approval
POST/users/invitationsDurable invitation job or deterministic simulation
GET/users/{id}Safe user projection
PATCH/users/{id}Owner/admin role and profile update
POST/users/{id}/disable/planExact ownership/workload preview
POST/users/{id}/disableApproved disablement plan
POST/users/{id}/enableVersioned membership enable
GET/teamsCursor-paginated tenant teams
POST/teamsTyped team creation
GET/teams/{id}Team and safe member projection
PATCH/teams/{id}Versioned team update
PUT/teams/{id}/membersTenant-checked membership replacement
POST/teams/{id}/archive/planExact workload archive plan · R2 approval
POST/teams/{id}/archiveWorkload-aware team archive
GET/workspaceWorkspace profile and settings
PATCH/workspaceVersioned workspace profile update
GET/workspace/brandingSafe branding projection
PATCH/workspace/brandingAllowlisted branding update
GET/workspace/notification-policiesTyped event policies
PUT/workspace/notification-policiesReplace typed policies with If-Match or version
GET/workspace/usageUsage counters
GET/workspace/entitlementsEntitlement status
GET/workspacesAgency-owned subaccounts only
POST/workspaces/planExact R3 creation and rebilling plan
POST/workspacesApproved subaccount creation job or simulation
GET/workspaces/{id}Owned relationship projection
PATCH/workspaces/{id}Versioned owned-subaccount update
POST/workspaces/{id}/suspend/planExact R3 suspension plan
POST/workspaces/{id}/suspendApproved suspension job or simulation
GET/domainsdomains:read · R0 · cursor
POST/domainsdomains:write · R1 · Idempotency-Key
GET/domains/{id}domains:read · R0
POST/domains/{id}/verifydomains:write · R2 · 202 · Idempotency-Key
POST/domains/{id}/remove/plandomains:write · R3 · exact plan
POST/domains/{id}/removedomains:write · R3 · approved plan · 202
GET/integrationsintegrations:read · R0 · opaque cursor · max 100
GET/integrations/{provider}integrations:read · R0
POST/integrations/{provider}/authorizeintegrations:write · R1 · server-bound OAuth state
POST/integrations/{provider}/syncintegrations:write · R2 · 202 · Idempotency-Key
POST/integrations/{provider}/disconnect/planintegrations:write · R3 · exact plan
POST/integrations/{provider}/disconnectintegrations:write · R3 · approved plan · 202
GET/onboarding/stateworkspace:read · R0 · independent nested cursors · max 100
PATCH/onboarding/business-profileworkspace:write · R1 · If-Match
POST/onboarding/texting-registrationworkspace:write · R3 · carrier plan/job
GET/onboarding/texting-registrationworkspace:read · R0
POST/onboarding/email-domainsdomains:write · R1 · Idempotency-Key
POST/onboarding/email-domains/{id}/verifydomains:write · R2 · 202 · Idempotency-Key
GET/settingsworkspace:read · R0 · typed/redacted
PATCH/settingsworkspace:write · R1 · If-Match
user, team, role, workspace admin, or workspace owner), with bounded settings and recursive secret rejection.Domains, integrations, onboarding, and settings
The Domains/Integrations/Onboarding/Settings surface adds 22 tenant-bound operations for customer domains, provider connections, carrier registration, email sending domains, and typed workspace settings.
Integration authorization accepts only an allowlisted provider, exact HTTPS redirect URI, PKCE S256 challenge, and OIDC nonce/scopes. OAuth state is generated and stored server-side bound to the credential, actor, workspace, redirect, challenge, nonce hash, and expiry; callbacks accept the standard provider state/code redirect and validate nonce only from a cryptographically verified ID token. Callbacks never accept client-supplied provider secrets. Status projections redact access tokens, refresh tokens, provider IDs, raw URLs, and storage keys.
/domainsCursor-paginated custom domains
POST/domainsProvider-backed domain job or simulation
POST/domains/{id}/verifyDNS verification job or simulation
POST/domains/{id}/remove/planExact dependency-aware R3 plan
POST/domains/{id}/removeApproved removal job or simulation
GET/integrationsSafe provider status list
POST/integrations/{provider}/authorizeServer-bound PKCE authorization
POST/integrations/{provider}/authorize/completeBounded authorization completion
GET/integrations/{provider}/authorize/statusRedacted authorization status
POST/integrations/{provider}/syncDurable sync job or simulation
POST/integrations/{provider}/disconnect/planExact dependency-aware R3 plan
POST/integrations/{provider}/disconnectApproved disconnect job or simulation
GET/onboarding/stateBusiness, carrier, email-domain, and integration state
PATCH/onboarding/business-profileTyped profile with If-Match
POST/onboarding/texting-registrationExact carrier plan or registration job
GET/onboarding/texting-registrationSafe carrier registration state
POST/onboarding/email-domainsEmail sending domain job or simulation
POST/onboarding/email-domains/{id}/verifyEmail DNS verification job
GET/settingsAllowlisted typed settings
PATCH/settingsTyped settings with If-Match
user, team, role, workspace admin, or workspace owner), with bounded settings and recursive secret rejection. Replacements require If-Match or the numeric version from the read response. Integration lists accept workspace-bound opaque cursors up to 100 items; onboarding state exposes independent email_domains_cursor and integrations_cursor inputs and returns a cursor for each nested collection.Billing and plan management
Billing adds 8 tenant-scoped operations for safe subscription state, usage, the self-serve catalog, exact downgrades to Free, usage-credit top-ups, and provider-hosted portal sessions. Reads use billing:read; owner/admin mutations use billing:write.
GET /billing/plans returns sales_led: true, the Free plan's limits and quotas, the usage-credit topup_packs, and two journey-form links: upgrade_url for a package for your own business and white_label_url for agencies reselling LeadTracker AI under their own brand. GET /billing/state returns the workspace's own tier_key (free, custom for any paid package, or internal), plan_name, paid_access, and the same two links. A plan-change preview or execution whose target is anything other than free, or that enables an add-on, returns 409 sales_led_plan with upgrade_url and white_label_url in error.details; no operation plan or approval is created. Usage top-ups remain available to a workspace with paid access; without it they return 402 subscription_required with the same links.Raw card, bank, provider credential, token, storage-key, and secret fields are rejected. Use the provider-hosted portal or tokenized provider flow; the API never stores or returns raw payment data.
/billing/stateSafe subscription and billable state
GET/billing/usageUsage and quotas in minor units
GET/billing/plansFree plan, upgrade links, top-up packs
POST/billing/plan-changes/previewExact R3 downgrade-to-Free plan
POST/billing/plan-changesApproved downgrade execution or simulation
POST/billing/topups/previewExact R3 usage-credit plan
POST/billing/topupsApproved top-up execution or simulation
POST/billing/portal-sessionsProvider-hosted portal URL
operation_id, approval_id, request hash, resolved-resource-versions hash, one-time approval, and unexpired plan; stale or changed catalog/subscription state must fail closed. Amounts are integer minor units and the catalog currency is USD.Idempotency-Key. With external effects disabled, previews, executions, jobs, and events are deterministic simulations with no provider call; live mode returns only safe provider-hosted or tokenized projections.Native workflows and triggers
Build tenant-owned workflows from the validated node catalog, inspect durable runs, and trigger or simulate them through the same scope, plan, idempotency, audit, and disabled-effects gates as the rest of the API. HTTP and webhook nodes accept only prevalidated workspace destinations; provider URLs, storage keys, and raw credentials never enter the public contract.
/workflowsList definitions and statuses
PUT/workflows/{id}/nodesReplace a typed, validated graph
POST/workflows/{id}/trigger/planBind the exact graph and version
POST/workflows/{id}/test-runQueue a deterministic simulation
GET/workflow-runs/{id}/stepsInspect redacted run steps
POST/workflow-runs/{id}/retryRetry with original effect lineage
/workflows/{workflow_id}/triggerworkflows:triggerThe compatibility webhook trigger accepts { "event": "voice.call.completed", "payload": { ... } } with an Idempotency-Key. Native workflow runs additionally accept an exact operation plan where policy requires it, persist retry lineage, and simulate all effects while external effects are disabled.
Jobs, approvals, and audit
Phase 1 operation resources are workspace-scoped and available through the same API-key or delegated OAuth credential boundary. Job reads require a held domain read scope; cancellation requires the execute scope that originated the job.
POST /approval-requests creates a request from a server-generated operation plan. There is intentionally no public /approve endpoint. Owner decisions happen through the existing authenticated approval channel, then execution must present the exact request hash, workspace, resource versions, expiry, and one-time approval state.
/jobsR0 · domain read scope · cursor/jobs/{job_id}R0 · domain read scope/jobs/{job_id}/cancelR1 · originating execute scope · Idempotency-Key/approval-requestsR0 · approvals:read · cursor/approval-requestsR1 · approvals:request · Idempotency-Key/approval-requests/{approval_request_id}R0 · approvals:read/approval-requests/{approval_request_id}/cancelR1 · approvals:request · Idempotency-Key/audit-eventsR0 · audit:read · cursor/audit-events/{audit_event_id}R0 · audit:read| Operation | Scope / risk | Idempotency and approval | Stable errors |
|---|---|---|---|
GET /jobs | domain_readR0 | Signed cursor bound to workspace, route, and filters | invalid_api_key, invalid_access_token, insufficient_scope, invalid_request, invalid_filter, invalid_cursor, rate_limited |
GET /jobs/{job_id} | domain_readR0 | None | invalid_api_key, invalid_access_token, insufficient_scope, resource_not_found |
POST /jobs/{job_id}/cancel | originating_executeR1 | Required Idempotency-Key; cancellation is only allowed for cancellable jobs | idempotency_key_required, idempotency_key_reused, resource_not_found, job_not_cancellable, invalid_state_transition |
GET /approval-requests | approvals:readR0 | Signed cursor; callback evidence is omitted | invalid_filter, invalid_cursor, rate_limited |
POST /approval-requests | approvals:requestR1 | Required Idempotency-Key; server-generated operation plan only | unknown_field, idempotency_key_reused, resource_not_found, approval_mismatch, approval_expired |
GET /approval-requests/{approval_request_id} | approvals:readR0 | Cross-workspace IDs return resource_not_found | resource_not_found, insufficient_scope |
POST /approval-requests/{approval_request_id}/cancel | approvals:requestR1 | Required Idempotency-Key; initiator or owner may cancel | idempotency_key_reused, resource_not_found, insufficient_role, invalid_state_transition |
GET /audit-events | audit:readR0 | Signed cursor and bounded filters | invalid_filter, invalid_cursor, rate_limited |
GET /audit-events/{audit_event_id} | audit:readR0 | Redacts authorization, OAuth, API-key, callback, and provider secrets | resource_not_found, insufficient_scope |
curl https://leadtrackerai.com/api/v1/jobs?limit=50 \
-H "Authorization: Bearer $LEADTRACKER_API_TOKEN"
curl -X POST https://leadtrackerai.com/api/v1/approval-requests \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: campaign-approval-2026-08-14" \ -H "Content-Type: application/json" \ -d '{"operation_id":"op_01JABCDEF1234567","reason":"recipient threshold"}'
Service-account control plane
Service-account administration is a human owner/admin control plane. It uses the same workspace-bound API-key or delegated OAuth chain, requires developer:credentials:admin, and never treats a legacy API key as a human administrator.
Credential creation and rotation return client_secret once with Cache-Control: no-store. List, get, revoke, idempotent replay, and /whoami responses contain metadata only. Store the secret immediately; it cannot be recovered.
/developer/scopesR0 · developer:credentials:admin/service-accountsR0 · cursor/service-accountsR1 · Idempotency-Key/service-accounts/{service_account_id}R0 · metadata only/service-accounts/{service_account_id}R1 · Idempotency-Key + If-Match/service-accounts/{service_account_id}/rotateR3 · Idempotency-Key + If-Match/service-accounts/{service_account_id}/disableR3 · Idempotency-Key + If-Match/service-accounts/{service_account_id}/enableR1 · Idempotency-Key + If-Match/service-accounts/{service_account_id}/credentialsR0 · cursor · metadata only/service-accounts/{service_account_id}/credentialsR3 · one-time client_secret/service-accounts/{service_account_id}/credentials/{credential_id}R3 · Idempotency-Key + If-Match| Operation | Grantability | Safety contract | Stable errors |
|---|---|---|---|
GET /developer/scopes | Owner/admin only | Returns exact server-owned scope definitions and grantable subset | insufficient_role, insufficient_scope, resource_access_denied |
POST /service-accounts | Requested scopes must be grantable | Required Idempotency-Key; no secret is created or returned | invalid_request, unknown_field, idempotency_key_reused |
PATCH /service-accounts/{service_account_id} | Owner/admin grant set | Required Idempotency-Key and current If-Match | precondition_required, version_conflict, insufficient_scope |
POST /service-accounts/{service_account_id}/rotate | Owner/admin grant set | R3; exact ETag and idempotency; bounded overlap; one-time secret reveal | invalid_state_transition, version_conflict, resource_not_found |
POST /service-accounts/{service_account_id}/disable | Owner/admin only | R3; revokes issued access tokens; final owner account is protected | resource_in_use, precondition_required, version_conflict |
POST /service-accounts/{service_account_id}/credentials | Subset of account grant | R3; secret appears once and replay never re-reveals it | invalid_request, invalid_state_transition, idempotency_key_reused |
DELETE /service-accounts/{service_account_id}/credentials/{credential_id} | Owner/admin only | R3; revokes tokens; the final recovery credential and final owner automation credential are protected | resource_in_use, precondition_required, version_conflict |
curl -X POST https://leadtrackerai.com/api/v1/service-accounts \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: create-sa-2026-08-14" \ -H "Content-Type: application/json" \ -d '{"name":"Sales automation","purpose":"automation","scopes":["leads:read"]}'
curl -X POST https://leadtrackerai.com/api/v1/service-accounts/sa_01JABCDEF1234567/credentials \ -H "Authorization: Bearer $LEADTRACKER_API_TOKEN" \ -H "Idempotency-Key: create-credential-2026-08-14" \ -H "Content-Type: application/json" \ -d '{"purpose":"automation","scopes":["leads:read"]}'
Generic event webhooks
Manage workspace-scoped endpoints for the generic event stream with an API key. These routes are separate from the legacy booking webhook settings below and never accept booking lifecycle event names.
POST /webhook-endpoints and POST /webhook-endpoints/{endpoint_id}/rotate-secret return signing_secret once. Replay responses, list responses, and delivery responses never contain a secret. Store it immediately and use it to verify the signed event envelope.
/webhook-endpointsR0 · developer:webhooks:read · no key/webhook-endpointsR1 · developer:webhooks:write · Idempotency-Key/webhook-endpoints/{endpoint_id}R0 · developer:webhooks:read · no key/webhook-endpoints/{endpoint_id}R1 · developer:webhooks:write · Idempotency-Key + If-Match/webhook-endpoints/{endpoint_id}R3 · developer:webhooks:write · policy · Idempotency-Key + If-Match/webhook-endpoints/{endpoint_id}/rotate-secretR3 · developer:webhooks:write · Idempotency-Key + If-Match/webhook-endpoints/{endpoint_id}/deliveriesR0 · developer:webhooks:read · cursor/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}R0 · developer:webhooks:read · no key/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/retryR1 · developer:webhooks:write · Idempotency-Key| Operation | Scope / risk | Idempotency and precondition | Errors |
|---|---|---|---|
GET /webhook-endpoints | developer:webhooks:readR0 | None | invalid_api_key, insufficient_scope, invalid_endpoint_id, resource_not_found, rate_limited |
POST /webhook-endpoints | developer:webhooks:writeR1 | Required Idempotency-Key; replay returns the original projection without a secret | invalid_api_key, insufficient_scope, invalid_request, unknown_field, invalid_webhook_name, invalid_webhook_url, unsafe_webhook_destination, destination_unresolvable, invalid_webhook_events, legacy_booking_webhook_event, invalid_idempotency_key, idempotency_key_reused, quota_exceeded, rate_limited, idempotency_unavailable, webhook_encryption_unavailable |
GET /webhook-endpoints/{endpoint_id} | developer:webhooks:readR0 | None | invalid_api_key, insufficient_scope, invalid_endpoint_id, resource_not_found, rate_limited |
PATCH /webhook-endpoints/{endpoint_id} | developer:webhooks:writeR1 | Required Idempotency-Key and current If-Match | invalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_request, unknown_field, invalid_webhook_name, invalid_webhook_url, unsafe_webhook_destination, destination_unresolvable, invalid_webhook_events, legacy_booking_webhook_event, invalid_idempotency_key, idempotency_key_reused, resource_not_found, precondition_required, version_conflict, rate_limited, idempotency_unavailable |
DELETE /webhook-endpoints/{endpoint_id} | developer:webhooks:writeR3 · policy | Policy evaluation, required Idempotency-Key and current If-Match | invalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_request, invalid_idempotency_key, idempotency_key_reused, resource_not_found, precondition_required, version_conflict, rate_limited, idempotency_unavailable |
POST /webhook-endpoints/{endpoint_id}/rotate-secret | developer:webhooks:writeR3 | Required Idempotency-Key and current If-Match | invalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_request, invalid_idempotency_key, idempotency_key_reused, resource_not_found, precondition_required, version_conflict, rate_limited, idempotency_unavailable, webhook_encryption_unavailable |
GET /webhook-endpoints/{endpoint_id}/deliveries | developer:webhooks:readR0 | Opaque cursor pagination; no key | invalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_filter, invalid_cursor, resource_not_found, rate_limited |
GET /webhook-endpoints/{endpoint_id}/deliveries/{delivery_id} | developer:webhooks:readR0 | None | invalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_delivery_id, resource_not_found, rate_limited |
POST /webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/retry | developer:webhooks:writeR1 | Required Idempotency-Key | invalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_delivery_id, invalid_request, invalid_idempotency_key, idempotency_key_reused, resource_not_found, resource_in_use, invalid_state_transition, rate_limited, idempotency_unavailable |
curl -X POST https://leadtrackerai.com/api/v1/webhook-endpoints \ -H "Authorization: Bearer $LEADTRACKER_API_KEY" \ -H "Idempotency-Key: crm-events-2026-08-14" \ -H "Content-Type: application/json" \ -d '{"name":"CRM events","url":"https://hooks.example.com/leadtracker","events":["deal.updated","lead.created"]}'
{
"data": { "id": "wep_01JABCDEF1234567", "version": 1 },
"signing_secret": "whsec_one_time_value"
}
// Replay and GET/list responses omit signing_secret.
{
"data": {
"id": "whd_01JABCDEF1234567",
"event_type": "deal.updated",
"status": "delivered",
"event": { "api_version": "2026-08-14", "data": { "object": { "id": 91 } } }
}
}
If-Match: "wep_...:1"versioned writesConfiguration updates, deletion, and secret rotation require the current ETag. A stale or missing tag returns 428 precondition_required or 412 version_conflict. Destination changes, subscription changes, and deletion discard queued generic deliveries.
Booking webhooks
Create endpoints from LeadTracker AI app → Developer API. Endpoint configuration is owner/admin session-only; API keys cannot add a destination or reveal a signing secret.
booking.createdNative booking was confirmedbooking.rescheduledNative booking time changedbooking.cancelledNative booking was cancelledbooking.no_showAttendance was marked no-showYour configured HTTPS endpointHMAC SHA-256LeadTracker AI sends JSON over DNS-pinned public HTTPS, never follows redirects, and retries at least once with a stable event ID. De-duplicate deliveries with X-LeadTracker-Event-Id. Every booking payload includes brand_id so downstream systems can retain the same tenant identity.
| Header | Description |
|---|---|
| X-LeadTracker-Event | The booking event name. |
| X-LeadTracker-Event-Id | Stable event identifier for receiver de-duplication. |
| X-LeadTracker-Timestamp | Unix timestamp in seconds. |
| X-LeadTracker-Signature | v1= + HMAC SHA-256 of timestamp + "." + raw_body. |
Errors and limits
All errors include a stable machine-readable code and a request_id for support and diagnostics.
brand_id is not a positive integer.quota_exceeded.subscription_required.error.details.upgrade_url (their own business) or error.details.white_label_url (agencies reselling under their own brand).{
"error": {
"code": "slot_taken",
"message": "That slot is no longer available."
},
"request_id": "4c0725d0-..."
}Security practices
Use separate keys for every provider and environment. Give each key a recognizable name, set a practical expiration, and replace it before sharing changes hands.
Never put a LeadTracker AI API key in a frontend bundle, publicly accessible webhook URL, or transcript. For a suspected exposure, create a replacement key and revoke the existing one immediately.