LeadTracker AI Developer
Version 1

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.

Base URL https://leadtrackerai.com/api/v1 Download OpenAPI 3.1
i
Built for server-to-server integrations

Use 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.

Authorization header
curl https://leadtrackerai.com/api/v1/scheduling/brands \
  -H "Authorization: Bearer lt_live_..."
Alternative header
X-API-Key: lt_live_...
Write requests: send an 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.
API keys are plan-limited: Free allows 1; a paid package raises the cap. Minting past the cap returns 402 quota_exceeded.
Free plan: every new workspace starts on the permanent Free plan (no card, no expiry) with 2,500 CRM records, 1 API key and the same rate limits as paid plans. 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.
Metadata: 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.
Calendar OAuth: 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.

Install JavaScript / TypeScript
npm install @leadtracker/developer-api
Install Python
python -m pip install leadtracker-developer-api
Server-side JavaScript
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);
}
Retries and control flow: SDK retries are limited to safe reads and operations whose OpenAPI contract requires idempotency. For R3 or policy-evaluated R2 effects, call the server-provided plan, submit its exact 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.

MCP host configuration
{
  "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.

Remote MCP connector
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.

POST/support/cases/{uid}/diagnosticssupport:write; see support contract
GET/support/cases/{uid}/attachmentssupport:read; see support contract
GET/support/cases/{uid}/attachments/{attachmentUid}support:read; see support contract
POST/support/cases/{uid}/attachmentssupport:write; see support contract
POST/support/identity/linksupport:write; see support contract
GET/support/statussupport:read or support:write; see contract
GET/support/casessupport:read or support:write; see contract
POST/support/casessupport:read or support:write; see contract
GET/support/cases/{uid}support:read or support:write; see contract
POST/support/cases/{uid}/messagessupport:read or support:write; see contract
POST/support/cases/{uid}/handoffsupport:read or support:write; see contract
POST/support/cases/{uid}/feedbacksupport:read or support:write; see contract
GET/support/knowledgesupport:read or support:write; see contract
GET/support/knowledge/{articleId}support:read or support:write; see contract
GET/crm/duplicatesleads:read; owner/admin review
POST/crm/leads/mergeleads:write; versioned reviewed merge
POST/crm/deals/exportsdeals:read; manager export
POST/crm/tasks/exportstasks:read; manager export
GET/crm/entity-exportsleads:bulk
GET/crm/entity-exports/{id}leads:bulk + entity read
POST/crm/entity-exports/{id}/cancelleads:bulk + entity read
POST/crm/entity-exports/{id}/resumeleads:bulk + entity read
GET/crm/entity-exports/{id}/downloadleads:bulk + entity read; binary CSV
GET/crm/metricsanalytics:read + leads:read + deals:read
GET/crm/metrics/recordsBounded milestone drill-through
POST/crm/companies/{id}/archiveleads:write
POST/crm/companies/{id}/restoreleads:write
DELETE/crm/companies/{id}/contacts/{leadId}leads:write
GET/crm/companies/{id}/reconciliationleads:read
DELETE/crm/deals/{id}/stakeholders/{leadId}deals:write
POST/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
GET/crm/task-alertstasks:read
POST/crm/task-alerts/{id}tasks:write
GET/crm/companiesleads:read
POST/crm/companiesleads:write
GET/crm/companies/{id}leads:read
PUT/crm/companies/{id}leads:write
POST/crm/companies/{id}/contactsleads:write
GET/crm/leads/{id}/workspaceleads:read
GET/crm/deals/{id}/stakeholdersdeals:read
POST/crm/deals/{id}/stakeholdersdeals:write
GET/crm/stages/{id}/policypipelines:read
PUT/crm/stages/{id}/policypipelines:write
POST/crm/deals/{id}/stage-approvalsdeals:write
PUT/crm/deals/{id}/next-actiondeals:write
GET/crm/task-templatestasks:read
POST/crm/task-templatestasks:write
POST/crm/task-templates/{id}/taskstasks:write
POST/crm/tasks/{id}/stop-recurrencetasks:write
POST/crm/audiencesleads:bulk
GET/crm/audiences/{id}leads:bulk
POST/crm/audiences/{id}/jobsleads:bulk
GET/crm/jobsleads:bulk
GET/crm/jobs/{id}leads:bulk
GET/crm/jobs/{id}/failuresleads:bulk
POST/crm/jobs/{id}/cancelleads:bulk
GET/crm/jobs/{id}/downloadleads:bulk + leads:read
PUT/crm/pipelines/{id}/configurationpipelines:write
GET/metaauthenticated
GET/whoamiauthenticated
GET/capabilitiesauthenticated
POST/operation-planstarget scope · R1 · immutable MCP plan
GET/scheduling/brandsscheduling:read
GET/scheduling/event-typesscheduling:read
GET/scheduling/availabilityscheduling:read
GET/scheduling/bookingsscheduling:read
GET/scheduling/bookings/{uid}scheduling:read
POST/scheduling/bookingsscheduling:write · R2 · Idempotency-Key
POST/scheduling/bookings/{uid}/reschedulescheduling:write · R2 · Idempotency-Key
POST/scheduling/bookings/{uid}/cancelscheduling:write · R2 · Idempotency-Key
GET/scheduling/calendarsscheduling:read · R0 · cursor
POST/scheduling/calendarsscheduling:configure · R1 · Idempotency-Key
GET/scheduling/calendars/{id}scheduling:read · R0
PATCH/scheduling/calendars/{id}scheduling:configure · R1 · If-Match
POST/scheduling/calendars/{id}/archivescheduling:configure · R1 · If-Match
POST/scheduling/event-typesscheduling:configure · R1 · Idempotency-Key
GET/scheduling/event-types/{id}scheduling:read · R0
PATCH/scheduling/event-types/{id}scheduling:configure · R1 · If-Match
DELETE/scheduling/event-types/{id}scheduling:configure · R1 · If-Match
GET/scheduling/event-types/{id}/remindersscheduling:read · R0
PUT/scheduling/event-types/{id}/remindersscheduling:configure · R1 · If-Match
GET/scheduling/precall-sequencesscheduling:read · R0
POST/scheduling/precall-sequencesscheduling:configure · R1 · Idempotency-Key
GET/scheduling/precall-sequences/{id}scheduling:read · R0
PATCH/scheduling/precall-sequences/{id}scheduling:configure · R1 · If-Match
POST/scheduling/precall-sequences/{id}/archivescheduling:configure · R1 · If-Match
PUT/scheduling/precall-sequences/{id}/event-typesscheduling:configure · R1 · If-Match
POST/scheduling/precall-sequences/{id}/assetsscheduling:configure · R1 · multipart · Idempotency-Key
DELETE/scheduling/precall-sequences/{id}/assets/{asset_id}scheduling:configure · R1 · If-Match
GET/scheduling/calendars/{id}/availability-rulesscheduling:read · R0
PUT/scheduling/calendars/{id}/availability-rulesscheduling:configure · R1 · If-Match
GET/scheduling/calendars/{id}/exceptionsscheduling:read · R0
POST/scheduling/calendars/{id}/exceptionsscheduling:configure · R1 · Idempotency-Key
PATCH/scheduling/calendars/{id}/exceptions/{exception_id}scheduling:configure · R1 · If-Match
DELETE/scheduling/calendars/{id}/exceptions/{exception_id}scheduling:configure · R1 · If-Match
GET/scheduling/time-offscheduling:read · R0
POST/scheduling/time-offscheduling:configure · R1 · Idempotency-Key
PATCH/scheduling/time-off/{id}scheduling:configure · R1 · If-Match
DELETE/scheduling/time-off/{id}scheduling:configure · R1 · If-Match
GET/scheduling/routing-poolsscheduling:read · R0 · single page
POST/scheduling/routing-poolsscheduling:configure · R1 · Idempotency-Key
GET/scheduling/routing-pools/{id}scheduling:read · R0
PATCH/scheduling/routing-pools/{id}scheduling:configure · R1 · If-Match
PUT/scheduling/routing-pools/{id}/membersscheduling:configure · R1 · If-Match
GET/scheduling/connectionsscheduling:connections · R0
POST/scheduling/connections/{provider}/authorizescheduling:connections · R1 · Idempotency-Key
GET/scheduling/connections/{provider}/callbackpublic state/PKCE/OIDC-ID-token callback · MCP hidden
GET/scheduling/authorizations/{id}scheduling:connections · R0 · status only
POST/scheduling/connections/{id}/syncscheduling:connections · R2 · 202 · Idempotency-Key
PATCH/scheduling/connections/{id}/calendars/{calendar_id}scheduling:connections · R1 · If-Match
POST/scheduling/connections/{id}/disconnect/planscheduling:connections · R2 · Idempotency-Key
POST/scheduling/connections/{id}/disconnectscheduling:connections · R3 · If-Match
POST/scheduling/holdsscheduling:write · R1 · Idempotency-Key
POST/scheduling/bookings/{uid}/attendancescheduling:write · R1 · If-Match
POST/scheduling/bookings/{uid}/refresh-conferencescheduling:write · R1 · Idempotency-Key
POST/scheduling/bookings/{uid}/guestsscheduling:write · R1 · Idempotency-Key
GET/scheduling/bookings/{uid}/guestsscheduling:read · R0
GET/scheduling/booking-links/mescheduling:read · R0 · the token's own person only
PATCH/scheduling/booking-links/mescheduling:write · R1 · Idempotency-Key · the token's own person only
GET/leads/searchleads:read
GET/leadsleads:read
POST/leads/queryleads:read
GET/leads/{id}leads:read
GET/leads/{id}/taskstasks:read · R0 · cursor
POST/leads/{id}/researchleads:write · R2 · 202 · Idempotency-Key
POST/leads/{id}/enrichmentleads:write · R2 · 202 · Idempotency-Key
POST/leads/bulkleads:bulk · R1 · 202 · Idempotency-Key
POST/leadsleads:write
POST/leads/upsertleads:write
POST/leads/importsleads:bulk · R1 · 202 · Idempotency-Key
GET/leads/imports/{job_id}leads:bulk · R0
POST/leads/imports/{import_id}/commitleads:bulk · R1 · 202 · Idempotency-Key
POST/leads/exportsanalytics:export · R1 · 202 · Idempotency-Key
GET/leads/exports/{artifact_id}analytics:export · R0 · expires
GET/leads/exports/{artifact_id}/downloadanalytics:export · R0 · audited
PATCH/leads/{id}leads:write
POST/leads/{id}/archiveleads:archive
POST/leads/{id}/restoreleads:archive
GET/leads/{id}/notesleads:read
POST/leads/{id}/notesleads:write
PATCH/leads/{id}/notes/{note_id}leads:write
DELETE/leads/{id}/notes/{note_id}leads:write
GET/leads/{id}/activitiesleads:read
POST/leads/{id}/activitiesleads:write
POST/conversations/inboundconversations:write
POST/conversations/inbound-callsconversations:write
GET/conversationsconversations:read · R0 · cursor
GET/conversations/{id}conversations:read · R0
POST/conversations/{id}/assignconversations:write · R1 · Idempotency-Key
POST/conversations/{id}/closeconversations:write · R1 · Idempotency-Key
POST/conversations/{id}/reopenconversations:write · R1 · Idempotency-Key
GET/conversations/{id}/messagesconversations:read · R0 · cursor
GET/conversations/{id}/send-eligibilityconversations:send · R0
POST/conversations/{id}/messagesconversations:send · R2 · 202 · Idempotency-Key
POST/conversations/{id}/messages/scheduleconversations:send · R2 · 202 · Idempotency-Key
POST/conversations/{id}/messages/{message_id}/replyconversations:send · R2 · 202 · Idempotency-Key
GET/suppression/statusconversations:read · R0
POST/suppression/requestsconversations:write · R1 · Idempotency-Key
GET/callscalls:read · R0 · cursor
POST/callscalls:start · R2 · 201/202 · Idempotency-Key
GET/calls/{id}calls:read · R0
GET/calls/{id}/statuscalls:read · R0
POST/calls/{id}/statuscalls:control · R2 · Idempotency-Key
POST/calls/{id}/dtmfcalls:control · R2 · Idempotency-Key
POST/calls/{id}/hangupcalls:control · R2 · Idempotency-Key
POST/calls/{id}/dispositioncalls:control · R1 · Idempotency-Key
POST/calls/{id}/retrycalls:start · R2 · 201/202 · Idempotency-Key
GET/calls/{id}/recordingrecordings:read · R0 · signed expiry
GET/calls/{id}/transcriptrecordings:read · R0 · signed expiry
GET/calls/{id}/summarycalls:read · R0 · signed expiry
GET/scheduled-callscalls:read · R0 · cursor
POST/scheduled-callscalls:start · R1 · Idempotency-Key
PATCH/scheduled-calls/{id}calls:start · R1 · If-Match · Idempotency-Key
POST/scheduled-calls/{id}/completecalls:control · R1 · Idempotency-Key
POST/scheduled-calls/{id}/snoozecalls:control · R1 · Idempotency-Key
POST/scheduled-calls/{id}/skipcalls:control · R1 · Idempotency-Key
GET/call-queuescalls:read · R0 · cursor
POST/call-queuescalls:start · R1 · Idempotency-Key
POST/call-queues/previewcalls:read · R0 · Idempotency-Key
GET/call-queues/{id}calls:read · R0
POST/call-queues/{id}/start-nextcalls:start · R2 · 202 · Idempotency-Key
POST/call-queues/{id}/pausecalls:control · R1 · If-Match · Idempotency-Key
POST/call-queues/{id}/resumecalls:control · R1 · If-Match · Idempotency-Key
GET/scriptsscripts:read · R0 · cursor
POST/scriptsscripts:write · R1 · Idempotency-Key
GET/scripts/{id}scripts:read · R0
PATCH/scripts/{id}scripts:write · R1 · If-Match · Idempotency-Key
POST/scripts/{id}/publishscripts:write · R1 · Idempotency-Key
POST/scripts/{id}/archivescripts:write · R1 · Idempotency-Key
POST/scripts/{id}/clonescripts:write · R1 · Idempotency-Key
GET/scripts/{id}/versionsscripts:read · R0 · cursor
GET/scripts/{id}/assignmentsscripts:read · R0
POST/scripts/{id}/assignscripts:write · R1 · Idempotency-Key
GET/voicemailsvoicemails:read · R0 · cursor
POST/voicemailsvoicemails:write · R1 · 201/202 · Idempotency-Key
GET/voicemails/{id}voicemails:read · R0
PATCH/voicemails/{id}voicemails:write · R1 · If-Match · Idempotency-Key
POST/voicemails/previewvoicemails:write · R2 · 200/202 · Idempotency-Key
POST/voicemails/{id}/previewvoicemails:read · R0 · Idempotency-Key
POST/voicemails/{id}/set-defaultvoicemails:write · R1 · Idempotency-Key
POST/voicemails/{id}/archivevoicemails:write · R1 · Idempotency-Key
GET/voicemails/{id}/versionsvoicemails:read · R0 · cursor
GET/campaignscampaigns:read · R0 · cursor
POST/campaignscampaigns:write · R1 · Idempotency-Key
GET/campaigns/{id}campaigns:read · R0
PATCH/campaigns/{id}campaigns:write · R1 · If-Match · Idempotency-Key
POST/campaigns/{id}/archivecampaigns:write · R1 · If-Match · Idempotency-Key
GET/campaigns/{id}/stepscampaigns:read · R0
PUT/campaigns/{id}/stepscampaigns:write · R1 · If-Match · Idempotency-Key
POST/campaigns/{id}/validatecampaigns:write · R1 · Idempotency-Key
POST/campaigns/{id}/activatecampaigns:execute · R2 · If-Match · Idempotency-Key
POST/campaigns/{id}/pausecampaigns:execute · R2 · If-Match · Idempotency-Key
POST/campaigns/{id}/resumecampaigns:execute · R2 · If-Match · Idempotency-Key
POST/campaigns/{id}/launch/plancampaigns:execute · R2 · plan · Idempotency-Key
POST/campaigns/{id}/launchcampaigns:execute · R3 · approved · 202 · Idempotency-Key
POST/campaigns/{id}/enrollmentscampaigns:execute · R2 · 202 · Idempotency-Key
GET/campaigns/{id}/enrollmentscampaigns:read · R0 · cursor
POST/campaigns/{id}/enrollments/{enrollment_id}/pausecampaigns:execute · R2 · If-Match · Idempotency-Key
POST/campaigns/{id}/enrollments/{enrollment_id}/resumecampaigns:execute · R2 · If-Match · Idempotency-Key
POST/campaigns/{id}/enrollments/{enrollment_id}/removecampaigns:execute · R2 · If-Match · Idempotency-Key
GET/campaigns/{id}/analyticsanalytics:read · R0
GET/workflowsworkflows:read · R0 · cursor
POST/workflowsworkflows:write · R1 · Idempotency-Key
GET/workflows/{id}workflows:read · R0
PATCH/workflows/{id}workflows:write · R1 · If-Match · Idempotency-Key
POST/workflows/{id}/cloneworkflows:write · R1 · Idempotency-Key
POST/workflows/{id}/archiveworkflows:write · R1 · If-Match · Idempotency-Key
PUT/workflows/{id}/nodesworkflows:write · R1 · If-Match · Idempotency-Key
POST/workflows/{id}/validateworkflows:write · R0 · Idempotency-Key
POST/workflows/{id}/activate/planworkflows:execute · R2 · plan · Idempotency-Key
POST/workflows/{id}/activateworkflows:execute · R2 · If-Match · Idempotency-Key
POST/workflows/{id}/deactivate/planworkflows:execute · R2 · plan · Idempotency-Key
POST/workflows/{id}/deactivateworkflows:execute · R2 · If-Match · Idempotency-Key
POST/workflows/{id}/trigger/planworkflows:trigger · R2 · plan · Idempotency-Key
POST/workflows/{id}/triggerworkflows:trigger · R2 · 202 · Idempotency-Key

Dry-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.

POST/workflows/{id}/test-runworkflows:execute · R2 · simulated · 202 · Idempotency-Key
GET/workflows/{id}/runsworkflows:read · R0 · cursor
GET/workflow-runs/{id}workflows:read · R0
GET/workflow-runs/{id}/stepsworkflows:read · R0 · cursor
POST/workflow-runs/{id}/cancelworkflows:execute · R2 · Idempotency-Key
POST/workflow-runs/{id}/retryworkflows:execute · R2 · lineage · 202 · Idempotency-Key
GET/meetingsmeetings:read · R0 · cursor
POST/meetingsmeetings:write · R1 · 201 · Idempotency-Key
GET/meetings/{id}meetings:read · R0
PATCH/meetings/{id}meetings:write · R1 · If-Match · Idempotency-Key
POST/meetings/{id}/cancelmeetings:write · R2 · policy · If-Match
GET/meetings/{id}/inviteesmeetings:read · R0 · single page
POST/meetings/{id}/inviteesmeetings:write · R2 · external timezone required · Idempotency-Key
DELETE/meetings/{id}/invitees/{invitee_id}meetings:write · R2 · Idempotency-Key
POST/meetings/{id}/join-tokenmeetings:write · R1 · short-lived grant
POST/meetings/{id}/endmeetings:write · R2 · artifacts · If-Match
GET/meetings/{id}/recordingsmeeting_artifacts:read · R0
GET/meetings/{id}/transcriptmeeting_artifacts:read · R0
GET/meetings/{id}/summarymeeting_artifacts:read · R0
GET/meetings/{id}/action-itemsmeeting_artifacts:read · R0
GET/meetings/{id}/send-notes/eligibilitymeetings:write · R0 · policy check
POST/meetings/{id}/send-notes/planmeetings:write · R2 · plan · Idempotency-Key
POST/meetings/{id}/send-notesmeetings:write · R2 · 202 · Idempotency-Key
POST/meetings/{id}/refresh-conferencemeetings:write · R1 · Idempotency-Key
GET/performance/leaderboardanalytics:read · R0 · single page
GET/performance/reps/{user_id}analytics:read · R0
GET/coaching/templatescoaching:read · R0
POST/coaching/templatescoaching:write · R1 · Idempotency-Key
PATCH/coaching/templates/{id}coaching:write · R1 · If-Match · Idempotency-Key
GET/coaching/sessionscoaching:read · R0 · cursor
POST/coaching/sessionscoaching:write · R1 · Idempotency-Key
GET/coaching/sessions/{id}coaching:read · R0
POST/coaching/sessions/{id}/startcoaching:write · R1 · If-Match · Idempotency-Key
POST/coaching/sessions/{id}/completecoaching:write · R1 · If-Match · Idempotency-Key
POST/coaching/sessions/{id}/ai-insightscoaching:write · R2 · 202 · Idempotency-Key
GET/closer-assist/sessionscoaching:read · R0 · cursor
GET/closer-assist/sessions/{id}coaching:read · R0
GET/roleplay/nichesroleplay:read · R0
GET/roleplay/certificationsroleplay:read · R0
POST/roleplay/certifications/{mode}/startroleplay:execute · R1 · If-Match · Idempotency-Key
POST/roleplay/certifications/{mode}/completeroleplay:execute · R1 · If-Match · Idempotency-Key
POST/roleplay/sessionsroleplay:execute · R2 · simulated/202 · Idempotency-Key
GET/roleplay/sessionsroleplay:read · R0 · cursor
GET/roleplay/sessions/{id}roleplay:read · R0
POST/roleplay/sessions/{id}/messagesroleplay:execute · R2 · simulated/202 · Idempotency-Key
POST/roleplay/sessions/{id}/endroleplay:execute · R2 · If-Match · Idempotency-Key
GET/roleplay/sessions/{id}/scoreroleplay:read · R0
POST/roleplay/sessions/{id}/scoreroleplay:execute · R2 · Idempotency-Key
GET/supervisor/presencecoaching:read · R0 · owner/admin
GET/supervisor/agents/{user_id}coaching:read · R0 · owner/admin
POST/supervisor/agents/{user_id}/monitorcoaching:write · R2 · 202 · Idempotency-Key
POST/supervisor/agents/{user_id}/monitor/endcoaching:write · R2 · Idempotency-Key
GET/projectsprojects:read · R0 · offset
POST/projectsprojects:write · R1 · Idempotency-Key
GET/projects/{id}projects:read · R0 · project member
PATCH/projects/{id}projects:write · R1 · admin · If-Match · Idempotency-Key
POST/projects/{id}/archiveprojects:write · R1 · admin · If-Match · Idempotency-Key
POST/projects/{id}/restoreprojects:write · R1 · admin · If-Match · Idempotency-Key
GET/projects/{id}/membersprojects:read · R0 · member
PUT/projects/{id}/membersprojects:write · R1 · admin · If-Match · Idempotency-Key
POST/projects/{id}/membersprojects:write · R1 · Idempotency-Key
PATCH/projects/{id}/members/{user_id}projects:write · R1 · If-Match · Idempotency-Key
DELETE/projects/{id}/members/{user_id}projects:write · R1 · Idempotency-Key
GET/projects/{id}/columnsprojects:read · R0 · member
POST/projects/{id}/columnsprojects:write · R1 · admin · Idempotency-Key
PATCH/projects/{id}/columns/{column_id}projects:write · R1 · admin · If-Match · Idempotency-Key
POST/projects/{id}/columns/{column_id}/archiveprojects:write · R1 · Idempotency-Key
POST/projects/{id}/columns/reorderprojects:write · R1 · admin · If-Match · Idempotency-Key
GET/projects/{id}/tasksprojects:read · R0 · offset
POST/projects/{id}/tasksprojects:write · R1 · Idempotency-Key
GET/projects/{id}/tasks/{task_id}projects:read · R0 · member
PATCH/projects/{id}/tasks/{task_id}projects:write · R1 · If-Match · Idempotency-Key
POST/projects/{id}/tasks/{task_id}/moveprojects:write · R1 · If-Match · Idempotency-Key
POST/projects/{id}/tasks/{task_id}/archiveprojects:write · R1 · If-Match · Idempotency-Key
PUT/projects/{id}/tasks/{task_id}/assigneesprojects:write · R1 · If-Match · Idempotency-Key
PUT/projects/{id}/tasks/{task_id}/labelsprojects:write · R1 · If-Match · Idempotency-Key
POST/projects/{id}/tasks/{task_id}/checklistprojects:write · R1 · Idempotency-Key
PATCH/projects/{id}/tasks/{task_id}/checklist/{item_id}projects:write · R1 · If-Match · Idempotency-Key
DELETE/projects/{id}/tasks/{task_id}/checklist/{item_id}projects:write · R1 · If-Match · Idempotency-Key
GET/projects/{id}/tasks/{task_id}/commentsprojects:read · R0 · member
POST/projects/{id}/tasks/{task_id}/commentsprojects:write · R1 · Idempotency-Key
POST/projects/{id}/tasks/{task_id}/restoreprojects:write · R1 · Idempotency-Key
POST/projects/{id}/labelsprojects:write · R1 · Idempotency-Key
PATCH/projects/{id}/labels/{label_id}projects:write · R1 · Idempotency-Key
DELETE/projects/{id}/labels/{label_id}projects:write · R1 · Idempotency-Key
POST/projects/{id}/inviteprojects:write · R1 · Idempotency-Key
GET/projects/my-tasksprojects:read · R0
GET/projects/summaryprojects:read · R0
POST/files/uploadsfiles:write · R1 · validated private intent · Idempotency-Key
GET/files/{id}files:read · R0 · tenant-owned metadata
GET/files/{id}/downloadfiles:read · R0 · resource-bound expiry
POST/files/{id}/archivefiles:write · R1 · If-Match · Idempotency-Key
GET/chat/userschat:read · R0
GET/chat/roomschat:read · R0
POST/chat/channelschat:write · R1 · admin · Idempotency-Key
GET/chat/channels/{id}chat:read · R0 · room access
PATCH/chat/channels/{id}chat:write · R1 · admin · If-Match · Idempotency-Key
POST/chat/channels/{id}/archivechat:write · R1 · admin · If-Match · Idempotency-Key
GET/chat/channels/{id}/memberschat:read · R0 · room access
PUT/chat/channels/{id}/memberschat:write · R1 · admin · Idempotency-Key
POST/chat/channels/{id}/memberschat:write · R1 · Idempotency-Key
DELETE/chat/channels/{id}/members/{user_id}chat:write · R1 · Idempotency-Key
POST/chat/dmschat:write · R1 · human actor · Idempotency-Key
GET/chat/rooms/{id}/messageschat:read · R0 · room access · cursor
POST/chat/rooms/{id}/messageschat:write · R1 · client UUID · Idempotency-Key
PATCH/chat/messages/{id}chat:write · R1 · authorship · If-Match · Idempotency-Key
DELETE/chat/messages/{id}chat:write · R1 · authorship/admin · If-Match · Idempotency-Key
POST/chat/messages/{id}/reactionschat:write · R1 · Idempotency-Key
POST/chat/rooms/{id}/readchat:write · R1 · Idempotency-Key
POST/chat/attachmentschat:write · R1 · Idempotency-Key
GET/invoicesfinance:read · R0 · cursor
POST/invoicesinvoices:write · R1 · draft · Idempotency-Key
GET/invoices/{id}finance:read · R0
PATCH/invoices/{id}invoices:write · R1 · If-Match · Idempotency-Key
POST/invoices/{id}/issue/planinvoices:write · R2 · exact plan · Idempotency-Key
POST/invoices/{id}/issueinvoices:write · R2 · approved plan · If-Match · Idempotency-Key
POST/invoices/{id}/void/planinvoices:write · R3 · exact plan · Idempotency-Key
POST/invoices/{id}/voidinvoices:write · R3 · approved plan · If-Match · Idempotency-Key
GET/paymentsfinance:read · R0 · cursor
GET/payments/{id}finance:read · R0
POST/payments/record/planpayments:write · R2 · exact tenant payment plan · Idempotency-Key
POST/paymentspayments:write · R2 · hosted/tokenized · Idempotency-Key
POST/payments/{id}/refund/planpayments:write · R3 · exact plan · Idempotency-Key
POST/payments/{id}/refundpayments:write · R3 · approved plan · If-Match · Idempotency-Key
GET/subscriptionsfinance:read · R0 · cursor
GET/subscriptions/{id}finance:read · R0
GET/documentsfinance:read · R0 · cursor
POST/documentsdocuments:write · R1 · draft · Idempotency-Key
GET/documents/{id}finance:read · R0
POST/documents/{id}/send/plandocuments:write · R2 · exact plan · Idempotency-Key
POST/documents/{id}/senddocuments:write · R2 · approved plan · If-Match · Idempotency-Key
GET/legal-template-catalogfinance:read · R0
GET/legal-template-catalog/{id}finance:read · R0
GET/legal-clausesfinance:read · R0
POST/legal-clausesdocuments:write · R1 · Idempotency-Key
GET/legal-clauses/{id}finance:read · R0
GET/legal-clauses/{id}/versionsfinance:read · R0
POST/legal-clauses/{id}/versionsdocuments:write · R1 · Idempotency-Key
POST/legal-clauses/{id}/approvedocuments:write · R1 · Idempotency-Key
GET/legal-clauses/{id}/usagefinance:read · R0
POST/document-drafts/importdocuments:write · R1 · PDF/DOC/DOCX upload · Idempotency-Key
GET/document-draftsdocuments:write · R0
GET/document-drafts/{id}documents:write · R0
PATCH/document-drafts/{id}documents:write · R1 · If-Match · Idempotency-Key
POST/native-documents/{id}/edit-copydocuments:write · R1 · creates a new editable draft; the original and its evidence remain unchanged
GET/document-drafts/{id}/sourcedocuments:write · R0 · canonical PDF
POST/document-drafts/{id}/retry-conversiondocuments:write · R1 · Idempotency-Key
POST/document-drafts/{id}/senddocuments:write · R1 · Idempotency-Key
GET/document-content-blocksfinance:read · R0
POST/document-content-blocksdocuments:write · R1 · Idempotency-Key
DELETE/document-content-blocks/{id}documents:write · R1 · Idempotency-Key
GET/document-commentsfinance:read · R0
POST/document-commentsdocuments:write · R1 · Idempotency-Key
PATCH/document-comments/{id}documents:write · R1 · Idempotency-Key
GET/document-templatesfinance:read · R0
POST/document-templatesdocuments:write · R1 · Idempotency-Key
GET/document-templates/{id}finance:read · R0
PATCH/document-templates/{id}documents:write · R1 · If-Match · Idempotency-Key
POST/document-templates/{id}/previewfinance:read · R0
GET/document-templates/{id}/versionsfinance:read · R0
POST/document-templates/{id}/versionsdocuments:write · R1 · Idempotency-Key
GET/document-templates/{id}/versions/{versionId}/pdf-layoutdocuments:write · R0 · MCP
GET/document-templates/{id}/versions/{versionId}/source-pdfdocuments:write · R0 · private PDF bytes
POST/document-templates/{id}/versions/{versionId}/preview-pdfdocuments:write · R0 · PDF bytes · MCP resource

Visual 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.

POST/document-templates/{id}/submit-reviewdocuments:write · R1 · Idempotency-Key
POST/document-templates/{id}/approvedocuments:write · R1 · Idempotency-Key
POST/document-templates/{id}/archivedocuments:write · R1 · Idempotency-Key

Private 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.

GET/private-contactsdocuments:write · delegated owner/admin
POST/private-contactsdocuments:write · delegated owner/admin · Idempotency-Key
GET/private-contacts/{id}documents:write · delegated owner/admin
PATCH/private-contacts/{id}documents:write · delegated owner/admin · Idempotency-Key
GET/private-contacts/{id}/documentsdocuments:write · delegated owner/admin
POST/private-contacts/{id}/preview-pdfdocuments:write · delegated owner/admin
POST/private-contacts/{id}/senddocuments:write · delegated owner/admin · Idempotency-Key
GET/native-documentsfinance:read · R0
POST/native-documentsdocuments:write · R1 · Idempotency-Key
GET/native-documents/{id}finance:read · R0
GET/native-documents/{id}/statusfinance:read · R0
POST/native-documents/{id}/senddocuments:write · R1 · Idempotency-Key
POST/native-documents/{id}/resenddocuments:write · R1 · Idempotency-Key
POST/native-documents/{id}/voiddocuments:write · R1 · Idempotency-Key
GET/native-documents/{id}/eventsfinance:read · R0
GET/native-documents/{id}/evidencefinance:read · R0
GET/native-documents/{id}/downloadfinance:read · R0
POST/native-documents/{id}/retry-onboardingdocuments:write · R1 · Idempotency-Key
GET/native-documents/{id}/billingfinance:read · R0
POST/native-documents/{id}/billing/changesdocuments:write · R1 · Idempotency-Key
POST/native-documents/{id}/billing/chargesdocuments:write · R1 · Idempotency-Key
POST/native-documents/{id}/billing/charges/{charge_id}/issuedocuments:write · R1 · Idempotency-Key
POST/native-documents/{id}/billing/charges/{charge_id}/mark-paiddocuments:write · R1 · Idempotency-Key
POST/native-documents/{id}/billing/charges/{charge_id}/voiddocuments:write · R1 · Idempotency-Key
GET/payment-settingsfinance:read · R0
PATCH/payment-settingsdocuments:write · R1 · Idempotency-Key

Free 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.

GET/documents/{id}/evidencefinance:read · R0
POST/documents/{id}/native-signing-linkdocuments:write · R1 · Idempotency-Key
GET/deals/{deal_id}/documentsdocuments:read · R0
GET/commissionscommissions:read · R0 · cursor
GET/commissions/{id}commissions:read · R0
PATCH/commissions/{id}commissions:write · R1 · If-Match · Idempotency-Key
POST/commissions/{id}/approve/plancommissions:approve · R3 · exact plan
POST/commissions/{id}/approvecommissions:approve · R3 · separate approver · Idempotency-Key
POST/commissions/{id}/mark-paid/plancommissions:approve · R3 · exact plan
POST/commissions/{id}/mark-paidcommissions:approve · R3 · separate approver · Idempotency-Key
POST/commissions/bulk-mark-paid/plancommissions:approve · R3 · exact set/total plan
POST/commissions/bulk-mark-paidcommissions:approve · R3 · separate approver · Idempotency-Key
GET/phone-numbersphone_numbers:read · R0 · cursor
GET/phone-numbers/{id}phone_numbers:read · R0
POST/phone-numbers/searchphone_numbers:manage · R0 · provider read
POST/phone-numbers/purchases/planphone_numbers:manage · R3 · plan
POST/phone-numbers/purchasesphone_numbers:manage · R3 · approved · Idempotency-Key
POST/phone-numbers/{id}/health-checkphone_numbers:manage · R2 · provider read
GET/phone-numbers/{id}/health-historyphone_numbers:read · R0 · cursor
GET/phone-numbers/local-presence-policyphone_numbers:read · R0
PUT/phone-numbers/local-presence-policyphone_numbers:manage · R2 · If-Match · Idempotency-Key
POST/phone-numbers/{id}/replacement/planphone_numbers:manage · R3 · plan
POST/phone-numbers/{id}/replacementphone_numbers:manage · R3 · approved · If-Match
POST/phone-numbers/{id}/retire/planphone_numbers:manage · R3 · plan
POST/phone-numbers/{id}/retirephone_numbers:manage · R3 · approved · If-Match
POST/phone-numbers/{id}/quarantine/planphone_numbers:manage · R2 · plan
POST/phone-numbers/{id}/quarantinephone_numbers:manage · R2 · If-Match · Idempotency-Key
GET/receptionist/agentsreceptionist:read · R0 · cursor
POST/receptionist/agentsreceptionist:write · R1 · Idempotency-Key
GET/receptionist/agents/{id}receptionist:read · R0
PATCH/receptionist/agents/{id}receptionist:write · R1 · If-Match · Idempotency-Key
POST/receptionist/agents/{id}/activatereceptionist:write · R2 · If-Match
POST/receptionist/agents/{id}/deactivatereceptionist:write · R2 · If-Match
GET/receptionist/agents/{id}/config-versionsreceptionist:read · R0
GET/receptionist/routesreceptionist:read · R0 · cursor
PUT/receptionist/routes/{phone_number_id}receptionist:write · R2 · If-Match · Idempotency-Key
GET/receptionist/knowledge-sourcesreceptionist:read · R0 · cursor
POST/receptionist/knowledge-sourcesreceptionist:write · R1 · Idempotency-Key
GET/receptionist/knowledge-sources/{id}receptionist:read · R0
PATCH/receptionist/knowledge-sources/{id}receptionist:write · R1 · If-Match · Idempotency-Key
POST/receptionist/knowledge-sources/{id}/approvereceptionist:write · R2 · If-Match · Idempotency-Key
PUT/receptionist/agents/{id}/knowledgereceptionist:write · R1 · If-Match · Idempotency-Key
GET/receptionist/sessionsreceptionist:read · R0 · cursor
GET/receptionist/sessions/{id}receptionist:read · R0
GET/receptionist/sessions/{id}/transcriptrecordings:read · R0
POST/receptionist/sessions/{id}/handoffreceptionist:write · R2 · policy/usage gate
GET/receptionist/analyticsanalytics:read · R0
GET/formsforms:read · R0 · cursor
POST/formsforms:write · R1 · Idempotency-Key
GET/forms/{brand}forms:read
PATCH/forms/{brand}forms:write · R1 · If-Match · Idempotency-Key
POST/forms/{brand}/publishforms:write · R1 · If-Match · Idempotency-Key
POST/forms/{brand}/unpublishforms:write · R1 · If-Match · Idempotency-Key
POST/forms/{brand}/archiveforms:write · R1 · If-Match · Idempotency-Key
POST/forms/{brand}/cloneforms:write · R1 · Idempotency-Key
PUT/forms/{brand}/serving-areaforms:write · R1 · Idempotency-Key · If-Match
GET/forms/{brand}/revisionsforms:read · R0 · cursor
GET/forms/{brand}/revisions/{revision_id}forms:read · R0
GET/forms/{brand}/submissionsforms:submissions:read · R0 · cursor
GET/forms/{brand}/submissions/{id}forms:submissions:read · R0
POST/forms/{brand}/submissions/{id}/reviewforms:write · R1 · Idempotency-Key
GET/forms/{brand}/analyticsanalytics:read · R0
POST/forms/{brand}/eventsforms:submit · R1 · 204 · Idempotency-Key
POST/forms/{brand}/submissionsforms:submit
GET/public-linksforms:read · R0 · cursor
PATCH/public-links/{id}forms:write · R1 · If-Match · Idempotency-Key
GET/analytics/application-funnelanalytics:read
GET/analytics/dashboardanalytics:read · R0
GET/analytics/funnelanalytics:read · R0
GET/analytics/sourcesanalytics:read · R0 · cursor
GET/analytics/velocityanalytics:read · R0 · cursor
GET/analytics/attributionanalytics:read · R0 · cursor
GET/analytics/cohortsanalytics:read · R0 · cursor
GET/analytics/paid-performancemarketing:read · R0 · cursor
GET/analytics/creativesmarketing:read · R0 · cursor
GET/analytics/unit-economicsmarketing:read · R0 · cursor
GET/analytics/data-qualityanalytics:read · R0 · cursor
GET/analytics/attendanceanalytics:read · R0 · cursor
GET/analytics/leaderboardanalytics:read · R0 · cursor
POST/analytics/exportsanalytics:export · R1 · 202 · Idempotency-Key
POST/tracking/eventsforms:submit · R1 · 200/201 · Idempotency-Key
POST/tracking/conversion-eventsforms:submit · R1 · 200/201 · Idempotency-Key
POST/commerce/eventsforms:submit · R1 · 200/201 · Idempotency-Key
GET/tracking/events/{event_id}analytics:read · R0
GET/marketing/connectionsintegrations:read · R0 · cursor
POST/marketing/connections/{provider}/authorizeintegrations:write · R1 · hosted OAuth · Idempotency-Key
GET/marketing/connections/{provider}/callbackintegrations:write · R1 · state/PKCE/nonce-bound callback
GET/marketing/authorizations/{id}integrations:read · R0 · redacted status
GET/marketing/connections/{id}integrations:read · R0 · redacted
POST/marketing/connections/{id}/syncforms:submit · R2 · queued/simulated · Idempotency-Key
POST/marketing/connections/{id}/disconnect/planintegrations:write · R3 · exact plan · Idempotency-Key
POST/marketing/connections/{id}/disconnectintegrations:write · R3 · approved/simulated · Idempotency-Key
GET/marketing/goal-mappingsmarketing:read · R0 · cursor
PUT/marketing/goal-mappings/{provider}forms:submit · R1 · Idempotency-Key
GET/marketing/consent-policiesmarketing:read · R0 · cursor
PUT/marketing/consent-policies/{brand_id}forms:submit · R2 · Idempotency-Key
GET/marketing/tracking-gateway/{brand_id}marketing:read · R0
PUT/marketing/tracking-gateway/{brand_id}marketing:configure · R2 · plan-first · Idempotency-Key
GET/marketing/tracking-block-rulesmarketing:read · R0 · cursor
POST/marketing/tracking-block-rulesmarketing:configure · R1 · Idempotency-Key
DELETE/marketing/tracking-block-rules/{id}marketing:configure · R1 · Idempotency-Key
GET/marketing/recommendationsmarketing:read · R0 · cursor
GET/marketing/recommendations/{id}marketing:read · R0
POST/marketing/recommendations/{id}/reviewforms:submit · R1 · Idempotency-Key
POST/marketing/recommendations/{id}/execute/planmarketing:execute · R2 · quality/plan gate
POST/marketing/recommendations/{id}/executemarketing:execute · R2 · queued/simulated · Idempotency-Key
POST/marketing/actions/{id}/rollback/planmarketing:execute · R3 · prior-state plan
POST/marketing/actions/{id}/rollbackmarketing:execute · R3 · approved/simulated · Idempotency-Key
GET/marketing/actionsmarketing:read · R0 · cursor
GET/marketing/forecastsmarketing:read · R0 · freshness warnings · cursor
POST/marketing/forecastsforms:submit · R2 · queued/simulated · Idempotency-Key
GET/marketing/identity/unresolvedmarketing:read · R0 · cursor
POST/marketing/identity/correctionsforms:submit · R1 · redacted · Idempotency-Key
GET/growth/stategrowth:read · R0 · entitlement
GET/growth/brandsgrowth:read · R0 · cursor
POST/growth/brandsgrowth:write · R1 · Idempotency-Key
GET/growth/brands/{id}growth:read · R0
PATCH/growth/brands/{id}growth:write · R1 · If-Match
GET/growth/brands/{id}/keyword-plannergrowth:read · R0
GET/growth/brands/{id}/keyword-planner/accountsseo:configure · R0
PUT/growth/brands/{id}/keyword-plannerseo:configure · R1 · If-Match
POST/growth/brands/{id}/assetsgrowth:write · R1 · bounded upload
DELETE/growth/brands/{id}/assets/{role}growth:write · R1 · If-Match
GET/growth/brands/{id}/topicsgrowth:read · R0 · cursor
POST/growth/brands/{id}/topicsgrowth:write · R1 · Idempotency-Key
POST/growth/brands/{id}/topics/suggestgrowth:generate · R2 · queued/simulated
GET/growth/postsgrowth:read · R0 · cursor
POST/growth/posts/generategrowth:generate · R2 · queued/simulated
GET/growth/posts/{id}growth:read · R0
PATCH/growth/posts/{id}growth:write · R1 · If-Match
POST/growth/posts/{id}/enhancegrowth:generate · R2 · queued/simulated
POST/growth/posts/{id}/approvegrowth:write · R1 · editorial only
POST/growth/posts/{id}/rejectgrowth:write · R1 · editorial only
POST/growth/posts/{id}/publish/plangrowth:publish · R3 · exact plan
POST/growth/posts/{id}/publishgrowth:publish · R3 · approved/simulated
POST/growth/posts/{id}/unpublish/plangrowth:publish · R2 · exact plan
POST/growth/posts/{id}/unpublishgrowth:publish · R2 · approved/simulated
GET/growth/metricsgrowth:read · R0
GET/growth/brands/{id}/pipeline-healthgrowth:read · R0
GET/growth/brands/{id}/index-healthseo:read · R0
GET/growth/brands/{id}/niche-coverageseo:read · R0
GET/growth/brands/{id}/cta-experimentsgrowth:read · R0
GET/growth/brands/{id}/ai-visibilityseo:read · R0 · versioned evidence
GET/growth/brands/{id}/backlinksseo:read · R0 · cursor
POST/growth/brands/{id}/backlinks/{backlinkId}/reviewgrowth:write · R1 · If-Match
GET/seo/connectionsseo:read · R0 · cursor
POST/seo/connections/google/authorizeseo:configure · R1 · hosted OAuth
GET/seo/connections/google/callbackseo:configure · R1 · state/PKCE/nonce-bound callback
GET/seo/authorizations/{id}seo:read · R0 · redacted status
POST/seo/connections/{id}/syncseo:configure · R2 · queued/simulated
GET/seo/opportunitiesseo:read · R0 · cursor
GET/seo/recommendationsseo:read · R0 · cursor
GET/seo/google-updatesseo:read · R0
POST/seo/recommendations/{id}/reviewseo:configure · R1 · If-Match
GET/signalssignals:read · R0 · cursor
GET/signals/{id}signals:read · R0
POST/signals/{id}/convert-to-leadleads:write · R1 · idempotent conversion
GET/prospect-packsleads:read · R0 · cursor
POST/prospect-packs/requests/planleads:bulk · R3 · exact criteria/cost plan
POST/prospect-packs/requestsleads:bulk · R3 · approved · queued/simulated
GET/prospect-packs/requests/{id}leads:read · R0 · job state
GET/usersusers:read · R0 · cursor
POST/users/invitations/planusers:write · R1 · exact team_ids plan + approval
POST/users/invitationsusers:write · R1 · 202 · Idempotency-Key
GET/users/{id}users:read · R0
PATCH/users/{id}users:write · R1 · If-Match · Idempotency-Key
POST/users/{id}/disable/planusers:write · R3 · exact ownership/workload plan
POST/users/{id}/disableusers:write · R3 · approved plan
POST/users/{id}/enableusers:write · R1 · If-Match · Idempotency-Key
PATCH/users/meusers:write · R1 · Idempotency-Key
GET/teamsteams:read · R0 · cursor
POST/teamsteams:write · R1 · Idempotency-Key
GET/teams/{id}teams:read · R0
PATCH/teams/{id}teams:write · R1 · If-Match · Idempotency-Key
PUT/teams/{id}/membersteams:write · R1 · tenant membership
POST/teams/{id}/membersteams:write · R1 · Idempotency-Key
DELETE/teams/{id}/members/{user_id}teams:write · R1 · Idempotency-Key
POST/teams/{id}/archive/planteams:write · R1 · workload plan + approval
POST/teams/{id}/archiveteams:write · R1 · workload/If-Match
GET/workspaceworkspace:read · R0
PATCH/workspaceworkspace:write · R1 · If-Match · Idempotency-Key
GET/workspace/brandingworkspace:read · R0
PATCH/workspace/brandingworkspace:write · R1 · allowlisted HTTPS logo
GET/workspace/notification-policiesworkspace:read · R0 · typed
PUT/workspace/notification-policiesworkspace:write · R1 · typed destinations · If-Match or version · Idempotency-Key
GET/workspace/usageworkspace:read · R0
GET/workspace/entitlementsworkspace:read · R0
GET/workspacesworkspace:read · agency-owned cursor
POST/workspaces/planworkspace:write · R3 · exact plan
POST/workspacesworkspace:write · R3 · approved/simulated
GET/workspaces/{id}workspace:read · R0 · owned relationship
PATCH/workspaces/{id}workspace:write · R1 · If-Match
POST/workspaces/{id}/suspend/planworkspace:write · R3 · exact plan
POST/workspaces/{id}/suspendworkspace:write · R3 · approved/simulated
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}/authorize/completeintegrations:write · R1 · bounded/redacted completion
GET/integrations/{provider}/authorize/statusintegrations:read · R0 · redacted status
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 email_domains_cursor/integrations_cursor · 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
GET/billing/statebilling:read · R0
GET/billing/usagebilling:read · R0 · minor units
GET/billing/plansbilling:read · R0 · Free plan and upgrade links
POST/billing/plan-changes/previewbilling:write · R3 · downgrade to Free only · Idempotency-Key
POST/billing/plan-changesbilling:write · R3 · approved provider/simulation · 200 · Idempotency-Key
POST/billing/topups/previewbilling:write · R3 · exact plan · Idempotency-Key
POST/billing/topupsbilling:write · R3 · approved provider/simulation · 200 · Idempotency-Key
POST/billing/portal-sessionsbilling:write · R1 · provider-hosted URL · Idempotency-Key
GET/webhook-endpointsdeveloper:webhooks:read
POST/webhook-endpointsdeveloper:webhooks:write
GET/webhook-endpoints/{endpoint_id}developer:webhooks:read
PATCH/webhook-endpoints/{endpoint_id}developer:webhooks:write
DELETE/webhook-endpoints/{endpoint_id}developer:webhooks:write · R3 · policy · Idempotency-Key + If-Match
POST/webhook-endpoints/{endpoint_id}/rotate-secretdeveloper:webhooks:write
GET/webhook-endpoints/{endpoint_id}/deliveriesdeveloper:webhooks:read
GET/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}developer:webhooks:read
POST/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/retrydeveloper:webhooks:write
POST/workflows/{workflowId}/triggerworkflows:trigger
GET/jobsdomain read scope
GET/jobs/{job_id}domain read scope
POST/jobs/{job_id}/canceloriginating execute scope
GET/approval-requestsapprovals:read
POST/approval-requestsapprovals:request
GET/approval-requests/{approval_request_id}approvals:read
POST/approval-requests/{approval_request_id}/cancelapprovals:request
GET/audit-eventsaudit:read
GET/audit-events/{audit_event_id}audit:read
GET/developer/scopesdeveloper:credentials:admin
GET/service-accountsdeveloper:credentials:admin
POST/service-accountsdeveloper:credentials:admin
GET/service-accounts/{service_account_id}developer:credentials:admin
PATCH/service-accounts/{service_account_id}developer:credentials:admin
POST/service-accounts/{service_account_id}/rotatedeveloper:credentials:admin
POST/service-accounts/{service_account_id}/disabledeveloper:credentials:admin
POST/service-accounts/{service_account_id}/enabledeveloper:credentials:admin
GET/service-accounts/{service_account_id}/credentialsdeveloper:credentials:admin
POST/service-accounts/{service_account_id}/credentialsdeveloper:credentials:admin
DELETE/service-accounts/{service_account_id}/credentials/{credential_id}developer:credentials:admin
GET/tagstags:read
POST/tagstags:write · R1 · Idempotency-Key
GET/tags/{tag_id}tags:read
PATCH/tags/{tag_id}tags:write · R1 · If-Match
POST/tags/{tag_id}/archivetags:write · R1 · If-Match
GET/leads/{lead_id}/tagstags:read
PUT/leads/{lead_id}/tagstags:write · R1 · Idempotency-Key
GET/deals/{deal_id}/tagstags:read
PUT/deals/{deal_id}/tagstags:write · R1 · Idempotency-Key
GET/custom-fieldscustom_fields:read
POST/custom-fieldscustom_fields:write · R1 · Idempotency-Key
GET/custom-fields/{field_id}custom_fields:read
PATCH/custom-fields/{field_id}custom_fields:write · R1 · If-Match
POST/custom-fields/{field_id}/archivecustom_fields:write · R1 · If-Match
GET/leads/{lead_id}/custom-fieldscustom_fields:read
PUT/leads/{lead_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key
POST/leads/deduplicateleads:write · R2 · Idempotency-Key
POST/leads/notes/bulk-deleteleads:write · R1 · Idempotency-Key
POST/leads/idsleads:read · R0 · Idempotency-Key
GET/leads/pipelineleads:read · R0
POST/leads/import/jsonleads:bulk · R1 · Idempotency-Key
GET/leads/import/templateleads:bulk · R0
GET/deals/{deal_id}/custom-fieldscustom_fields:read
PUT/deals/{deal_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key
GET/smart-lists/filter-schemasmart_lists:read
GET/smart-listssmart_lists:read · cursor
POST/smart-listssmart_lists:write · R1 · Idempotency-Key
POST/smart-lists/previewsmart_lists:write · R0 · Idempotency-Key
GET/smart-lists/{id}smart_lists:read
PATCH/smart-lists/{id}smart_lists:write · R1 · If-Match
DELETE/smart-lists/{id}smart_lists:write · R1 · If-Match
GET/smart-lists/{id}/leadsleads:read · cursor
GET/pipelinespipelines:read
POST/pipelinespipelines:write · R1 · Idempotency-Key
GET/pipelines/{id}pipelines:read
PATCH/pipelines/{id}pipelines:write · R1 · If-Match
POST/pipelines/{id}/archivepipelines:write · R1 · If-Match
POST/pipelines/{id}/stagespipelines:write · R1 · Idempotency-Key
PATCH/pipelines/{id}/stages/{stage_id}pipelines:write · R1 · If-Match
POST/pipelines/{id}/stages/{stage_id}/archivepipelines:write · R1 · If-Match
POST/pipelines/{id}/stages/reorderpipelines:write · R1 · If-Match
GET/dealsdeals:read · R0 · cursor
POST/dealsdeals:write · R1 · Idempotency-Key
GET/deals/{id}deals:read · R0
PATCH/deals/{id}deals:write · R1 · If-Match
POST/deals/{id}/movedeals:write · R1 · If-Match
POST/deals/{id}/wondeals:write · R1 · If-Match
POST/deals/{id}/lostdeals:write · R1 · If-Match
POST/deals/{id}/reopendeals:write · R1 · If-Match
POST/deals/{id}/archivedeals:archive · R1 · If-Match
POST/deals/{id}/restoredeals:archive · R1 · If-Match
GET/deals/{id}/activitiesdeals:read · R0 · cursor
POST/deals/{id}/activitiesdeals:write · R1 · Idempotency-Key
GET/deals/filter-schemadeals:read · R0
POST/deals/querydeals:read · R0 · cursor · Idempotency-Key
GET/pipelines/{id}/boarddeals:read · R0 · single page
GET/pipelines/{id}/forecastanalytics:read · R0
GET/taskstasks:read · R0 · cursor
POST/taskstasks:write · R1 · Idempotency-Key
GET/tasks/{id}tasks:read · R0
PATCH/tasks/{id}tasks:write · R1 · If-Match
POST/tasks/{id}/completetasks:write · R1 · If-Match
POST/tasks/{id}/reopentasks:write · R1 · If-Match
POST/tasks/{id}/archivetasks:write · R1 · If-Match
DELETE/tasks/{id}tasks:write · R1 · If-Match
POST/tasks/querytasks:read · R0 · Idempotency-Key
GET/tasks/filter-schematasks:read · R0
GET/task-summarytasks:read · R0
GET/calendar/entriestasks:read · R0 · cursor
GET/calendar/entries/{id}tasks:read · R0
POST/calendar/entriestasks:write · R1 · Idempotency-Key
PATCH/calendar/entries/{id}tasks:write · R1 · If-Match
DELETE/calendar/entries/{id}tasks:write · R1 · If-Match
GET/calendar/bootstraptasks:read · R0
GET/calendar/feedtasks:read · R0
GET/notifications/mentionsnotifications:read · R0
POST/notifications/mentions/{id}/readnotifications:write · R1 · Idempotency-Key
POST/notifications/mentions/read-allnotifications:write · R1 · Idempotency-Key
GET/webhook-eventsdeveloper:webhooks:read · R0
GET/saved-viewssaved_views:read · R0
GET/saved-views/{id}saved_views:read · R0
POST/saved-viewssaved_views:write · R1 · Idempotency-Key
PATCH/saved-views/{id}saved_views:write · R1 · Idempotency-Key
DELETE/saved-views/{id}saved_views:write · R1 · Idempotency-Key
POST/saved-views/{id}/defaultsaved_views:write · R1 · Idempotency-Key
POST/saved-views/reordersaved_views:write · R1 · Idempotency-Key

Calls 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.

i
Protected artifacts

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.

Scopes: call lifecycle uses 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.

i
Concurrency and live-floor controls

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.

Scopes and retries: queues use 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.

i
Tenant-safe routing

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.

Scopes: use 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.

i
Audience-bound execution

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.

Scopes: use 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.

i
Durable and simulation-safe

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.

Scopes: meetings use 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.

i
Private storage by construction

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.

Scopes: use 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.

i
Actor identity is explicit

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.

Scopes and retries: use 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.

i
Token-safe provider flows

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.

Scopes and plans: reads use 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.

i
Exact R3 payout controls

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.

Scopes and retries: use 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.

i
Replay-safe concurrency

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.

i
Preview first, commit deliberately

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.

POST/leads/importsleads:bulk · R1 · 202

Send 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.

FieldTypeContract
file requiredCSV/TSVUTF-8 upload; raw bytes are parsed and not retained by the public response.
mappingsJSON objectSource 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 requiredheader8–200 URL-safe characters; replay returns the original 202 response.
Request
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"}'
202 response
{
  "data": {
    "job_id": "job_01JIMPORT",
    "status": "succeeded",
    "resource_type": "lead_import",
    "resource_id": "imp_01JIMPORT",
    "simulated": true,
    "import": { "counts": { "rows": 1, "valid": 1 } }
  }
}
Preview errors: 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.
POST/leads/imports/{import_id}/commitleads:bulk · R1 · 202

Send 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.

POST/leads/exportsanalytics:export · R1 · 202

Provide 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.

Request
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"}'
202 response
{
  "data": {
    "job_id": "job_01JEXPORT",
    "status": "queued",
    "resource_id": "art_01JEXPORT",
    "artifact": { "status": "pending", "download_url": null }
  }
}
Explicit projection: the response and artifact metadata never expose workspace_id, credential data, internal provider columns, storage keys, raw URLs, or an unbounded Excel buffer.
GET/leads/exports/{artifact_id}analytics:export · R0

Inspect 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.

GET/leads/exports/{artifact_id}/downloadanalytics:export · R0 · audited

The 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.

1
Brand selection is only required when there is a choice

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.

GET/scheduling/brandsscheduling:read

Returns 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.

Request
curl https://leadtrackerai.com/api/v1/scheduling/brands \
  -H "Authorization: Bearer $LEADTRACKER_API_KEY"
200 response
{
  "data": [{
    "id": 17,
    "identifier": "acme-consulting",
    "name": "Acme Consulting",
    "event_type_ids": [42],
    "routing_mode": "round_robin",
    "active_calendar_count": 2
  }]
}
Validated as one pair: a brand from another workspace, an unknown ID, or an event type assigned to another brand is rejected before a lead, room, calendar event, or email is created. Brand names are never hard-coded by the API.

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.

GET/scheduling/event-typesscheduling:read

Returns active event types and their scheduling constraints.

Request
curl https://leadtrackerai.com/api/v1/scheduling/event-types \
  -H "Authorization: Bearer $LEADTRACKER_API_KEY"
200 response
{
  "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.

GET/scheduling/availabilityscheduling:read
Query parameterTypeDescription
brand_idintegerOptional when the event type has exactly one active brand. Required when more than one brand is possible.
event_type_id requiredintegerAn ID returned by the event types endpoint.
start_date requiredYYYY-MM-DDFirst calendar date to inspect.
end_date requiredYYYY-MM-DDLast calendar date to inspect. Ranges may be up to 31 days.
routing_keystringA 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_idintegerOptional known LeadTracker user. If that active closer belongs to the brand pool, they remain pinned instead of consuming a round-robin turn.
Request
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"
200 response
{
  "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.

POST/scheduling/bookingsscheduling:write
Body fieldTypeDescription
brand_idintegerOptional when the event type has exactly one active brand. For multi-brand workspaces, reuse the explicit value sent to availability.
event_type_id requiredintegerThe active LeadTracker AI event type.
routing_keystringThe 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_idintegerOptional known closer override. Otherwise an existing active lead closer is preserved, then the brand round robin is used.
start requiredISO 8601 UTCThe exact slot start returned by availability.
attendee.name requiredstringProspect name.
attendee.email or attendee.phone requiredstringAt least one contact method. Phone is recommended for SMS reminders.
attendee.timezone requiredCanonical IANA timezoneFor example America/Chicago or Asia/Dubai. Fixed aliases such as EST and numeric offsets are rejected.
sourcestringYour integration label, such as vapi or retell.
external_referencestringYour call, conversation, or booking identifier for reconciliation.
metadataobjectOptional integration context, stored with the booking. Maximum 16 KB.
Request
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" }
  }'
201 Created
Response
{
  "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
}
i
Two different emails are sent

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 and retries: use one call/conversation ID as both 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.

GET/scheduling/bookingsscheduling:read
Query fieldTypeDescription
emailemailExact attendee email filter.
statusstringBooking status filter, such as scheduled or cancelled.
fromstringLower date/time bound in the existing scheduler filter format.
tostringUpper date/time bound in the existing scheduler filter format.
Request
curl "https://leadtrackerai.com/api/v1/scheduling/bookings?status=scheduled" \
  -H "Authorization: Bearer $LEADTRACKER_API_KEY"
200 response
{
  "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" }
  }]
}
Legacy collection: this endpoint uses bounded filters rather than cursor pagination for compatibility. Use the single-booking endpoint when reconciling a known booking UID.

Read a booking

GET/scheduling/bookings/{booking_id}scheduling:read

Use the LeadTracker AI booking ID returned when an appointment is created. The record is only accessible within the API key's workspace.

Request
curl https://leadtrackerai.com/api/v1/scheduling/bookings/ltbk_9c7bd1... \
  -H "Authorization: Bearer $LEADTRACKER_API_KEY"

Reschedule a booking

POST/scheduling/bookings/{booking_id}/reschedulescheduling:write

LeadTracker AI validates the requested slot again, updates the connected calendar event and native meeting, and re-evaluates reminder delivery.

Request body
{
  "start": "2026-07-16T16:00:00.000Z",
  "reason": "Caller requested a later time"
}

Cancel a booking

POST/scheduling/bookings/{booking_id}/cancelscheduling:write

Cancelling removes the provider event when connected, stops pending reminders, clears the active appointment from the CRM lead, and retains the booking history.

Request body
{
  "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.

Stage values: READ operations (list, query, filter) accept all five stages: 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.
GET/leads?filter=...&sort=...List leads with optional structured filter and sort
POST/leads/queryQuery leads with structured filter document
GET/leads/search?q=... | email=... | phone=...Find a specific lead
GET/leads/{lead_id}Read one lead
POST/leads | /leads/upsertCreate or match a lead
PATCH/leads/{lead_id}Update CRM-safe fields
POST/leads/{lead_id}/notes | /activitiesAdd CRM history
Endpoint-specific contracts: /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.
POST/leads/queryleads:read

Query 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.

Request
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
  }'
Search grammar example
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" }
      ]
    }
  }'
GET/leads?filter=...&sort=...leads:read

GET /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.

Request
curl "https://leadtrackerai.com/api/v1/leads?sort=lead_score:desc&limit=50" \
  -H "Authorization: Bearer $LEADTRACKER_API_KEY"
POST/leads/upsertleads:write

Provide an email or phone to match an existing record. Every lead mutation requires Idempotency-Key.

Request
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.

GET/tagstags:read · R0 · cursor
POST/tagstags:write · R1 · Idempotency-Key
GET/tags/{tag_id}tags:read · R0
PATCH/tags/{tag_id}tags:write · R1 · Idempotency-Key + If-Match
POST/tags/{tag_id}/archivetags:write · R1 · Idempotency-Key + If-Match
GET/leads/{lead_id}/tagstags:read · R0
PUT/leads/{lead_id}/tagstags:write · R1 · Idempotency-Key
GET/deals/{deal_id}/tagstags:read · R0
PUT/deals/{deal_id}/tagstags:write · R1 · Idempotency-Key
GET/custom-fieldscustom_fields:read · R0 · cursor
POST/custom-fieldscustom_fields:write · R1 · Idempotency-Key
GET/custom-fields/{field_id}custom_fields:read · R0
PATCH/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key + If-Match
POST/custom-fields/{field_id}/archivecustom_fields:write · R1 · Idempotency-Key + If-Match
GET/leads/{lead_id}/custom-fieldscustom_fields:read · R0
PUT/leads/{lead_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key
GET/deals/{deal_id}/custom-fieldscustom_fields:read · R0
PUT/deals/{deal_id}/custom-fields/{field_id}custom_fields:write · R1 · Idempotency-Key
ContractExact behaviorError taxonomy
ReadsR0, 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
MutationsR1, 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 safetyLead 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.
Replace lead tags
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]}'
Create a custom field
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.

GET/smart-lists/filter-schemasmart_lists:read · R0 · schema v2
GET/smart-listssmart_lists:read · R0 · cursor
POST/smart-listssmart_lists:write · R1 · Idempotency-Key
POST/smart-lists/previewsmart_lists:write · R0 · Idempotency-Key
GET/smart-lists/{id}smart_lists:read · R0
PATCH/smart-lists/{id}smart_lists:write · R1 · Idempotency-Key + If-Match
DELETE/smart-lists/{id}smart_lists:write · R1 · Idempotency-Key + If-Match
GET/smart-lists/{id}/leadsleads:read · R0 · cursor
Exact errors: reads may return invalid_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.
Preview a smart list
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.

GET/pipelinespipelines:read · R0
POST/pipelinespipelines:write · R1 · Idempotency-Key
GET/pipelines/{id}pipelines:read · R0
PATCH/pipelines/{id}pipelines:write · R1 · Idempotency-Key + If-Match
POST/pipelines/{id}/archivepipelines:write · R1 · Idempotency-Key + If-Match
POST/pipelines/{id}/stagespipelines:write · R1 · Idempotency-Key
PATCH/pipelines/{id}/stages/{stage_id}pipelines:write · R1 · Idempotency-Key + If-Match
POST/pipelines/{id}/stages/{stage_id}/archivepipelines:write · R1 · Idempotency-Key + If-Match
POST/pipelines/{id}/stages/reorderpipelines:write · R1 · Idempotency-Key + If-Match
Exact errors: route-specific failures include pipeline_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.
Create a pipeline stage
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.

GET/dealsdeals:read · R0 · cursor
POST/dealsdeals:write · R1 · Idempotency-Key
GET/deals/{id}deals:read · R0
PATCH/deals/{id}deals:write · R1 · If-Match
POST/deals/{id}/movedeals:write · R1 · If-Match
POST/deals/{id}/wondeals:write · R1 · If-Match
POST/deals/{id}/lostdeals:write · R1 · If-Match
POST/deals/{id}/reopendeals:write · R1 · If-Match
POST/deals/{id}/archivedeals:archive · R1 · If-Match
POST/deals/{id}/restoredeals:archive · R1 · If-Match
GET/deals/{id}/activitiesdeals:read · R0 · cursor
POST/deals/{id}/activitiesdeals:write · R1 · Idempotency-Key
GET/pipelines/{id}/boarddeals:read · R0 · single page
GET/pipelines/{id}/forecastanalytics:read · R0
Exact money contract: responses expose value.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.
Forecast contract: 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.
ContractExact behaviorErrors
TransitionsOnly 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
ConcurrencySend 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
OutcomesMarking 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 safetyReuse 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
Events: successful mutations can emit 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.
Create a deal with exact money
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"
  }'
Move with the current version
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.

GET/conversationsList workspace conversations (cursor)
GET/conversations/{id}Read one safe conversation projection
GET/conversations/{id}/messagesList messages and delivery state (cursor)
GET/conversations/{id}/send-eligibilityExplain DNC, opt-out, quiet-hours, entitlement, and usage checks
POST/conversations/{id}/messagesQueue an outbound message — Idempotency-Key
POST/conversations/{id}/messages/scheduleSchedule an outbound message — Idempotency-Key
POST/conversations/{id}/messages/{message_id}/replyReply to an inbound message — Idempotency-Key
GET/suppression/statusRead masked suppression state
POST/suppression/requestsRecord a workspace suppression request — Idempotency-Key
POST/conversations/inboundStore an inbound channel message
POST/conversations/inbound-callsStore an inbound call transcript or outcome
POST/conversations/{id}/messagesconversations:send · R2 · 202

Send 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.

Request
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."}'
Queued response
{
  "data": {
    "status": "queued",
    "simulated": true,
    "outbox_id": "mout_01JABC"
  },
  "request_id": "req_01JABC"
}
Compliance is fail-closed: DNC, lead DNC, channel opt-outs, and quiet hours produce a durable suppressed message with no provider job or outbox row. Duplicate idempotency keys replay the original result without charging usage twice.
POST/conversations/inbound-callsconversations:write

Supply 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.

Required idempotency: use a stable key from the upstream call provider. The API records a workspace-scoped external call ID and does not send a reply.

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.

GET/formsList owned forms (cursor)
POST/formsCreate a draft form — forms:write
GET/forms/{brand}Fetch the saved form definition
PATCH/forms/{brand}Save a versioned draft — If-Match
POST/forms/{brand}/publishPublish a draft — If-Match
POST/forms/{brand}/unpublishUnpublish without deleting submissions
POST/forms/{brand}/archiveArchive while retaining history
POST/forms/{brand}/cloneClone into a new tenant-owned brand
PUT/forms/{brand}/serving-areaReplace the serving-area country list — If-Match
GET/forms/{brand}/revisionsList immutable revisions (cursor)
GET/forms/{brand}/revisions/{revision_id}Read one immutable revision
GET/forms/{brand}/submissionsList explicit PII-safe submissions (cursor)
GET/forms/{brand}/submissions/{id}Read one explicit PII-safe submission, with its review decision
POST/forms/{brand}/submissions/{id}/reviewVerify as a real prospect or confirm fake — appended, never rewritten
GET/forms/{brand}/analyticsRead aggregate funnel analytics
POST/forms/{brand}/eventsAppend a funnel event · Idempotency-Key · 204 replay
POST/forms/{brand}/submissionsValidate and submit a completed form
GET/public-linksList owned public links (cursor)
PATCH/public-links/{id}Update link routing — If-Match
POST/forms/acme/submissionsforms:submit

The 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.

Server-side only: do not expose an lt_live_ key in a browser embed. Use LeadTracker AI's public hosted journey for client-side pages.

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.

GET/analytics/application-funnel?days=30&brand=acmeanalytics:read

days 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.

GET/analytics/dashboardanalytics:read · aggregate summary
GET/analytics/funnelanalytics:read · aggregate stages
GET/analytics/sourcesanalytics:read · cursor
GET/analytics/velocityanalytics:read · cursor
GET/analytics/attributionanalytics:read · model + currency basis · cursor
GET/analytics/cohortsanalytics:read · model + currency basis · cursor
GET/analytics/paid-performancemarketing:read · cursor
GET/analytics/creativesmarketing:read · cursor
GET/analytics/unit-economicsmarketing:read · cursor
GET/analytics/data-qualityanalytics:read · freshness/coverage · cursor
GET/analytics/attendanceanalytics:read · cursor
GET/analytics/leaderboardanalytics:read · cursor
POST/analytics/exportsanalytics:export · queued/202 · Idempotency-Key
POST/tracking/eventsforms:submit · deduplicated · Idempotency-Key
POST/tracking/conversion-eventsforms:submit · authoritative outcomes stay server-side
POST/commerce/eventsforms:submit · minor-unit currency · Idempotency-Key
GET/tracking/events/{event_id}analytics:read · workspace-scoped projection
Privacy and quality: event IDs are caller-stable and deduplicated per workspace; attribution and event attributes are sanitized before storage, and PII is never projected. Monetary values use integer amount_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.
Exports and effects: exports create durable queued jobs and require 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.

i
Stored credentials stay server-side

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.

Data-quality and plans: recommendation planning and execution fail closed when freshness, reconciliation, or attribution coverage evidence is missing or stale. Plans carry exact request and resource-version hashes; execution requires the matching operation and approval context. Rollback plans bind the prior action state/version and cannot run after that state changes.
Simulation and jobs: with external effects disabled, provider reads and writes are deterministic simulations. Syncs and forecasts still create durable queued job intents, and action execution records simulated effects without calling a provider. Every mutation requires 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.

i
Editorial approval is not publishing

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.

Entitlements fail closed: Growth operations require the workspace Growth add-on; SEO operations require seo:configure only for approved configuration actions and eligible subscription verification. An unavailable billing or provider configuration check cannot enable an external action.
Credential and job boundary: Google authorization persists server-owned state bound to the actor, workspace, PKCE challenge, redirect URI, nonce, and expiry. Generation, enhancement, topic suggestions, publishing, and SEO sync use durable jobs; disabled external effects return deterministic simulation records and no raw provider data.

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.

i
Exact plan and tenancy boundary

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.

Fail-closed provider boundary: Prospect criteria accept only typed geography, company size, role, count, and allowlisted enrichment fields. Provider queries, credentials, and arbitrary recipients are rejected. The plan and request routes require 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.

i
One credential, one tenant

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.

GET/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
Role, plan, and secrecy gates: owner/admin or manager checks are enforced in addition to scopes; the final active owner cannot be disabled or demoted. Agency operations require the separate agency control-plane audience and stored ownership relationship. Invitation and team-archive plans bind exact request and resource versions, team memberships/workload, approval context, entitlement state, and expiry; execution requires the matching one-time approval. Invitations, agency provisioning, and suspension create durable jobs; external-effects-disabled mode returns deterministic simulations and never accepts or returns provider credentials, tokens, or arbitrary destinations.
Typed policies: notification policies are typed event, channel, and destination policies that accept only allowlisted channels and destinations (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.

i
Provider state stays server-bound

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.

Exact R3 and durable jobs: domain removal and integration disconnect create dependency-aware plans that bind the current resource version, request hash, policy decision, approval, and expiry. Execution requires the exact plan and one-time approval; stale or changed dependencies fail closed. Texting registration follows the same plan-first carrier boundary, while verification and synchronization are durable jobs with deterministic simulations when external effects are disabled.
Typed settings and tenant isolation: domains, integrations, onboarding records, and settings are always scoped to the authenticated workspace. Settings accept only allowlisted timezone, locale, date format, channel, notification, branding, website, and quiet-hour fields; unsafe keys, nested secrets, provider credentials, raw URLs, and storage references are rejected or redacted.
Typed policies and bounded traversal: notification policies are typed event, channel, and destination policies that accept only allowlisted channels and destinations (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.

Paid packages are sales-led: Free is the only self-serve plan. Paid packages are custom-built and priced with the LeadTracker AI team, so the API never lists a paid package or returns a paid price. 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.
i
Provider-hosted and tokenized only

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.

Exact approval and currency gates: previews resolve the target plan, currency, entitlement deltas, and server resource versions; no paid price is computed, so plan-change amounts are 0 and any credit on a custom subscription is settled in the provider-hosted flow. Plan and top-up execution requires the exact 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.
Usage and effects: owner/admin role and paid-entitlement checks run in addition to scopes. Every mutation requires 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.

POST/workflows/{workflow_id}/triggerworkflows:trigger

The 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.

Destination and billing gates are server-side: workflow execution resolves only workspace-owned prevalidated destinations, enforces usage/paid-plan checks for live effects, and never calls a provider directly from the request handler.

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.

!
Approval separation is enforced

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.

GET/jobsR0 · domain read scope · cursor
GET/jobs/{job_id}R0 · domain read scope
POST/jobs/{job_id}/cancelR1 · originating execute scope · Idempotency-Key
GET/approval-requestsR0 · approvals:read · cursor
POST/approval-requestsR1 · approvals:request · Idempotency-Key
GET/approval-requests/{approval_request_id}R0 · approvals:read
POST/approval-requests/{approval_request_id}/cancelR1 · approvals:request · Idempotency-Key
GET/audit-eventsR0 · audit:read · cursor
GET/audit-events/{audit_event_id}R0 · audit:read
OperationScope / riskIdempotency and approvalStable errors
GET /jobsdomain_read
R0
Signed cursor bound to workspace, route, and filtersinvalid_api_key, invalid_access_token, insufficient_scope, invalid_request, invalid_filter, invalid_cursor, rate_limited
GET /jobs/{job_id}domain_read
R0
Noneinvalid_api_key, invalid_access_token, insufficient_scope, resource_not_found
POST /jobs/{job_id}/canceloriginating_execute
R1
Required Idempotency-Key; cancellation is only allowed for cancellable jobsidempotency_key_required, idempotency_key_reused, resource_not_found, job_not_cancellable, invalid_state_transition
GET /approval-requestsapprovals:read
R0
Signed cursor; callback evidence is omittedinvalid_filter, invalid_cursor, rate_limited
POST /approval-requestsapprovals:request
R1
Required Idempotency-Key; server-generated operation plan onlyunknown_field, idempotency_key_reused, resource_not_found, approval_mismatch, approval_expired
GET /approval-requests/{approval_request_id}approvals:read
R0
Cross-workspace IDs return resource_not_foundresource_not_found, insufficient_scope
POST /approval-requests/{approval_request_id}/cancelapprovals:request
R1
Required Idempotency-Key; initiator or owner may cancelidempotency_key_reused, resource_not_found, insufficient_role, invalid_state_transition
GET /audit-eventsaudit:read
R0
Signed cursor and bounded filtersinvalid_filter, invalid_cursor, rate_limited
GET /audit-events/{audit_event_id}audit:read
R0
Redacts authorization, OAuth, API-key, callback, and provider secretsresource_not_found, insufficient_scope
List jobs
curl https://leadtrackerai.com/api/v1/jobs?limit=50 \
  -H "Authorization: Bearer $LEADTRACKER_API_TOKEN"
Request approval
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.

!
Secrets are one-time values

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.

GET/developer/scopesR0 · developer:credentials:admin
GET/service-accountsR0 · cursor
POST/service-accountsR1 · Idempotency-Key
GET/service-accounts/{service_account_id}R0 · metadata only
PATCH/service-accounts/{service_account_id}R1 · Idempotency-Key + If-Match
POST/service-accounts/{service_account_id}/rotateR3 · Idempotency-Key + If-Match
POST/service-accounts/{service_account_id}/disableR3 · Idempotency-Key + If-Match
POST/service-accounts/{service_account_id}/enableR1 · Idempotency-Key + If-Match
GET/service-accounts/{service_account_id}/credentialsR0 · cursor · metadata only
POST/service-accounts/{service_account_id}/credentialsR3 · one-time client_secret
DELETE/service-accounts/{service_account_id}/credentials/{credential_id}R3 · Idempotency-Key + If-Match
OperationGrantabilitySafety contractStable errors
GET /developer/scopesOwner/admin onlyReturns exact server-owned scope definitions and grantable subsetinsufficient_role, insufficient_scope, resource_access_denied
POST /service-accountsRequested scopes must be grantableRequired Idempotency-Key; no secret is created or returnedinvalid_request, unknown_field, idempotency_key_reused
PATCH /service-accounts/{service_account_id}Owner/admin grant setRequired Idempotency-Key and current If-Matchprecondition_required, version_conflict, insufficient_scope
POST /service-accounts/{service_account_id}/rotateOwner/admin grant setR3; exact ETag and idempotency; bounded overlap; one-time secret revealinvalid_state_transition, version_conflict, resource_not_found
POST /service-accounts/{service_account_id}/disableOwner/admin onlyR3; revokes issued access tokens; final owner account is protectedresource_in_use, precondition_required, version_conflict
POST /service-accounts/{service_account_id}/credentialsSubset of account grantR3; secret appears once and replay never re-reveals itinvalid_request, invalid_state_transition, idempotency_key_reused
DELETE /service-accounts/{service_account_id}/credentials/{credential_id}Owner/admin onlyR3; revokes tokens; the final recovery credential and final owner automation credential are protectedresource_in_use, precondition_required, version_conflict
Create a service account
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"]}'
Create one-time credential
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.

!
Signing secrets are one-time values

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.

GET/webhook-endpointsR0 · developer:webhooks:read · no key
POST/webhook-endpointsR1 · developer:webhooks:write · Idempotency-Key
GET/webhook-endpoints/{endpoint_id}R0 · developer:webhooks:read · no key
PATCH/webhook-endpoints/{endpoint_id}R1 · developer:webhooks:write · Idempotency-Key + If-Match
DELETE/webhook-endpoints/{endpoint_id}R3 · developer:webhooks:write · policy · Idempotency-Key + If-Match
POST/webhook-endpoints/{endpoint_id}/rotate-secretR3 · developer:webhooks:write · Idempotency-Key + If-Match
GET/webhook-endpoints/{endpoint_id}/deliveriesR0 · developer:webhooks:read · cursor
GET/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}R0 · developer:webhooks:read · no key
POST/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/retryR1 · developer:webhooks:write · Idempotency-Key
OperationScope / riskIdempotency and preconditionErrors
GET /webhook-endpointsdeveloper:webhooks:read
R0
Noneinvalid_api_key, insufficient_scope, invalid_endpoint_id, resource_not_found, rate_limited
POST /webhook-endpointsdeveloper:webhooks:write
R1
Required Idempotency-Key; replay returns the original projection without a secretinvalid_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:read
R0
Noneinvalid_api_key, insufficient_scope, invalid_endpoint_id, resource_not_found, rate_limited
PATCH /webhook-endpoints/{endpoint_id}developer:webhooks:write
R1
Required Idempotency-Key and current If-Matchinvalid_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:write
R3 · policy
Policy evaluation, required Idempotency-Key and current If-Matchinvalid_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-secretdeveloper:webhooks:write
R3
Required Idempotency-Key and current If-Matchinvalid_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}/deliveriesdeveloper:webhooks:read
R0
Opaque cursor pagination; no keyinvalid_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:read
R0
Noneinvalid_api_key, insufficient_scope, invalid_endpoint_id, invalid_delivery_id, resource_not_found, rate_limited
POST /webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/retrydeveloper:webhooks:write
R1
Required Idempotency-Keyinvalid_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
Create and reveal once
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"]}'
201 response
{
  "data": { "id": "wep_01JABCDEF1234567", "version": 1 },
  "signing_secret": "whsec_one_time_value"
}
// Replay and GET/list responses omit signing_secret.
Delivery response
{
  "data": {
    "id": "whd_01JABCDEF1234567",
    "event_type": "deal.updated",
    "status": "delivered",
    "event": { "api_version": "2026-08-14", "data": { "object": { "id": 91 } } }
  }
}
PATCHIf-Match: "wep_...:1"versioned writes

Configuration 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.

EVENTbooking.createdNative booking was confirmed
EVENTbooking.rescheduledNative booking time changed
EVENTbooking.cancelledNative booking was cancelled
EVENTbooking.no_showAttendance was marked no-show
POSTYour configured HTTPS endpointHMAC SHA-256

LeadTracker 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.

HeaderDescription
X-LeadTracker-EventThe booking event name.
X-LeadTracker-Event-IdStable event identifier for receiver de-duplication.
X-LeadTracker-TimestampUnix timestamp in seconds.
X-LeadTracker-Signaturev1= + 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.

400invalid_brand_idbrand_id is not a positive integer.
400brand_event_type_mismatchThe selected event type is not configured for this booking brand.
400brand_id_requiredThe event type is shared by multiple brands, so the brand must be selected explicitly.
400brand_not_configuredThe event type has no active booking-brand association; configure one before using it through the Developer API.
400invalid_attendeeRequired contact information or timezone is missing or invalid.
401invalid_api_keyThe key is unknown, expired, revoked, or belongs to an inactive workspace.
402subscription_requiredA paid-domain action (communications, telephony, video, marketing, growth, AI, enrichment, file storage) was requested from a Free-plan workspace, or from a paid workspace whose subscription is canceled or past its dunning grace period.
402quota_exceededA plan count limit (Free CRM records, seats, event types, bookings/mo, phone numbers, active forms, API keys) is at its cap. New CRM records return the current usage and limit; existing records remain readable and editable. Upgrade to raise it. Form submissions are never refused: inbound capture remains stored and is marked for upgrade when no new CRM record can be created.
402trial_limit_reachedLegacy alias some Free-plan count caps still emit; treat it exactly like quota_exceeded.
402trial_expiredRetained for compatibility only. The Free plan never expires, so workspaces created after 2026-09-11 will not see it; a client should still treat it like subscription_required.
403insufficient_scopeThe credential does not include the required capability scope.
404brand_not_foundThe brand does not exist in the API key's workspace or is not booking-enabled.
404booking_not_foundThe booking does not exist in this workspace.
409slot_takenThe slot changed after availability was fetched. Fetch availability again and offer a new time.
409idempotency_key_reusedThe same write key was sent with a different request body.
409sales_led_planA billing plan change targeted a paid package or add-on. Paid packages are built with the LeadTracker AI team: send the user to error.details.upgrade_url (their own business) or error.details.white_label_url (agencies reselling under their own brand).
429rate_limitedAuthenticated keys are limited to 120 requests per minute. Respect the standard rate-limit response headers.
503subscription_verification_unavailablePaid external actions fail closed while entitlement verification is unavailable.
Error response
{
  "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.

!
Keep keys server-side

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.

Payment and compliance gates cannot be delegated: an API key grants only a capability scope. It never grants a plan, usage allowance, phone number, billing role, or exemption from consent, quiet-hours, opt-out, and provider checks.