TrustPager Docs

API Reference

948 endpoints across 78 resources. Every endpoint below is statically rendered — AI agents can read this page directly via WebFetch.

Base URL & auth

Full auth details — scopes, approval queue, pagination, idempotency, rate limits — are on the Authentication & scopes page.

Discovery surface — machine-readable everything

Every endpoint on this page is also available in machine-readable form for AI agents and tooling:

Resources

Jump to a resource:

Universal Search (1) Contacts (17) Companies (12) Opportunities (55) Pipelines (12) Products (9) Supplier Catalog (5) Activities (5) Stage Changes (1) Tasks (10) Work Orders (6) Work Order Settings (15) STAKEHOLDERS (17) Automations (26) Custom Scripts (13) Skills (6) Auto Queues (15) Auto Schedules (9) SCHEDULING (24) Email (21) Email Templates (2) Email Campaigns (21) SMS (6) WhatsApp (14) Chat (13) Phone (13) Agents (31) Agent Knowledge Bases (8) VOICE_CALL_DIRECTIVES (5) Voice Agent Toolkit (11) Knowledge Bases (14) Text Agents (6) Transcripts (10) Document Templates (13) Signing (5) Forms (25) Websites (32) SEO Research (15) Portals (25) Order Forms (6) Stores (9) Orders (5) Invoices (13) Recurring Invoices (5) Files (15) Images (1) Notepads (18) Whiteboards (8) Spreadsheets (16) Reports (18) AI Knowledge (7) Agent Memory (7) Company (33) CRM Templates (5) Integrations (5) Webhooks (17) AI (15) Billing (4) Service Requests (8) Approvals (6) AI Instructions (1) Voices (8) Agent Proposals (6) Lead Generation (10) Lead Gen Initiatives (12) Playbooks (8) Roles & Permissions (9) Scheduled Communications (7) Schemas (2) Reputation (22) Referrals (18) CRM Export (1) Export Templates (13) Evie (In-App Agent) (2) Agent Ops (28) Auto Responders (6) INVENTORY (14) COMPONENTS (12)

Contacts (17 endpoints)

Manage individual contacts (people) in the CRM. Supports search, filtering, sub-resources (opportunities, activities, employers), and AI enrichment.

📄 Full markdown: /api/contacts.md

POST /contacts/:contact_id/employers/:customer_id Scopes: contacts:write

Link a contact to a company as an employer.

3 parameters
Name In Type Required Description
contact_id path string yes
customer_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts-contact-id-employers-customer-id.md

POST /contacts/bulk-create Scopes: contacts:write

Create up to 100 contacts in one request. Each record must have at least first_name.

3 parameters
Name In Type Required Description
records body array yes Array of contact objects
skip_automations body boolean no Set true to suppress contact_created automation triggers for every record in this batch. Use for imports and backfills.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts-bulk-create.md

POST /contacts/bulk-delete Scopes: contacts:delete

Delete up to 100 contacts in one request. Destructive.

2 parameters
Name In Type Required Description
ids body array yes Contact UUIDs
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts-bulk-delete.md

POST /contacts/bulk-update Scopes: contacts:write

Update up to 100 contacts in one request. Each record must include id plus fields to change. Include archived:true to bulk-archive (or archived:false to bulk-restore).

2 parameters
Name In Type Required Description
records body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts-bulk-update.md

POST /contacts Scopes: contacts:write

Create a new contact. first_name is required. To link to a company pass customer_id.

21 parameters
Name In Type Required Description
first_name body string yes Given name (required)
last_name body string no
email body string no
phone body string no Mobile, any format — normalised to E.164
landline body string no
job_title body string no
contact_type body string no
customer_id body string no UUID of the company to link this contact to
date_of_birth body string no ISO date (YYYY-MM-DD). Pass "" to clear.
notes body string no
source body string no How this contact entered the CRM. One of: manual, form_submission, voice_call, order_form, import, api. Defaults to "manual"; use "api" for anything you create programmatically. This is NOT campaign attribution: to record which ad, channel or campaign a lead came from, set the opportunity's lead_source instead.
address_line1 body string no Street address, first line.
address_line2 body string no Street address, second line (unit, level).
city body string no Suburb or city.
state body string no State or region, e.g. "VIC", "NSW".
postal_code body string no Postcode.
country body string no Country. Defaults to Australia when omitted.
alternate_emails body array no Other email addresses this record uses. Bookings, public forms and inbound email match on ANY of them, so a person or business with two addresses resolves to this one record instead of creating a duplicate. Stored lowercased; the main `email` is never duplicated in here. RECOGNITION ONLY - outbound email always goes to `email`. Replaces the whole list, so read the record and merge first.
metadata body object no Arbitrary JSON stored on the contact.
skip_automations body boolean no Set true to suppress contact_created automation triggers for this write. Use for bulk imports and backfills that should not fire client-facing automations.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts.md

DELETE /contacts/:contact_id Scopes: contacts:delete

Delete a contact by UUID. Destructive.

2 parameters
Name In Type Required Description
contact_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/delete-contacts-contact-id.md

GET /contacts/:contact_id Scopes: contacts:read

Fetch a single contact by UUID. Returns the full record including custom fields.

1 parameter
Name In Type Required Description
contact_id path string yes

📄 /api/contacts/get-contacts-contact-id.md

GET /contacts/:contact_id/activities Scopes: contacts:readactivities:read

List all activities (calls, meetings, notes, emails) logged against a contact.

1 parameter
Name In Type Required Description
contact_id path string yes

📄 /api/contacts/get-contacts-contact-id-activities.md

GET /contacts/:contact_id/deals Scopes: contacts:readopportunities:read

List all opportunities/deals associated with a contact.

1 parameter
Name In Type Required Description
contact_id path string yes

📄 /api/contacts/get-contacts-contact-id-deals.md

GET /contacts Scopes: contacts:read

List contacts in the current workspace. Returns active (non-archived) contacts by default. Supports cursor-based pagination, free-text search via `search`, and filtering by source, customer_id, created date range, and unsubscribe flags. Pass archived="true" for only archived, or archived="all" for both.

12 parameters
Name In Type Required Description
limit query number no Max contacts (1-100, default 25)
after query string no Pagination cursor
search query string no Free-text across first_name, last_name, email, phone
created_after query string no Only contacts created on or after this ISO date/timestamp.
created_before query string no Only contacts created on or before this ISO date/timestamp.
email_unsubscribed query string no Filter by email unsubscribe flag.
sms_unsubscribed query string no Filter by SMS unsubscribe flag.
voice_unsubscribed query string no Filter by voice unsubscribe flag.
fields query string no Comma-separated field list to return instead of the default set, e.g. "id,email,phone".
source query string no
customer_id query string no Filter to contacts linked to a specific company
archived query string no Archive scope. "false" (default) = active only, "true" = archived only, "all" = both.

📄 /api/contacts/get-contacts.md

DELETE /contacts/:contact_id/employers/:customer_id Scopes: contacts:delete

Unlink a contact from a company employer.

3 parameters
Name In Type Required Description
contact_id path string yes
customer_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/delete-contacts-contact-id-employers-customer-id.md

POST /contacts/search Scopes: contacts:read

Fuzzy search across contacts by name, email, or phone. Returns matching contact records.

2 parameters
Name In Type Required Description
query body string yes Search query
limit body number no

📄 /api/contacts/post-contacts-search.md

POST /contacts/:contact_id/unsubscribe Scopes: contacts:write

Unsubscribe a contact across email/sms/voice/whatsapp channels. Cancels queued comms and auto-enrolments, tags linked opportunities, and writes an audit activity.

5 parameters
Name In Type Required Description
contact_id path string yes
channels body array no Channels to suppress. Omit for every channel. Suppress one channel only (e.g. ["voice"]) when the contact objected to AI calls but still wants email.
reason body string no Why they unsubscribed. Stored on the contact and the audit activity.
source body string no Where the opt-out came from, for ops triage (e.g. "voice_objection").
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts-contact-id-unsubscribe.md

PATCH /contacts/:contact_id Scopes: contacts:write

Update one or more fields on a contact. Pass only the fields you want to change. Set archived=true to archive (hide from active lists) or archived=false to restore.

18 parameters
Name In Type Required Description
contact_id path string yes
first_name body string no
last_name body string no
email body string no
phone body string no
landline body string no
alternate_emails body array no Other email addresses this contact uses. Bookings, public forms and inbound email match on ANY of them, so someone with two addresses resolves to this one contact instead of creating a duplicate. Stored lowercased; the main `email` is never duplicated in here. RECOGNITION ONLY - outbound email always goes to `email`. Replaces the whole list, so read the contact and merge first.
job_title body string no
contact_type body string no
date_of_birth body string no ISO date (YYYY-MM-DD). Pass "" to clear.
notes body string no
source body string no How this contact entered the CRM. One of: manual, form_submission, voice_call, order_form, import, api. This is NOT campaign attribution: to record which ad, channel or campaign a lead came from, set the opportunity's lead_source instead.
archived body boolean no true = archive, false = restore. Archived contacts stay searchable and API-accessible but drop out of active lists.
email_unsubscribed body boolean no true = stop all email to this contact (same effect as unsubscribe_contact). false = re-opt them in and clear the block.
sms_unsubscribed body boolean no true = stop all SMS to this contact. false = re-opt them in.
voice_unsubscribed body boolean no true = stop all voice calls to this contact. false = re-opt them in.
whatsapp_unsubscribed body boolean no true = stop all WhatsApp messages to this contact. false = re-opt them in.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/patch-contacts-contact-id.md

POST /contacts/voice/unsubscribe Scopes: contacts:write

AI voice agent unsubscribe — looks up contact by caller phone and flips voice_unsubscribed flag.

3 parameters
Name In Type Required Description
phone body string no Caller phone in E.164, e.g. "+61431377068". Optional: falls back to the number on the call payload, and the handler returns a spoken prompt asking for it when neither is present.
reason body string no Why they unsubscribed. Defaults to "voice_call:<call_id>".
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/contacts/post-contacts-voice-unsubscribe.md

Companies (12 endpoints)

Companies (customers) in the workspace, their contacts and their opportunities. The legacy /customers/* paths still work.

📄 Full markdown: /api/companies.md

POST /companies/bulk-create Scopes: companies:write

Create up to 100 companies in one request.

2 parameters
Name In Type Required Description
records body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/companies/post-companies-bulk-create.md

POST /companies/bulk-delete Scopes: companies:delete

Delete up to 100 companies in one request. Destructive.

2 parameters
Name In Type Required Description
ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/companies/post-companies-bulk-delete.md

POST /companies/bulk-update Scopes: companies:write

Update up to 100 companies in one request. Each record is { id, ...fields }. Include archived:true to bulk-archive (or archived:false to bulk-restore).

2 parameters
Name In Type Required Description
records body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/companies/post-companies-bulk-update.md

POST /companies Scopes: companies:write

Create a new CRM company (customer/account). Requires name. This creates a CRM account record — NOT the workspace org profile.

22 parameters
Name In Type Required Description
name body string yes
email body string no
alternate_emails body array no Other email addresses this record uses. Bookings, public forms and inbound email match on ANY of them, so a person or business with two addresses resolves to this one record instead of creating a duplicate. Stored lowercased; the main `email` is never duplicated in here. RECOGNITION ONLY - outbound email always goes to `email`. Replaces the whole list, so read the record and merge first.
phone body string no Mobile in E.164, e.g. +61412345678.
landline body string no Landline in E.164, e.g. +61299991234.
website body string no
industry body string no
account_type body string no Account/organisation type. Get options from get_crm_settings.account_type_options.
is_customer body boolean no Is this a customer/client (default true).
is_supplier body boolean no Is this a supplier/vendor (default false).
tax_number body string no Tax number (e.g. ABN).
relationship_started_at body string no When the real-world relationship began (YYYY-MM-DD or ISO 8601). Cannot be in the future.
address_line1 body string no
address_line2 body string no
city body string no
state body string no
postal_code body string no
country body string no
timezone body string no
notes body string no
metadata body object no Custom field values keyed by field_id (get ids from get_crm_settings.custom_fields.account).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/companies/post-companies.md

DELETE /companies/:company_id Scopes: companies:delete

Delete a company by UUID. Destructive.

2 parameters
Name In Type Required Description
company_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/companies/delete-companies-company-id.md

GET /companies/:company_id Scopes: companies:read

Fetch a single company by UUID. Returns the full record including custom fields.

1 parameter
Name In Type Required Description
company_id path string yes

📄 /api/companies/get-companies-company-id.md

GET /companies/:company_id/activities Scopes: companies:readactivities:read

List activities (calls, meetings, notes, emails) on a company.

1 parameter
Name In Type Required Description
company_id path string yes

📄 /api/companies/get-companies-company-id-activities.md

GET /companies/:company_id/deals Scopes: companies:readopportunities:read

List all opportunities/deals tied to a company.

1 parameter
Name In Type Required Description
company_id path string yes

📄 /api/companies/get-companies-company-id-deals.md

GET /companies Scopes: companies:read

List companies (customers) in the workspace. Returns active (non-archived) companies by default. Supports cursor-based pagination, search, and filters. Pass archived="true" for only archived, or archived="all" for both.

5 parameters
Name In Type Required Description
limit query number no
after query string no
search query string no
industry query string no
archived query string no Archive scope. "false" (default) = active only, "true" = archived only, "all" = both.

📄 /api/companies/get-companies.md

POST /companies/search Scopes: companies:read

Fuzzy search across companies by name, email, phone, website. Returns matching company records.

2 parameters
Name In Type Required Description
query body string yes
limit body number no

📄 /api/companies/post-companies-search.md

PATCH /companies/:company_id Scopes: companies:write

Update a CRM company (customer/account). Pass only the fields you want to change. Set archived=true to archive (hide from active lists) or archived=false to restore. This edits a CRM account record — NOT the workspace org profile (use update_our_company for that).

24 parameters
Name In Type Required Description
company_id path string yes
name body string no
email body string no
alternate_emails body array no Other email addresses this record uses. Bookings, public forms and inbound email match on ANY of them, so a person or business with two addresses resolves to this one record instead of creating a duplicate. Stored lowercased; the main `email` is never duplicated in here. RECOGNITION ONLY - outbound email always goes to `email`. Replaces the whole list, so read the record and merge first.
phone body string no Mobile in E.164, e.g. +61412345678.
landline body string no Landline in E.164, e.g. +61299991234. Set null to clear.
website body string no
industry body string no
account_type body string no Account/organisation type (e.g. Client, Trustee-Liquidator). Get options from get_crm_settings.account_type_options. Set null to clear.
is_customer body boolean no Is this a customer/client.
is_supplier body boolean no Is this a supplier/vendor.
tax_number body string no Tax number (e.g. ABN).
relationship_started_at body string no When the real-world relationship began (YYYY-MM-DD or ISO 8601). Set null to clear. Cannot be in the future.
address_line1 body string no
address_line2 body string no
city body string no
state body string no
postal_code body string no
country body string no
timezone body string no
notes body string no
metadata body object no Custom field values keyed by field_id (get ids from get_crm_settings.custom_fields.account). Replaces the whole object — read with get_company and merge first.
archived body boolean no true = archive, false = restore. Archived companies stay searchable and API-accessible but drop out of active lists.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/companies/patch-companies-company-id.md

Opportunities (55 endpoints)

Opportunities (deals) and everything hanging off them: products, contacts, invoices, documents and pipeline placement. The legacy /deals/* paths still work.

📄 Full markdown: /api/opportunities.md

POST /opportunities/:opportunity_id/billing-parties/:customer_id Scopes: opportunities:writeinvoices:write

Add a billing party (payer company) to an opportunity. Invoices raised in your accounting integration to that company then surface on this opportunity in addition to the client’s, without changing the opportunity’s client. Use when a related entity pays the fees for the matter. A manually pinned invoice (linked directly to another opportunity) is never pulled in.

4 parameters
Name In Type Required Description
opportunity_id path string yes
customer_id path string yes The crm_customers id of the paying company.
notes body string no Optional note, e.g. why this entity pays the fees.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-billing-parties-customer-id.md

POST /opportunities/:opportunity_id/add-card Scopes: opportunities:write

Add an additional pipeline placement card to an opportunity (multi-pipeline workspaces).

4 parameters
Name In Type Required Description
opportunity_id path string yes
pipeline_id body string yes
stage_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-add-card.md

POST /opportunities/:opportunity_id/contacts/:contact_id Scopes: opportunities:write

Link a contact to an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
contact_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-contacts-contact-id.md

POST /opportunities/:opportunity_id/documents/:attachment_id Scopes: opportunities:writedocuments:read

Attach a document to an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
attachment_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-documents-attachment-id.md

POST /opportunities/:opportunity_id/files/:attachment_id Scopes: opportunities:writefiles:read

Attach a file to an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
attachment_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-files-attachment-id.md

POST /opportunities/:opportunity_id/images/:attachment_id Scopes: opportunities:writefiles:read

Attach an image to an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
attachment_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-images-attachment-id.md

POST /opportunities/:opportunity_id/products Scopes: opportunities:write

Attach a product to an opportunity.

9 parameters
Name In Type Required Description
opportunity_id path string yes
product_id body string no
quantity body number no
unit_price body number no
discount_percent body number no
deposit_percent body number no
bucket_id body string no Optional product bucket id to file this line item under (create buckets with create_opportunity_product_bucket). Buckets group line items by area (e.g. "Main Bathroom") with their own subtotal, and let the same product appear in more than one bucket.
invoice_description body string no The exact text this line prints on the invoice: the "Invoice description" field on the line item's Details tab. Use it to describe the work actually done for this customer instead of the generic catalogue wording. Leave it unset and the line falls back to the catalogue product name plus its description, as before. Pass an empty string to clear an override and go back to the catalogue text.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-products.md

POST /opportunities/:opportunity_id/spreadsheets/:spreadsheet_id Scopes: opportunities:writespreadsheets:write

Attach a spreadsheet to an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
spreadsheet_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-spreadsheets-spreadsheet-id.md

POST /opportunities/:opportunity_id/users/:user_id Scopes: opportunities:write

Assign a workspace user to an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
user_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-users-user-id.md

POST /opportunities/bulk-link-contacts Scopes: opportunities:write

Link up to 100 contact-to-opportunity pairs in one request. Each record is { deal_id, contact_id, role?, notes? }. Already-linked pairs are returned in skipped[] (idempotent), unknown ids in errors[]. Returns created[], skipped[], errors[].

2 parameters
Name In Type Required Description
records body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-bulk-link-contacts.md

POST /opportunities/:opportunity_id/products/bulk Scopes: opportunities:write

Add multiple products to an opportunity in a single request.

3 parameters
Name In Type Required Description
opportunity_id path string yes
products body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-products-bulk.md

POST /opportunities/bulk-products Scopes: opportunities:write

Add product line items to up to 100 opportunities in a single request (cross-opportunity bulk). Each item is { opportunity_id, products: [{ product_id, quantity, unit_price, discount_percent?, sort_order?, section? }] }. Per-item errors are isolated; each affected opportunity's value rolls up automatically. Built for high-volume migrations / batch quoting.

2 parameters
Name In Type Required Description
items body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-bulk-products.md

POST /opportunities/bulk-create Scopes: opportunities:write

Create up to 100 opportunities in one request. Pass dedup_key (a metadata field name, e.g. "external_id") to make the call idempotent: any record whose metadata[dedup_key] already exists on an opportunity is skipped, so a half-finished import can be re-run safely. Returns created[], skipped[], errors[].

6 parameters
Name In Type Required Description
records body array yes
pipeline_id body string no Default pipeline for every record, overridable per record. Must be passed together with stage_id. Get a real id from list_pipelines: a pipeline_id that does not exist in this workspace fails the whole record rather than creating an unplaced opportunity.
stage_id body string no Default stage for every record, overridable per record. Must be passed together with pipeline_id and must be a stage OF that pipeline. Get a real id from list_pipeline_stages: a wrong or invented stage_id fails the record instead of creating an opportunity that appears on no board.
skip_automations body boolean no
dedup_key body string no Name of a metadata field to treat as a stable external id for idempotent re-runs.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-bulk-create.md

POST /opportunities/bulk-delete Scopes: opportunities:delete

Delete up to 100 opportunities in one request. Destructive.

2 parameters
Name In Type Required Description
ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-bulk-delete.md

POST /opportunities/bulk-move Scopes: opportunities:write

Move up to 100 opportunities into a target pipeline + stage at once.

6 parameters
Name In Type Required Description
ids body array yes
pipeline_id body string yes
stage_id body string yes
skip_automations body boolean no Set true to suppress stage-change automation triggers across every opportunity in this batch.
skip_action_ids body array no Automation action UUIDs to skip for this batch, when you want most of the stage-change automations to run but not these.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-bulk-move.md

POST /opportunities/bulk-update Scopes: opportunities:write

Update up to 100 opportunities in one request. Each record is { id, ...fields }. Include archived:true to bulk-archive (or archived:false to bulk-restore).

2 parameters
Name In Type Required Description
records body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-bulk-update.md

POST /opportunities Scopes: opportunities:write

Create a new opportunity (deal). Requires name. To place it on a pipeline board, pass pipeline_id and stage_id together; omit both to create it unplaced. Both ids are validated, so a wrong stage_id returns an error rather than creating an opportunity that appears on no board.

24 parameters
Name In Type Required Description
name body string yes
contact_id body string no
customer_id body string no
pipeline_id body string no Pipeline to place the opportunity on. Must be passed together with stage_id. Get a real id from list_pipelines.
stage_id body string no Stage to place the opportunity in. Must be passed together with pipeline_id and must be a stage OF that pipeline. Get a real id from list_pipeline_stages: never construct or pad a UUID by hand.
value body number no
currency body string no
value_is_manual body boolean no Force this opportunity to manual value (true, locked from product auto-sum) or auto (false). Defaults to the workspace CRM setting for opportunity value.
expected_close body string no ISO date
status body string no
owner_id body string no
notes body string no
lead_source body string no Campaign attribution: which ad, channel or campaign this opportunity came from. Distinct from a contact's `source`, which records how the contact entered the CRM.
tags body array no Tags on the opportunity. Full-replace array.
metadata body object no Arbitrary JSON stored on the opportunity. `metadata.dedup_key` is treated as a stable external id for de-duplication.
skip_automations body boolean no Set true to suppress opportunity_created automation triggers for this write. Use for bulk imports and backfills.
next_action_name body string no Title of the opportunity's next action, e.g. "Follow-up call". Shows on the opportunity card and on the calendar at https://app.trustpager.com/tasks/calendar.
next_action_date body string no Date of the next action as ISO "YYYY-MM-DD". Pass null to clear the reminder.
next_action_time body string no Time of the next action as a UTC wall time, "HH:MM" or "HH:MM:SS". Paired with next_action_date — a date with no time renders as an untimed reminder.
next_action_duration body number no Length of the next action in minutes. Drives the end time shown on the calendar and the block height in Day view. Omit for a point-in-time reminder: with no duration the calendar shows a start time only and never invents an end time.
next_action_type body string no "next_action" = a plain reminder. "google_meeting" = a Google Meet (a meeting URL is generated on save). A custom event type id is also accepted.
next_action_description body string no Longer notes for the next action, shown in the reminder editor.
next_action_color body string no Colour of the calendar chip: blue, red, green, purple, orange, teal, pink, yellow, indigo, or gray.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities.md

POST /opportunities/:opportunity_id/invoices Scopes: opportunities:writeinvoices:write

Create an invoice via the workspace accounting integration.

2 parameters
Name In Type Required Description
opportunity_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-invoices.md

POST /opportunities/:opportunity_id/buckets Scopes: opportunities:write

Create a product bucket on an opportunity. A bucket is a labelled grouping (e.g. "Main Bathroom") that line items file under, so the quote breaks down per area with its own subtotal on the products list, invoices, and the rendered estimate.

4 parameters
Name In Type Required Description
opportunity_id path string yes
label body string yes The bucket heading shown everywhere this opportunity is priced (e.g. "Main Bathroom").
sort_order body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-buckets.md

POST /opportunities/:opportunity_id/product-costs/:deal_product_id Scopes: opportunities:write

Add a supplier cost to an opportunity product line.

3 parameters
Name In Type Required Description
opportunity_id path string yes
deal_product_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-product-costs-deal-product-id.md

DELETE /opportunities/:opportunity_id Scopes: opportunities:delete

Delete an opportunity by UUID. Destructive.

2 parameters
Name In Type Required Description
opportunity_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id.md

DELETE /opportunities/:opportunity_id/buckets/:bucket_id Scopes: opportunities:delete

Delete a product bucket from an opportunity. Line items in the bucket are kept but become ungrouped; their prices are unchanged.

3 parameters
Name In Type Required Description
opportunity_id path string yes
bucket_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-buckets-bucket-id.md

GET /opportunities/:opportunity_id Scopes: opportunities:read

Fetch a single opportunity by UUID. Returns the full record including custom fields, products, contacts, and current stage placement.

1 parameter
Name In Type Required Description
opportunity_id path string yes

📄 /api/opportunities/get-opportunities-opportunity-id.md

GET /opportunities Scopes: opportunities:read

List opportunities (deals) in the workspace. Returns active (non-archived) opportunities by default. Supports cursor pagination, search, and filtering by pipeline, stage, status, assigned_to, contact, company, dates. Pass archived="true" for only archived, or archived="all" for both.

12 parameters
Name In Type Required Description
limit query number no
after query string no
search query string no
pipeline_id query string no
stage_id query string no
status query string no
assigned_to query string no Owner. User UUID of the assigned team member.
contact_id query string no
customer_id query string no
created_after query string no ISO timestamp. Only opportunities created on or after this.
created_before query string no ISO timestamp. Only opportunities created on or before this.
archived query string no Archive scope. "false" (default) = active only, "true" = archived only, "all" = both.

📄 /api/opportunities/get-opportunities.md

GET /opportunities/:opportunity_id/billing-parties Scopes: opportunities:readinvoices:read

List the billing parties (payer companies) on an opportunity. A billing party is a separate company that pays the fees for this matter; invoices raised to it surface on this opportunity in addition to the client’s, without changing who the client is.

1 parameter
Name In Type Required Description
opportunity_id path string yes

📄 /api/opportunities/get-opportunities-opportunity-id-billing-parties.md

GET /opportunities/:opportunity_id/invoices Scopes: opportunities:readinvoices:read

List native invoices linked to an opportunity. Returns invoice headers (invoice_number, status, total, amount_due, amount_paid, due_date, …); use get_invoice for line items.

1 parameter
Name In Type Required Description
opportunity_id path string yes

📄 /api/opportunities/get-opportunities-opportunity-id-invoices.md

GET /opportunities/:opportunity_id/buckets Scopes: opportunities:read

List the product buckets (groupings like "Main Bathroom", "Ensuite") on an opportunity, in display order.

1 parameter
Name In Type Required Description
opportunity_id path string yes

📄 /api/opportunities/get-opportunities-opportunity-id-buckets.md

POST /opportunities/:opportunity_id/move Scopes: opportunities:write

Move an opportunity to a different stage. Provide pipeline_id + stage_id (or just stage_id if it already has a placement).

4 parameters
Name In Type Required Description
opportunity_id path string yes
pipeline_id body string no
stage_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-move.md

POST /opportunities/:opportunity_id/move-card Scopes: opportunities:write

Alias of move_opportunity (legacy path).

4 parameters
Name In Type Required Description
opportunity_id path string yes
pipeline_id body string yes
stage_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-move-card.md

DELETE /opportunities/:opportunity_id/billing-parties/:customer_id Scopes: opportunities:writeinvoices:delete

Remove a billing party from an opportunity. The paying company and its invoices are untouched; only the link that surfaces them on this opportunity is removed.

3 parameters
Name In Type Required Description
opportunity_id path string yes
customer_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-billing-parties-customer-id.md

POST /opportunities/:opportunity_id/remove-card Scopes: opportunities:write

Remove an opportunity card from a pipeline.

3 parameters
Name In Type Required Description
opportunity_id path string yes
pipeline_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-remove-card.md

DELETE /opportunities/:opportunity_id/contacts/:contact_id Scopes: opportunities:delete

Unlink a contact from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
contact_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-contacts-contact-id.md

DELETE /opportunities/:opportunity_id/documents/:attachment_id Scopes: opportunities:write

Detach a document from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
attachment_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-documents-attachment-id.md

DELETE /opportunities/:opportunity_id/files/:attachment_id Scopes: opportunities:write

Detach a file from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
attachment_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-files-attachment-id.md

DELETE /opportunities/:opportunity_id/images/:attachment_id Scopes: opportunities:write

Detach an image from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
attachment_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-images-attachment-id.md

DELETE /opportunities/:opportunity_id/products/:deal_product_id Scopes: opportunities:delete

Remove a product from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
deal_product_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-products-deal-product-id.md

DELETE /opportunities/:opportunity_id/spreadsheets/:spreadsheet_id Scopes: opportunities:writespreadsheets:write

Detach a spreadsheet from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
spreadsheet_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-spreadsheets-spreadsheet-id.md

DELETE /opportunities/:opportunity_id/users/:user_id Scopes: opportunities:delete

Unassign a user from an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
user_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/delete-opportunities-opportunity-id-users-user-id.md

POST /opportunities/:opportunity_id/buckets/reorder Scopes: opportunities:write

Reorder the product buckets on an opportunity. Pass bucket_ids in the order you want them displayed.

3 parameters
Name In Type Required Description
opportunity_id path string yes
bucket_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-buckets-reorder.md

POST /opportunities/:opportunity_id/products/reorder Scopes: opportunities:write

Reorder products on an opportunity.

3 parameters
Name In Type Required Description
opportunity_id path string yes
product_ids body array yes Opportunity-product row UUIDs in the desired display order.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/post-opportunities-opportunity-id-products-reorder.md

POST /opportunities/search Scopes: opportunities:read

Fuzzy search across opportunities by name, contact, or company. Returns matching opportunity records. Optionally narrow the search to a pipeline, stage, or status.

5 parameters
Name In Type Required Description
query body string yes
limit body number no
pipeline_id body string no
stage_id body string no
status body string no

📄 /api/opportunities/post-opportunities-search.md

PATCH /opportunities/:opportunity_id Scopes: opportunities:write

Update one or more fields on an opportunity. Pass only the fields you want to change. Set archived=true to archive (hide from active lists, pipeline, and dashboard counts) or archived=false to restore. The next_action_* fields set the opportunity's reminder, which appears on its card and on the calendar.

20 parameters
Name In Type Required Description
opportunity_id path string yes
name body string no
value body number no
currency body string no
value_is_manual body boolean no Whether this opportunity's value is set manually (locked) or summed automatically from its products. Setting value also sets this to true, so products stop overwriting it. Pass false to revert to auto — the value is immediately recomputed from the products.
status body string no
owner_id body string no
expected_close body string no
notes body string no
contact_id body string no
customer_id body string no
archived body boolean no true = archive, false = restore. Archived opportunities stay searchable and API-accessible but drop out of active lists, the pipeline board, and dashboard counts.
next_action_name body string no Title of the opportunity's next action, e.g. "Follow-up call". Shows on the opportunity card and on the calendar at https://app.trustpager.com/tasks/calendar.
next_action_date body string no Date of the next action as ISO "YYYY-MM-DD". Pass null to clear the reminder.
next_action_time body string no Time of the next action as a UTC wall time, "HH:MM" or "HH:MM:SS". Paired with next_action_date — a date with no time renders as an untimed reminder.
next_action_duration body number no Length of the next action in minutes. Drives the end time shown on the calendar and the block height in Day view. Omit for a point-in-time reminder: with no duration the calendar shows a start time only and never invents an end time.
next_action_type body string no "next_action" = a plain reminder. "google_meeting" = a Google Meet (a meeting URL is generated on save). A custom event type id is also accepted.
next_action_description body string no Longer notes for the next action, shown in the reminder editor.
next_action_color body string no Colour of the calendar chip: blue, red, green, purple, orange, teal, pink, yellow, indigo, or gray.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/patch-opportunities-opportunity-id.md

PATCH /opportunities/:opportunity_id/products/:deal_product_id Scopes: opportunities:write

Update an opportunity product line item.

9 parameters
Name In Type Required Description
opportunity_id path string yes
deal_product_id path string yes
quantity body number no
unit_price body number no
discount_percent body number no
deposit_percent body number no
bucket_id body string no Product bucket id to file this line item under. Pass an empty string or null to unbucket it. Buckets group line items by area (e.g. "Main Bathroom") with their own subtotal.
invoice_description body string no The exact text this line prints on the invoice: the "Invoice description" field on the line item's Details tab. Use it to describe the work actually done for this customer instead of the generic catalogue wording. Leave it unset and the line falls back to the catalogue product name plus its description, as before. Pass an empty string to clear an override and go back to the catalogue text.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/patch-opportunities-opportunity-id-products-deal-product-id.md

PATCH /opportunities/:opportunity_id/buckets/:bucket_id Scopes: opportunities:write

Rename or reorder a single product bucket on an opportunity.

5 parameters
Name In Type Required Description
opportunity_id path string yes
bucket_id path string yes
label body string no
sort_order body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/opportunities/patch-opportunities-opportunity-id-buckets-bucket-id.md

Pipelines (12 endpoints)

Manage sales pipelines and their stages. Opportunities move through pipeline stages to track progress.

📄 Full markdown: /api/pipelines.md

POST /pipelines Scopes: pipelines:write

Create a new pipeline in the workspace. Requires a name; optional fields include description, is_active, is_default, position, sop_url, learning_hub_canvas_id, connected_pipeline_ids, exclude_from_lead_reporting.

8 parameters
Name In Type Required Description
name body string yes Pipeline name (e.g. "Sales", "Onboarding")
description body string no Optional plain-text description of what this pipeline tracks
is_active body boolean no Whether the pipeline is currently active (default true)
is_default body boolean no Make this the workspace default pipeline
position body number no Display order across all pipelines
learning_hub_canvas_id body string no Optional UUID of a Playbook to attach as this pipeline's training resource. Mutually exclusive with sop_url. When set, the "View Training" button opens the Playbook in-app rather than an external URL.
exclude_from_lead_reporting body boolean no When true, opportunities in this pipeline are excluded from the Lead Sources leaderboard (totals, per-source cards, conversion rate). Defaults to false. Use for non-lead pipelines like supplier or referral-partner networks stored as opportunities.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/post-pipelines.md

POST /pipelines/:pipeline_id/stages Scopes: pipelines:write

Add a new stage to a pipeline. Requires a name. Optional: position (defaults to end), color (hex), is_won_stage, is_lost_stage.

7 parameters
Name In Type Required Description
pipeline_id path string yes UUID of the parent pipeline
name body string yes Stage name
position body number no Display order within the pipeline (0-based)
color body string no Hex colour code for the stage chip
is_won_stage body boolean no Mark this stage as a "won" terminal stage
is_lost_stage body boolean no Mark this stage as a "lost" terminal stage
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/post-pipelines-pipeline-id-stages.md

DELETE /pipelines/:pipeline_id Scopes: pipelines:delete

Delete a pipeline by UUID. Destructive — pipeline cannot be deleted if it has opportunities placed in any of its stages.

2 parameters
Name In Type Required Description
pipeline_id path string yes UUID of the pipeline to delete
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/delete-pipelines-pipeline-id.md

DELETE /pipelines/:pipeline_id/stages/:stage_id Scopes: pipelines:delete

Delete a single stage from a pipeline. Destructive — fails if opportunities are placed in this stage.

3 parameters
Name In Type Required Description
pipeline_id path string yes
stage_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/delete-pipelines-pipeline-id-stages-stage-id.md

GET /pipelines/:pipeline_id Scopes: pipelines:read

Fetch a single pipeline by UUID. Returns the pipeline record (does not include stages — use list_pipeline_stages for that).

1 parameter
Name In Type Required Description
pipeline_id path string yes UUID of the pipeline

📄 /api/pipelines/get-pipelines-pipeline-id.md

GET /pipelines/:pipeline_id/summary Scopes: pipelines:read

Fetch summary statistics for a pipeline: deal counts and value totals per stage. Use this for "pipeline health" or "what is in stage X" questions.

1 parameter
Name In Type Required Description
pipeline_id path string yes

📄 /api/pipelines/get-pipelines-pipeline-id-summary.md

GET /pipelines/:pipeline_id/deals Scopes: pipelines:readopportunities:read

List all opportunities (deals) placed in any stage of a pipeline. Returns opportunity records with their current stage placement.

3 parameters
Name In Type Required Description
pipeline_id path string yes
limit query number no Max rows (1-100, default 25)
after query string no Pagination cursor

📄 /api/pipelines/get-pipelines-pipeline-id-deals.md

GET /pipelines/:pipeline_id/stages Scopes: pipelines:read

List all stages of a pipeline in display order. Each stage includes a deal_count. Use this to find a stage UUID for create_opportunity or move_opportunity.

1 parameter
Name In Type Required Description
pipeline_id path string yes UUID of the pipeline

📄 /api/pipelines/get-pipelines-pipeline-id-stages.md

GET /pipelines Scopes: pipelines:read

List all pipelines in the workspace. Each pipeline represents a workflow (e.g. "Sales", "Onboarding", "Support Tickets"). Use this when you need a pipeline UUID for creating or moving an opportunity.

📄 /api/pipelines/get-pipelines.md

POST /pipelines/:pipeline_id/stages/reorder Scopes: pipelines:write

Reorder the stages of a pipeline. Pass an array of stage UUIDs in the desired new order — position numbers are reassigned in array order.

3 parameters
Name In Type Required Description
pipeline_id path string yes UUID of the pipeline
stage_ids body array yes Stage UUIDs in their new display order
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/post-pipelines-pipeline-id-stages-reorder.md

PATCH /pipelines/:pipeline_id Scopes: pipelines:write

Update a pipeline by UUID. Pass only the fields you want to change. Writable: name, description, is_active, is_default, position, sop_url, learning_hub_canvas_id, connected_pipeline_ids, exclude_from_lead_reporting.

9 parameters
Name In Type Required Description
pipeline_id path string yes UUID of the pipeline to update
name body string no
description body string no
is_active body boolean no
is_default body boolean no
position body number no
learning_hub_canvas_id body string no UUID of a Playbook to link as this pipeline's training resource, or null to clear. Mutually exclusive with sop_url.
exclude_from_lead_reporting body boolean no When true, opportunities in this pipeline are excluded from the Lead Sources leaderboard (totals, per-source cards, conversion rate). Use for non-lead pipelines like supplier or referral-partner networks stored as opportunities.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/patch-pipelines-pipeline-id.md

PATCH /pipelines/:pipeline_id/stages/:stage_id Scopes: pipelines:write

Update a single stage within a pipeline. Pass only the fields you want to change.

8 parameters
Name In Type Required Description
pipeline_id path string yes
stage_id path string yes
name body string no
position body number no
color body string no
is_won_stage body boolean no
is_lost_stage body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/pipelines/patch-pipelines-pipeline-id-stages-stage-id.md

Products (9 endpoints)

Manage products and services that can be added to deals.

📄 Full markdown: /api/products.md

POST /products Scopes: products:write

Create a new product/service. Requires name and price.

10 parameters
Name In Type Required Description
name body string yes
sku body string no
price body number yes
currency body string no
category body string no
description body string no
unit body string no
deposit_percent body number no
is_active body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/products/post-products.md

POST /products/:product_id/costs Scopes: products:write

Add a cost entry to a product (e.g. supplier price).

8 parameters
Name In Type Required Description
product_id path string yes
label body string no
cost_price body number no
quantity body number no
currency body string no
supplier_id body string no
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/products/post-products-product-id-costs.md

DELETE /products/:product_id Scopes: products:delete

Delete a product by UUID. Destructive.

2 parameters
Name In Type Required Description
product_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/products/delete-products-product-id.md

DELETE /products/:product_id/costs/:cost_id Scopes: products:delete

Delete a product cost entry by UUID. Destructive.

3 parameters
Name In Type Required Description
product_id path string yes
cost_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/products/delete-products-product-id-costs-cost-id.md

GET /products/:product_id Scopes: products:read

Fetch a single product by UUID, including pricing and metadata.

1 parameter
Name In Type Required Description
product_id path string yes

📄 /api/products/get-products-product-id.md

GET /products/:product_id/costs Scopes: products:read

List all cost entries (supplier costs) for a product.

1 parameter
Name In Type Required Description
product_id path string yes

📄 /api/products/get-products-product-id-costs.md

GET /products Scopes: products:read

List products / services in the workspace catalog. Use for quotes, line items on opportunities, or pricing questions.

5 parameters
Name In Type Required Description
limit query number no
after query string no
search query string no Free-text across name and sku
category query string no
is_active query boolean no

📄 /api/products/get-products.md

PATCH /products/:product_id Scopes: products:write

Update a product. Pass only the fields you want to change.

8 parameters
Name In Type Required Description
product_id path string yes
name body string no
sku body string no
price body number no
category body string no
description body string no
is_active body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/products/patch-products-product-id.md

PATCH /products/:product_id/costs/:cost_id Scopes: products:write

Update a product cost entry. Pass only the fields you want to change.

6 parameters
Name In Type Required Description
product_id path string yes
cost_id path string yes
label body string no
cost_price body number no
quantity body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/products/patch-products-product-id-costs-cost-id.md

Supplier Catalog (5 endpoints)

Supplier catalog products you can pull into your own product list and quote from.

📄 Full markdown: /api/supplier-catalog.md

POST /supplier-catalog Scopes: products:write

Add a supplier catalog entry.

7 parameters
Name In Type Required Description
supplier_id body string yes
supplier_price body number yes
sku body string no
name body string no
lead_time_days body number no
min_order_quantity body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/supplier-catalog/post-supplier-catalog.md

DELETE /supplier-catalog/:supplier_product_id Scopes: products:delete

Delete a supplier catalog entry.

2 parameters
Name In Type Required Description
supplier_product_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/supplier-catalog/delete-supplier-catalog-supplier-product-id.md

GET /supplier-catalog Scopes: products:read

List supplier catalog entries — products available from suppliers (prices, SKUs, lead times).

2 parameters
Name In Type Required Description
limit query number no
supplier_id query string no

📄 /api/supplier-catalog/get-supplier-catalog.md

PATCH /supplier-catalog/:supplier_product_id Scopes: products:write

Update a supplier catalog entry.

5 parameters
Name In Type Required Description
supplier_product_id path string yes
supplier_price body number no
sku body string no
lead_time_days body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/supplier-catalog/patch-supplier-catalog-supplier-product-id.md

Activities (5 endpoints)

Log and manage CRM activities (calls, meetings, notes) linked to contacts, deals, and customers.

📄 Full markdown: /api/activities.md

DELETE /activities/:activity_id Scopes: activities:delete

Delete an activity by UUID. Destructive.

2 parameters
Name In Type Required Description
activity_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/activities/delete-activities-activity-id.md

GET /activities/:activity_id Scopes: activities:read

Fetch a single activity by UUID — the full record including description, occurred_at, and linked entities.

1 parameter
Name In Type Required Description
activity_id path string yes UUID of the activity

📄 /api/activities/get-activities-activity-id.md

GET /activities Scopes: activities:read

List CRM activity log entries (free-text notes and one-line records of calls, meetings, sms, emails, tasks) anchored to contacts/companies/opportunities. Use for "recent notes", "what was logged", "activity history on this deal/contact". DO NOT use for phone-specific queries — list_phone_call_logs returns the actual call records with duration, recording, direction. DO NOT use for inbox queries — list_email_threads / list_sms_conversations / list_bookings / list_transcripts have richer per-channel data.

7 parameters
Name In Type Required Description
limit query number no Max activities (1-100, default 25)
after query string no Pagination cursor
contact_id query string no Filter to activities on a specific contact
customer_id query string no Filter to activities on a specific company
deal_id query string no Filter to activities on a specific opportunity
task_id query string no Filter to activities logged from a specific task
activity_type query string no Filter by type (call, meeting, note, email)

📄 /api/activities/get-activities.md

POST /activities Scopes: activities:write

Log an activity (call, meeting, note, email) against a contact, company, opportunity, or task. Use after a phone call, meeting, or to add a note. When task_id is set, the activity appears on the task detail page AND on the linked opportunity timeline.

9 parameters
Name In Type Required Description
activity_type body string yes Type: call, meeting, note, email, sms, task
subject body string no Short title / summary
description body string no Detail / notes content
contact_id body string no UUID of the contact this is about
customer_id body string no UUID of the company this is about
deal_id body string no UUID of the opportunity this is about
deal_ids body array no Multiple opportunity UUIDs to fan out
task_id body string no UUID of the task this activity came from. Shows on the task detail page; pair with deal_id to also surface on the opportunity timeline.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/activities/post-activities.md

PATCH /activities/:activity_id Scopes: activities:write

Update an activity. Pass only the fields you want to change. Pass deal_ids array to replace linked opportunities atomically.

9 parameters
Name In Type Required Description
activity_id path string yes
activity_type body string no
subject body string no
description body string no
contact_id body string no
customer_id body string no
task_id body string no
deal_ids body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/activities/patch-activities-activity-id.md

Stage Changes (1 endpoint)

The audit trail of every time an opportunity moved between pipeline stages.

📄 Full markdown: /api/stage-changes.md

GET /stage-changes Scopes: opportunities:read

List pipeline stage-change (card-movement) events — the audit trail of every time an opportunity moved between stages, on any pipeline. Each event records who moved it (moved_by, null = automation/system), the from-stage and to-stage (id + name), the pipeline, and when (moved_at). This is the source for "who moved this card out of <stage>, and when", card-movement reports, and stage-velocity analysis — human and automated moves alike, told apart by moved_by. Use human_only=true for people-only moves. Covers manual kanban drags, API/MCP moves, and automation moves.

8 parameters
Name In Type Required Description
limit query number no Max events (1-100, default 25)
after query string no Pagination cursor
opportunity_id query string no Filter to one opportunity — its full move history in chronological order
pipeline_id query string no Filter to moves within a specific pipeline
moved_by query string no Filter to moves made by a specific user (UUID)
human_only query boolean no When true, return only moves made by a real user (excludes automation/system moves where moved_by is null)
moved_after query string no ISO timestamp — only events at/after this time
moved_before query string no ISO timestamp — only events at/before this time

📄 /api/stage-changes/get-stage-changes.md

Tasks (10 endpoints)

Create, assign, and manage tasks linked to deals and contacts.

📄 Full markdown: /api/tasks.md

POST /tasks Scopes: tasks:write

Create a new task. Requires title. The task modal has two text fields: "Summary" (short one-liner — maps to the `description` field) and "Detailed Description" (long-form notes — maps to the `body` field). Use the right one for the length of content. Link to records via deal_id / contact_id / customer_id.

13 parameters
Name In Type Required Description
title body string yes Title (required). Matches the "Title" field on the task modal.
description body string no Summary — short one-line summary (target under ~200 chars). Matches the "Summary" field on the task modal. For multi-paragraph content use `body` instead.
body body string no Detailed Description — long-form notes, acceptance criteria, multi-paragraph content. Matches the "Detailed Description" field on the task modal.
due_date body string no ISO date (YYYY-MM-DD) when the task is due
due_time body string no Time of day (HH:MM) when the task is due
assigned_to body string no UUID of the user to assign
category body string no Category name
status body string no todo, in_progress, completed, or cancelled. Defaults to todo. An unrecognised value is rejected with a 400, not coerced.
priority body string no low, medium, high, or urgent. Defaults to medium.
deal_id body string no
contact_id body string no
customer_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/post-tasks.md

POST /tasks/categories Scopes: tasks:write

Create a new task category in the workspace.

2 parameters
Name In Type Required Description
name body string yes Category name
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/post-tasks-categories.md

DELETE /tasks/:task_id Scopes: tasks:delete

Delete a task by UUID. Destructive.

2 parameters
Name In Type Required Description
task_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/delete-tasks-task-id.md

DELETE /tasks/categories/:category_id Scopes: tasks:delete

Delete a task category by UUID. Destructive.

2 parameters
Name In Type Required Description
category_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/delete-tasks-categories-category-id.md

GET /tasks/:task_id Scopes: tasks:read

Fetch a single task by UUID. Returns the full task record.

1 parameter
Name In Type Required Description
task_id path string yes UUID of the task

📄 /api/tasks/get-tasks-task-id.md

GET /tasks/categories Scopes: tasks:read

List task categories defined in the workspace. Use this to find a category UUID for assigning to a task.

📄 /api/tasks/get-tasks-categories.md

GET /tasks Scopes: tasks:read

List tasks in the workspace. Supports filtering by status, assigned_to, priority, category, deal_id, contact_id, customer_id.

9 parameters
Name In Type Required Description
limit query number no Max number of tasks to return (1-100, default 25)
after query string no Pagination cursor
status query string no Filter by status: todo, in_progress, completed, or cancelled
assigned_to query string no UUID of the assignee
priority query string no Filter by priority
category query string no Filter by category
deal_id query string no Filter to a specific opportunity
contact_id query string no Filter to a specific contact
customer_id query string no Filter to a specific company

📄 /api/tasks/get-tasks.md

POST /tasks/reorder Scopes: tasks:write

Reorder a set of tasks. Pass task_ids array in desired display order; sort_order is reassigned from the array index.

2 parameters
Name In Type Required Description
task_ids body array yes Task UUIDs in new display order
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/post-tasks-reorder.md

PATCH /tasks/:task_id Scopes: tasks:write

Update a task. Set status to "completed" to mark complete. Pass only fields you want to change. Note: the task modal has two text fields — "Summary" (maps to `description`) and "Detailed Description" (maps to `body`). Pick the right one for the length of content.

11 parameters
Name In Type Required Description
task_id path string yes
title body string no Title. Matches the "Title" field on the task modal.
description body string no Summary — short one-line summary (target under ~200 chars). Matches the "Summary" field on the task modal. For multi-paragraph content use `body` instead.
body body string no Detailed Description — long-form notes, acceptance criteria, multi-paragraph content. Matches the "Detailed Description" field on the task modal.
due_date body string no
due_time body string no
assigned_to body string no
status body string no todo, in_progress, completed, or cancelled. Set to completed when the work was done; set to cancelled when it stopped being relevant (comes off overdue counts without counting as done). An unrecognised value is rejected with a 400, not coerced.
priority body string no low, medium, high, or urgent
category body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/patch-tasks-task-id.md

PATCH /tasks/categories/:category_id Scopes: tasks:write

Rename a task category.

3 parameters
Name In Type Required Description
category_id path string yes
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/tasks/patch-tasks-categories-category-id.md

Work Orders (6 endpoints)

Manage work orders linked to deals for tracking project execution. Work orders appear on the CRM Calendar, support team assignment, and scheduled dates.

📄 Full markdown: /api/work-orders.md

POST /work-orders Scopes: work-orders:write

Create a work order. Pass deal_id for a deal-level work order, or deal_product_id to attach it to a specific product line. At least one is required. Pass assignee_ids (array of user UUIDs) to assign a crew — the first becomes the primary assignee.

7 parameters
Name In Type Required Description
deal_id body string no
deal_product_id body string no
status_id body string no
status body string no
data body object no
assignee_ids body array no User UUIDs to assign as the crew; the first is kept as the primary assignee.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-orders/post-work-orders.md

DELETE /work-orders/:work_order_id Scopes: work-orders:delete

Delete a work order by UUID.

2 parameters
Name In Type Required Description
work_order_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-orders/delete-work-orders-work-order-id.md

GET /work-orders/:work_order_id Scopes: work-orders:read

Fetch a single work order by UUID, including its assignee crew (assignees[]).

1 parameter
Name In Type Required Description
work_order_id path string yes

📄 /api/work-orders/get-work-orders-work-order-id.md

GET /work-orders Scopes: work-orders:read

List work orders. Filter by deal_id (returns deal-level work orders plus any attached to that deal's product lines), deal_product_id, status_id, or assigned_to. Each work order includes its assignee crew (assignees[]).

4 parameters
Name In Type Required Description
limit query number no
deal_id query string no
deal_product_id query string no
status_id query string no

📄 /api/work-orders/get-work-orders.md

POST /work-orders/send-work-status Scopes: work-orders:write

Send a work-status update email to a contact for an opportunity. Costs credits.

6 parameters
Name In Type Required Description
deal_id body string yes
recipient_email body string yes
recipient_name body string yes
personal_message body string no Optional note included in the work-status email.
expires_in_days body number no How long the portal link stays valid. Defaults to 30.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-orders/post-work-orders-send-work-status.md

PATCH /work-orders/:work_order_id Scopes: work-orders:write

Update a work order (status, schedule, data fields, and/or its assignee crew). `data` MERGES: send only the field slugs you are changing and the rest are left alone. Pass assignee_ids (array of user UUIDs) to replace the crew; the first becomes the primary assignee.

8 parameters
Name In Type Required Description
work_order_id path string yes
status_id body string no
status body string no
data body object no Work-order field slugs to values. MERGED into the existing data, so send only what you are changing — omitted fields keep their current values and job photos are preserved. Set a key to null to clear just that field.
schedule_date body string no
schedule_time body string no
assignee_ids body array no User UUIDs for the crew; replaces the current assignees. First is kept as the primary.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-orders/patch-work-orders-work-order-id.md

Work Order Settings (15 endpoints)

Work order settings: statuses, field definitions and their ordering.

📄 Full markdown: /api/work-order-config.md

POST /work-order-fields Scopes: work-orders:write

Add a work-order custom field. The generated slug is what automation configs address the field by (see the create_work_orders action's `data` object), so read it back off the response.

9 parameters
Name In Type Required Description
label body string yes Display label, e.g. "Offer Amount (AUD)".
slug body string no Machine key that automations address this field by (the create_work_orders action's `data` object). Auto-generated from the label when omitted, and immutable afterwards.
product_id body string no Scope the field to one catalogue product instead of the whole workspace.
type body string no Field type. Drives both the input rendered on the work order and the coercion applied to values an automation prefills into it. Defaults to text.
options body array no Choices for a select field. Required for type "select". Without them the field renders an empty dropdown.
required body boolean no Marks the field as expected: it renders with an asterisk and counts toward the work order's "scoped" progress indicator. It does NOT block anything on its own — a work order can still change status with it empty. To actually gate a status change, use requiredFieldsByStatus on a portal's work_orders sharing rule (set_portal_data_sharing).
is_title body boolean no Make this the field rendered as the work order title. Only one field per workspace should carry it.
position body number no Display order among the workspace fields.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/post-work-order-fields.md

POST /work-order-statuses Scopes: work-orders:write

Create a work-order status.

3 parameters
Name In Type Required Description
label body string yes
color body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/post-work-order-statuses.md

POST /work-order-templates Scopes: work-orders:write

Add a templated work order to a product. The data object keys should match your work order field slugs (e.g. deliverable, scope, dependencies).

3 parameters
Name In Type Required Description
product_id body string yes
data body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/post-work-order-templates.md

DELETE /work-order-fields/:field_id Scopes: work-orders:delete

Delete a work-order field.

2 parameters
Name In Type Required Description
field_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/delete-work-order-fields-field-id.md

DELETE /work-order-statuses/:status_id Scopes: work-orders:delete

Delete a work-order status.

2 parameters
Name In Type Required Description
status_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/delete-work-order-statuses-status-id.md

DELETE /work-order-templates/:template_id Scopes: work-orders:delete

Delete a templated work order.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/delete-work-order-templates-template-id.md

GET /work-order-templates Scopes: work-orders:read

List the templated work orders for a product. These are stamped onto a real work order automatically the moment that product is added to an opportunity. Requires product_id.

1 parameter
Name In Type Required Description
product_id query string yes

📄 /api/work-order-config/get-work-order-templates.md

POST /work-order-fields/reorder Scopes: work-orders:write

Reorder work-order fields.

2 parameters
Name In Type Required Description
field_ids body array yes Work-order field UUIDs in the desired display order.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/post-work-order-fields-reorder.md

POST /work-order-statuses/reorder Scopes: work-orders:write

Reorder work-order statuses.

2 parameters
Name In Type Required Description
status_ids body array yes Work-order status UUIDs in the desired display order.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/post-work-order-statuses-reorder.md

POST /work-order-templates/reorder Scopes: work-orders:write

Reorder the templated work orders for a product.

2 parameters
Name In Type Required Description
template_ids body array yes Work-order template UUIDs in the desired display order.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/post-work-order-templates-reorder.md

PATCH /work-order-fields/:field_id Scopes: work-orders:write

Update a work-order field. `slug` is immutable after creation. Everything else can be changed.

8 parameters
Name In Type Required Description
field_id path string yes
label body string no Display label.
type body string no Field type. Drives both the input rendered on the work order and the coercion applied to values an automation prefills into it. Defaults to text.
options body array no Choices for a select field. Required for type "select". Without them the field renders an empty dropdown.
required body boolean no Marks the field as expected: it renders with an asterisk and counts toward the work order's "scoped" progress indicator. It does NOT block anything on its own — a work order can still change status with it empty. To actually gate a status change, use requiredFieldsByStatus on a portal's work_orders sharing rule (set_portal_data_sharing).
is_title body boolean no Make this the field rendered as the work order title. Only one field per workspace should carry it.
position body number no Display order among the workspace fields.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/patch-work-order-fields-field-id.md

PATCH /work-order-statuses/:status_id Scopes: work-orders:write

Update a work-order status.

2 parameters
Name In Type Required Description
status_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/patch-work-order-statuses-status-id.md

PATCH /work-order-templates/:template_id Scopes: work-orders:write

Update a templated work order.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/work-order-config/patch-work-order-templates-template-id.md

STAKEHOLDERS (17 endpoints)

stakeholders endpoints.

📄 Full markdown: /api/stakeholders.md

POST /stakeholder-types/:type_id/members Scopes: contacts:write

Add a contact to a stakeholder type. Requires contact_id.

3 parameters
Name In Type Required Description
type_id path string yes
contact_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/post-stakeholder-types-type-id-members.md

POST /tasks/:task_id/stakeholders Scopes: opportunities:write

Assign a stakeholder to a task. The contact must belong to a stakeholder type with "assignable to work" enabled. The task appears in that stakeholder's portal My Tasks tab.

3 parameters
Name In Type Required Description
task_id path string yes
contact_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/post-tasks-task-id-stakeholders.md

POST /work-orders/:work_order_id/stakeholders Scopes: opportunities:write

Assign a stakeholder to a work order. The contact must belong to a stakeholder type with "assignable to work" enabled. Also shares the work order into that stakeholder's portal so it shows in their Work Orders tab.

3 parameters
Name In Type Required Description
work_order_id path string yes
contact_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/post-work-orders-work-order-id-stakeholders.md

POST /deal-stakeholders Scopes: opportunities:write

Attach a stakeholder contact to an opportunity. Requires deal_id and contact_id; optional bucket_id (the stakeholder type) and role.

5 parameters
Name In Type Required Description
deal_id body string yes
contact_id body string yes
bucket_id body string no Stakeholder type UUID this attachment belongs to.
role body string no Free-text role on this opportunity, e.g. Lead tiler.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/post-deal-stakeholders.md

POST /stakeholder-types Scopes: contacts:write

Create a stakeholder type. Requires name; optional capability flags default to off.

7 parameters
Name In Type Required Description
name body string yes
color body string no Hex colour for the type chip, e.g. #6366f1.
portal_eligible body boolean no People in this type can be given a scoped portal login.
commission_eligible body boolean no People in this type earn trackable commissions/payouts.
assignable_to_work_orders body boolean no People in this type can be assigned jobs/work orders.
sort_order body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/post-stakeholder-types.md

DELETE /stakeholder-types/:type_id Scopes: contacts:delete

Delete a stakeholder type by UUID. Destructive; its membership links go too.

2 parameters
Name In Type Required Description
type_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/delete-stakeholder-types-type-id.md

DELETE /deal-stakeholders/:id Scopes: opportunities:delete

Detach a stakeholder from an opportunity by the attachment row UUID.

2 parameters
Name In Type Required Description
id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/delete-deal-stakeholders-id.md

GET /deal-stakeholders Scopes: opportunities:read

List the external stakeholders attached to an opportunity. Requires the deal_id query parameter.

1 parameter
Name In Type Required Description
deal_id query string yes

📄 /api/stakeholders/get-deal-stakeholders.md

GET /stakeholder-types Scopes: contacts:read

List stakeholder types (external-people groups such as Contractors, Referrers, Partners) with their capability flags (portal_eligible, commission_eligible, assignable_to_work_orders).

1 parameter
Name In Type Required Description
limit query number no

📄 /api/stakeholders/get-stakeholder-types.md

DELETE /stakeholder-types/:type_id/members/:member_id Scopes: contacts:delete

Remove a contact from a stakeholder type by the membership row UUID.

3 parameters
Name In Type Required Description
type_id path string yes
member_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/delete-stakeholder-types-type-id-members-member-id.md

DELETE /tasks/:task_id/stakeholders/:contact_id Scopes: opportunities:delete

Unassign a stakeholder from a task by contact UUID.

3 parameters
Name In Type Required Description
task_id path string yes
contact_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/delete-tasks-task-id-stakeholders-contact-id.md

DELETE /work-orders/:work_order_id/stakeholders/:contact_id Scopes: opportunities:delete

Unassign a stakeholder from a work order by contact UUID.

3 parameters
Name In Type Required Description
work_order_id path string yes
contact_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/delete-work-orders-work-order-id-stakeholders-contact-id.md

PATCH /stakeholder-types/:type_id Scopes: contacts:write

Update a stakeholder type (name, colour, or the capability flags). Pass only the fields you want to change.

8 parameters
Name In Type Required Description
type_id path string yes
name body string no
color body string no Hex colour for the type chip, e.g. #6366f1.
portal_eligible body boolean no People in this type can be given a scoped portal login.
commission_eligible body boolean no People in this type earn trackable commissions/payouts.
assignable_to_work_orders body boolean no People in this type can be assigned jobs/work orders.
sort_order body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stakeholders/patch-stakeholder-types-type-id.md

Automations (26 endpoints)

Create and manage workflow automations. Includes sub-resources for triggers, actions, and execution runs. Supports enable/disable and manual triggering.

📄 Full markdown: /api/automations.md

POST /automations/:automation_id/actions Scopes: automations:write

Add an action to an automation. Omit run_priority and the action is appended to run LAST, which is almost always what you want; pass it only to place the action deliberately, and note it counts DOWN (higher runs first). `config` carries the action's settings and is REQUIRED (the column is NOT NULL) — pass {} for an action that needs none, or call describe_action_type first to get the exact config fields for this action_type. Use list_action_types to see what is available. The response includes chain_run_order so you can confirm where the action landed.

7 parameters
Name In Type Required Description
automation_id path string yes
action_type body string yes Which action to run, e.g. send_email, send_sms, create_task, update_deal. Call list_action_types for the full vocabulary, then describe_action_type for one action's config shape.
run_priority body number no Higher run_priority runs first. The action with the highest value executes at the start of the chain, counting down. Omit this and the actions run in the order you supply them.
config body object yes Settings for this action type (recipients, template ids, field values). The required shape depends on action_type. Call describe_action_type for its config schema before writing. Two keys work on EVERY action type regardless of action_type: "run_if" gates just this step (same condition shape as the automation's own conditions, e.g. { "contact.phone": { "starts_with": "+61" } }; when it does not match the step is SKIPPED, the rest of the chain still runs, and no error is raised), and "stop_on_failure" halts the remaining chain if this step errors. A trigger payload field is addressable both flattened and namespaced — `form_id` and `trigger.form_id` are the same field — because the payload is copied to the top level and mirrored under `trigger`. Enriched CRM records use their own namespaces: `contact.*`, `deal.*`, `company.*`. Supported run_if operators: exists, not_exists, eq, neq, gt, lt, gte, lte, contains, not_contains, contains_any, contains_text, starts_with, not_starts_with, in. An unrecognized operator is rejected with a 400 at write time. To gate a step, the key is "run_if" — "conditions" on an ACTION is rejected, because it means the automation-level field and nothing reads it here.
integration_id body string no UUID of the connected integration this action runs through, when the action type needs one.
integration_type body string no Which integration platform the action targets, when the action type needs one.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-actions.md

POST /automations/:automation_id/triggers Scopes: automations:write

Add a trigger to an automation. An automation may have multiple triggers - it fires when ANY of them matches (OR logic). Pass trigger_type to give this trigger its own event class (e.g. add a webhook_received trigger to a form_completed automation so both entry points run the same actions); omit it to inherit the automation's primary trigger_type.

6 parameters
Name In Type Required Description
automation_id path string yes
trigger_type body string no Optional. This trigger's own event class. Omit to inherit the automation's primary trigger_type. Set it to fire one automation from multiple different event types (OR-matched).
source_type body string no
source_id body string no
config body object no Trigger-specific settings. For opportunity events (deal_created / deal_updated), scope the trigger with { scope_pipeline_id, scope_stage_id } so it only fires for that pipeline/stage.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-triggers.md

POST /automations Scopes: automations:write

Create a new automation.

17 parameters
Name In Type Required Description
name body string yes Automation name shown in the Automations list.
description body string no What this automation does. Internal note for your team; never shown to a customer.
trigger_type body string yes What fires the automation, e.g. stage_changed, deal_created, form_completed, webhook_received, facebook_lead_ad, scheduled. Call list_trigger_schemas for the full list, or get_trigger_schema for one trigger's trigger_data shape.
stage_id body string no Pipeline stage UUID this automation fires on. Only meaningful when trigger_type is stage_changed, where it is the ONLY way to bind the automation: add_automation_trigger rejects stage_changed on purpose. Pass null to unbind.
enabled body boolean no Whether the automation runs. False leaves it configured but dormant.
priority body number no Run order when several automations match the same event. Lower runs first.
max_executions_per_day body number no Safety cap on how many times this automation may run per day across the workspace. Null means uncapped.
show_in_quick_links body boolean no Show this automation as a manually-fireable Quick Link button on the opportunity page.
conditions body object no Optional AND-conditions gating whether the automation fires. Shape: { "field": { "operator": value } }, or plain equality shorthand { "field": value }. Supported operators: exists, not_exists, eq, neq, gt, lt, gte, lte, contains, not_contains, contains_any, contains_text, starts_with, not_starts_with, in. An unrecognized operator is rejected with a 400 at write time (it used to fail silently at runtime). For "field has a value", use { "field": { "exists": true } }. A trigger payload field is addressable both flattened and namespaced — `form_id` and `trigger.form_id` are the same field — because the payload is copied to the top level and mirrored under `trigger`. Enriched CRM records use their own namespaces: `contact.*`, `deal.*`, `company.*`. To gate a SINGLE action rather than the whole automation, put the same shape in that action's config.run_if instead.
crm_integration body object no Maps incoming trigger payload fields onto CRM records for webhook-style triggers (which pipeline/stage to create in, which fields map where). Full-replace on write. Custom fields and quick links need BOTH halves: the value bag (custom_fields_deal / quick_links_deal, and the contact/account equivalents) AND a matching target in field_mappings (custom.deal.<field_id> / quicklink.deal.<type_id>). With the bag but no target, the whole group is written on a NEWLY CREATED record and silently dropped on an EXISTING one, with no error on the run, and the write returns _warnings naming the affected field ids (SR 77381a31).
folder body string no Folder name this automation is filed under in the Automations list. Pass null to move it back to the root.
dedup_enabled body boolean no Suppress repeat runs for the same subject inside dedup_window_minutes. Use when a noisy source can fire the same event twice.
dedup_window_minutes body number no How long the deduplication window lasts, in minutes. Only applies when dedup_enabled is true.
unskippable body boolean no Stage automations only. When true the automation is pre-selected and locked on in the stage-move window, and still runs if the mover declines everything. Defaults to false, which leaves it up to whoever moves the opportunity.
triggers body array no Optional trigger rows to create alongside the automation.
actions body array no Optional action chain to create alongside the automation. Supply them in the order you want them to RUN — the first element executes first — and leave run_priority off each one; the API numbers them for you. The response returns the chain in run order so you can confirm it.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations.md

POST /automations/folders Scopes: automations:write

Create an automation folder. kind defaults to general; pass workflow, queue, or schedule to file it under another primitive.

3 parameters
Name In Type Required Description
name body string yes
kind body string no general (default), workflow, queue, or schedule.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-folders.md

DELETE /automations/:automation_id Scopes: automations:delete

Delete an automation.

2 parameters
Name In Type Required Description
automation_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/delete-automations-automation-id.md

DELETE /automations/:automation_id/actions/:action_id Scopes: automations:delete

Delete an automation action.

3 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/delete-automations-automation-id-actions-action-id.md

DELETE /automations/folders/:folder_id Scopes: automations:delete

Delete an automation folder. Items keep their folder name string; clear it via update_automation if needed.

2 parameters
Name In Type Required Description
folder_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/delete-automations-folders-folder-id.md

DELETE /automations/:automation_id/triggers/:trigger_id Scopes: automations:delete

Delete a trigger.

3 parameters
Name In Type Required Description
automation_id path string yes
trigger_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/delete-automations-automation-id-triggers-trigger-id.md

GET /automations/action-types/:action_type

Return the full config schema, example, warnings, and related actions for one automation action_type. Call this RIGHT BEFORE writing that action via add_automation_action — do not memorise multiple types upfront. Free read.

1 parameter
Name In Type Required Description
action_type path string yes Canonical action_type key, e.g. "add_tasks", "send_custom_email", "move_deal". Aliases (e.g. "set_crm_field" → "set_custom_field") are accepted.

📄 /api/automations/get-automations-action-types-action-type.md

POST /automations/:automation_id/disable Scopes: automations:write

Disable an automation.

2 parameters
Name In Type Required Description
automation_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-disable.md

POST /automations/:automation_id/enable Scopes: automations:write

Enable an automation.

2 parameters
Name In Type Required Description
automation_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-enable.md

POST /automations/:automation_id/actions/:action_id/execute Scopes: automations-trigger:trigger

Execute a single automation action (testing).

5 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
trigger_data body object no Data passed to the trigger, available to the action as variables (e.g. contact_id, deal_id, email).
payload body object no Alias for trigger_data. Either name works; trigger_data is preferred.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-actions-action-id-execute.md

GET /automations/:automation_id/actions Scopes: automations:read

List actions on an automation, in RUN ORDER: the first action returned is the first one that executes. Each row carries run_priority, which counts DOWN (highest runs first).

1 parameter
Name In Type Required Description
automation_id path string yes

📄 /api/automations/get-automations-automation-id-actions.md

GET /automations/folders Scopes: automations:read

List automation folders. Pass kind (general | workflow | queue | schedule) to scope to one primitive.

1 parameter
Name In Type Required Description
kind query string no Optional. Filter to one primitive: general, workflow, queue, or schedule.

📄 /api/automations/get-automations-folders.md

GET /automations Scopes: automations:read

List automations in the workspace.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/automations/get-automations.md

POST /automations/:automation_id/actions/reorder Scopes: automations:write

Reorder an automation's actions. Pass action_ids in the order you want them to RUN — first id runs first. The response returns the resulting chain in run order so you can confirm it.

3 parameters
Name In Type Required Description
automation_id path string yes
action_ids body array yes Every action on the automation, in the order they should run: the first id executes first. Must list the whole chain, not a subset — get the ids from list_automation_actions.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-actions-reorder.md

POST /automations/:automation_id/trigger Scopes: automations-trigger:trigger

Manually trigger an automation.

4 parameters
Name In Type Required Description
automation_id path string yes
trigger_data body object no Data passed to the trigger, available to the automation's actions as variables (e.g. contact_id, deal_id, email). Reserved keys: skip_action_ids (string[]) suppresses those actions, only_action_ids (string[]) runs ONLY those.
payload body object no Alias for trigger_data. Either name works; trigger_data is preferred.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/post-automations-automation-id-trigger.md

PATCH /automations/:automation_id Scopes: automations:write

Update an automation. For a stage automation, this is where stage_id is set: stage automations are wired via automations.stage_id, NOT by adding a trigger row.

16 parameters
Name In Type Required Description
automation_id path string yes UUID of the automation to update. Get ids from list_automations.
name body string no Automation name shown in the Automations list.
description body string no What this automation does. Internal note for your team; never shown to a customer.
trigger_type body string no What fires the automation, e.g. stage_changed, deal_created, form_completed, webhook_received, facebook_lead_ad, scheduled. Call list_trigger_schemas for the full list, or get_trigger_schema for one trigger's trigger_data shape.
stage_id body string no Pipeline stage UUID this automation fires on. Only meaningful when trigger_type is stage_changed, where it is the ONLY way to bind the automation: add_automation_trigger rejects stage_changed on purpose. Pass null to unbind.
enabled body boolean no Whether the automation runs. False leaves it configured but dormant.
priority body number no Run order when several automations match the same event. Lower runs first.
max_executions_per_day body number no Safety cap on how many times this automation may run per day across the workspace. Null means uncapped.
show_in_quick_links body boolean no Show this automation as a manually-fireable Quick Link button on the opportunity page.
conditions body object no Optional AND-conditions gating whether the automation fires. Shape: { "field": { "operator": value } }, or plain equality shorthand { "field": value }. Supported operators: exists, not_exists, eq, neq, gt, lt, gte, lte, contains, not_contains, contains_any, contains_text, starts_with, not_starts_with, in. An unrecognized operator is rejected with a 400 at write time (it used to fail silently at runtime). For "field has a value", use { "field": { "exists": true } }. A trigger payload field is addressable both flattened and namespaced — `form_id` and `trigger.form_id` are the same field — because the payload is copied to the top level and mirrored under `trigger`. Enriched CRM records use their own namespaces: `contact.*`, `deal.*`, `company.*`. To gate a SINGLE action rather than the whole automation, put the same shape in that action's config.run_if instead.
crm_integration body object no Maps incoming trigger payload fields onto CRM records for webhook-style triggers (which pipeline/stage to create in, which fields map where). Full-replace on write. Custom fields and quick links need BOTH halves: the value bag (custom_fields_deal / quick_links_deal, and the contact/account equivalents) AND a matching target in field_mappings (custom.deal.<field_id> / quicklink.deal.<type_id>). With the bag but no target, the whole group is written on a NEWLY CREATED record and silently dropped on an EXISTING one, with no error on the run, and the write returns _warnings naming the affected field ids (SR 77381a31).
folder body string no Folder name this automation is filed under in the Automations list. Pass null to move it back to the root.
dedup_enabled body boolean no Suppress repeat runs for the same subject inside dedup_window_minutes. Use when a noisy source can fire the same event twice.
dedup_window_minutes body number no How long the deduplication window lasts, in minutes. Only applies when dedup_enabled is true.
unskippable body boolean no Stage automations only. When true the automation is pre-selected and locked on in the stage-move window, and still runs if the mover declines everything. Defaults to false, which leaves it up to whoever moves the opportunity.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/patch-automations-automation-id.md

PATCH /automations/:automation_id/actions/:action_id Scopes: automations:write

Update an automation action: its config (settings), its action_type, or its run_priority (position in the chain). To move an action, prefer reorder_automation_actions, which takes the order you want rather than a number. `config` REPLACES the stored object rather than merging into it, so read the action first via list_automation_actions and pass the full object back with your change applied. The response includes chain_run_order.

8 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
action_type body string no Which action to run, e.g. send_email, send_sms, create_task, update_deal. Call list_action_types for the full vocabulary, then describe_action_type for one action's config shape.
run_priority body number no Higher run_priority runs first. The action with the highest value executes at the start of the chain, counting down. Omit this and the actions run in the order you supply them.
config body object no Settings for this action type (recipients, template ids, field values). The required shape depends on action_type. Call describe_action_type for its config schema before writing. Two keys work on EVERY action type regardless of action_type: "run_if" gates just this step (same condition shape as the automation's own conditions, e.g. { "contact.phone": { "starts_with": "+61" } }; when it does not match the step is SKIPPED, the rest of the chain still runs, and no error is raised), and "stop_on_failure" halts the remaining chain if this step errors. A trigger payload field is addressable both flattened and namespaced — `form_id` and `trigger.form_id` are the same field — because the payload is copied to the top level and mirrored under `trigger`. Enriched CRM records use their own namespaces: `contact.*`, `deal.*`, `company.*`. Supported run_if operators: exists, not_exists, eq, neq, gt, lt, gte, lte, contains, not_contains, contains_any, contains_text, starts_with, not_starts_with, in. An unrecognized operator is rejected with a 400 at write time. To gate a step, the key is "run_if" — "conditions" on an ACTION is rejected, because it means the automation-level field and nothing reads it here.
integration_id body string no UUID of the connected integration this action runs through, when the action type needs one.
integration_type body string no Which integration platform the action targets, when the action type needs one.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/patch-automations-automation-id-actions-action-id.md

PATCH /automations/folders/:folder_id Scopes: automations:write

Rename an automation folder. To move automations into it, set their folder field via update_automation.

4 parameters
Name In Type Required Description
folder_id path string yes UUID of the automation folder to update. Get ids from list_automation_folders.
name body string no Folder name shown in the Automations list.
kind body string no What the folder groups: general (plain folder), workflow, queue, or schedule. Drives how the folder is presented in the Automations UI.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/patch-automations-folders-folder-id.md

PATCH /automations/:automation_id/triggers/:trigger_id Scopes: automations:write

Update a trigger - its event class, source, or config (e.g. the pipeline/stage scope on an opportunity trigger).

7 parameters
Name In Type Required Description
automation_id path string yes
trigger_id path string yes
trigger_type body string no Optional. This trigger's own event class (OR-matched with the automation's other triggers).
source_type body string no
source_id body string no
config body object no Trigger-specific settings. For opportunity events (deal_created / deal_updated), scope the trigger with { scope_pipeline_id, scope_stage_id } so it only fires for that pipeline/stage; omit or clear them to fire for every opportunity.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/automations/patch-automations-automation-id-triggers-trigger-id.md

Custom Scripts (13 endpoints)

Generate, edit, secure, test, and approve a Custom Script automation action -- an AI-written (or hand-written) JavaScript module that runs on its own automation as the final action.

📄 Full markdown: /api/custom-scripts.md

POST /automations/:automation_id/actions/:action_id/custom-script/approve-code Scopes: automations:write

Approve a Custom Script's current generated code for live execution (Gate B — separate from saving the action itself).

3 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/post-automations-automation-id-actions-action-id-custom-script-approve-code.md

PUT /custom-scripts/:script_id/tp-key Scopes: custom-scripts:write

Attach a TrustPager API key (tp_live_…) to a Custom Script so its code can call the TrustPager API via tp.*. The key's own scopes decide what the script may do - mint it in Settings → API with exactly the scopes needed. Write-only; the value is never returned. Redeploy (Test) the script to apply.

3 parameters
Name In Type Required Description
script_id path string yes
api_key body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/put-custom-scripts-script-id-tp-key.md

DELETE /automations/:automation_id/actions/:action_id/custom-script/secrets/:secret_name Scopes: automations:write

Remove a third-party secret from a Custom Script.

4 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
secret_name path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/delete-automations-automation-id-actions-action-id-custom-script-secrets-secret-name.md

DELETE /custom-scripts/:script_id/tp-key Scopes: custom-scripts:write

Remove the TrustPager API key from a Custom Script - tp.* becomes unavailable to it on the next deploy.

2 parameters
Name In Type Required Description
script_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/delete-custom-scripts-script-id-tp-key.md

POST /automations/:automation_id/actions/:action_id/custom-script/generate Scopes: automations:write

Generate (or regenerate) a Custom Script action's code from a plain-English description.

4 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
description body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/post-automations-automation-id-actions-action-id-custom-script-generate.md

GET /custom-scripts/:script_id Scopes: custom-scripts:read

Get one Custom Script by its id — description, generated code, approval/deploy status, secret names, last test result.

1 parameter
Name In Type Required Description
script_id path string yes

📄 /api/custom-scripts/get-custom-scripts-script-id.md

GET /custom-scripts/:script_id/invocations Scopes: custom-scripts:read

List recent runs of a Custom Script — status (dispatched/completed/failed/timed_out), result, error, who invoked it, and timing.

2 parameters
Name In Type Required Description
script_id path string yes
limit query number no

📄 /api/custom-scripts/get-custom-scripts-script-id-invocations.md

GET /custom-scripts Scopes: custom-scripts:read

List all Custom Scripts in the workspace — id, description, approval/deploy status, secret names, and the owning automation (if any).

1 parameter
Name In Type Required Description
limit query number no

📄 /api/custom-scripts/get-custom-scripts.md

POST /custom-scripts/:script_id/run Scopes: custom-scripts:write

Run an approved Custom Script by its id right now (a live run — enforces the code-approval gate). Optionally pass contact_id/deal_id/trigger so the script can resolve a real record. Async: poll get_custom_script_invocations for the result.

5 parameters
Name In Type Required Description
script_id path string yes
contact_id body string no
deal_id body string no
trigger body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/post-custom-scripts-script-id-run.md

PATCH /automations/:automation_id/actions/:action_id/custom-script/code Scopes: automations:write

Save hand-edited Custom Script code verbatim (marks it manually_edited so future regenerations never silently overwrite it).

4 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
code body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/patch-automations-automation-id-actions-action-id-custom-script-code.md

PUT /automations/:automation_id/actions/:action_id/custom-script/secrets/:secret_name Scopes: automations:write

Add or replace a third-party secret a Custom Script needs (write-only — the value is never returned).

5 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
secret_name path string yes
value body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/put-automations-automation-id-actions-action-id-custom-script-secrets-secret-name.md

POST /automations/:automation_id/actions/:action_id/custom-script/test Scopes: automations:write

Deploy and dry-run a Custom Script against sample trigger data. Bypasses both approval gates; never touches automation run history. Optionally pass contact_id/deal_id so tp.contact()/tp.deal()/tp.context() have a real record to resolve.

5 parameters
Name In Type Required Description
automation_id path string yes
action_id path string yes
contact_id body string no
deal_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/custom-scripts/post-automations-automation-id-actions-action-id-custom-script-test.md

Skills (6 endpoints)

Reusable skills: a model, a prompt, an allowed tool set and an input/output contract you can run on demand.

📄 Full markdown: /api/skills.md

POST /skills Scopes: agent-ops:write

Create a skill owned by your workspace. A skill is one tool_loop: a model, a system prompt, an allowed tool set, and an input/output contract. Set visibility "public" to make it usable by every workspace (only you can still edit it).

14 parameters
Name In Type Required Description
name body string yes Stable handle used to run it, e.g. "curate_memory". Unique per owner; unique globally when public.
display_name body string yes
description body string no
when_to_use body string yes When an agent should reach for this skill. This IS the tool description the agent reads to decide whether to invoke it (agent-invocation skills are compiled into its tool catalog and picked by this text).
visibility body string no Default "private".
invocation body string no Default "agent" (the agent chooses it as a callable tool, selected by when_to_use). "lifecycle" = always-on: fires on an event (e.g. after a chat turn), never chosen, and NOT exposed as a tool.
execution body string no How it runs. Default "tool_loop" (a general agentic loop). "briefing" fetches every allowlisted read once, in parallel, with the input, then does one grounded summarize call — fast, for gather-then-summarize skills.
model body string yes The Cloudflare Workers AI model the loop runs on, as a '@cf/...' model id (e.g. '@cf/qwen/qwen3-30b-a3b-fp8', the default). Claude/Anthropic models are not supported.
system_prompt body string yes The skill's instructions.
tool_allowlist body array no Tool names the loop may call (e.g. search_memory, write_memory).
input_schema body object no JSON Schema for the skill's input.
output_schema body object no JSON Schema for the skill's output.
status body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/skills/post-skills.md

DELETE /skills/:skill_id Scopes: agent-ops:delete

Delete a skill your workspace owns.

2 parameters
Name In Type Required Description
skill_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/skills/delete-skills-skill-id.md

GET /skills/:skill_id Scopes: agent-ops:read

Fetch a single skill by id (must be public or owned by your workspace).

1 parameter
Name In Type Required Description
skill_id path string yes

📄 /api/skills/get-skills-skill-id.md

GET /skills Scopes: agent-ops:read

List skills available to this workspace: every public skill plus the workspace's own private skills. Filter by visibility or status.

4 parameters
Name In Type Required Description
visibility query string no
status query string no
limit query number no
after query string no

📄 /api/skills/get-skills.md

POST /skills/run Scopes: agent-ops:write

Run a skill (by id or name) against an input and return its output, tool trace, and token usage. Runs one bounded tool_loop on the skill's configured model with its allowed tools. Use this to test a skill or to invoke one on demand. Only public skills and skills your workspace owns can be run.

3 parameters
Name In Type Required Description
skill body string yes The skill id (uuid) or its name (e.g. "curate_memory").
input body object no The input object matching the skill's input_schema.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/skills/post-skills-run.md

PATCH /skills/:skill_id Scopes: agent-ops:write

Update a skill your workspace owns (model, prompt, tools, visibility, status, etc.). You cannot edit another workspace's public skill.

15 parameters
Name In Type Required Description
skill_id path string yes
name body string no
display_name body string no
description body string no
when_to_use body string no
visibility body string no
invocation body string no
execution body string no
model body string no
system_prompt body string no
tool_allowlist body array no
input_schema body object no
output_schema body object no
status body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/skills/patch-skills-skill-id.md

Auto Queues (15 endpoints)

Auto queues: multi-step sequences contacts are enrolled into, with their steps and enrollments. The legacy /event-queues/* paths still work.

📄 Full markdown: /api/auto-queues.md

POST /auto-queues/:queue_id/steps Scopes: automations:write

Add a step to an event queue.

5 parameters
Name In Type Required Description
queue_id path string yes
automation_id body string yes
step_order body number yes
delay_minutes body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/post-auto-queues-queue-id-steps.md

POST /auto-queues/:queue_id/bulk-enroll Scopes: automations:write

Bulk-enrol contacts or opportunities in an event queue. Pass ids directly, or a filter to enrol everything matching it. At least one of contact_ids, deal_ids, contact_filter or customer_filter is required.

8 parameters
Name In Type Required Description
queue_id path string yes
contact_ids body array no Contact UUIDs to enrol.
deal_ids body array no Opportunity UUIDs to enrol.
contact_filter body object no Enrol every contact matching this filter instead of listing ids.
customer_filter body object no Enrol every company matching this filter instead of listing ids.
enrollment_time body string no When enrolment takes effect. Defaults to now.
skip_if_already_enrolled body boolean no Skip records already in the queue instead of re-enrolling them.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/post-auto-queues-queue-id-bulk-enroll.md

POST /auto-queues Scopes: automations:write

Create an automation event queue.

4 parameters
Name In Type Required Description
name body string yes
description body string no
respect_business_hours body boolean no Respect business hours: when true, steps only send during the workspace business-hours window (held to the next window otherwise). Defaults to false.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/post-auto-queues.md

DELETE /auto-queues/:queue_id Scopes: automations:delete

Delete an event queue.

2 parameters
Name In Type Required Description
queue_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/delete-auto-queues-queue-id.md

DELETE /auto-queues/:queue_id/steps/:step_id Scopes: automations:delete

Delete a step from an event queue.

3 parameters
Name In Type Required Description
queue_id path string yes
step_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/delete-auto-queues-queue-id-steps-step-id.md

GET /auto-queues/:queue_id/board Scopes: automations:read

Read-only kanban-shaped state for an Auto Queue. Returns active enrolments bucketed into columns by the step they last completed (column 0 = "Awaiting Step 1"; column N = after step N), plus terminal counts (completed / cancelled). Use this to answer "where is contact X in queue Y" or "how many contacts are at each step" without grouping per-task rows from list_auto_queue_enrollments client-side. Each column returns up to 50 cards — for terminal-state drill-in, call list_auto_queue_enrollments with status=completed or status=cancelled.

1 parameter
Name In Type Required Description
queue_id path string yes

📄 /api/auto-queues/get-auto-queues-queue-id-board.md

GET /auto-queues Scopes: automations:read

List automation event queues (drip sequences).

1 parameter
Name In Type Required Description
limit query number no

📄 /api/auto-queues/get-auto-queues.md

POST /auto-queues/remove-all-enrollments Scopes: automations:write

Remove a contact or deal from EVERY Auto Queue (drip sequence) in the workspace at once, cancelling all of their still-pending steps across all queues. Pass ONE of contact_id or deal_id. Use this instead of calling remove_from_auto_queue once per queue when you want a full unenrol (e.g. the customer unsubscribed or churned). Returns cancelled_count (total pending steps stopped) and queues_affected; cancelled_count: 0 means nothing was pending for that contact/deal in any queue.

3 parameters
Name In Type Required Description
contact_id body string no Cancel this contact's pending steps across all queues.
deal_id body string no Cancel this deal's pending steps across all queues.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/post-auto-queues-remove-all-enrollments.md

POST /auto-queues/:queue_id/remove-enrollment Scopes: automations:write

Remove a contact or deal from an auto queue (drip sequence) by cancelling their pending steps. Pass queue_id plus ONE of: enrollment_id (most precise — from get_auto_queue_board cards or list_auto_queue_enrollments), contact_id, or deal_id. This is the direct unenrol — no need to build, enable, and trigger a remove_from_event_queue automation. Returns cancelled_count (the real number of pending steps stopped) and a message; cancelled_count: 0 with an explanatory message means nothing was pending for that enrolment (already completed, already removed, or never enrolled).

5 parameters
Name In Type Required Description
queue_id path string yes The auto queue UUID.
enrollment_id body string no Preferred. The enrolment UUID from the board or enrollments list.
contact_id body string no Cancel this contact's pending steps in the queue.
deal_id body string no Cancel this deal's pending steps in the queue.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/post-auto-queues-queue-id-remove-enrollment.md

POST /auto-queues/:queue_id/retry-failed Scopes: automations:write

Retry failed steps in an auto queue (drip sequence), in bulk. Use this when steps show status "failed" with a reason saying they were never sent, which happens when the dispatcher stopped part-way through a large batch. Find them first with list_auto_queue_enrollments using status="failed" and read each last_error. Pass queue_id alone to consider every failed step in the queue, or narrow with event_queue_step_id (re-send one step to everyone it missed), contact_id, enrollment_id, or an explicit task_ids list. SAFE TO REPEAT: every step is checked against its automation run record first, and only steps proven never to have reached the send path are requeued, so this cannot message someone twice. Returns retried, skipped_already_sent, skipped_unconfirmed and considered. skipped_already_sent means those recipients did get the message and were deliberately left alone; skipped_unconfirmed means delivery could not be established either way, so they were not re-sent and need a human to check.

7 parameters
Name In Type Required Description
queue_id path string yes The auto queue UUID.
task_ids body array no Optional. Retry only these specific step UUIDs (the "id" values from list_auto_queue_enrollments). Omit to consider every failed step in the queue.
contact_id body string no Optional. Only retry failed steps for this contact.
enrollment_id body string no Optional. Only retry failed steps for this enrolment.
event_queue_step_id body string no Optional. Only retry failed steps for this one step of the queue, e.g. re-send step 1 to everyone it never reached.
limit body number no Optional. Maximum steps to retry in this call (default 200, max 500). Steps are taken oldest-scheduled first.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/post-auto-queues-queue-id-retry-failed.md

PATCH /auto-queues/:queue_id Scopes: automations:write

Update an event queue.

5 parameters
Name In Type Required Description
queue_id path string yes
name body string no
description body string no
respect_business_hours body boolean no Respect business hours: when true, steps only send during the workspace business-hours window (held to the next window otherwise). Defaults to false.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/patch-auto-queues-queue-id.md

PATCH /auto-queues/:queue_id/steps/:step_id Scopes: automations:write

Update a step in an event queue.

3 parameters
Name In Type Required Description
queue_id path string yes
step_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-queues/patch-auto-queues-queue-id-steps-step-id.md

Auto Schedules (9 endpoints)

Auto schedules: recurring jobs that fire on a cron, with their run history and audience preview. The legacy /event-schedules/* paths still work.

📄 Full markdown: /api/auto-schedules.md

POST /auto-schedules Scopes: schedules:write

Create an Auto Schedule: a cron (WHEN) plus a Source Data primitive (WHAT DATA) plus an automation (WHAT HAPPENS). Each row the Source resolves fires the automation once with that row as trigger_data. Every Source is bounded by its own data shape, so pick the one that matches what you want to act on. Use "report" when the answer is a number and a list rather than an action per record.

14 parameters
Name In Type Required Description
name body string yes
automation_id body string yes
cron_expression body string no
time_of_day body string no
timezone body string no
source_kind body string yes Required. Which Source Data primitive feeds the automation. 'report' = ONE email per named recipient carrying a count and a list; never fans out per record, and costs the same whether 18 or 25,000 records match. 'workflow_stage' = opportunities sitting in named stages of one pipeline (archived, won, lost and archived pipelines are always excluded). 'expiry_date' = records whose custom date field lands in a day window. 'staff' = workspace people, bounded by headcount (accounts that never accepted their invite are excluded). 'stakeholder_group' = the members of one curated stakeholder group. 'external_feed' = new records polled from a JSON URL, deduped. 'static' = fixed values authored on the schedule. The old free-form 'audience' source is RETIRED and cannot be created: an arbitrary filter over a growing table on a cron has no ceiling. For a mass contact send, use Email Blasts instead.
source_config body object no Config for the chosen source_kind. report: { recipients:{ user_ids?:[], emails?:[] } (required, max 20 total), count_of?:{ kind:'workflow_stage'|'expiry_date'|'staff'|'stakeholder_group', ...that kind's config } to attach a count plus a list of the matching records, list_limit? (rows listed in the email, default 25, max 200), dashboard_id? (target of the 'see the full report' link) }. workflow_stage: { pipeline_id (required), stage_ids[] (required, at least one — a whole pipeline is not allowed because it grows without bound), assigned_to_ids?, stale_days?, batch_size? (rows dispatched per run, default 100, max 500) }. expiry_date: { field_id (required, the custom date field), min_days? and/or max_days? (at least one required — the window is the bound; negatives allowed, e.g. max_days:0 = already lapsed; min_days:30,max_days:30 = exactly 30 days out), entity?:'contacts'|'deals', contact_type?, has_email?, respect_unsubscribes? (default true), batch_size? }. staff: { user_ids? (empty = everyone), roles?, with_open_tasks? (digest mode: only people who have open tasks, with their tasks attached as related_tasks), task_statuses?, overdue_only?, max_tasks_per_user?, batch_size? }. stakeholder_group: { bucket_id (required), batch_size? }. external_feed: { feed_url (required, tokenised JSON URL), format:'json_array', dedupe_key (required, the record key holding the stable external id), first_run:'seed'|'import_all' (default 'seed' = record everything as seen and import nothing on the first fire), filters:[{ field, op:'not_empty'|'equals'|'not_equals'|'in', value? }] }. static: { trigger_data:{...} } (one fixed row per fire) or { rows:[{...}] }.
row_cooldown_days body number no Repeat interval: how many days before the SAME record may fire again. REQUIRED for the record-selecting sources (workflow_stage, expiry_date, staff, stakeholder_group) and must be answered explicitly, including 0. 0 means 'every run', which is correct when the automation moves the record out of the source (e.g. a move_deal that empties the stage). A positive number means each record fires at most once per that many days, which is what an alert wants. It cannot be left unset because a record that matches today usually still matches tomorrow: leaving it unset is what turned one NSJ schedule into 7,060 duplicate tasks in four days. Ignored for report, external_feed and static, which are self-limiting.
description body string no Free-text note on what this schedule is for. Shown in the Auto Schedules list.
is_active body boolean no Whether the schedule fires. Defaults to true on create; set false to author a schedule without starting it.
end_at body string no ISO timestamp after which the schedule stops firing. Omit for no end date.
max_runs body number no Stop the schedule after this many total runs. Omit for unlimited.
days_of_week body array no Days of the week (0 = Sunday) the schedule fires. Combined with time_of_day and derived into cron_expression at save time; an alternative to writing cron_expression yourself.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-schedules/post-auto-schedules.md

DELETE /auto-schedules/:schedule_id Scopes: schedules:delete

Delete an event schedule.

2 parameters
Name In Type Required Description
schedule_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-schedules/delete-auto-schedules-schedule-id.md

POST /auto-schedules/:schedule_id/fire-now Scopes: schedules:write

Fire an event schedule immediately (out of band).

2 parameters
Name In Type Required Description
schedule_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-schedules/post-auto-schedules-schedule-id-fire-now.md

GET /auto-schedules Scopes: schedules:read

List automation event schedules (fire at wall-clock cron expressions).

2 parameters
Name In Type Required Description
limit query number no
after query string no Pagination cursor from a previous page.

📄 /api/auto-schedules/get-auto-schedules.md

POST /auto-schedules/preview-cron Scopes: schedules:read

Validate a cron expression and return the next N firing times.

4 parameters
Name In Type Required Description
cron_expression body string yes
timezone body string no
count body number no
n body number no

📄 /api/auto-schedules/post-auto-schedules-preview-cron.md

PATCH /auto-schedules/:schedule_id Scopes: schedules:write

Update an Auto Schedule. source_kind and source_config are validated as a MERGED state, so a patch that only clears the repeat interval or only widens the source config is refused the same way a bad create would be. A schedule still on the retired 'audience' source can be renamed, paused or deleted, but cannot be edited to stay on it.

12 parameters
Name In Type Required Description
schedule_id path string yes
name body string no
cron_expression body string no
time_of_day body string no
timezone body string no
source_kind body string no The Source Data primitive. See create_auto_schedule for what each one selects. 'audience' is retired and cannot be set.
source_config body object no Config for the chosen source_kind. See create_auto_schedule for the full per-source shape. Replaces the stored config wholesale, so send the complete object.
is_active body boolean no
end_at body string no
max_runs body number no
row_cooldown_days body number no Repeat interval: how many days before the SAME record may fire again. 0 means every run. Required for workflow_stage, expiry_date, staff and stakeholder_group, and a patch cannot clear it back to null. See create_auto_schedule.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-schedules/patch-auto-schedules-schedule-id.md

SCHEDULING (24 endpoints)

scheduling endpoints.

📄 Full markdown: /api/scheduling.md

POST /scheduling/bookings/:booking_id/cancel Scopes: scheduling:write

Cancel a booking. Invitee gets cancellation notice.

4 parameters
Name In Type Required Description
booking_id path string yes
reason body string no Why the booking was cancelled. Stored as cancellation_reason.
cancellation_reason body string no Alias of reason, the name it is stored under.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-cancel.md

POST /scheduling/check-availability Scopes: scheduling:read

Quick check whether a specific slot is available. Returns nearest available alternatives, and if unavailable, why: reason_code, plus for a Google Calendar conflict the blocking event's name (blocking_event) AND its exact times (blocking_event_start / blocking_event_end as ISO instants, blocking_event_window rendered in the requested timezone) so you can verify the event genuinely overlaps the slot.

3 parameters
Name In Type Required Description
event_type_id body string yes
date body string yes YYYY-MM-DD
time body string yes HH:MM, 24-hour

📄 /api/scheduling/post-scheduling-check-availability.md

POST /scheduling/bookings Scopes: scheduling:write

Create a calendar booking. Use get_available_slots first to find a valid event_type_id + date + time. Provide email + full_name for a new booker, OR attach_to_opportunity_id / attach_to_contact_id / attach_to_company_id to attach the booking to an existing record (booker email + name are then derived from that record's primary contact). IN-PERSON: if the event type has location_type "in_person" and in_person_direction "at_customer" (we travel to the customer), you MUST pass booker_address or the booking is rejected with MISSING_ADDRESS — putting the address in message does not work. Check those two fields on the event type first.

26 parameters
Name In Type Required Description
event_type_id body string yes Event type UUID, from list_scheduled_event_types / get_available_slots. Alternatively pass event_type_slug or event_type_name.
event_type_slug body string no Event type slug. Alternative to event_type_id.
event_type_name body string no Event type name. Alternative to event_type_id.
date body string yes YYYY-MM-DD, from get_available_slots.
time body string yes HH:MM (24h), from get_available_slots.
timezone body string no IANA timezone the date/time are expressed in, e.g. "Australia/Sydney". Defaults to the workspace timezone.
email body string no Booker email. Required unless attach_to_opportunity_id / attach_to_contact_id / attach_to_company_id is provided (then derived from that record's primary contact).
full_name body string no Booker full name. Required unless attach_to_opportunity_id / attach_to_contact_id / attach_to_company_id is provided (then derived from that record's primary contact). Also accepted as fullName.
phone body string no Booker phone. Normalised to E.164.
message body string no Notes from or about the booker, stored on the booking. NOT a substitute for booker_address — an address left only in here is ignored by an at_customer event type.
booker_state body string no Booker state/region, e.g. "VIC", "NSW". Written to the CRM contact's state only when that field is currently empty.
booker_timezone body string no IANA timezone to store on the CRM contact, e.g. "Australia/Perth". Falls back to timezone when omitted. Written only when the contact's timezone is currently empty.
booker_address body string no The booker's address — labelled "Your address" on the booking form. REQUIRED when the event type has location_type "in_person" and in_person_direction "at_customer" (we travel to the customer); the booking is rejected with MISSING_ADDRESS without it. Putting the address in message does NOT work. Becomes the calendar event location and appears in confirmations and reminders. Check location_type + in_person_direction on the event type before booking.
booker_address_notes body string no Arrival notes for that address — labelled "Access notes (optional)" on the booking form, e.g. "Parking in rear. Ring buzzer 3." Appended to the calendar event instructions.
attach_to_contact_id body string no Attach the booking to an existing contact instead of matching/creating one. Booker email + name are derived from the contact.
attach_to_opportunity_id body string no Attach the booking to an existing opportunity instead of matching/creating one. Booker email + name are derived from the opportunity's primary contact.
attach_to_company_id body string no Attach the booking to an existing company instead of matching/creating one. Booker email + name are derived from the company's primary contact, or its first contact.
attendees body array no Additional attendees beyond the booker: [{ "email": "...", "name": "...", "phone": "..." }]. All receive calendar invites. Each email must be a complete valid address or INVALID_ATTENDEE_EMAIL is returned.
internal body boolean no Set true for an internal staff meeting (the event type must have meeting_mode "internal"). Skips availability gating and CRM opportunity creation; still creates the meeting link and Notetaker. Omit date/time for an instant meeting on the next 5-minute boundary.
is_recurring_series body boolean no Set true only when creating the single series-anchor booking for a recurring internal meeting type. The anchor holds the shared meeting link and is topped up by the occurrence scheduler. Requires recurrence and event_timezone.
recurrence body array no RRULE strings for the recurring calendar event, e.g. ["RRULE:FREQ=WEEKLY;BYDAY=MO"]. Required when is_recurring_series is true; normally computed from the event type's recurrence_rule.
event_timezone body string no IANA timezone anchoring a recurring event's wall-clock time across DST, e.g. "Australia/Sydney". Required when is_recurring_series is true.
metadata body object no Arbitrary JSON merged into the booking's metadata alongside the message.
website_id body string no Website UUID to record as the source of the booking, when it came from an embedded booking widget.
site_key body string no Site key to record as the source of the booking, when it came from an embedded booking widget.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings.md

POST /scheduling/event-types Scopes: scheduling:write

Create a new scheduled event type (meeting template).

55 parameters
Name In Type Required Description
name body string yes Display name of the event type, e.g. "Discovery Call".
description body string no Shown to the booker on the public booking page, under the name.
slug body string no URL segment for the public booking link. Auto-derived from name on create when omitted.
icon body string no Lucide icon name shown on the event-type card and calendar, e.g. "calendar", "phone", "video".
color body string no Theme colour key for the card and calendar entries, e.g. "primary".
sort_order body integer no Position in the event-type list. Lower sorts first.
is_active body boolean no When false the event type is archived: hidden from the list and not bookable. Default true.
is_bookable body boolean no When true the event type has a public booking page and appears on booking links. When false it is internal-only. Setting this true defaults location_type to "video".
is_meeting body boolean no Legacy flag, kept in sync with location_type automatically (video = true, phone/in_person = false). Set location_type instead.
default_duration_minutes body number no How long a booking of this type runs, in minutes (15, 30, 45, 60...). This is the field returned when you read the event type back, and it sets each booking's end time.
buffer_before_minutes body integer no Padding held free immediately before each booking, in minutes. Blocks slots that would start too close to an existing one.
buffer_after_minutes body integer no Padding held free immediately after each booking, in minutes.
min_notice_hours body integer no How far ahead a booker must book, in hours. A slot closer than this is not offered.
max_advance_days body integer no How far into the future slots are offered, in days.
slot_interval_minutes body integer no Spacing between offered start times, in minutes. 30 offers 9:00, 9:30, 10:00; 15 offers 9:00, 9:15, 9:30.
meeting_mode body string no "booking" = public 1:1 booking (one attendee per slot, the default). "group" = public Group Session (multiple attendees per slot up to capacity; set capacity + waitlist_enabled). "internal" = internal meeting, not publicly bookable.
email_config_id body string no Optional sending identity (email_config UUID) for this event type's booking notifications. Confirmation and all reminders send FROM this config's name/address/reply. Unset (or null to clear) = the workspace default sending address. Use for a workspace running multiple brands so one brand's bookings send from its own sender.
event_queue_id body string no Auto Queue (UUID) a confirmed booking enrols the booker into, for reminder or follow-up sequences. Enrolment is deduped: a booker who already has pending steps in that queue is skipped rather than enrolled twice, so rebooking does not double the reminders. Pass null to unlink.
enrollment_offset_minutes body integer no Shifts when the Auto Queue clock starts, relative to the booking start time, in minutes. Negative counts backwards from the meeting (-1440 anchors step delays to 24 hours before it). Default 0, meaning the meeting start.
booking_confirmation_message body string no Custom text shown on the confirmation screen after a booker confirms a slot.
booking_form_fields body array no Extra questions to collect on the public booking form. Stored and returned to the booking page, but the page does not render custom fields yet, so setting this has no visible effect today.
booking_notifications body object no Per-event booking emails and SMS, keyed by moment. The keys that actually send: "confirmation" (immediate, supports attach_ics), "pre_meeting" (offset_minutes BEFORE the start), "meeting_start", "late", "no_show", "rebooking" (offset_minutes AFTER now), and "rsvp_declined" (immediate, fires the moment the booker declines the calendar invite). Each key holds an array of { label, channels, email_subject, email_body, sms_body, recipients, chromeless, offset_minutes } entries. A "pre_meeting" entry also accepts only_if_not_accepted: true, which skips anyone who has already accepted their calendar invite so a firmer second nudge only reaches the people who have not. Recipients are "booker" (the person who booked), "booker_and_attendees" (the booker plus the attendees on the booking, but NOT the assigned host), "team" (only the users in booking_assigned_user_ids, i.e. the assigned host), or "all" (booker, attendees and assigned host). The assigned host is only notified by "team" or "all". Once a booker declines, they are dropped from every later send aimed at them (pre_meeting, meeting_start, late, no_show and rebooking), so the "rsvp_declined" offer is the last thing they hear unless they rebook; "team" and "all" entries still reach the host. Note "reminder", "cancellation" and "reschedule" were previously documented here but have never had a consumer — "pre_meeting" is the reminder.
booking_default_products body array no Products attached to the opportunity a booking creates, as [{ id, quantity }].
booking_default_tags body array no Tags applied to the created opportunity and contact, as [{ name, color }].
booking_assigned_user_ids body array no Host user UUIDs. Their connected calendars gate availability and one of them is assigned each booking. A bookable event type needs at least one.
booking_default_attendee_contact_ids body array no Contact UUIDs added as attendees on every booking of this type, on top of the booker.
booking_default_attendee_emails body array no Plain email addresses added as attendees on every booking of this type, for people with no contact record.
auto_record_enabled body boolean no When true, the TrustPager Notetaker joins each booking of this type to record and transcribe it. Video bookings only. Default false.
recurrence_rule body object no Recurrence for internal meeting series (meeting_mode "internal"): { frequency, interval, days_of_week, until }. Not used by public booking types.
embed_config body object no Embed theme for the /embed booking page (colours, card style, width). Keys: surface, pageBg, field, text, muted, border, primary, secondary, cardStyle ("card"|"flat"), showLogoHeader (bool), maxWidth ("sm"|"md"|"lg"|"full"), align ("left"|"center"). Only affects the embeddable variant, not the public booking link.
location_type body string no Where the booking happens. "video" = a meeting link is generated. "phone" = you call the booker (or they call you). "in_person" = a physical address, which also requires in_person_direction. Determines the icon and location shown on the calendar and in booking confirmations. Bookable event types default to "video".
in_person_direction body string no Required when location_type is "in_person". "at_business" = "Customer comes to us" — the booker travels to you, so set location_address. "at_customer" = "We travel to customer" — the booking form asks the booker for their address, and a booking then requires booker_address.
location_address body string no Your physical address, shown to the booker before they confirm. Used when location_type is "in_person" and in_person_direction is "at_business".
location_instructions body string no Free-text arrival notes shown with the address, e.g. "Parking at rear, buzz unit 4".
booking_ignore_all_day_events body boolean no When true (the default), all-day entries on a host's connected calendar (leave, reminders, OOO markers) do NOT block bookings. Set false to let all-day events count as busy. To block a specific date, use a date override in Availability instead.
booking_ignore_free_events body boolean no When true, timed entries the host has marked "Show as Free" in Google do NOT block bookings, matching how Calendly and Cal.com read that flag. Default false, so a Free entry still consumes availability: an event on a host's calendar is usually a real commitment even when flagged Free by habit. Turn on for a host who uses Free deliberately for focus blocks, travel or tentative holds.
capacity body integer no Group Session only. Maximum number of independent bookings a single time slot accepts (e.g. 40 seats in a workshop). Each booker gets their own record and confirmation. Leave unset/null for a 1:1 event type (one booker per slot).
waitlist_enabled body boolean no Group Session only. When true, once a slot reaches capacity the public booking page offers a free waitlist (name + email, no booking) instead of blocking. Default false.
is_paid body boolean no When true, this event requires payment at the point of booking via the workspace's connected Stripe. The slot is held during checkout and the booking is only confirmed once payment succeeds. Requires price_amount and an active Stripe connection to publish. Default false.
price_amount body integer no Price in the smallest currency unit (e.g. cents): 9700 = $97.00. Required when is_paid is true. Each booker pays this amount for their own seat.
price_currency body string no ISO 4217 currency code for the price, e.g. "AUD", "USD". Defaults to AUD.
booking_auto_create_deal body boolean no Whether a booking creates/links an opportunity at all. Default true.
booking_deal_behavior body string no How a booking relates to an existing opportunity for the booker. "create" (or "always_create") = always mint a new opportunity. "update_or_create" (or "find_or_create") = match the booker's existing opportunity first, create one only if none matches. "never_create" (or "match_only") = only ever attach to a matching opportunity, never create. Matched by email/phone.
booking_match_fields body array no Identity fields used to match an existing contact/opportunity, e.g. ["email"] or ["email","phone"]. "name" is never honoured (fuzzy-name-collision risk).
booking_match_pipeline_id body string no Restrict opportunity matching to one pipeline (UUID). Unset = search all pipelines.
booking_match_status_filter body string no "all" | "open" | "won" | "lost" - which opportunity statuses are eligible to match. Default "open".
booking_match_strategy body string no "most_recent" | "highest_value" | "oldest" - tie-breaker when multiple opportunities match. Default "most_recent".
booking_card_behavior body string no "ignore" | "find_or_create" | "always_create" - what to do with the pipeline card placement once the opportunity is resolved.
booking_pipeline_id body string no Destination pipeline (UUID) for the opportunity when one is created. Falls back to the workspace default pipeline.
booking_stage_id body string no Destination stage (UUID) within booking_pipeline_id. Falls back to the first stage.
booking_lead_source body string no lead_source recorded on the created opportunity. Defaults to "booking".
booking_deal_name_template body string no Opportunity-name template. Tokens: {event_type} {customer_name} (or {booker_name}) {date} {time}. Any unrecognised token falls back to the booker name.
booking_update_next_action body boolean no When true, a booking stamps the linked opportunity's Next Action with this meeting (name, date, time) so it shows on the opportunity card, and a reschedule moves it to the new time. Default false.
duration_minutes body number no Alias for default_duration_minutes. Accepted for backwards compatibility; default_duration_minutes wins if both are sent.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-event-types.md

DELETE /scheduling/event-types/:event_type_id Scopes: scheduling:delete

Delete a scheduled event type by UUID. Destructive.

2 parameters
Name In Type Required Description
event_type_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/delete-scheduling-event-types-event-type-id.md

POST /scheduling/available-slots Scopes: scheduling:read

Get available booking slots for a scheduled event type within a date range. Returns slot start times in host timezone. Set include_blocked_slots to also see why in-window times are NOT offered (too soon, already booked, outside a host's personal hours, or a named event on their Google Calendar).

5 parameters
Name In Type Required Description
event_type_id body string yes
date_from body string yes YYYY-MM-DD
date_to body string yes YYYY-MM-DD
timezone body string no
include_blocked_slots body boolean no When true, each date also returns a blocked_slots array: { time, formatted, reason_code, summary?, busy_start?, busy_end?, busy_window?, detail } explaining every unavailable in-window time. For a host_calendar_busy block, busy_start/busy_end are the blocking event's exact ISO instants and busy_window is them rendered in the response timezone, so you can confirm the event really does overlap the slot.

📄 /api/scheduling/post-scheduling-available-slots.md

GET /scheduling/bookings/:booking_id Scopes: scheduling:read

Fetch a single booking by UUID with event details, invitee, host, status, linked records.

1 parameter
Name In Type Required Description
booking_id path string yes

📄 /api/scheduling/get-scheduling-bookings-booking-id.md

GET /scheduling/availability Scopes: scheduling:read

Get working-hours availability and date overrides. Defaults to the company-wide schedule; pass event_type_id to get one event type's own schedule, or user_id to get one host's personal schedule. Every response names which schedule actually governs via "source" ("event_type" | "company_default" | "user_default" | "default" | "unset") plus a "constrains_bookings" boolean. An event type with no schedule of its own reports the real company default it inherits, never a generic placeholder. A host who has saved no personal hours reports source "unset" with EMPTY weekly_hours and constrains_bookings false, which means they narrow nothing and are bookable across the whole base window — it does NOT mean they are never available.

2 parameters
Name In Type Required Description
event_type_id query string no Get this event type's own schedule instead of the company default.
user_id query string no Get this host's personal schedule instead of the company default. Ignored if event_type_id is set.

📄 /api/scheduling/get-scheduling-availability.md

POST /scheduling/bookings/:booking_id/link-opportunity Scopes: scheduling:write

Attach an existing booking to an opportunity — repairs a mis-linked booking (e.g. deal_id came back null) without cancelling and recreating it, which would re-fire client-facing confirmations. Only sets deal_id; contact_id/customer_id are backfilled from the opportunity only when the booking is missing them.

3 parameters
Name In Type Required Description
booking_id path string yes Booking UUID to attach (required).
opportunity_id body string yes Opportunity UUID to attach the booking to (required).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-link-opportunity.md

GET /scheduling/bookings Scopes: scheduling:read

List bookings (calendar appointments). Filter by date range, contact, company, opportunity, event type, or status.

10 parameters
Name In Type Required Description
limit query number no
after query string no
contact_id query string no
customer_id query string no
opportunity_id query string no
event_type_id query string no
status query string no
booker_rsvp_status query string no The booker's response to the calendar invite. "no_response" means the invite reached them and they have not replied — the useful filter for chasing likely no-shows. Absent entirely (null) on bookings with no connected calendar, which is different from "no_response".
date_from query string no YYYY-MM-DD. Bookings starting on or after this date.
date_to query string no YYYY-MM-DD. Bookings starting on or before this date.

📄 /api/scheduling/get-scheduling-bookings.md

GET /scheduling/event-types Scopes: scheduling:read

List the workspace scheduled event types (meeting templates). Use to find event_type_id for get_available_slots and create_booking.

2 parameters
Name In Type Required Description
is_bookable query boolean no Filter to publicly bookable event types (true) or internal-only ones (false). Omit for both. Read by listTypes but never published until SR da88447b, so no MCP caller could narrow the list.
is_active query boolean no Filter to live event types (true) or archived ones (false). Omit for both.

📄 /api/scheduling/get-scheduling-event-types.md

POST /scheduling/bookings/:booking_id/mark-attended Scopes: scheduling:write

Mark a booking as attended.

2 parameters
Name In Type Required Description
booking_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-mark-attended.md

POST /scheduling/bookings/:booking_id/mark-late Scopes: scheduling:write

Mark a booking as late.

2 parameters
Name In Type Required Description
booking_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-mark-late.md

POST /scheduling/bookings/:booking_id/mark-no-show Scopes: scheduling:write

Mark a booking as no-show.

2 parameters
Name In Type Required Description
booking_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-mark-no-show.md

POST /scheduling/bookings/:booking_id/reschedule Scopes: scheduling:write

Reschedule a booking. Use get_available_slots to find a valid new slot.

5 parameters
Name In Type Required Description
booking_id path string yes
slot body string yes
event_type_id body string no Defaults to the booking's current event type.
timezone body string no Defaults to the booking's current timezone.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-reschedule.md

POST /scheduling/bookings/:booking_id/notetaker Scopes: scheduling:write

Schedule the TrustPager Notetaker to join a booking.

2 parameters
Name In Type Required Description
booking_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-bookings-booking-id-notetaker.md

PATCH /scheduling/event-types/:event_type_id Scopes: scheduling:write

Update a scheduled event type.

56 parameters
Name In Type Required Description
event_type_id path string yes UUID of the event type to update.
name body string no Display name of the event type, e.g. "Discovery Call".
description body string no Shown to the booker on the public booking page, under the name.
slug body string no URL segment for the public booking link. Auto-derived from name on create when omitted.
icon body string no Lucide icon name shown on the event-type card and calendar, e.g. "calendar", "phone", "video".
color body string no Theme colour key for the card and calendar entries, e.g. "primary".
sort_order body integer no Position in the event-type list. Lower sorts first.
is_active body boolean no When false the event type is archived: hidden from the list and not bookable. Default true.
is_bookable body boolean no When true the event type has a public booking page and appears on booking links. When false it is internal-only. Setting this true defaults location_type to "video".
is_meeting body boolean no Legacy flag, kept in sync with location_type automatically (video = true, phone/in_person = false). Set location_type instead.
default_duration_minutes body number no How long a booking of this type runs, in minutes (15, 30, 45, 60...). This is the field returned when you read the event type back, and it sets each booking's end time.
buffer_before_minutes body integer no Padding held free immediately before each booking, in minutes. Blocks slots that would start too close to an existing one.
buffer_after_minutes body integer no Padding held free immediately after each booking, in minutes.
min_notice_hours body integer no How far ahead a booker must book, in hours. A slot closer than this is not offered.
max_advance_days body integer no How far into the future slots are offered, in days.
slot_interval_minutes body integer no Spacing between offered start times, in minutes. 30 offers 9:00, 9:30, 10:00; 15 offers 9:00, 9:15, 9:30.
meeting_mode body string no "booking" = public 1:1 booking (one attendee per slot, the default). "group" = public Group Session (multiple attendees per slot up to capacity; set capacity + waitlist_enabled). "internal" = internal meeting, not publicly bookable.
email_config_id body string no Optional sending identity (email_config UUID) for this event type's booking notifications. Confirmation and all reminders send FROM this config's name/address/reply. Unset (or null to clear) = the workspace default sending address. Use for a workspace running multiple brands so one brand's bookings send from its own sender.
event_queue_id body string no Auto Queue (UUID) a confirmed booking enrols the booker into, for reminder or follow-up sequences. Enrolment is deduped: a booker who already has pending steps in that queue is skipped rather than enrolled twice, so rebooking does not double the reminders. Pass null to unlink.
enrollment_offset_minutes body integer no Shifts when the Auto Queue clock starts, relative to the booking start time, in minutes. Negative counts backwards from the meeting (-1440 anchors step delays to 24 hours before it). Default 0, meaning the meeting start.
booking_confirmation_message body string no Custom text shown on the confirmation screen after a booker confirms a slot.
booking_form_fields body array no Extra questions to collect on the public booking form. Stored and returned to the booking page, but the page does not render custom fields yet, so setting this has no visible effect today.
booking_notifications body object no Per-event booking emails and SMS, keyed by moment. The keys that actually send: "confirmation" (immediate, supports attach_ics), "pre_meeting" (offset_minutes BEFORE the start), "meeting_start", "late", "no_show", "rebooking" (offset_minutes AFTER now), and "rsvp_declined" (immediate, fires the moment the booker declines the calendar invite). Each key holds an array of { label, channels, email_subject, email_body, sms_body, recipients, chromeless, offset_minutes } entries. A "pre_meeting" entry also accepts only_if_not_accepted: true, which skips anyone who has already accepted their calendar invite so a firmer second nudge only reaches the people who have not. Recipients are "booker" (the person who booked), "booker_and_attendees" (the booker plus the attendees on the booking, but NOT the assigned host), "team" (only the users in booking_assigned_user_ids, i.e. the assigned host), or "all" (booker, attendees and assigned host). The assigned host is only notified by "team" or "all". Once a booker declines, they are dropped from every later send aimed at them (pre_meeting, meeting_start, late, no_show and rebooking), so the "rsvp_declined" offer is the last thing they hear unless they rebook; "team" and "all" entries still reach the host. Note "reminder", "cancellation" and "reschedule" were previously documented here but have never had a consumer — "pre_meeting" is the reminder.
booking_default_products body array no Products attached to the opportunity a booking creates, as [{ id, quantity }].
booking_default_tags body array no Tags applied to the created opportunity and contact, as [{ name, color }].
booking_assigned_user_ids body array no Host user UUIDs. Their connected calendars gate availability and one of them is assigned each booking. A bookable event type needs at least one.
booking_default_attendee_contact_ids body array no Contact UUIDs added as attendees on every booking of this type, on top of the booker.
booking_default_attendee_emails body array no Plain email addresses added as attendees on every booking of this type, for people with no contact record.
auto_record_enabled body boolean no When true, the TrustPager Notetaker joins each booking of this type to record and transcribe it. Video bookings only. Default false.
recurrence_rule body object no Recurrence for internal meeting series (meeting_mode "internal"): { frequency, interval, days_of_week, until }. Not used by public booking types.
embed_config body object no Embed theme for the /embed booking page (colours, card style, width). Keys: surface, pageBg, field, text, muted, border, primary, secondary, cardStyle ("card"|"flat"), showLogoHeader (bool), maxWidth ("sm"|"md"|"lg"|"full"), align ("left"|"center"). Only affects the embeddable variant, not the public booking link.
location_type body string no Where the booking happens. "video" = a meeting link is generated. "phone" = you call the booker (or they call you). "in_person" = a physical address, which also requires in_person_direction. Determines the icon and location shown on the calendar and in booking confirmations. Bookable event types default to "video".
in_person_direction body string no Required when location_type is "in_person". "at_business" = "Customer comes to us" — the booker travels to you, so set location_address. "at_customer" = "We travel to customer" — the booking form asks the booker for their address, and a booking then requires booker_address.
location_address body string no Your physical address, shown to the booker before they confirm. Used when location_type is "in_person" and in_person_direction is "at_business".
location_instructions body string no Free-text arrival notes shown with the address, e.g. "Parking at rear, buzz unit 4".
booking_ignore_all_day_events body boolean no When true (the default), all-day entries on a host's connected calendar (leave, reminders, OOO markers) do NOT block bookings. Set false to let all-day events count as busy. To block a specific date, use a date override in Availability instead.
booking_ignore_free_events body boolean no When true, timed entries the host has marked "Show as Free" in Google do NOT block bookings, matching how Calendly and Cal.com read that flag. Default false, so a Free entry still consumes availability: an event on a host's calendar is usually a real commitment even when flagged Free by habit. Turn on for a host who uses Free deliberately for focus blocks, travel or tentative holds.
capacity body integer no Group Session only. Maximum number of independent bookings a single time slot accepts (e.g. 40 seats in a workshop). Each booker gets their own record and confirmation. Leave unset/null for a 1:1 event type (one booker per slot).
waitlist_enabled body boolean no Group Session only. When true, once a slot reaches capacity the public booking page offers a free waitlist (name + email, no booking) instead of blocking. Default false.
is_paid body boolean no When true, this event requires payment at the point of booking via the workspace's connected Stripe. The slot is held during checkout and the booking is only confirmed once payment succeeds. Requires price_amount and an active Stripe connection to publish. Default false.
price_amount body integer no Price in the smallest currency unit (e.g. cents): 9700 = $97.00. Required when is_paid is true. Each booker pays this amount for their own seat.
price_currency body string no ISO 4217 currency code for the price, e.g. "AUD", "USD". Defaults to AUD.
booking_auto_create_deal body boolean no Whether a booking creates/links an opportunity at all. Default true.
booking_deal_behavior body string no How a booking relates to an existing opportunity for the booker. "create" (or "always_create") = always mint a new opportunity. "update_or_create" (or "find_or_create") = match the booker's existing opportunity first, create one only if none matches. "never_create" (or "match_only") = only ever attach to a matching opportunity, never create. Matched by email/phone.
booking_match_fields body array no Identity fields used to match an existing contact/opportunity, e.g. ["email"] or ["email","phone"]. "name" is never honoured (fuzzy-name-collision risk).
booking_match_pipeline_id body string no Restrict opportunity matching to one pipeline (UUID). Unset = search all pipelines.
booking_match_status_filter body string no "all" | "open" | "won" | "lost" - which opportunity statuses are eligible to match. Default "open".
booking_match_strategy body string no "most_recent" | "highest_value" | "oldest" - tie-breaker when multiple opportunities match. Default "most_recent".
booking_card_behavior body string no "ignore" | "find_or_create" | "always_create" - what to do with the pipeline card placement once the opportunity is resolved.
booking_pipeline_id body string no Destination pipeline (UUID) for the opportunity when one is created. Falls back to the workspace default pipeline.
booking_stage_id body string no Destination stage (UUID) within booking_pipeline_id. Falls back to the first stage.
booking_lead_source body string no lead_source recorded on the created opportunity. Defaults to "booking".
booking_deal_name_template body string no Opportunity-name template. Tokens: {event_type} {customer_name} (or {booker_name}) {date} {time}. Any unrecognised token falls back to the booker name.
booking_update_next_action body boolean no When true, a booking stamps the linked opportunity's Next Action with this meeting (name, date, time) so it shows on the opportunity card, and a reschedule moves it to the new time. Default false.
duration_minutes body number no Alias for default_duration_minutes. Accepted for backwards compatibility; default_duration_minutes wins if both are sent.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/patch-scheduling-event-types-event-type-id.md

PUT /scheduling/availability Scopes: scheduling:write

Update working hours and date overrides. Defaults to the company-wide schedule; pass event_type_id to set one event type's own schedule, or user_id to set one host's personal schedule. Over REST both PUT and PATCH are accepted on /scheduling/availability. Note this replaces the whole record for the target schedule, so read it first with get_scheduling_availability and send back every field you want to keep.

6 parameters
Name In Type Required Description
event_type_id body string no Set this event type's own schedule instead of the company default.
user_id body string no Set this host's personal schedule instead of the company default. Ignored if event_type_id is set.
weekly_hours body array no Array of { day: 0-6 (Sunday-Saturday), start: "HH:MM", end: "HH:MM" }.
timezone body string no IANA timezone, e.g. "Australia/Sydney".
date_overrides body array no Array of { date: "YYYY-MM-DD", type: "blocked"|"custom", start?, end?, reason? }.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/put-scheduling-availability.md

POST /scheduling/voice/:event_type_id/book Scopes: scheduling:write

AI voice agent — create a booking from voice flow.

4 parameters
Name In Type Required Description
event_type_id path string yes
slot body string yes
invitee_name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-voice-event-type-id-book.md

POST /scheduling/voice/cancel-booking Scopes: scheduling:write

AI voice agent — cancel a booking keyed by caller phone.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-voice-cancel-booking.md

POST /scheduling/voice/reschedule-booking Scopes: scheduling:write

AI voice agent — reschedule a booking keyed by caller phone.

2 parameters
Name In Type Required Description
slot body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-voice-reschedule-booking.md

POST /scheduling/voice/schedule-callback Scopes: scheduling:write

AI voice agent — schedule an automatic AI callback at the time the caller requested. Rings them back from the agent's outbound number; phone is auto-resolved from the call. Pass callback_day + callback_time + state; the server works out the absolute date in the caller's timezone, so never compute a date yourself.

4 parameters
Name In Type Required Description
callback_day body string no Day to call back: "today", "tomorrow", a weekday, or YYYY-MM-DD. Do NOT compute a date.
callback_time body string yes Clock time the caller wants, e.g. "3pm", "2:30pm", "14:00".
state body string no Caller state/territory for timezone (e.g. QLD, NSW, VIC).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduling/post-scheduling-voice-schedule-callback.md

Email (21 endpoints)

Send and receive emails via TrustPager Mail or Gmail, manage threads, view logs, and configure email settings. Supports provider selection for Gmail integration.

📄 Full markdown: /api/email.md

POST /email/threads/mark-read Scopes: email:write

Mark multiple email threads as read.

2 parameters
Name In Type Required Description
thread_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-threads-mark-read.md

POST /email/configs Scopes: email-config:write

Create a new outbound email sender config.

22 parameters
Name In Type Required Description
from_email_handle body string yes Local-part of the sender address (before the @). Alone it composes <handle>@mail.trustpager.net.
from_email_domain body string no A verified sending domain for this workspace (see list_sending_domains). Composes from_email = <handle>@<domain>. Must be verified first.
from_name body string yes Sender name recipients see in the From field ("From Name" in the UI).
staff_email body string yes Where internal form/lead notifications are sent ("Staff Notification Email" in the UI).
config_name body string no Label for this sending address, e.g. "Lead Form" or "Company Default".
website_id body string no Scope this config to one website. Omit for a company-level (workspace-wide) config.
is_default body boolean no Make this the default config for its scope. Sends that do not name a config resolve to the default.
logo_url body string no Logo shown in this sender's branded emails. Leave unset to inherit the company logo.
primary_color body string no Brand primary colour as a hex value, e.g. "#3b82f6".
secondary_color body string no Brand secondary colour as a hex value, e.g. "#8b5cf6".
send_to_user body boolean no "Send to User" — email a confirmation to whoever submitted the form.
send_to_staff body boolean no "Send to Staff" — email a notification to staff_email on submission.
crm_auto_create_deal body boolean no Auto-create a CRM opportunity from each submission.
crm_pipeline_id body string no Workflow the auto-created opportunity lands in. Required when crm_auto_create_deal is true.
crm_initial_stage_id body string no Stage within that workflow. Required when crm_auto_create_deal is true.
gmail_sender_user_id body string no Team member whose connected Gmail sends for this config, when the rail is "gmail".
gmail_sender_alias body string no Gmail send-as alias to use. Must be unique across companies.
preferred_provider body string no Sending rail: "trustpager_mail" (your verified domain, never expires) or "gmail" (connected Team Gmail).
use_chromeless_confirmation body boolean no "On-brand confirmation email" — send the confirmation and staff notification on a clean branded card using your logo and colours, with no standard email frame. False keeps the default template.
crm_default_products body array no Product UUIDs attached to every opportunity auto-created from this form. Each must belong to this workspace.
signature body string no Signature appended to emails sent from this address.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-configs.md

DELETE /email/configs/:config_id Scopes: email-config:delete

Delete an email config by UUID. Destructive.

2 parameters
Name In Type Required Description
config_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/delete-email-configs-config-id.md

DELETE /email/threads/:thread_id Scopes: email:write

Delete an email thread by UUID.

2 parameters
Name In Type Required Description
thread_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/delete-email-threads-thread-id.md

GET /email/capabilities Scopes: email:read

Get the workspace email send capability summary; connected accounts, daily limits, configured aliases.

📄 /api/email/get-email-capabilities.md

GET /email/configs/:config_id Scopes: email:read

Fetch a single email config by UUID.

1 parameter
Name In Type Required Description
config_id path string yes

📄 /api/email/get-email-configs-config-id.md

GET /email/threads/:thread_id Scopes: email:read

Fetch a single email thread by UUID with all messages in chronological order.

1 parameter
Name In Type Required Description
thread_id path string yes

📄 /api/email/get-email-threads-thread-id.md

GET /email/logs Scopes: email:read

List recent outbound email send log entries.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/email/get-email-logs.md

GET /email/threads Scopes: email:read

List email threads in the workspace inbox. Filter by contact_id, customer_id, opportunity_id, unread, status, direction, participant, or free-text search on the subject.

12 parameters
Name In Type Required Description
limit query number no
after query string no
contact_id query string no
customer_id query string no
opportunity_id query string no
unread query boolean no true returns only unread threads; false only read ones.
is_read query boolean no Inverse of unread. Wins if both are sent.
status query string no
is_automated query boolean no
direction query string no Direction of the most recent message, inbound or outbound.
search query string no Free-text search on the thread subject.
participant query string no Exact email address of a thread participant.

📄 /api/email/get-email-threads.md

GET /email/sending-domains Scopes: email:read

List the workspace's bring-your-own sending domains and their verification status. A verified domain lets you send from your own address (e.g. support@yourcompany.com) instead of @mail.trustpager.net.

📄 /api/email/get-email-sending-domains.md

POST /email/sending-domains Scopes: email-config:write

Register your own domain for sending. Returns two DNS records (a DKIM TXT and a Return-Path CNAME) to add at your DNS host; no SPF or MX change, your existing inbox keeps receiving. After adding them, call verify_sending_domain. Once verified, set it as the sending address via update_email_config { from_email_domain }.

2 parameters
Name In Type Required Description
domain body string yes Bare domain, e.g. "yourcompany.com". No scheme, no @, no path.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-sending-domains.md

DELETE /email/sending-domains/:domain_id Scopes: email-config:delete

Remove a sending domain. Refused if it is currently your sending address (change update_email_config { from_email_domain } first). Otherwise removes it from TrustPager Mail entirely.

2 parameters
Name In Type Required Description
domain_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/delete-email-sending-domains-domain-id.md

POST /email/reply Scopes: email:send

Reply to an existing email thread, preserving threading. Costs credits. Supports the same attachments as send_email, inline or by file_id.

11 parameters
Name In Type Required Description
thread_id body string yes
to_email body string yes
to_name body string no
reply_html body string yes
cc body array no
mode body string no Sending identity. Omit or "default" sends from the workspace default outbound address. "personal" sends as a specific user via their connected Gmail; pair with sender_user_id and/or from_email.
sender_user_id body string no With mode "personal", the UUID of the workspace user to send as. Must belong to this company and have Gmail connected.
from_email body string no With mode "personal", the exact address or alias to send from; the system resolves the matching user.
in_reply_to body string no RFC 2822 Message-ID being replied to, with or without angle brackets. Sets In-Reply-To and References so the reply threads correctly for the recipient.
attachments body array no File attachments. Max 20 items. Supported on TrustPager Mail (<=7MB total) and Gmail (<=25MB total). Each item is ONE of two shapes: { file_id } to attach a file already stored in this workspace (name, type and bytes are read server-side), or { filename, mime_type, content } to supply base64 content inline. If a file_id cannot be read, the whole send is refused rather than delivering an email that promises a document it does not carry. Attaching by file_id also requires the files:read scope.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-reply.md

POST /email/save-attachment Scopes: email:readfiles:write

Save an attachment from a received email onto a CRM record. The file is attached to the contact, customer or opportunity you name: PDFs land in the documents array on that record, everything else in the files array. Only works for email received via Gmail, and only for attachments up to 5MB. Calling it twice for the same attachment and record is a no-op success, not an error.

5 parameters
Name In Type Required Description
inbound_email_id body string yes UUID of the received email holding the attachment. Get ids from list_inbound_emails or the thread messages. Must be an email received via Gmail; other providers cannot supply attachment bytes.
attachment_name body string yes Exact filename of the attachment as it appears on the email, e.g. "invoice_406154.pdf". Must match one of the names listed in the attachments array on that email. Limit 5MB.
entity_type body string yes Which kind of CRM record to attach the file to. "deal" is an opportunity. "customer" is a company/account.
entity_id body string yes UUID of the contact, customer or opportunity to attach the file to. Must belong to this workspace.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-save-attachment.md

POST /email/send Scopes: email:send

Send a new email. Defaults to the workspace default outbound address; pass mode:"personal" with sender_user_id and/or from_email to send as a specific user via their connected Gmail. For replies use reply_to_email. Costs credits. Pass opportunity_id (canonical) or deal_id (legacy alias) to auto-link the resulting thread to a deal. Set raw_html: true to send a fully-designed HTML email verbatim with no TrustPager header/footer chrome (for pixel-perfect branded sends). Attachments are supported on both the TrustPager Mail rail (<=7MB total) and the Gmail rail (<=25MB total), either as inline base64 or by file_id for a file already stored in this workspace.

21 parameters
Name In Type Required Description
to_email body string yes
to_name body string no
subject body string yes
html_body body string yes
cc body array no Visible carbon-copy recipients. A single comma-separated string is also accepted.
bcc body array no Blind carbon-copy recipients; the visible recipients never see them, and they are not added to the thread participants. A single comma-separated string is also accepted.
contact_id body string no
customer_id body string no Link to an account/company UUID. Stamps email_logs.customer_id and attributes the send on that account.
mode body string no Sending identity. Omit or "default" sends from the workspace default outbound address. "personal" sends as a specific user via their connected Gmail; pair with sender_user_id and/or from_email.
sender_user_id body string no With mode "personal", the UUID of the workspace user to send as. Must belong to this company and have Gmail connected. Provide sender_user_id and/or from_email.
from_email body string no With mode "personal", the exact address or alias to send from; the system resolves the matching user. Use GET /email/capabilities to see available senders and aliases.
email_config_id body string no Optional: send using a specific workspace email configuration instead of the default.
opportunity_id body string no Link to an opportunity UUID. Stamps email_logs.deal_id and registers the thread under the opportunity activity feed.
deal_id body string no Legacy alias for opportunity_id.
raw_html body boolean no When true, send html_body verbatim with no header/footer chrome for fully-designed branded emails. Default false wraps the body in the standard branded template.
thread_id body string no Continue an existing email_threads conversation (personal/Gmail rail only). The matching Gmail thread is resolved so the send threads correctly for the recipient. Use list_email_threads to find it.
in_reply_to body string no RFC 2822 Message-ID being replied to, with or without angle brackets (personal/Gmail rail only). Sets In-Reply-To and References for recipient-side threading.
email_type body string no Tag persisted on email_logs.email_type so automated workflows can filter their own sends, e.g. "nurture". Personal/Gmail rail only; the TrustPager Mail rail always records "api_send". Defaults to "api_send".
metadata body object no Arbitrary JSON persisted on email_logs.template_data.metadata for later querying, e.g. {"campaign_id":"..."}. Personal/Gmail rail only. Keep values to JSON scalars and objects.
attachments body array no File attachments. Max 20 items. Supported on TrustPager Mail (<=7MB total) and Gmail (<=25MB total). Each item is ONE of two shapes: { file_id } to attach a file already stored in this workspace (name, type and bytes are read server-side), or { filename, mime_type, content } to supply base64 content inline. If a file_id cannot be read, the whole send is refused rather than delivering an email that promises a document it does not carry. Attaching by file_id also requires the files:read scope.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-send.md

POST /email/send-with-file Scopes: files:reademail:send

Send an email with a workspace CRM file attached. Costs credits. Works on both TrustPager Mail (<=7MB) and Gmail (<=25MB) rails. Pass opportunity_id (canonical) or deal_id (legacy alias) to auto-link the resulting thread to a deal.

15 parameters
Name In Type Required Description
file_id body string yes
to_email body string yes
to_name body string no
subject body string yes
html_body body string yes
cc body array no Visible carbon-copy recipients. A single comma-separated string is also accepted.
bcc body array no Blind carbon-copy recipients; the visible recipients never see them. A single comma-separated string is also accepted.
contact_id body string no
mode body string no Sending identity. Omit or "default" sends from the workspace default outbound address. "personal" sends as a specific user via their connected Gmail; pair with sender_user_id and/or from_email.
sender_user_id body string no With mode "personal", the UUID of the workspace user to send as. Must belong to this company and have Gmail connected.
from_email body string no With mode "personal", the exact address or alias to send from; the system resolves the matching user.
email_config_id body string no Optional: send using a specific workspace email configuration instead of the default.
opportunity_id body string no Link to an opportunity UUID. Stamps email_logs.deal_id and registers the thread under the opportunity activity feed.
deal_id body string no Legacy alias for opportunity_id.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-send-with-file.md

PATCH /email/configs/:config_id Scopes: email-config:write

Update an email config. To send from your own verified domain, pass from_email_handle (local-part) + from_email_domain (a verified sending domain). Set preferred_provider to choose the workspace rail.

23 parameters
Name In Type Required Description
config_id path string yes
from_name body string no Sender name recipients see in the From field ("From Name" in the UI).
staff_email body string no Where internal form/lead notifications are sent ("Staff Notification Email" in the UI).
from_email_handle body string no Local-part of the sender address (before the @). With no from_email_domain it composes <handle>@mail.trustpager.net.
from_email_domain body string no A verified sending domain for this workspace (see list_sending_domains). Composes from_email = <handle>@<domain>, e.g. support@yourcompany.com. Must be verified first.
config_name body string no Label for this sending address, e.g. "Lead Form" or "Company Default".
website_id body string no Scope this config to one website. Omit for a company-level (workspace-wide) config.
is_default body boolean no Make this the default config for its scope. Sends that do not name a config resolve to the default.
logo_url body string no Logo shown in this sender's branded emails. Pass null to clear it and inherit the company logo.
primary_color body string no Brand primary colour as a hex value, e.g. "#3b82f6".
secondary_color body string no Brand secondary colour as a hex value, e.g. "#8b5cf6".
send_to_user body boolean no "Send to User" — email a confirmation to whoever submitted the form.
send_to_staff body boolean no "Send to Staff" — email a notification to staff_email on submission.
crm_auto_create_deal body boolean no Auto-create a CRM opportunity from each submission.
crm_pipeline_id body string no Workflow the auto-created opportunity lands in. Required when crm_auto_create_deal is true.
crm_initial_stage_id body string no Stage within that workflow. Required when crm_auto_create_deal is true.
gmail_sender_user_id body string no Team member whose connected Gmail sends for this config, when the rail is "gmail".
gmail_sender_alias body string no Gmail send-as alias to use. Must be unique across companies.
preferred_provider body string no Default Workspace Email Address rail: "trustpager_mail" (send via your verified domain, never expires) or "gmail" (send via connected Team Gmail). Governs general/automation email, form invitations, and signing invitations alike.
use_chromeless_confirmation body boolean no "On-brand confirmation email" — send the confirmation and staff notification on a clean branded card using your logo and colours, with no standard email frame. False keeps the default template.
crm_default_products body array no Product UUIDs attached to every opportunity auto-created from this form. Each must belong to this workspace.
signature body string no Signature appended to emails sent from this address.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/patch-email-configs-config-id.md

PATCH /email/threads/:thread_id Scopes: email:write

Update an email thread. Mutate read/status, or link the thread to an opportunity / contact / customer so it appears on the deal activity feed and in list_email_threads?opportunity_id=. Useful when send_email was called without an opportunity_id and you need to attach the thread after the fact.

7 parameters
Name In Type Required Description
thread_id path string yes
is_read body boolean no
status body string no active | archived | spam
link_opportunity_id body string no Link this thread to an opportunity UUID. Idempotent; safe to call repeatedly.
link_contact_id body string no Link this thread to a contact UUID. Idempotent.
link_customer_id body string no Link this thread to a customer UUID. Idempotent.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/patch-email-threads-thread-id.md

POST /email/sending-domains/:domain_id/verify Scopes: email-config:write

Re-check DNS for a sending domain and return its current verification state. Call after adding the DNS records. DNS can take a few minutes to propagate. status becomes "verified" once both DKIM and Return-Path resolve.

2 parameters
Name In Type Required Description
domain_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email/post-email-sending-domains-domain-id-verify.md

Email Templates (2 endpoints)

Reusable email templates for the workspace.

📄 Full markdown: /api/email-templates.md

POST /email-templates/preview Scopes: company:read

Preview the rendered HTML for a channel email template, applying optional workspace and per-template chrome overrides. Free read.

3 parameters
Name In Type Required Description
channel body string yes Channel template key
workspace_settings body object no
per_template_settings body object no

📄 /api/email-templates/post-email-templates-preview.md

Email Campaigns (21 endpoints)

Create and send bulk broadcast email campaigns to segmented audiences. Supports tag-based and pipeline-based audience filters, delivery tracking (opens, clicks, bounces), and automatic unsubscribe management.

📄 Full markdown: /api/email-campaigns.md

DELETE /email-campaigns/:campaign_id/sends/:send_id Scopes: email-blasts:delete

Cancel a SCHEDULED run of an email blast so it never sends, and remove it from the Runs list. Only runs with status 'scheduled' can be cancelled; a run that has already sent (or is mid-send) is a permanent record and cannot be removed.

3 parameters
Name In Type Required Description
campaign_id path string yes
send_id path string yes The scheduled run to cancel, from list_blast_runs.
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/delete-email-campaigns-campaign-id-sends-send-id.md

POST /email-campaigns Scopes: email-blasts:write

Create an email marketing campaign.

6 parameters
Name In Type Required Description
name body string yes
subject body string no
body_html body string no
segment_filter body object no Audience for the blast: which contacts it resolves at send time. Shape is the shared opportunity-contact filter: { pipeline_id, stage_ids[], status('open'|'won'|'lost'|'all'), tags[{name}], stale_days, assigned_to_ids[], contact_type, has_email, has_phone, metadata_date_within }. A deliverable email address is always required and unsubscribed contacts are always excluded, so neither needs setting. Omit for an empty audience, which you can fill in later before scheduling a run.
folder body string no Optional folder name to file this blast under (must be an existing folder from list_email_blast_folders, or a new name).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns.md

POST /email-campaigns/folders Scopes: email-blasts:write

Create an email blast folder.

2 parameters
Name In Type Required Description
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-folders.md

DELETE /email-campaigns/:campaign_id Scopes: email-blasts:delete

Delete an email campaign.

2 parameters
Name In Type Required Description
campaign_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/delete-email-campaigns-campaign-id.md

DELETE /email-campaigns/folders/:folder_id Scopes: email-blasts:delete

Delete an email blast folder. Blasts filed under it are moved to unfiled (not deleted).

2 parameters
Name In Type Required Description
folder_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/delete-email-campaigns-folders-folder-id.md

POST /email-campaigns/:campaign_id/sends/:send_id/duplicate Scopes: email-blasts:write

Copy a run into a new PAUSED run, offset by offset_days (default 7). This is how a send series is built: schedule the invite, duplicate it twice, then rewrite each copy as the reminder and the last call. The copy is independent from the moment it exists, so editing it never touches the original. It is always created paused, because a duplicate exists to be edited, and is armed with resume_email_blast_run once it says what it should.

4 parameters
Name In Type Required Description
campaign_id path string yes
send_id path string yes The run to copy.
offset_days body number no Days after the source run's send time to place the copy. Defaults to 7. Negative values place it earlier.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-campaign-id-sends-send-id-duplicate.md

GET /email-campaigns/:campaign_id/recipients Scopes: email-blasts:read

List recipients of an email blast with delivery status. Add ?send_id=… to scope to one run.

2 parameters
Name In Type Required Description
campaign_id path string yes
send_id query string no

📄 /api/email-campaigns/get-email-campaigns-campaign-id-recipients.md

GET /email-campaigns Scopes: email-blasts:read

List email marketing campaigns (blasts). Pass folder to list only the blasts filed under that folder name.

3 parameters
Name In Type Required Description
limit query number no
status query string no
folder query string no Filter to blasts filed under this folder name.

📄 /api/email-campaigns/get-email-campaigns.md

POST /email-campaigns/:campaign_id/sends/:send_id/pause Scopes: email-blasts:write

Pause a scheduled run so it cannot send. The run keeps its content, its audience and its intended send time, and stays editable; it simply is not queued, so nothing can fire it. Use this to park a send while people review or approve it, instead of cancelling and rebuilding it later. Arm it again with resume_email_blast_run.

3 parameters
Name In Type Required Description
campaign_id path string yes
send_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-campaign-id-sends-send-id-pause.md

POST /email-campaigns/:campaign_id/sends/:send_id/resume Scopes: email-blasts:write

Arm a paused run so it will send at its scheduled time. If that time has already passed while the run was paused, it is clamped to now and sends promptly rather than never. Costs credits per recipient when it fires. Returns the run with the instant it will actually send.

3 parameters
Name In Type Required Description
campaign_id path string yes
send_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-campaign-id-sends-send-id-resume.md

POST /email-campaigns/:campaign_id/schedule Scopes: email-blasts:write

Schedule a run of an email blast for a future time, or immediately. Creates a scheduled run that appears in the blast's Runs list and snapshots the blast's current subject, body, CTA and audience filter, so editing the blast afterwards does not change what this run sends. Omit scheduled_for (or pass a past time) to send as soon as possible. The audience is re-resolved when the run fires, so contacts added between scheduling and sending are included. Costs credits per recipient at fire time. Edit a scheduled run with update_email_blast_run, or cancel it with cancel_email_blast_run.

4 parameters
Name In Type Required Description
campaign_id path string yes
scheduled_for body string no ISO 8601 instant to send at, e.g. 2026-08-07T01:00:00Z. This is an absolute moment, not a local wall-clock time, so convert from the workspace timezone first. Omit to send now.
paused body boolean no Create the run PAUSED: it keeps its content, audience and intended send time but is not queued, so it cannot fire until someone arms it with resume_email_blast_run. Use this when a send needs sign-off before it goes out. Defaults to false.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-campaign-id-schedule.md

POST /email-campaigns/:campaign_id/send Scopes: email-blasts:write

Trigger sending of an email campaign to its saved audience. Costs credits per recipient. Optionally override the content for this send (subject, body_html, intro_text, cta_text, cta_url, show_reply_button) — the overrides are written onto the blast before it fires. The audience is NOT overridable here; it stays set on the blast. Duplicate guard: if the content is byte-identical to the last successful send, the request is refused with HTTP 409 { duplicate: true, last_sent_at } and nothing is sent — pass confirm_duplicate: true to override. To preview a blast in a real inbox without sending to the audience, use send_email_blast_test.

9 parameters
Name In Type Required Description
campaign_id path string yes
subject body string no Optional. Override the blast subject for this send.
body_html body string no Optional. Override the blast HTML body for this send.
intro_text body string no Optional. Override the intro text for this send.
cta_text body string no Optional. Override the CTA button text.
cta_url body string no Optional. Override the CTA button URL.
show_reply_button body boolean no Optional. Toggle the reply button for this send.
confirm_duplicate body boolean no Set true to override the duplicate-content guard and re-send content identical to a previous send. Omit for the default safe behaviour.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-campaign-id-send.md

POST /email-campaigns/:campaign_id/send-test Scopes: email-blasts:write

Send a test copy of a blast to up to 5 specific email addresses. Renders exactly like a real send but resolves no audience, creates no contacts, and does not affect stats. Pass send_id to test one specific RUN's copy instead of the blast's current copy, which is what you want before arming a run in a series, since each run carries its own subject, body, attachments and sender.

4 parameters
Name In Type Required Description
campaign_id path string yes
recipients body array yes Up to 5 email addresses to receive the test.
send_id body string no Optional. Test this run's exact content rather than the blast's current content.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/post-email-campaigns-campaign-id-send-test.md

PATCH /email-campaigns/:campaign_id Scopes: email-blasts:write

Update an email blast: its content, its audience (segment_filter), its design mode, or which folder it is filed under.

8 parameters
Name In Type Required Description
campaign_id path string yes
name body string no
subject body string no
body_html body string no
design_mode body string no How the blast body is edited: "text" (rich-text editor, plain announcements), "html" (raw HTML source with live preview — designed table-based emails should use this so the editor never reflows the markup), or "guided" (Visual mode: edit only the designer-marked editable regions of a locked HTML design). "visual" is the legacy alias for "text".
folder body string no Folder name to file this blast under (pass "" or null to unfile).
segment_filter body object no Audience for the blast: which contacts it resolves at send time. Shape is the shared opportunity-contact filter: { pipeline_id, stage_ids[], status('open'|'won'|'lost'|'all'), tags[{name}], stale_days, assigned_to_ids[], contact_type, has_email, has_phone, metadata_date_within }. A deliverable email address is always required and unsubscribed contacts are always excluded, so neither needs setting. Omit for an empty audience, which you can fill in later before scheduling a run.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/patch-email-campaigns-campaign-id.md

PATCH /email-campaigns/folders/:folder_id Scopes: email-blasts:write

Rename an email blast folder. Blasts filed under it move to the new name.

3 parameters
Name In Type Required Description
folder_id path string yes
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/patch-email-campaigns-folders-folder-id.md

PATCH /email-campaigns/:campaign_id/sends/:send_id Scopes: email-blasts:write

Edit a SCHEDULED run of an email blast before it sends: its content (subject, intro_text, body_html, cta_text, cta_url), its audience (segment_filter), or its send time (scheduled_for). Each scheduled run carries its own copy, which is how a series of sends can say something different each time (invite, then reminder, then last call) without touching the blast itself. Only runs with status 'scheduled' can be edited; a run that has already sent is a permanent record.

10 parameters
Name In Type Required Description
campaign_id path string yes
send_id path string yes The run to edit, from list_blast_runs.
subject body string no Subject line for this run only.
intro_text body string no Intro text for this run only.
body_html body string no HTML body for this run only.
cta_text body string no CTA button text for this run only.
cta_url body string no CTA button URL for this run only.
segment_filter body object no Audience filter for this run only, same shape as the blast's segment_filter.
scheduled_for body string no New ISO 8601 send instant. Also moves the queued send.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/email-campaigns/patch-email-campaigns-campaign-id-sends-send-id.md

SMS (6 endpoints)

Send and receive SMS messages. View conversations and message history.

📄 Full markdown: /api/sms.md

POST /sms/conversations/mark-read Scopes: sms:write

Mark multiple SMS conversations as read at once.

2 parameters
Name In Type Required Description
conversation_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/sms/post-sms-conversations-mark-read.md

GET /sms/conversations/:conversation_id Scopes: sms:read

Fetch a single SMS conversation by UUID, including the full message history.

1 parameter
Name In Type Required Description
conversation_id path string yes

📄 /api/sms/get-sms-conversations-conversation-id.md

GET /sms/conversations Scopes: sms:read

List SMS conversations in the workspace inbox. Filter by contact_id, opportunity_id, external_phone_number, phone_number_id, status, or unread. external_phone_number is the most reliable way to find someone's SMS history, because it also finds conversations that were never linked to a contact record.

8 parameters
Name In Type Required Description
limit query number no
after query string no
contact_id query string no Only conversations linked to this contact UUID.
opportunity_id query string no Only conversations linked to this opportunity UUID.
external_phone_number query string no The other party's number in E.164, e.g. +61431377068. Exact match.
phone_number_id query string no Only conversations on this workspace phone number UUID.
status query string no Conversation status, e.g. active or archived.
unread query boolean no true returns only conversations with unread messages; false only those fully read.

📄 /api/sms/get-sms-conversations.md

POST /sms/send Scopes: sms:send

Send an SMS message from a workspace phone number. `phone_number_id` is OPTIONAL — when omitted, auto-resolves to the workspace's single active SMS-capable phone number (the common case). Only pass `phone_number_id` if the workspace has multiple SMS numbers and you need to choose one; in that case call `list_phone_numbers` first and never invent a UUID. Keep under 160 chars where possible. Costs credits.

6 parameters
Name In Type Required Description
to_number body string yes Recipient phone in E.164, e.g. +61431377068
message body string yes SMS body. Keep concise — ideally under 160 chars.
phone_number_id body string no OPTIONAL. UUID of the workspace phone number to send from. Omit to auto-pick the single active SMS-capable number. If the workspace has multiple SMS numbers, call list_phone_numbers first.
contact_id body string no
deal_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/sms/post-sms-send.md

PATCH /sms/conversations/:conversation_id Scopes: sms:write

Update an SMS conversation, e.g. mark it read.

5 parameters
Name In Type Required Description
conversation_id path string yes
is_read body boolean no true marks the conversation read (clears unread_count).
unread_count body number no
status body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/sms/patch-sms-conversations-conversation-id.md

WhatsApp (14 endpoints)

Send and receive WhatsApp messages. Pair a phone number, view 1:1 conversations and group conversations, send messages, and manage CRM links.

📄 Full markdown: /api/whatsapp.md

POST /whatsapp/disconnect Scopes: whatsapp:write

Disconnect the workspace's WhatsApp pairing. Deletes the Evolution instance and clears the pairing row. Use to re-pair against a different phone.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/post-whatsapp-disconnect.md

GET /whatsapp/groups/:group_id Scopes: whatsapp:read

Fetch a single WhatsApp group by UUID, including member list snapshot.

1 parameter
Name In Type Required Description
group_id path string yes

📄 /api/whatsapp/get-whatsapp-groups-group-id.md

GET /whatsapp/pairing Scopes: whatsapp:read

Get the workspace's WhatsApp pairing status (connected / awaiting_qr / disconnected / etc.) and paired phone identity.

📄 /api/whatsapp/get-whatsapp-pairing.md

POST /whatsapp/groups/:group_id/link Scopes: whatsapp:write

Link a WhatsApp group to a deal or customer so its messages appear in the deal/customer timeline.

4 parameters
Name In Type Required Description
group_id path string yes
deal_id body string no
customer_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/post-whatsapp-groups-group-id-link.md

GET /whatsapp/conversations Scopes: whatsapp:read

List WhatsApp 1:1 conversations in the workspace inbox. Supports filtering by external_phone_number and unread.

4 parameters
Name In Type Required Description
limit query number no
after query string no
external_phone_number query string no
unread query boolean no

📄 /api/whatsapp/get-whatsapp-conversations.md

GET /whatsapp/groups Scopes: whatsapp:read

List WhatsApp groups the workspace's paired account is in. Filter by linked_deal_id, linked_customer_id, or unlinked.

5 parameters
Name In Type Required Description
limit query number no
after query string no
linked_deal_id query string no
linked_customer_id query string no
linked query boolean no true = only linked groups, false = only unlinked

📄 /api/whatsapp/get-whatsapp-groups.md

POST /whatsapp/send Scopes: whatsapp:send

Send a WhatsApp message to a contact. Provide either to_phone (E.164) or conversation_id. Costs credits.

7 parameters
Name In Type Required Description
to_phone body string no Recipient phone in E.164, e.g. +61431377068
body body string yes WhatsApp message body (text only in v1).
conversation_id body string no Existing conversation UUID. Mutually exclusive with to_phone.
contact_id body string no
deal_id body string no
customer_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/post-whatsapp-send.md

POST /whatsapp/groups/send Scopes: whatsapp:send

Send a WhatsApp message into a registered group. Group must be visible to the workspace (paired account is a member). Costs credits.

3 parameters
Name In Type Required Description
group_id body string yes TrustPager whatsapp_groups UUID (not the WhatsApp JID).
body body string yes Message body (text only in v1).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/post-whatsapp-groups-send.md

POST /whatsapp/pair Scopes: whatsapp:write

Begin pairing a WhatsApp account to the workspace. Returns a QR code data URL the user scans with their phone (Settings → Linked Devices → Link a Device). The pairing becomes "connected" automatically once they scan.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/post-whatsapp-pair.md

POST /whatsapp/groups/:group_id/unlink Scopes: whatsapp:write

Remove a WhatsApp group's deal/customer link. The group remains visible in the inbox.

2 parameters
Name In Type Required Description
group_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/post-whatsapp-groups-group-id-unlink.md

PATCH /whatsapp/conversations/:conversation_id Scopes: whatsapp:write

Update a WhatsApp conversation (e.g. mark read, archive).

4 parameters
Name In Type Required Description
conversation_id path string yes
unread_count body number no
status body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whatsapp/patch-whatsapp-conversations-conversation-id.md

Chat (13 endpoints)

Team chat rooms, members, and messages. Workspace-scoped in Phase 0; portal and cross-workspace rooms in later phases.

📄 Full markdown: /api/chat.md

POST /chat/rooms/:room_id/members Scopes: chat:write

Add a workspace user to a chat room. In Phase 0 the user must belong to this workspace; cross-workspace adds (which need a consent handshake) come later.

4 parameters
Name In Type Required Description
room_id path string yes
user_id body string yes UUID of the workspace user to add.
member_role body string no owner or member (default member).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/post-chat-rooms-room-id-members.md

POST /chat/rooms Scopes: chat:write

Create a chat room. The API key owner joins as owner; pass member_user_ids to add teammates (they must belong to this workspace). Use room_type "dm" for 1:1, "group" for a named group, "self" for a private notes-to-self room, "workspace" for a team-wide channel.

4 parameters
Name In Type Required Description
room_type body string no dm, group, self, or workspace. Defaults to group.
title body string no Room title (optional for dm/self).
member_user_ids body array no UUIDs of workspace users to add as members. Non-workspace UUIDs are skipped and returned in skipped_member_ids.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/post-chat-rooms.md

DELETE /chat/rooms/:room_id/messages/:message_id Scopes: chat:write

Soft-delete one of your own chat messages (sets deleted_at; history preserved). Only the original sender can delete.

3 parameters
Name In Type Required Description
room_id path string yes
message_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/delete-chat-rooms-room-id-messages-message-id.md

PATCH /chat/rooms/:room_id/messages/:message_id Scopes: chat:write

Edit one of your own chat messages (sets edited_at). Only the original sender can edit. Pass the new `body` and/or `content`.

5 parameters
Name In Type Required Description
room_id path string yes
message_id path string yes
body body string no New message text.
content body object no New structured payload.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/patch-chat-rooms-room-id-messages-message-id.md

GET /chat/rooms/:room_id Scopes: chat:read

Fetch a single chat room by UUID.

1 parameter
Name In Type Required Description
room_id path string yes UUID of the room.

📄 /api/chat/get-chat-rooms-room-id.md

POST /chat/rooms/:room_id/invite Scopes: chat:write

Invite someone to a chat room by email — the cross-workspace path. Existing TrustPager users are added immediately; a new email is provisioned an account and added so they land in the room when they accept. Optionally set member_role "host" so they can invite their own people.

4 parameters
Name In Type Required Description
room_id path string yes
email body string yes Email address of the person to invite.
member_role body string no member (default) or host (can invite others + manage the room).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/post-chat-rooms-room-id-invite.md

GET /chat/rooms/:room_id/messages Scopes: chat:read

List messages in a chat room, newest first, paginated. Soft-deleted messages are excluded.

3 parameters
Name In Type Required Description
room_id path string yes
limit query number no Max messages (1-100, default 25).
after query string no Pagination cursor.

📄 /api/chat/get-chat-rooms-room-id-messages.md

GET /chat/rooms/:room_id/members Scopes: chat:read

List the members of a chat room, with each member's user profile (name, email, avatar).

1 parameter
Name In Type Required Description
room_id path string yes

📄 /api/chat/get-chat-rooms-room-id-members.md

GET /chat/rooms Scopes: chat:read

List chat rooms in the workspace. A room is a set of participants (a DM, a group, a self-note, or a workspace channel). Filter by room_type or is_archived. Newest activity first.

4 parameters
Name In Type Required Description
room_type query string no Filter by type: dm, group, self, or workspace.
is_archived query string no "true" for archived only, "all" for both. Defaults to active only.
limit query number no Max rooms to return (1-100, default 25).
after query string no Pagination cursor.

📄 /api/chat/get-chat-rooms.md

POST /chat/rooms/:room_id/read Scopes: chat:write

Mark a chat room as read up to now for the API key owner, updating their last_read_at. You can only mark your own read state.

2 parameters
Name In Type Required Description
room_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/post-chat-rooms-room-id-read.md

DELETE /chat/rooms/:room_id/members/:user_id Scopes: chat:write

Remove a member from a chat room (marks them removed; message history is preserved).

3 parameters
Name In Type Required Description
room_id path string yes
user_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/delete-chat-rooms-room-id-members-user-id.md

POST /chat/rooms/:room_id/messages Scopes: chat:write

Post a message to a chat room. When sent via API/MCP the message is attributed as an AI actor on the workspace's behalf (actor_type defaults to "ai"); pass actor_type "human" only when relaying a real person. Provide `body` text and/or structured `content`.

7 parameters
Name In Type Required Description
room_id path string yes
body body string yes The message text.
content body object no Optional structured payload (attachments, rich content).
actor_type body string no human, ai, or system. Defaults to ai for API/MCP sends.
sender_label body string no Display label for an AI/system sender (e.g. "TrustPager AI").
reply_to_message_id body string no UUID of the message being replied to.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/post-chat-rooms-room-id-messages.md

PATCH /chat/rooms/:room_id Scopes: chat:write

Update a chat room title or archive it. Pass only the fields to change.

4 parameters
Name In Type Required Description
room_id path string yes
title body string no
is_archived body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/chat/patch-chat-rooms-room-id.md

Phone (13 endpoints)

Manage phone numbers and call logs. Search for available numbers to purchase.

📄 Full markdown: /api/phone.md

POST /phone/numbers/buy Scopes: phone:write

Buy a phone number. Costs credits and recurring fees.

3 parameters
Name In Type Required Description
phone_number body string yes
friendly_name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/phone/post-phone-numbers-buy.md

POST /phone/addresses Scopes: phone:write

Create a regulatory address.

9 parameters
Name In Type Required Description
customer_name body string yes Legal name of the person or business the address belongs to. Must match the regulatory paperwork.
street body string yes Street address line 1.
street_secondary body string no Street address line 2 (unit, level, suite).
city body string yes City or suburb.
region body string yes State, province or territory, e.g. "VIC".
postal_code body string yes Postcode or ZIP.
iso_country body string yes Two-letter ISO country code, e.g. "AU".
emergency_enabled body boolean no Register this address for emergency calling. Only valid where the number type supports it.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/phone/post-phone-addresses.md

POST /phone/bundles Scopes: phone:write

Create a regulatory bundle.

9 parameters
Name In Type Required Description
friendly_name body string no Label for this regulatory bundle in the phone settings list.
country_code body string yes Two-letter ISO country code the bundle is for, e.g. "AU".
number_type body string yes Which class of number the bundle covers, e.g. local, national, mobile or toll-free. Regulatory requirements differ per class.
end_user_type body string yes Whether the number is held by an individual or a business. Determines which documents the regulator requires.
regulation_sid body string no Identifier of the specific regulation this bundle satisfies, from the regulations list for that country and number type.
address_sid body string no Identifier of the regulatory address to attach. Create one first with create_phone_address.
document_sid body string no Identifier of a supporting document already uploaded for this bundle.
end_user_data body object no Details about the end user the regulator requires (legal name, business number, contact). The exact keys depend on country_code and end_user_type.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/phone/post-phone-bundles.md

GET /phone/numbers/:phone_number_id Scopes: phone:read

Fetch a phone number by UUID. Includes after_hours_enabled/after_hours_config and the derived active_inbound_mode field — see list_phone_numbers.

1 parameter
Name In Type Required Description
phone_number_id path string yes

📄 /api/phone/get-phone-numbers-phone-number-id.md

GET /phone/call-logs Scopes: calls:read

List phone-call records (inbound + outbound). USE THIS for any "recent calls", "phone call history", "missed calls", "who called", or similar phone-specific query. Returns the raw call log (timestamps, duration, direction, phone number, recording url, voice-agent linkage) — richer than list_activities for calls. Prefer this over list_activities when the user asks specifically about phone activity.

6 parameters
Name In Type Required Description
limit query number no Max call logs to return.
after query string no Pagination cursor from a previous response.
direction query string no Filter to calls placed TO the workspace ("inbound") or FROM it ("outbound"). These are the only two stored values.
status query string no Filter by call status, e.g. "completed", "no-answer", "busy", "failed".
phone_number_id query string no Filter to calls on one workspace phone number (UUID).
contact_id query string no Filter to calls linked to a specific contact (UUID).

📄 /api/phone/get-phone-call-logs.md

GET /phone/numbers Scopes: phone:read

List workspace phone numbers. Each number includes after_hours_enabled/after_hours_config (a second, clock-gated inbound mode that overrides the primary routing fields outside its schedule) and active_inbound_mode — a derived field answering "what actually answers a call on this number right now" (agent / app / forward / none), already accounting for after-hours. Read active_inbound_mode instead of reasoning about the primary fields plus after_hours_config yourself.

📄 /api/phone/get-phone-numbers.md

POST /phone/numbers/:phone_number_id/release Scopes: phone:write

Release a phone number (stops billing).

2 parameters
Name In Type Required Description
phone_number_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/phone/post-phone-numbers-phone-number-id-release.md

POST /phone/numbers/search Scopes: phone:read

Search for available phone numbers to purchase. country_code is an ISO 3166-1 alpha-2 code (e.g. "US", "AU"). By default the search returns SMS-capable numbers of the right type for the country (US/CA return Local numbers, AU/GB/NZ return Mobile); pass number_type to force a specific type. Each result includes address_requirements ("none" | "any" | "local" | "foreign") indicating whether an address must be supplied to buy that number.

6 parameters
Name In Type Required Description
country_code body string no ISO 3166-1 alpha-2 country code, e.g. "US" or "AU". Defaults to US.
area_code body string no Area/region code to filter by (e.g. "415" for US, "2" for AU).
contains body string no Digit sequence the number must contain.
number_type body string no Force a specific Twilio number type. Omit to let the search pick the SMS-capable type for the country.
sms_enabled body boolean no Only return SMS-capable numbers. Defaults to true.
voice_enabled body boolean no Only return voice-capable numbers.

📄 /api/phone/post-phone-numbers-search.md

POST /phone/bundles/:bundle_id/submit Scopes: phone:write

Submit a regulatory bundle for review.

2 parameters
Name In Type Required Description
bundle_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/phone/post-phone-bundles-bundle-id-submit.md

PATCH /phone/numbers/:phone_number_id Scopes: phone:write

Update a phone number: friendly_name, voice-agent routing, the outbound in-app-dialler allowlist, and the "When Busy" no-answer fallback. IMPORTANT: binding an agent here (inbound_voice_agent_id / outbound_voice_agent_id) controls INBOUND answering (who picks up calls TO this number) and is one-agent-per-number. OUTBOUND dialling does NOT use this binding; set the caller-ID number on the agent via create_voice_agent_outbound_config (default_phone_number_id), which lets one number serve many agents. outbound_caller_user_ids restricts which workspace users may present THIS number as caller ID from the in-app dialler ("Call from TrustPager"): pass an array of user IDs to restrict to exactly those people, or [] / null to let anyone with calling permission dial from it (the default). Every ID must be a member of this workspace. Toll-free numbers (1800/1300) cannot dial out at all. WHEN BUSY (Answer-in-TrustPager numbers only): when the number rings staff browsers ("Answer in TrustPager") and nobody answers within ring_timeout_seconds, no_answer_action decides what happens next instead of dropping the call: "voicemail" (record a message; needs voicemail_greeting_text or voicemail_greeting_audio_url, else a default greeting is spoken; the recording is transcribed and attached to the caller's contact), "forward" (ring no_answer_forward_number), "agent" (hand to the AI voice agent no_answer_agent_config_id), or "none"/null to disable the fallback. no_answer_agent_config_id must be a voice agent in this workspace. AFTER HOURS: after_hours_enabled + after_hours_config define a SECOND inbound mode that overrides everything above (inbound_voice_agent_id, inbound ring routing, transfer_number) whenever the current moment falls OUTSIDE the configured schedule. Setting after_hours_enabled true requires after_hours_config to be provided (either in this same request or already stored from a prior one). Use get_phone_number's active_inbound_mode field to check what a number actually does right now instead of reasoning about business hours yourself.

15 parameters
Name In Type Required Description
phone_number_id path string yes
friendly_name body string no
inbound_voice_agent_id body string no
outbound_voice_agent_id body string no
outbound_caller_user_ids body array no User IDs allowed to dial out from this number via the in-app dialler. [] or null = anyone with calling permission.
ring_timeout_seconds body integer no How long (5-120s, default 25) to ring staff browsers before the When Busy fallback fires. Answer-in-TrustPager numbers only.
no_answer_action body string no What to do when no one answers an Answer-in-TrustPager call. null/"none" = drop (no fallback).
no_answer_forward_number body string no E.164 number to ring when no_answer_action = "forward".
no_answer_agent_config_id body string no Voice agent (this workspace) to hand the call to when no_answer_action = "agent".
voicemail_greeting_text body string no Spoken greeting for no_answer_action = "voicemail" (max 1000 chars). Ignored if voicemail_greeting_audio_url is set.
voicemail_greeting_audio_url body string no http(s) URL of a pre-generated greeting audio to play for voicemail (e.g. from ai_generate_speech). Takes priority over voicemail_greeting_text.
allowed_inbound_country_list body array no Restrict which countries may call this number IN. Array of ISO 3166-1 alpha-2 codes (e.g. ["AU"] for Australia only). Calls from any country not listed are rejected before reaching the agent (spam/fraud control). [] or null = allow all countries (the default).
after_hours_enabled body boolean no Turn the after-hours mode on/off. Turning it on requires after_hours_config to exist (in this request or already stored). Turning it off keeps the stored config so re-enabling restores the same schedule.
after_hours_config body object no The after-hours schedule and routing target. Shape: { schedule: { days: array of "mon".."sun" (at least one), start_hour: integer 0-23, end_hour: integer 1-24 and greater than start_hour, timezone: IANA name e.g. "Australia/Brisbane" (default "Australia/Sydney"), holidays: optional array of "YYYY-MM-DD" strings }, mode: "agent" | "forward" | "app" | "none", plus exactly the one field that mode needs — voice_agent_config_id (mode "agent", must be a voice agent in this workspace), transfer_number (mode "forward", E.164), or ring_user_ids (mode "app", non-empty array of workspace member user ids) }. Required together with after_hours_enabled the first time it is turned on.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/phone/patch-phone-numbers-phone-number-id.md

Agents (31 endpoints)

Manage AI voice agents and text agents under the unified /agents endpoint. Use ?type=voice or ?type=text to filter listings. The type field is required in the create body.

📄 Full markdown: /api/voice-agents.md

POST /voice-agents/blocklist Scopes: voice-agents:write

Stop placing AI voice calls to a number. Takes effect on the next call attempt, across every dispatch path. Idempotent: re-adding an existing number updates its reason.

3 parameters
Name In Type Required Description
phone body string yes The number to stop calling, ideally E.164 (e.g. "+61431377068"). AU local form ("0431377068") also matches at dial time. Adding a number already on the list updates its reason instead of creating a duplicate.
reason body string no Why this number is on the list, shown in the workspace. In-call opt-outs record "Caller asked to be removed during a call".
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-blocklist.md

POST /voice-agents/:agent_id/apply-template Scopes: voice-agents:write

Stamp a profile/source template onto a target voice agent.

3 parameters
Name In Type Required Description
agent_id path string yes
template_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-apply-template.md

POST /voice-agents Scopes: voice-agents:write

Create a voice agent.

3 parameters
Name In Type Required Description
agent_name body string yes
voice_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents.md

POST /voice-agents/:agent_id/outbound-config Scopes: voice-agents:write

Enable OUTBOUND dialling for a voice agent. Set default_phone_number_id to an imported number: that number becomes the caller ID and is all outbound needs (each call passes the agent itself, so no number-level binding is required and ONE number can be the default for many agents). Do NOT use update_phone_number to bind the number to the agent for outbound; that binding is inbound-only. Per-agent, no website required.

13 parameters
Name In Type Required Description
agent_id path string yes
default_phone_number_id body string no
website_id body string no
allowed_country_codes body array no Country codes this agent may dial, e.g. ["AU"]. Empty or omitted allows all.
rate_limit_max_requests body number no Max calls ONE visitor (per IP / browser fingerprint / email / phone) may start per window. Default 2.
rate_limit_window_hours body number no Length of the per-visitor rate-limit window, in hours. Default 24.
global_rate_limit_max_requests body number no Max calls ALL visitors combined may start per window, i.e. the spend ceiling. Default 50.
global_rate_limit_window_hours body number no Length of the global rate-limit window, in hours. Default 24.
crm_auto_create_deal body boolean no Whether a caller who identifies themselves also gets an opportunity created, not just a contact.
crm_pipeline_id body string no Pipeline the auto-created opportunity lands in. Required for crm_auto_create_deal to do anything.
crm_initial_stage_id body string no Stage within that pipeline the opportunity starts at.
crm_default_products body array no Product ids attached to the auto-created opportunity.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-outbound-config.md

POST /voice-agents/:agent_id/website-config Scopes: voice-agents:write

Bind a voice agent to a website, so it can take in-browser "talk to the AI" calls from that site. Optionally set the rate limits and CRM routing at the same time.

11 parameters
Name In Type Required Description
agent_id path string yes
website_id body string yes
rate_limit_max_requests body number no Max calls ONE visitor (per IP / browser fingerprint / email / phone) may start per window. Default 2.
rate_limit_window_hours body number no Length of the per-visitor rate-limit window, in hours. Default 24.
global_rate_limit_max_requests body number no Max calls ALL visitors combined may start per window, i.e. the spend ceiling. Default 50.
global_rate_limit_window_hours body number no Length of the global rate-limit window, in hours. Default 24.
crm_auto_create_deal body boolean no Whether a caller who identifies themselves also gets an opportunity created, not just a contact.
crm_pipeline_id body string no Pipeline the auto-created opportunity lands in. Required for crm_auto_create_deal to do anything.
crm_initial_stage_id body string no Stage within that pipeline the opportunity starts at.
crm_default_products body array no Product ids attached to the auto-created opportunity.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-website-config.md

DELETE /voice-agents/:agent_id Scopes: voice-agents:delete

Delete a voice agent.

2 parameters
Name In Type Required Description
agent_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/delete-voice-agents-agent-id.md

DELETE /voice-agents/:agent_id/outbound-config/:config_id Scopes: voice-agents:delete

Delete an outbound-call config.

3 parameters
Name In Type Required Description
agent_id path string yes
config_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/delete-voice-agents-agent-id-outbound-config-config-id.md

DELETE /voice-agents/:agent_id/website-config/:config_id Scopes: voice-agents:delete

Delete a voice-agent website config.

3 parameters
Name In Type Required Description
agent_id path string yes
config_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/delete-voice-agents-agent-id-website-config-config-id.md

DELETE /voice-agents/:agent_id/toolkit-access Scopes: voice-agents:write

Disable agent toolkit access: deactivate the agent dedicated toolkit key. In-call booking stops working until re-enabled.

2 parameters
Name In Type Required Description
agent_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/delete-voice-agents-agent-id-toolkit-access.md

POST /voice-agents/:agent_id/toolkit-access Scopes: voice-agents:write

Enable agent toolkit access for a voice agent: mint a non-expiring agent_toolkit:use key named after the agent, attach it, migrate the agent in-call booking tools (check_calendar_availability / book_appointment) off the legacy scheduling endpoints onto the session-bound native endpoints carrying that key, and publish. Fixes silent in-call booking failures caused by hand-pasted expiring keys. Idempotent.

2 parameters
Name In Type Required Description
agent_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-toolkit-access.md

GET /voice-agents/:agent_id/toolkit-access Scopes: voice-agents:read

Check whether a voice agent has toolkit access enabled (a non-expiring agent_toolkit:use key) and whether its in-call booking tools are on the native session-bound endpoints.

1 parameter
Name In Type Required Description
agent_id path string yes

📄 /api/voice-agents/get-voice-agents-agent-id-toolkit-access.md

POST /voice-agents/:agent_id/call Scopes: calls:initiate

Initiate an outbound voice call via this agent.

3 parameters
Name In Type Required Description
agent_id path string yes
to_number body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-call.md

GET /voice-agents Scopes: voice-agents:read

List voice agents in the workspace.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/voice-agents/get-voice-agents.md

GET /voice-agents/blocklist Scopes: voice-agents:read

List the phone numbers this workspace will not place AI voice calls to. Covers numbers with no contact record, which contact-level unsubscribe cannot. Entries added during a call carry the call id in source.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/voice-agents/get-voice-agents-blocklist.md

POST /voice-agents/:agent_id/patch-flow Scopes: voice-agents:write

Partial update to the voice-agent flow. Provide nodes_patch and/or edges_patch to merge into specific nodes/edges by id, patches for top-level flow fields, and/or refresh_briefing=true.

6 parameters
Name In Type Required Description
agent_id path string yes
nodes_patch body object no Partial nodes object to merge into existing flow nodes. Keys are node IDs.
edges_patch body object no Partial edges object to merge into existing flow edges. Keys are edge IDs.
patches body object no Partial top-level conversation flow fields to shallow-merge (e.g. global_prompt, or flex_mode). A node's instruction can be set to { type: "static_text", text } for verbatim delivery (same mechanism as voicemail_option), but this ONLY holds if the flow-level flex_mode is false - with flex_mode true (the default from provisioning) the whole flow runs as one single prompt and static_text is not guaranteed to be spoken as written. flex_mode has no per-node override: forcing one line verbatim means setting flex_mode:false for the whole agent, which also makes every other node run strict instead of free-flowing. Confirmed by live test call, SR 58972773.
refresh_briefing body boolean no Regenerate and inject the AI briefing into global_prompt.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-patch-flow.md

POST /voice-agents/:agent_id/provision Scopes: voice-agents:write

Provision a voice agent that was created as an orphan row.

2 parameters
Name In Type Required Description
agent_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-provision.md

POST /voice-agents/:agent_id/publish Scopes: voice-agents:write

Publish a voice agent draft to live.

2 parameters
Name In Type Required Description
agent_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-publish.md

POST /voice-agents/calls/:call_id/recording/rehost Scopes: voice-agents:write

Re-host a voice-agent call recording into private storage.

2 parameters
Name In Type Required Description
call_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-calls-call-id-recording-rehost.md

DELETE /voice-agents/blocklist/:entry_id Scopes: voice-agents:delete

Take a number off the voice do-not-call list, so AI voice calls to it are allowed again. Use when a number was blocked in error.

2 parameters
Name In Type Required Description
entry_id path string yes UUID of the blocklist entry. Get ids from list_voice_call_blocklist.
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/delete-voice-agents-blocklist-entry-id.md

POST /voice-agents/:agent_id/sync Scopes: voice-agents:write

Sync a voice agent config with the upstream provider.

2 parameters
Name In Type Required Description
agent_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-sync.md

PATCH /voice-agents/:agent_id Scopes: voice-agents:write

Update a voice agent. Provider-native settings (voice, language, timeouts, voicemail_option, begin_message_delay_ms, etc.) are pushed to the live agent; call publish_voice_agent to make them live.

7 parameters
Name In Type Required Description
agent_id path string yes
agent_name body string no
voice_id body string no
voicemail_option body object no Native voicemail handling. On answering-machine detection the provider runs this action deterministically (no AI free-wheeling). Pass null to disable. Shape: { action: { type: "static_text"|"prompt"|"hangup", text?: string }, detection_prompt?: string }.
begin_message_delay_ms body number no Milliseconds (0–5000) to wait before the agent speaks its first message on a call it initiates, so it does not talk over a voicemail greeting/beep.
max_concurrent_calls body number no Maximum calls this agent may have in progress at the same time (1-100, default 5). A hard ceiling on simultaneous outward calls: calls beyond it are refused, and calls queued by an Auto Queue wait and dial later instead. Raise it deliberately - it is the control that stops one bulk enrolment placing hundreds of paid calls at once. Does not limit inbound calls.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/patch-voice-agents-agent-id.md

POST /voice-agents/:agent_id/update-flow Scopes: voice-agents:write

Replace the entire voice-agent conversation flow. Use patch_voice_agent_flow for a partial update.

3 parameters
Name In Type Required Description
agent_id path string yes
conversation_flow_config body object yes Full Retell conversation flow config object with nodes and edges (required). A node's instruction can be { type: "static_text", text }, spoken verbatim like voicemail_option, instead of { type: "prompt" } which the model paraphrases. VERBATIM ONLY WORKS IF THE FLOW-LEVEL flex_mode FIELD IS FALSE - when flex_mode is true (the platform default from provisioning) Retell treats the whole flow as one single prompt and a node's static_text instruction is not guaranteed to be spoken as written. There is no per-node override, so making one line verbatim requires setting flex_mode:false for the entire agent, which also switches the rest of the conversation from free-flowing to strict node-by-node. Confirmed by live test call, SR 58972773.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-update-flow.md

PATCH /voice-agents/:agent_id/outbound-config/:config_id Scopes: voice-agents:write

Update an outbound-call config: caller-ID number, which countries it may dial, the call rate limits, and CRM routing.

14 parameters
Name In Type Required Description
agent_id path string yes
config_id path string yes
default_phone_number_id body string no
website_id body string no
allowed_country_codes body array no Country codes this agent may dial, e.g. ["AU"]. Empty or omitted allows all.
rate_limit_max_requests body number no Max calls ONE visitor (per IP / browser fingerprint / email / phone) may start per window. Default 2.
rate_limit_window_hours body number no Length of the per-visitor rate-limit window, in hours. Default 24.
global_rate_limit_max_requests body number no Max calls ALL visitors combined may start per window, i.e. the spend ceiling. Default 50.
global_rate_limit_window_hours body number no Length of the global rate-limit window, in hours. Default 24.
crm_auto_create_deal body boolean no Whether a caller who identifies themselves also gets an opportunity created, not just a contact.
crm_pipeline_id body string no Pipeline the auto-created opportunity lands in. Required for crm_auto_create_deal to do anything.
crm_initial_stage_id body string no Stage within that pipeline the opportunity starts at.
crm_default_products body array no Product ids attached to the auto-created opportunity.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/patch-voice-agents-agent-id-outbound-config-config-id.md

POST /voice-agents/:agent_id/update-settings Scopes: voice-agents:write

Update provider-native voice-agent settings (pushed to the live agent). Pass the fields to change inside a "settings" object. Then call publish_voice_agent to make them live.

3 parameters
Name In Type Required Description
agent_id path string yes
settings body object yes Provider-native settings to change. Accepts any of: voice_id, voice_speed, voice_temperature, volume, responsiveness, interruption_sensitivity, max_call_duration_ms, end_call_after_silence_ms, voicemail_option, begin_message_delay_ms, and other provider fields.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/post-voice-agents-agent-id-update-settings.md

PATCH /voice-agents/:agent_id/website-config/:config_id Scopes: voice-agents:write

Update a voice-agent website config: the per-visitor and global call rate limits, and the CRM routing for callers who identify themselves. Use this to loosen the limit for testing (then put it back) or to change which pipeline web-call leads land in.

12 parameters
Name In Type Required Description
agent_id path string yes
config_id path string yes
website_id body string no
rate_limit_max_requests body number no Max calls ONE visitor (per IP / browser fingerprint / email / phone) may start per window. Default 2.
rate_limit_window_hours body number no Length of the per-visitor rate-limit window, in hours. Default 24.
global_rate_limit_max_requests body number no Max calls ALL visitors combined may start per window, i.e. the spend ceiling. Default 50.
global_rate_limit_window_hours body number no Length of the global rate-limit window, in hours. Default 24.
crm_auto_create_deal body boolean no Whether a caller who identifies themselves also gets an opportunity created, not just a contact.
crm_pipeline_id body string no Pipeline the auto-created opportunity lands in. Required for crm_auto_create_deal to do anything.
crm_initial_stage_id body string no Stage within that pipeline the opportunity starts at.
crm_default_products body array no Product ids attached to the auto-created opportunity.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agents/patch-voice-agents-agent-id-website-config-config-id.md

Agent Knowledge Bases (8 endpoints)

Manage Retell-backed knowledge bases for voice agents. Each KB stores documents that agents can retrieve during calls. KBs can be seeded from help center articles or populated with custom content. Required scopes: voice-kbs:read, voice-kbs:write, voice-kbs:delete. NOTE: Retell KB write API (create and add-sources) is occasionally unavailable -- if create or add_doc returns a 500, this is a Retell-side outage, not a TrustPager bug.

📄 Full markdown: /api/voice-agent-kbs.md

POST /voice-agent-kbs/:kb_id/documents Scopes: voice-kbs:write

Add a document (title + text) to a voice-agent KB.

4 parameters
Name In Type Required Description
kb_id path string yes
title body string yes
text body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agent-kbs/post-voice-agent-kbs-kb-id-documents.md

POST /voice-agent-kbs Scopes: voice-kbs:write

Create a new voice-agent knowledge base (Retell-backed).

3 parameters
Name In Type Required Description
name body string yes
description body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agent-kbs/post-voice-agent-kbs.md

DELETE /voice-agent-kbs/:kb_id Scopes: voice-kbs:delete

Delete a voice-agent KB (Retell + local).

2 parameters
Name In Type Required Description
kb_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agent-kbs/delete-voice-agent-kbs-kb-id.md

DELETE /voice-agent-kbs/:kb_id/documents/:doc_id Scopes: voice-kbs:delete

Remove a document from a voice-agent KB.

3 parameters
Name In Type Required Description
kb_id path string yes
doc_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agent-kbs/delete-voice-agent-kbs-kb-id-documents-doc-id.md

POST /voice-agent-kbs/:kb_id/sync-help-center Scopes: voice-kbs:write

Sync help-center articles into a voice-agent KB.

2 parameters
Name In Type Required Description
kb_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-agent-kbs/post-voice-agent-kbs-kb-id-sync-help-center.md

VOICE_CALL_DIRECTIVES (5 endpoints)

voice-call-directives endpoints.

📄 Full markdown: /api/voice-call-directives.md

POST /voice-directives Scopes: voice-directives:write

Create a call directive. For business_hours_forward, config needs forward_to (E.164), windows, timezone, and mode.

6 parameters
Name In Type Required Description
directive_type body string yes
voice_agent_config_id body string no
enabled body boolean no
priority body number no
config body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-call-directives/post-voice-directives.md

DELETE /voice-directives/:directive_id Scopes: voice-directives:delete

Delete a call directive.

2 parameters
Name In Type Required Description
directive_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-call-directives/delete-voice-directives-directive-id.md

GET /voice-directives Scopes: voice-directives:read

List call directives (e.g. business-hours forwarding) for the workspace.

4 parameters
Name In Type Required Description
directive_type query string no
voice_agent_config_id query string no
enabled query string no
limit query number no

📄 /api/voice-call-directives/get-voice-directives.md

PATCH /voice-directives/:directive_id Scopes: voice-directives:write

Update a call directive (enable/disable, priority, config).

5 parameters
Name In Type Required Description
directive_id path string yes
enabled body boolean no
priority body number no
config body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voice-call-directives/patch-voice-directives-directive-id.md

Voice Agent Toolkit (11 endpoints)

Endpoints your voice agents call mid-conversation to check availability and book, reschedule or cancel an appointment for the caller.

📄 Full markdown: /api/agent-toolkit-voice.md

POST /agent/v1/voice/scheduling/:event_type_id/book Scopes: agent_toolkit:use

Voice agent toolkit — book an appointment for the caller.

3 parameters
Name In Type Required Description
event_type_id path string yes
slot body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-scheduling-event-type-id-book.md

POST /agent/v1/voice/cancel-booking Scopes: agent_toolkit:use

Voice agent toolkit — cancel a booking keyed by caller phone.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-cancel-booking.md

POST /agent/v1/voice/pricing Scopes: agent_toolkit:use

Voice agent toolkit (optional, opt-in per agent) — read the workspace live product pricing from the catalogue so the agent never quotes prices from memory. Wire this tool only into agents whose workspace wants pricing shared by voice.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-pricing.md

POST /agent/v1/voice/request-callback Scopes: agent_toolkit:use

Voice agent toolkit — record a callback request.

2 parameters
Name In Type Required Description
reason body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-request-callback.md

POST /agent/v1/voice/reschedule-booking Scopes: agent_toolkit:use

Voice agent toolkit — reschedule a booking keyed by caller phone.

2 parameters
Name In Type Required Description
slot body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-reschedule-booking.md

POST /agent/v1/voice/schedule-callback Scopes: agent_toolkit:use

Voice agent toolkit — schedule an automatic AI callback at the time the caller requested (rings them back from the agent's outbound number). Pass callback_day + callback_time + state; the server resolves the absolute date in the caller's timezone, so never compute a date yourself.

4 parameters
Name In Type Required Description
callback_day body string no Day to call back: "today", "tomorrow", a weekday, or YYYY-MM-DD. Do NOT compute a date.
callback_time body string yes Clock time the caller wants, e.g. "3pm", "2:30pm", "14:00".
state body string no Caller state/territory for timezone (e.g. QLD, NSW, VIC).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-schedule-callback.md

POST /agent/v1/voice/take-message Scopes: agent_toolkit:use

Voice agent toolkit — log an inbound message from the caller.

2 parameters
Name In Type Required Description
message body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-take-message.md

POST /agent/v1/voice/unsubscribe Scopes: agent_toolkit:use

Voice agent toolkit: stop contacting the caller. A caller we recognise is unsubscribed across their contact records; a caller we do not recognise has their number added to the voice do-not-call list, so an opt-out is always honoured.

2 parameters
Name In Type Required Description
channel body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-toolkit-voice/post-agent-v1-voice-unsubscribe.md

Knowledge Bases (14 endpoints)

Knowledge bases that ground your voice and workflow agents, plus the entries and sources inside them.

📄 Full markdown: /api/knowledge-bases.md

POST /knowledge-bases/adopt Scopes: knowledge:write

Adopt an existing voice-provider knowledge base into the unified system: links it in place (no duplicate), imports its web-page sources into search, and attaches any voice agents already using it. Pass retell_kb_id.

3 parameters
Name In Type Required Description
retell_kb_id body string yes
name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-adopt.md

POST /knowledge-bases/:kb_id/attach Scopes: knowledge:write

Attach a knowledge base to an agent so the agent's searches are grounded in it. agent_type is 'voice' or 'workflow'; agent_id is the voice agent or workflow agent UUID.

4 parameters
Name In Type Required Description
kb_id path string yes
agent_type body string yes
agent_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-kb-id-attach.md

POST /knowledge-bases Scopes: knowledge:write

Create a named knowledge base. Populate it via sync-help-center, sync-products, or by creating entries with this kb_id, then attach it to agents.

5 parameters
Name In Type Required Description
name body string yes
description body string no
auto_resync_enabled body boolean no
resync_frequency body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases.md

DELETE /knowledge-bases/:kb_id Scopes: knowledge:delete

Delete a knowledge base. Its entries are kept (unlinked); agent attachments are removed.

2 parameters
Name In Type Required Description
kb_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/delete-knowledge-bases-kb-id.md

POST /knowledge-bases/:kb_id/detach Scopes: knowledge:write

Detach a knowledge base from an agent. The KB and its entries are kept.

4 parameters
Name In Type Required Description
kb_id path string yes
agent_type body string yes
agent_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-kb-id-detach.md

GET /knowledge-bases/:kb_id Scopes: knowledge:read

Fetch a knowledge base by UUID, with entry and attached-agent counts.

1 parameter
Name In Type Required Description
kb_id path string yes

📄 /api/knowledge-bases/get-knowledge-bases-kb-id.md

POST /knowledge-bases/:kb_id/ingest-text Scopes: knowledge:write

Add a block of text (e.g. an uploaded document's content) to a knowledge base as an embedded entry.

5 parameters
Name In Type Required Description
kb_id path string yes
title body string yes
text body string yes
source_ref body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-kb-id-ingest-text.md

POST /knowledge-bases/:kb_id/ingest-url Scopes: knowledge:write

Fetch a web page, extract its text, and add it to a knowledge base as an embedded entry. Idempotent per URL.

3 parameters
Name In Type Required Description
kb_id path string yes
url body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-kb-id-ingest-url.md

GET /knowledge-bases/:kb_id/entries Scopes: knowledge:read

List the entries (documents) inside a knowledge base.

3 parameters
Name In Type Required Description
kb_id path string yes
limit query number no
after query string no

📄 /api/knowledge-bases/get-knowledge-bases-kb-id-entries.md

GET /knowledge-bases Scopes: knowledge:read

List knowledge bases in the workspace. Pass agent_type + agent_id to list only the KBs attached to a given voice or workflow agent.

2 parameters
Name In Type Required Description
agent_type query string no
agent_id query string no

📄 /api/knowledge-bases/get-knowledge-bases.md

POST /knowledge-bases/:kb_id/sync-help-center Scopes: knowledge:write

Ingest help-center articles into a knowledge base as embedded entries. Pass article_ids to select specific articles, or omit to sync all. Idempotent.

3 parameters
Name In Type Required Description
kb_id path string yes
article_ids body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-kb-id-sync-help-center.md

POST /knowledge-bases/:kb_id/sync-products Scopes: knowledge:write

Ingest the active CRM product catalog into a knowledge base as embedded entries. Idempotent.

2 parameters
Name In Type Required Description
kb_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/post-knowledge-bases-kb-id-sync-products.md

PATCH /knowledge-bases/:kb_id Scopes: knowledge:write

Update a knowledge base (name, description, auto-resync settings).

6 parameters
Name In Type Required Description
kb_id path string yes
name body string no
description body string no
auto_resync_enabled body boolean no
resync_frequency body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge-bases/patch-knowledge-bases-kb-id.md

Text Agents (6 endpoints)

Text agents are now part of the unified /agents endpoint. Use GET /agents?type=text to list text agents. See the Agents resource group for full documentation.

📄 Full markdown: /api/text-agents.md

GET /agents/:id Scopes: voice-agents:read

Retrieve a text agent. Auto-detects type.

1 parameter
Name In Type Required Description
id path uuid yes Text agent ID

📄 /api/text-agents/get-agents-id.md

POST /agents Scopes: voice-agents:write

Create a text agent. Include "type": "text" and "name" in the request body.

2 parameters
Name In Type Required Description
type body string yes Must be "text"
name body string yes Agent name

📄 /api/text-agents/post-agents.md

PATCH /agents/:id Scopes: voice-agents:write

Update a text agent. Auto-detects type.

1 parameter
Name In Type Required Description
id path uuid yes Text agent ID

📄 /api/text-agents/patch-agents-id.md

DELETE /agents/:id Scopes: voice-agents:write

Delete a text agent. Auto-detects type.

1 parameter
Name In Type Required Description
id path uuid yes Text agent ID

📄 /api/text-agents/delete-agents-id.md

GET /agents/:id/responses Scopes: voice-agents:read

List responses generated by a text agent.

1 parameter
Name In Type Required Description
id path uuid yes Text agent ID

📄 /api/text-agents/get-agents-id-responses.md

Transcripts (10 endpoints)

Transcribe call recordings and meetings, view results, and access AI coaching. Use POST /transcripts/transcribe to kick off transcription from any audio URL. Coaching results are under /transcripts/coaching.

📄 Full markdown: /api/transcripts.md

DELETE /transcripts/:transcript_id Scopes: transcripts:delete

Delete a transcript by UUID. Destructive — also removes associated recording from storage.

2 parameters
Name In Type Required Description
transcript_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/transcripts/delete-transcripts-transcript-id.md

GET /transcripts/:transcript_id Scopes: transcripts:read

Fetch a single transcript by UUID — full text + speaker segments. Use with ai_transcript_summary for highlights.

1 parameter
Name In Type Required Description
transcript_id path string yes

📄 /api/transcripts/get-transcripts-transcript-id.md

GET /transcripts/coaching Scopes: transcripts:read

List AI call-coaching results across all transcripts.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/transcripts/get-transcripts-coaching.md

GET /transcripts Scopes: transcripts:read

List call and meeting transcripts. Filter by participant (email or phone), type, source, status, or date. Use before ai_transcript_summary.

11 parameters
Name In Type Required Description
limit query number no
after query string no
type query string no phone_call -> /inbox/phone-calls, meeting -> /inbox/meetings.
source query string no Producer label (e.g. retell, recall, twilio-call, api).
transcription_status query string no Only "complete" rows have transcript_text.
occurred_after query string no ISO timestamp lower bound on occurred_at.
occurred_before query string no ISO timestamp upper bound on occurred_at.
participant_email query string no Find transcripts where a participant has this email (exact match).
participant_phone query string no Find transcripts where a participant has this phone. Digit-normalised last-9 match, so 0408119890, +61408119890 and 61408119890 all resolve to the same calls.
booking_id query string no Transcript recorded during a specific scheduling booking.
query query string no Partial, case-insensitive search on the transcript title.

📄 /api/transcripts/get-transcripts.md

POST /transcripts/:transcript_id/recording/rehost Scopes: transcripts:write

Re-host a transcript recording from external storage into the workspace bucket.

2 parameters
Name In Type Required Description
transcript_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/transcripts/post-transcripts-transcript-id-recording-rehost.md

POST /transcripts/transcribe Scopes: transcripts:write

Kick off transcription of an audio/video recording via Whisper. Lands as a transcript in /inbox/phone-calls or /inbox/meetings and creates a single linked crm_activities row. Pass deal_id/contact_id when known at recording time to authoritatively link the activity (skips post-hoc phone/email matching). Set participants[].role to "caller" for the workspace user side so their email/phone is excluded from contact-matching.

14 parameters
Name In Type Required Description
recording_url body string yes Publicly fetchable HTTPS URL, or a TrustPager-rehosted private R2 URL. For raw Twilio recording URLs also pass recording_auth.
recording_auth body string no Optional basic-auth credentials "USER:PASSWORD". For Twilio: "ACCOUNT_SID:AUTH_TOKEN".
title body string yes Display title shown on the transcript and on the auto-created activity.
type body string yes phone_call (or alias "call") -> /inbox/phone-calls. meeting -> /inbox/meetings. voicemail -> /inbox.
source body string no Producer label for filtering later. Defaults to "api".
source_id body string no Optional foreign key in the producer system (call_sid, upload_id). Stored on metadata.
occurred_at body string no ISO timestamp the audio was captured. Defaults to now.
participants body array no Speakers on the recording. Used for diarisation AND for auto-linking to contacts/deals (by email and phone-last-9). Set role="caller" on the workspace-user side to exclude them from contact-matching.
metadata body object no Free-form metadata to attach to the transcript row.
contact_id body string no Authoritative callee contact known at recording time (e.g. softphone dialed from a contact card). Overrides the matcher's best guess for the activity's contact_id.
deal_id body string no Authoritative opportunity known at recording time (e.g. softphone dialed from an opportunity page). The activity is linked directly to this deal instead of being inferred by phone/email matching.
model body string no Override the workspace default. whisper-1 is forced internally regardless (needed for verbose_json diarisation).
existing_transcript_id body string no UUID of an existing transcript to overwrite. Used for fallback/retry flows.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/transcripts/post-transcripts-transcribe.md

PATCH /transcripts/:transcript_id Scopes: transcripts:write

Update a transcript (e.g. rename, re-link to a contact/deal).

5 parameters
Name In Type Required Description
transcript_id path string yes
title body string no
contact_id body string no Re-link this transcript to a contact. Replaces the existing contact link; pass null to unlink.
deal_id body string no Re-link this transcript to an opportunity. Replaces the existing opportunity link; pass null to unlink.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/transcripts/patch-transcripts-transcript-id.md

Document Templates (13 endpoints)

Manage document templates with sections for proposals, contracts, and more.

📄 Full markdown: /api/document-templates.md

POST /document-templates/:template_id/sections Scopes: documents:write

Add a section to a document template.

7 parameters
Name In Type Required Description
template_id path string yes
type body string yes Section type in kebab-case. One of: cover-page, text-block, two-column, table, product-table, product-showcase, image-block, signature-block, signer-input, divider, page-break, quote-callout, terms-conditions, guarantee, doc-header, doc-footer, dynamic-pricing, dynamic-products, dynamic-images, dynamic-timeline, dynamic-executive-summary, dynamic-needs-solutions, dynamic-recommendations, dynamic-callout, dynamic-guarantee, rich-content, raw-html, product-brochure, referrer-statement-info, referrer-commission-items.
content body object no Section body. Shape depends on type, e.g. rich-content: { html, tiptapJson }; text-block: { heading, text }; dynamic-images: { heading, source: "opportunity_images" (the only supported source), columns: 1|2|3, startIndex, limit, aspect: "original"|"square"|"4:3"|"16:9", captionFrom: "none"|"filename"|"label" (label = the photo tags), label }. On dynamic-images, `label` is the "Only Photos Tagged" filter: a photo is included when any of its file tags matches it, case-insensitively (e.g. "Before"). Leave it blank for all photos.
styling body object no Styling overrides, e.g. backgroundColor, paddingTop, paddingBottom.
order_index body number no Display order (1-based). Sections render ascending.
is_visible body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/post-document-templates-template-id-sections.md

POST /document-templates Scopes: documents:write

Create a document template.

2 parameters
Name In Type Required Description
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/post-document-templates.md

DELETE /document-templates/:template_id/sections/:section_id Scopes: documents:delete

Delete a section.

3 parameters
Name In Type Required Description
template_id path string yes
section_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/delete-document-templates-template-id-sections-section-id.md

DELETE /document-templates/:template_id Scopes: documents:delete

Delete a document template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/delete-document-templates-template-id.md

POST /document-templates/:template_id/duplicate Scopes: documents:write

Duplicate a document template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/post-document-templates-template-id-duplicate.md

POST /document-templates/:template_id/render Scopes: documents:write

Render a document template to PDF and save to the file library (costs credits). Pass deal_id to auto-fill {{tokens}} from that opportunity. Set preview:true for a FREE dry-run that returns the rendered HTML + any unresolved_tokens WITHOUT saving or charging — use it to validate merge fields before send_for_signing (which resolves strictly and blocks on any gap).

9 parameters
Name In Type Required Description
template_id path string yes
deal_id body string no Opportunity to resolve merge tokens from.
preview body boolean no true = free dry-run: return html + unresolved_tokens + would_send, no PDF saved, no credits charged.
variables body object no Extra {{token}} values merged on top of the opportunity data.
strict_tokens body boolean no true = fail if any token is unresolved (ignored when preview:true).
folder body string no
filename body string no
document_type body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/post-document-templates-template-id-render.md

POST /document-templates/:template_id/sections/reorder Scopes: documents:write

Reorder sections in a document template.

3 parameters
Name In Type Required Description
template_id path string yes
section_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/post-document-templates-template-id-sections-reorder.md

POST /document-templates/:template_id/send Scopes: documents:write

Render a document template to PDF and email it to a recipient in one call. Costs credits (PDF render). Use render_document_template with preview:true first to validate merge fields — this call resolves tokens strictly and fails on any unresolved {{token}} in the document body or the email subject/message.

12 parameters
Name In Type Required Description
template_id path string yes
deal_id body string no Opportunity to resolve {{tokens}} from, and (with recipient_source contact/account) the recipient. Required unless recipient_source is "custom".
recipient_source body string yes "contact"/"account" resolve the recipient from deal_id's linked contact/company. "custom" uses recipient_email/recipient_name directly.
recipient_email body string no Required when recipient_source is "custom"; used as a fallback otherwise.
recipient_name body string no
email_subject body string yes May contain {{tokens}} (e.g. {{deal.name}}). Must fully resolve.
email_message body string yes May contain {{tokens}}. Must fully resolve.
intro_html body string no Per-call HTML override for the branded email intro — wins over the workspace/per-template default for this send only.
subject_override body string no Per-call subject override (plain text, may contain {{tokens}}).
variables body object no Extra {{token}} values merged on top of the opportunity data.
document_type body string no crm_documents.document_type. Defaults to "Other".
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/post-document-templates-template-id-send.md

PATCH /document-templates/:template_id/sections/:section_id Scopes: documents:write

Update a section. Partial: only the fields you pass are changed. Note that content is replaced wholesale, not deep-merged, so send the whole body.

8 parameters
Name In Type Required Description
template_id path string yes
section_id path string yes
type body string no Section type in kebab-case. One of: cover-page, text-block, two-column, table, product-table, product-showcase, image-block, signature-block, signer-input, divider, page-break, quote-callout, terms-conditions, guarantee, doc-header, doc-footer, dynamic-pricing, dynamic-products, dynamic-images, dynamic-timeline, dynamic-executive-summary, dynamic-needs-solutions, dynamic-recommendations, dynamic-callout, dynamic-guarantee, rich-content, raw-html, product-brochure, referrer-statement-info, referrer-commission-items.
content body object no Section body, replaced wholesale. Shape depends on type, e.g. rich-content: { html, tiptapJson } (html is what the PDF renderer reads, tiptapJson is what the document builder editor loads, so keep both in step).
styling body object no Styling overrides, e.g. backgroundColor, paddingTop, paddingBottom.
order_index body number no Display order (1-based). Sections render ascending.
is_visible body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/patch-document-templates-template-id-sections-section-id.md

PATCH /document-templates/:template_id Scopes: documents:write

Update a document template.

15 parameters
Name In Type Required Description
template_id path string yes
name body string no
description body string no
category body string no
page_size body string no
page_margins body object no
brand_colors body object no
brand_typography body object no
header body object no
footer body object no
filename_template body string no
is_archived body boolean no
email_template_settings body object no
signing_settings body object no Signing delivery: { deliver: "email"|"portal", portalTemplateId, sendEmail }.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/document-templates/patch-document-templates-template-id.md

Signing (5 endpoints)

Manage e-signature envelopes. Send documents for signing and track completion status.

📄 Full markdown: /api/signing.md

GET /signing/envelopes/:envelope_id Scopes: documents:read

Fetch a signing envelope by UUID — signer status, document state, and the full audit trail (crm_signing_audit_log: sent/viewed/signed/split_generated/certificate_delivered/sealed_pdf_generated events, each with a metadata payload — e.g. emailed_to / shared_portal_ids for delivery events).

1 parameter
Name In Type Required Description
envelope_id path string yes

📄 /api/signing/get-signing-envelopes-envelope-id.md

GET /signing/envelopes Scopes: documents:read

List e-signing envelopes (documents sent for signature).

4 parameters
Name In Type Required Description
limit query number no
after query string no
status query string no
deal_id query string no

📄 /api/signing/get-signing-envelopes.md

POST /signing/envelopes/:envelope_id/resend Scopes: signing:send

Resend a signing envelope (re-deliver the request to a specific pending signer). Use get_signing_envelope first to find the recipient_id (crm_signing_recipients[].id) for the signer to resend to.

3 parameters
Name In Type Required Description
envelope_id path string yes
recipient_id body string yes The pending signer to resend to (crm_signing_recipients.id, from get_signing_envelope).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/signing/post-signing-envelopes-envelope-id-resend.md

POST /signing/send Scopes: signing:send

Send a document for e-signature. Requires a template and signers, plus an anchor: either deal_id (an opportunity) or referrer_contact_id (a referrer contact). Costs credits. Two delivery modes: default emails the signer a standalone e-sign link; deliver:"portal" instead surfaces the signing item inside the anchored client portal (find-or-created from portal_template_id) and SUPPRESSES the standalone email, so the signer signs in the portal reached via the portal invite. Set show_in_portal:true (additive) to surface the item in the portal AND still email the link.

12 parameters
Name In Type Required Description
template_id body string yes
signers body array yes
deal_id body string no Opportunity anchor. Provide this OR referrer_contact_id. (opportunity_id is accepted as an alias.)
opportunity_id body string no Alias for deal_id (the opportunity anchor).
referrer_contact_id body string no Referrer anchor (a crm_contacts id). Provide this OR deal_id. The portal is anchored to this contact.
subject body string no
message body string no
deliver body string no Delivery mode. "email" (default) sends the standalone e-sign link. "portal" surfaces the item in the anchored portal and suppresses the email.
portal_template_id body string no Portal template to stamp a fresh portal from when none exists for the anchor (used with deliver:"portal").
portal_members body array no Extra people to invite to the portal as members/viewers beyond the signers (deliver:"portal"). Each { email, name? }. Signers are invited automatically.
show_in_portal body boolean no Additive: surface the signing item inside the anchored client portal AND still email the link. Default false.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/signing/post-signing-send.md

POST /signing/envelopes/:envelope_id/void Scopes: signing:send

Void a sent envelope (cancel the signing request).

2 parameters
Name In Type Required Description
envelope_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/signing/post-signing-envelopes-envelope-id-void.md

Forms (25 endpoints)

Create form templates, manage fields, send forms to contacts, and view submissions. Field types: text, textarea, number, date, select, checkbox, radio, file, spreadsheet, email, phone, url, currency, consent, rating, abn. Fields support CRM Variable Injection - map a field to a CRM variable so submitted values are written back to the linked deal, contact, or account before automations run. Set settings.public_mode=true to make a form publicly submittable (auto-creates contacts and opportunities on each submission).

📄 Full markdown: /api/forms.md

POST /forms/templates/:template_id/fields Scopes: forms:write

Add a field to a form template. The content JSON carries per-field config: static min/max on number fields (content.min/max), conditional visibility (content.visibility), and CROSS-FIELD VALIDATION on number/date fields via content.validation = { match: 'all'|'any', rules: [{ operator: 'lte'|'gte'|'lt'|'gt'|'date_after'|'date_before', target: { kind: 'literal', value: <number> } OR { kind: 'field', fieldId: '<other field id>', factor?: <number>, divideBy?: <number> }, message: '<shown when it fails>' }] }. Blocks submission when the value breaks the rule (e.g. IP benefit <= 70% of annual income / 12 => operator 'lte', target { kind:'field', fieldId:'<income field>', factor:0.7, divideBy:12 }); the target can be any other same-type field.

12 parameters
Name In Type Required Description
template_id path string yes UUID of the form template to add the field to.
type body string yes Field type, e.g. text, textarea, email, phone, number, date, select, checkbox, radio, file, heading. Drives how the field renders and validates on the public form.
label body string yes Visible label for the field on the public form.
placeholder body string no Placeholder text shown inside the empty input.
description body string no Helper text shown under the field to explain what to enter.
is_required body boolean no Whether the form cannot be submitted without this field.
is_visible body boolean no Whether the field renders at all. False hides it without deleting it or losing existing answers.
order_index body number no Position of the field within its step. Fields render in ascending order.
step_number body number no Which step of a multi-step form this field belongs to. Starts at 1.
content body object no Per-field JSON config: options, crm_variable/crm_variable_mode, min/max, visibility, and validation (cross-field rule set; see the tool description).
styling body object no Per-field presentation overrides (width, alignment and similar). Full-replace on write.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates-template-id-fields.md

POST /forms/templates/:template_id/archive Scopes: forms:write

Archive a form template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates-template-id-archive.md

POST /forms/templates/:template_id/wiring Scopes: forms:write

Bulk-set CRM-variable wiring on form fields.

4 parameters
Name In Type Required Description
template_id path string yes
mappings body array no Each entry is { field_id, crm_variable, crm_variable_mode }.
create_custom_fields body array no Custom fields to persist on company_settings before mapping. Each is { label, type, entity, options? }.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates-template-id-wiring.md

POST /forms/folders Scopes: forms:write

Create a form folder.

2 parameters
Name In Type Required Description
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-folders.md

POST /forms/templates Scopes: forms:write

Create a form template.

7 parameters
Name In Type Required Description
name body string yes Form name shown in the Forms list and as the default heading on the public form.
description body string no Short description of the form, shown under the heading on the public form.
settings body object no Free-form per-template config. On update_form_template the top-level keys you send are MERGED into the stored settings - unrelated keys (e.g. public_mode, completionMessage) are preserved, so you can PATCH a single key without fetching first. To clear a key, send it explicitly as null (omitting it keeps the stored value). Note create_form_template writes settings as given (there is nothing to merge into). Known keys: public_mode (bool) - form must have this true to be publicly submittable via submit_public_form / the hosted form page. public_pipeline_id / public_stage_id (uuid) - where a newly-created opportunity lands; falls back to the workspace default pipeline then its first stage. public_lead_source (string) - lead_source recorded on the new contact/deal, defaults to "Public form". public_deal_behavior ("create" default | "update_or_create" | "never_create") - controls whether a submission from a contact who already has a matching deal updates that deal instead of always creating a new one. "never_create" only ever attaches to an existing match and never creates a deal. Mirrors booking_deal_behavior on scheduled event types. public_match_fields (string[], default ["email"]) - which identity fields to match an existing contact on. "name" is never honoured (fuzzy-name-collision risk). public_match_pipeline_id (uuid) - restrict deal matching to one pipeline; unset searches all pipelines. public_match_status_filter ("all" | "open" | "won" | "lost", default "open") - which deal statuses are eligible to match. public_match_strategy ("most_recent" | "highest_value" | "oldest", default "most_recent") - tie-breaker when multiple deals match. completionMessage (string), notifyEmails (string[]), submissionFolder (string), archivePdfOnSubmit (bool), stepCount (number), stepHeaders (object) are also recognised builder-managed keys.
folder body string no Folder name this form is filed under in the Forms list. Pass null to move it back to the root.
slug body string no URL-safe segment for the public form link. Changing it changes the public URL and breaks any link already shared.
email_template_settings body object no Per-form override of the email chrome used for this form's invite and completion emails. Takes precedence over the workspace-wide email_template_settings. Shape: { intro_html, subject_override }. Full-replace on write; pass null to fall back to the workspace default.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates.md

POST /forms/submissions/internal-fill Scopes: forms:write

Create an internal-fill submission for staff entry. No email, PIN pre-cleared.

3 parameters
Name In Type Required Description
template_id body string yes
deal_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-submissions-internal-fill.md

DELETE /forms/templates/:template_id/fields/:field_id Scopes: forms:delete

Delete a form field.

3 parameters
Name In Type Required Description
template_id path string yes
field_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/delete-forms-templates-template-id-fields-field-id.md

DELETE /forms/folders/:folder_id Scopes: forms:delete

Delete a form folder.

2 parameters
Name In Type Required Description
folder_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/delete-forms-folders-folder-id.md

DELETE /forms/submissions/:submission_id Scopes: forms:delete

Permanently delete a form submission (and any uploaded files). Optional ?delete_archived_pdf=true also removes the auto-archived PDF in the Documents library. Cannot be undone.

3 parameters
Name In Type Required Description
submission_id path string yes
delete_archived_pdf query boolean no When true, also deletes the auto-archived PDF stored in crm_documents from this submission.
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/delete-forms-submissions-submission-id.md

DELETE /forms/templates/:template_id Scopes: forms:delete

Delete a form template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/delete-forms-templates-template-id.md

POST /forms/templates/:template_id/duplicate Scopes: forms:write

Duplicate a form template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates-template-id-duplicate.md

GET /forms/submissions Scopes: forms:read

List form submissions. Pass include_responses: true to embed every answer inline (same shape as get_form_submission) instead of one call per submission, with signed URLs on uploaded files. Filter on answers with response_field plus response_value / response_value_from / response_value_to. To pull one account's submissions where the form is opportunity-scoped, use deal_customer_id (the account on the opportunity), not customer_id.

13 parameters
Name In Type Required Description
template_id query string no
include_responses query boolean no Embed form_submission_responses inline on each submission, with a files[] array carrying short-lived signed_url values for uploads. Avoids an N+1 of get_form_submission calls.
deal_id query string no Opportunity id, or a comma separated list of them. Alias: opportunity_id.
opportunity_id query string no Alias for deal_id. Accepts a comma separated list.
deal_customer_id query string no Account (customer) id on the OPPORTUNITY, comma separated list allowed. Use this to pull every submission for one account when the form is opportunity-scoped, where each opportunity is a single event and deal_id therefore cannot group them.
contact_id query string no Contact id, or a comma separated list of them.
customer_id query string no Account id set directly on the submission. Usually null on opportunity-scoped forms; prefer deal_customer_id there.
status query string no Submission status, e.g. completed, sent, expired.
response_field query string no Field to filter answers on, by field label or field id. Required to use any response_value filter.
response_value query string no Exact answer match on response_field.
response_value_from query string no Lower bound on response_field. TEXT comparison: correct for ISO dates (2026-05-04), not valid for numbers.
response_value_to query string no Upper bound on response_field. TEXT comparison: correct for ISO dates, not valid for numbers.
limit query number no

📄 /api/forms/get-forms-submissions.md

GET /forms/templates Scopes: forms:read

List form templates.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/forms/get-forms-templates.md

POST /forms/templates/:template_id/fields/reorder Scopes: forms:write

Reorder fields on a form template.

3 parameters
Name In Type Required Description
template_id path string yes
field_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates-template-id-fields-reorder.md

POST /forms/submissions/:submission_id/resend Scopes: forms:write

Resend a form submission invitation.

2 parameters
Name In Type Required Description
submission_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-submissions-submission-id-resend.md

POST /forms/send Scopes: forms:send

Send a form to a recipient. Costs credits. Requires at least one of deal_id, contact_id or customer_id so the submission links to a CRM record. To send to co-applicants (e.g. joint mortgage applicants) pass additional_recipients: they SHARE one submission with the primary recipient, each gets their own link + PIN, all write to the same answers, and any of them can finalize.

14 parameters
Name In Type Required Description
template_id body string yes UUID of the form template to send. Get ids from list_form_templates.
recipient_email body string yes Primary recipient email. Owns the shared submission.
recipient_name body string yes Primary recipient name, used to address the invite email.
deal_id body string no Opportunity to link the submission to. Preferred when the form is opportunity-scoped. At least one of deal_id, contact_id or customer_id is required.
contact_id body string no Contact to link the submission to. Sufficient on its own for a standalone client-profile form. At least one of deal_id, contact_id or customer_id is required.
customer_id body string no Company/account to link the submission to. At least one of deal_id, contact_id or customer_id is required.
personal_message body string no Short personal note from the sender, rendered inside the invite email above the form link.
intro_html body string no HTML body for this send only, overriding the per-template and workspace email chrome. Wins over both.
subject_override body string no Subject line for this send only, overriding the per-template and workspace default.
expires_in_days body number no How many days the form link stays valid. Omit to use the platform default.
notify_emails body array no Addresses to notify when this submission is completed, for this send only. Merged with the per-template and workspace-level notify lists.
additional_recipients body array no Co-applicants who share ONE submission with the primary recipient. Each gets their own secure link + PIN; all write to the same responses; any can submit to finalize.
prefill body object no Prefill values keyed by each field's prefill key (set in the form builder under "Prefill via link"). Seeded onto the submission so the recipient opens the form pre-populated; fields set to hide-when-prefilled are filled silently. Example: { "broker_last_name": "Smith" }.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-send.md

POST /forms/templates/:template_id/submit Scopes: forms:write

Submit a public form. Find-or-creates a contact + opportunity from the submitted answers (matched by the fields wired to contact.email / first_name / last_name / phone / account.name), then writes every wired field onto the records. The template must have public mode enabled. Credit-free.

4 parameters
Name In Type Required Description
template_id path string yes Form template id (must have public mode enabled).
responses body array no Submitted answers.
fields body object no Convenience alternative to responses — an object keyed by form field id with the answer as the value.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-templates-template-id-submit.md

PATCH /forms/templates/:template_id/fields/:field_id Scopes: forms:write

Update a form field. Pass content to change per-field config: min/max, visibility, CRM wiring, or cross-field validation. content.validation = { match: 'all'|'any', rules: [{ operator: 'lte'|'gte'|'lt'|'gt'|'date_after'|'date_before', target: { kind: 'literal', value: <number> } OR { kind: 'field', fieldId: '<other field id>', factor?: <number>, divideBy?: <number> }, message: '<shown when it fails>' }] } (number/date fields; blocks submission on a failing value). Pass { validation: null } inside content to clear it.

13 parameters
Name In Type Required Description
template_id path string yes UUID of the form template the field belongs to.
field_id path string yes UUID of the field to update. Get ids from get_form_template.
type body string no Field type, e.g. text, textarea, email, phone, number, date, select, checkbox, radio, file, heading. Drives how the field renders and validates on the public form.
label body string no Visible label for the field on the public form.
placeholder body string no Placeholder text shown inside the empty input.
description body string no Helper text shown under the field to explain what to enter.
is_required body boolean no Whether the form cannot be submitted without this field.
is_visible body boolean no Whether the field renders at all. False hides it without deleting it or losing existing answers.
order_index body number no Position of the field within its step. Fields render in ascending order.
step_number body number no Which step of a multi-step form this field belongs to. Starts at 1.
content body object no Per-field JSON config: options, crm_variable/crm_variable_mode, min/max, visibility, and validation (cross-field rule set; see the tool description).
styling body object no Per-field presentation overrides (width, alignment and similar). Full-replace on write.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/patch-forms-templates-template-id-fields-field-id.md

PATCH /forms/folders/:folder_id Scopes: forms:write

Update a form folder.

3 parameters
Name In Type Required Description
folder_id path string yes UUID of the form folder to update. Get ids from list_form_folders.
name body string no Folder name shown in the Forms list.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/patch-forms-folders-folder-id.md

PATCH /forms/templates/:template_id Scopes: forms:write

Update a form template.

8 parameters
Name In Type Required Description
template_id path string yes UUID of the form template to update. Get ids from list_form_templates.
name body string no Form name shown in the Forms list and as the default heading on the public form.
description body string no Short description of the form, shown under the heading on the public form.
settings body object no Free-form per-template config. On update_form_template the top-level keys you send are MERGED into the stored settings - unrelated keys (e.g. public_mode, completionMessage) are preserved, so you can PATCH a single key without fetching first. To clear a key, send it explicitly as null (omitting it keeps the stored value). Note create_form_template writes settings as given (there is nothing to merge into). Known keys: public_mode (bool) - form must have this true to be publicly submittable via submit_public_form / the hosted form page. public_pipeline_id / public_stage_id (uuid) - where a newly-created opportunity lands; falls back to the workspace default pipeline then its first stage. public_lead_source (string) - lead_source recorded on the new contact/deal, defaults to "Public form". public_deal_behavior ("create" default | "update_or_create" | "never_create") - controls whether a submission from a contact who already has a matching deal updates that deal instead of always creating a new one. "never_create" only ever attaches to an existing match and never creates a deal. Mirrors booking_deal_behavior on scheduled event types. public_match_fields (string[], default ["email"]) - which identity fields to match an existing contact on. "name" is never honoured (fuzzy-name-collision risk). public_match_pipeline_id (uuid) - restrict deal matching to one pipeline; unset searches all pipelines. public_match_status_filter ("all" | "open" | "won" | "lost", default "open") - which deal statuses are eligible to match. public_match_strategy ("most_recent" | "highest_value" | "oldest", default "most_recent") - tie-breaker when multiple deals match. completionMessage (string), notifyEmails (string[]), submissionFolder (string), archivePdfOnSubmit (bool), stepCount (number), stepHeaders (object) are also recognised builder-managed keys.
folder body string no Folder name this form is filed under in the Forms list. Pass null to move it back to the root.
slug body string no URL-safe segment for the public form link. Changing it changes the public URL and breaks any link already shared.
email_template_settings body object no Per-form override of the email chrome used for this form's invite and completion emails. Takes precedence over the workspace-wide email_template_settings. Shape: { intro_html, subject_override }. Full-replace on write; pass null to fall back to the workspace default.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/patch-forms-templates-template-id.md

POST /forms/submissions/:submission_id/void Scopes: forms:write

Void a form submission.

2 parameters
Name In Type Required Description
submission_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/forms/post-forms-submissions-submission-id-void.md

Websites (32 endpoints)

Manage TrustPager-hosted websites, pages, and page sections.

📄 Full markdown: /api/websites.md

POST /websites/:website_id/deploy/domain Scopes: websites:write

Attach a custom domain to a website's deployment and return the exact DNS record(s) the owner must add at their registrar to point the domain at the site. Attaches both the bare domain and its "www" (or vice-versa) and sets one canonical host, 308-redirecting the other to it. Also stores the records on the website so the UI can show them.

4 parameters
Name In Type Required Description
website_id path string yes
domain body string yes The custom domain to point at the site, e.g. "www.example-client.com".
canonical body string no Which host is canonical: "www" (default) redirects the bare domain to www; "apex" redirects www to the bare domain.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-deploy-domain.md

POST /websites/:website_id/redirect-domains Scopes: websites:write

Point a legacy or secondary domain at a live website as a redirect-only domain: it 301-redirects every visitor (and their path + query) cross-domain to the site, so retired URLs keep their SEO value instead of 404ing. Does NOT serve the site or touch its hosting. website_id is the TARGET site to redirect to. Returns the A/AAAA DNS records the domain owner adds at their registrar to point it at our redirect service. Use for domain consolidations, rebrands, or capturing traffic from an old domain.

3 parameters
Name In Type Required Description
website_id path string yes The TARGET website the legacy domain should redirect to.
redirect_domain body string yes The legacy/secondary domain to redirect FROM, e.g. "oldbrand.com".
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-redirect-domains.md

POST /websites Scopes: websites:write

Create a new website. Registers the site record (site_key, domain, branding) used by public-form embeds and the website lead gateway.

18 parameters
Name In Type Required Description
name body string yes Site name shown in the Websites list. Internal label, not rendered on the site.
domain body string no Live custom domain as a BARE HOSTNAME, e.g. "www.example.com". A pasted full URL is normalized to the bare host on write. Pass null to unset.
staging_domain body string no Preview/staging hostname, bare like `domain`. A pasted full URL is normalized on write. Pass null to unset.
is_public body boolean no Whether the published site is reachable. False keeps it deployed but private.
brand_colors body object no Site colour palette, e.g. { "primary": "#0f172a", "secondary": "#38bdf8", "accent": "#f97316" }. Full-replace on write.
brand_typography body object no Font choices for the site, e.g. { "heading": "Inter", "body": "Inter" }. Full-replace on write.
navbar body object no Navigation bar configuration: links, layout and CTA. Full-replace on write — read the current value first and send it back modified.
footer body object no Footer configuration: columns, links, social and legal text. Full-replace on write.
lead_gen_form body object no Lead-capture form config for the site. Submissions post to the public website trigger endpoint using the site_key and land in the CRM. Full-replace on write.
default_meta_title body string no Fallback <title> for pages that do not set their own. Per-page values win.
default_meta_description body string no Fallback meta description for pages that do not set their own. Per-page values win.
default_og_image body string no Absolute URL of the fallback Open Graph / social share image (1200x630).
google_tag_manager_id body string no Google Tag Manager container id, e.g. "GTM-XXXXXXX". Injected into every page.
microsoft_clarity_id body string no Microsoft Clarity project id. Injected into every page.
header_scripts body string no Raw HTML injected into <head> on every page. Runs on the live site — only add markup you trust.
footer_scripts body string no Raw HTML injected before </body> on every page. Runs on the live site — only add markup you trust.
github_repo body string no Repository backing this site, as "owner/repo". Connects the site to its source; the deploy fields themselves are managed and not writable here.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites.md

POST /websites/:website_id/repo Scopes: websites:write

Create a GitHub repository for this website in our org (from the website starter template) and store it on the website record. Use this to spin up a brand-new site before provisioning its deployment. Optional: repo_name, private (default true), description.

5 parameters
Name In Type Required Description
website_id path string yes
repo_name body string no Repository name (defaults to a slug of the website name).
private body boolean no Whether the repo is private. Defaults to true.
description body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-repo.md

POST /websites/:website_id/turnstile Scopes: websites:write

Set up bot protection (Turnstile) for a website: creates a bot-protection widget scoped to the site's domain and enables verification on its public forms. The website needs a domain or a deployed URL first. Optional mode: managed (default, shows a checkbox when the visitor looks suspicious), non-interactive (near-invisible, no checkbox), invisible (fully invisible).

3 parameters
Name In Type Required Description
website_id path string yes
mode body string no Widget interaction mode. Defaults to managed.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-turnstile.md

DELETE /websites/:website_id Scopes: websites:delete

Delete a website and its associated content. This action cannot be undone.

2 parameters
Name In Type Required Description
website_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/delete-websites-website-id.md

DELETE /websites/:website_id/analytics Scopes: websites:write

Turn traffic reporting off for a website and stop collecting its page views. Historical data is discarded. The tracking snippet can be left in the site; it reports nowhere once this is done.

2 parameters
Name In Type Required Description
website_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/delete-websites-website-id-analytics.md

POST /websites/:website_id/analytics Scopes: websites:write

Connect a website to traffic reporting, so its page views and broken URLs can be read straight from the website record instead of the client's own analytics. Requires that Web Analytics has already been switched on for this site in the hosting dashboard (a one-time manual step); this finds that and links it to the website record. Returns a tracking snippet that must be added to the site's <head> before any data arrives; nothing is reported until it is. Safe to call twice: an already-connected site returns its existing snippet.

2 parameters
Name In Type Required Description
website_id path string yes UUID of the website. Get ids from list_websites.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-analytics.md

GET /websites/:website_id Scopes: websites:read

Fetch a website by UUID, including site_key, domain, branding, navbar, footer, and SEO configuration.

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id.md

GET /websites/:website_id/broken-urls Scopes: websites:read

Find the URLs on a website that visitors are hitting but that are not real pages, worst first. For each one: the actual HTTP status (checked live, so 404 means 404), how many page views it took, and the referrer sending people there, which is what tells you whether to fix a link or add a redirect. Answers "which page is broken and how badly". Compares real traffic against the site's own sitemap, then status-checks the top 25 suspects. Requires traffic reporting to be on (enable_website_traffic_reporting).

3 parameters
Name In Type Required Description
website_id path string yes UUID of the website. Get ids from list_websites.
from query string no Start of the window, YYYY-MM-DD or an ISO timestamp. Defaults to 7 days ago.
to query string no End of the window, YYYY-MM-DD or an ISO timestamp. Defaults to now.

📄 /api/websites/get-websites-website-id-broken-urls.md

GET /websites/:website_id/deploy/status Scopes: websites:read

Get the current deployment status for a website (building, live, or error), including the latest build stage, deployment URL, and when it last deployed.

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id-deploy-status.md

GET /websites/:website_id/deploy/domain Scopes: websites:read

Check whether a website's attached custom domain has verified (DNS propagated) and return the stored DNS records. Each host also reports "recoverable": true when the domain provider has stopped trying to verify it, which means the owner's DNS is NOT the problem and retry_website_domain is needed - do not tell the owner to re-check their DNS in that case.

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id-deploy-domain.md

GET /websites/:website_id/integration-guides/:system Scopes: websites:read

Get the full copy-paste guide for wiring one TrustPager system into a website, pre-filled with this site's real site_key + slug (and its Turnstile Site Key, if Bot Protection is on). Hand the returned "guide" text straight to a web designer or their AI. system: notepads, email, documents, forms, scheduling, order-forms, stripe, ecommerce, docusign, voice-agent, voice-agent-outbound, outgoing-webhook, native-integrations, turnstile. Call list_website_integration_guides to see them all.

2 parameters
Name In Type Required Description
website_id path string yes
system path string yes Which system to integrate: notepads | email | documents | forms | scheduling | order-forms | stripe | ecommerce | docusign | voice-agent | voice-agent-outbound | outgoing-webhook | native-integrations | turnstile.

📄 /api/websites/get-websites-website-id-integration-guides-system.md

GET /websites/:website_id/traffic Scopes: websites:read

Get a website's traffic: page views and visits for a date range, grouped by page path (default), referrer, country, device, browser, or date. Answers "is traffic up or down since we changed X" and "which pages do people actually read". Bot traffic is excluded. Requires traffic reporting to be on (enable_website_traffic_reporting). For finding broken URLs specifically, use get_website_broken_urls instead.

5 parameters
Name In Type Required Description
website_id path string yes UUID of the website. Get ids from list_websites.
from query string no Start of the window, YYYY-MM-DD or an ISO timestamp. Defaults to 7 days ago. Windows wider than 92 days are rejected, and data older than 7 days is sampled by the hosting layer.
to query string no End of the window, YYYY-MM-DD or an ISO timestamp. Defaults to now.
group_by query string no What to break the numbers down by. Defaults to path.
limit query number no Maximum rows to return, 1 to 500. Defaults to 50.

📄 /api/websites/get-websites-website-id-traffic.md

GET /websites/:website_id/analytics Scopes: websites:read

Check whether traffic reporting is on for a website, whether its tracking snippet is installed on the live site, and get the snippet to install. Call this first if get_website_traffic or get_website_broken_urls returns no data.

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id-analytics.md

GET /websites/:website_id/turnstile Scopes: websites:read

Get a website's bot protection status: whether it's configured, enabled, its widget mode, and its Turnstile Site Key (the public key custom-built forms render the Turnstile widget with). Never returns the widget secret.

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id-turnstile.md

GET /websites/:website_id/integration-guides Scopes: websites:read

List the copy-paste integration guides available for a website (e.g. blog). Each entry says whether anything is published yet. Use get_website_integration_guide to fetch the full instructions.

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id-integration-guides.md

GET /websites/:website_id/redirect-domains Scopes: websites:read

List the redirect-only domains pointing at a website, each with its DNS records and whether it is live (actually 301-redirecting to the site yet).

1 parameter
Name In Type Required Description
website_id path string yes

📄 /api/websites/get-websites-website-id-redirect-domains.md

GET /websites/:website_id/redirects Scopes: websites:read

List the path redirects on a website: each source path, where it sends visitors, and its status code. Also returns how many redirect slots are used against the limit. These are paths on this site (e.g. "/video"), NOT whole legacy domains - for those use list_website_redirect_domains.

1 parameter
Name In Type Required Description
website_id path string yes UUID of the website. Get ids from list_websites.

📄 /api/websites/get-websites-website-id-redirects.md

POST /websites/:website_id/deploy/provision Scopes: websites:write

Provision a git-connected Cloudflare Pages deployment for this website's connected GitHub repo. Creates the hosting project so every push auto-builds and deploys. The repo must already be connected (via create_website_repo). Optional: project_name, branch (default main), build_command (default "npm run build"), output_dir (default "dist"), root_dir. Returns the production and staging URLs.

7 parameters
Name In Type Required Description
website_id path string yes
project_name body string no
branch body string no
build_command body string no
output_dir body string no
root_dir body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-deploy-provision.md

POST /websites/:website_id/redirects/publish Scopes: websites:write

Publish a website's redirects to the live site in one rebuild. Only needed after adding several redirects with publish:false, or to retry a publish that failed. A single set_website_redirect already publishes itself.

2 parameters
Name In Type Required Description
website_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-redirects-publish.md

POST /websites/:website_id/deploy Scopes: websites:write

Trigger a fresh deployment of the website from its connected git branch (default main). Use to rebuild without pushing new code.

3 parameters
Name In Type Required Description
website_id path string yes
branch body string no Branch to deploy. Defaults to main.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-deploy.md

DELETE /websites/:website_id/deploy Scopes: websites:delete

Take a website offline: delete its Cloudflare Pages deployment (the hosting project). The GitHub repo is kept. Acts only on this website's own deployment.

2 parameters
Name In Type Required Description
website_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/delete-websites-website-id-deploy.md

DELETE /websites/:website_id/redirects/:redirect_id Scopes: websites:delete

Remove one path redirect from a website and republish the live site without it. Identify it by its id from list_website_redirects. To switch a redirect off without losing it, call set_website_redirect with is_active false instead.

3 parameters
Name In Type Required Description
website_id path string yes
redirect_id path string yes UUID of the redirect to remove. Get ids from list_website_redirects.
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/delete-websites-website-id-redirects-redirect-id.md

DELETE /websites/:website_id/redirect-domains/:host Scopes: websites:delete

Remove a redirect-only domain from a website. The domain stops redirecting once its DNS is repointed or removed.

3 parameters
Name In Type Required Description
website_id path string yes
host path string yes The redirect domain to remove, e.g. "oldbrand.com".
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/delete-websites-website-id-redirect-domains-host.md

DELETE /websites/:website_id/turnstile Scopes: websites:write

Remove bot protection from a website: deletes the Turnstile widget and its configuration. Public forms on this site will no longer be verified.

2 parameters
Name In Type Required Description
website_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/delete-websites-website-id-turnstile.md

POST /websites/:website_id/deploy/domain/retry Scopes: websites:write

Revive a custom domain that the hosting provider has stopped serving, when get_website_domain_status reports "recoverable": true for a host. Restarts verification in place where possible, and only as a last resort briefly detaches and re-attaches the domain (a short outage on an otherwise-working site). Rate limited to once per 24 hours per website, because each attempt consumes part of the certificate allowance for that domain. Do NOT call this on a domain that is merely pending - pending resolves on its own once DNS propagates.

2 parameters
Name In Type Required Description
website_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-deploy-domain-retry.md

POST /websites/:website_id/redirects Scopes: websites:write

Add or update one path redirect on a website, then publish it to the live site. Use for short branded links (send "/video" to a long booking URL so an SMS carries the client's own domain) and for fixing broken URLs found by get_website_broken_urls. Re-calling with the same source_path re-points it, so this both creates and edits. Publishing commits to the site's repo and rebuilds it, so the redirect is normally live within a couple of minutes. The website must have a connected repository.

7 parameters
Name In Type Required Description
website_id path string yes UUID of the website. Get ids from list_websites.
source_path body string yes The path on this site to redirect FROM, starting with "/", e.g. "/video". A single trailing "*" redirects a whole section, e.g. "/old-blog/*".
target_url body string yes Where to send the visitor: a full https:// address, or a path on the same site starting with "/".
status_code body number no HTTP redirect status: 301 (permanent), 302 (temporary, the default), 307, or 308. Use 302 unless the destination is settled, because browsers cache a 301 hard.
is_active body boolean no Whether the redirect is live. Defaults to true. Set false to switch one off without deleting it.
publish body boolean no Whether to rebuild the live site now. Defaults to true. Pass false for each of a batch of redirects, then call publish_website_redirects once, so the site rebuilds a single time instead of once per redirect. Note this only defers the rebuild: publishing always writes every active redirect, so the next publish from any redirect takes this one live too. To keep a redirect off the live site regardless, set is_active false instead.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/post-websites-website-id-redirects.md

PATCH /websites/:website_id Scopes: websites:write

Update a website: name, domain, branding, navbar, footer, SEO meta tags, lead gen form, or custom scripts.

19 parameters
Name In Type Required Description
website_id path string yes UUID of the website to update. Get ids from list_websites.
name body string no Site name shown in the Websites list. Internal label, not rendered on the site.
domain body string no Live custom domain as a BARE HOSTNAME, e.g. "www.example.com". A pasted full URL is normalized to the bare host on write. Pass null to unset.
staging_domain body string no Preview/staging hostname, bare like `domain`. A pasted full URL is normalized on write. Pass null to unset.
is_public body boolean no Whether the published site is reachable. False keeps it deployed but private.
brand_colors body object no Site colour palette, e.g. { "primary": "#0f172a", "secondary": "#38bdf8", "accent": "#f97316" }. Full-replace on write.
brand_typography body object no Font choices for the site, e.g. { "heading": "Inter", "body": "Inter" }. Full-replace on write.
navbar body object no Navigation bar configuration: links, layout and CTA. Full-replace on write — read the current value first and send it back modified.
footer body object no Footer configuration: columns, links, social and legal text. Full-replace on write.
lead_gen_form body object no Lead-capture form config for the site. Submissions post to the public website trigger endpoint using the site_key and land in the CRM. Full-replace on write.
default_meta_title body string no Fallback <title> for pages that do not set their own. Per-page values win.
default_meta_description body string no Fallback meta description for pages that do not set their own. Per-page values win.
default_og_image body string no Absolute URL of the fallback Open Graph / social share image (1200x630).
google_tag_manager_id body string no Google Tag Manager container id, e.g. "GTM-XXXXXXX". Injected into every page.
microsoft_clarity_id body string no Microsoft Clarity project id. Injected into every page.
header_scripts body string no Raw HTML injected into <head> on every page. Runs on the live site — only add markup you trust.
footer_scripts body string no Raw HTML injected before </body> on every page. Runs on the live site — only add markup you trust.
github_repo body string no Repository backing this site, as "owner/repo". Connects the site to its source; the deploy fields themselves are managed and not writable here.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/patch-websites-website-id.md

PATCH /websites/:website_id/analytics Scopes: websites:write

Record whether the tracking snippet is present on the live site. Set beacon_installed true once the snippet has been added and the site redeployed, so the traffic reports stop warning that data may be missing.

3 parameters
Name In Type Required Description
website_id path string yes
beacon_installed body boolean no Whether the tracking snippet is now present in the live site. Set true after adding it to the site and redeploying; the traffic reports stop warning about missing data once this is true.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/patch-websites-website-id-analytics.md

PATCH /websites/:website_id/turnstile Scopes: websites:write

Update a website's bot protection: toggle the master switch on/off (enabled), change the widget mode (managed, non-interactive, invisible), or set per-surface overrides (surface_policy). The master switch protects every widget-capable surface at once; surface_policy overrides individual surfaces while the master is on, e.g. {"lead_form":"rate_limited"} keeps forms/bookings challenged but drops the Lead Form to rate limiting. Pass surface_policy: null to clear all overrides.

5 parameters
Name In Type Required Description
website_id path string yes
enabled body boolean no
mode body string no
surface_policy body object,null no Per-surface overrides while the master is on. Keys: forms, bookings, lead_form, voice. Values: widget | rate_limited | off. A surface with no entry inherits widget while the master is on. "voice" governs in-browser AI voice calls ("Talk to the AI"): set it to widget only once the site actually renders a Turnstile widget before the call starts, otherwise every call is rejected; rate_limited leaves it guarded by the per-visitor and global call limits instead. null clears all overrides.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/websites/patch-websites-website-id-turnstile.md

SEO Research (15 endpoints)

Keyword research, competitor gap analysis and live search result snapshots.

📄 Full markdown: /api/seo.md

POST /seo-research/ai-visibility Scopes: seo:write

Check how visible a brand is in AI-generated search answers via TrustPager SEO. Costs credits.

5 parameters
Name In Type Required Description
brand body string no Brand or business name.
topics body string no Comma or newline-separated queries to check.
website_id body string yes UUID of the website this research is for.
location body string no Country code: AU (default), US, GB, NZ, CA.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-ai-visibility.md

POST /seo-research/backlink-links Scopes: seo:write

Drill into the INDIVIDUAL backlinks for a domain via TrustPager SEO — the linking page, where it points (url_to), and whether it is broken. Optionally filter to one referring_domain. Use after seo_backlinks to inspect a specific domain or find broken inbound links. Costs credits.

4 parameters
Name In Type Required Description
domain body string yes Your domain whose inbound links to inspect, e.g. yoursite.com.
referring_domain body string no Optional — limit to links coming from this one referring domain.
website_id body string yes UUID of the website this research is for.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-backlink-links.md

POST /seo-research/backlinks Scopes: seo:write

Analyse backlinks for a domain via TrustPager SEO. Returns referring domains with rank, backlink count, and dofollow status. Costs credits.

3 parameters
Name In Type Required Description
domain body string yes Domain to analyse, e.g. yoursite.com.
website_id body string yes UUID of the website this research is for.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-backlinks.md

POST /seo-research/brand-mentions Scopes: seo:write

Find web mentions of a brand or business with sentiment via TrustPager SEO. Costs credits.

3 parameters
Name In Type Required Description
brand body string yes Brand or business name to search for.
website_id body string yes UUID of the website this research is for.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-brand-mentions.md

POST /seo-research/competitor-gap Scopes: seo:write

Find the keywords a competitor domain ranks for via TrustPager SEO, with volume/CPC/difficulty. Optionally pass your_domain to focus on the gap. Costs credits. Saved as a run.

6 parameters
Name In Type Required Description
competitor_domain body string yes Competitor domain, e.g. competitor.com.
website_id body string yes UUID of the website this research is for. Always required — every SEO run must belong to a website.
your_domain body string no Optional — your own domain to compare against.
location body string no Country code: AU (default), US, GB, NZ, CA.
language body string no Language code, default en.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-competitor-gap.md

GET /seo-research/runs/:run_id Scopes: seo:read

Fetch a TrustPager SEO research run by UUID with its full result rows.

1 parameter
Name In Type Required Description
run_id path string yes

📄 /api/seo/get-seo-research-runs-run-id.md

POST /seo-research/keyword-research Scopes: seo:write

Run keyword research via TrustPager SEO. Returns each keyword with monthly search volume, CPC, competition, and keyword difficulty. Costs credits. Results are saved as a run you can re-open without paying again.

5 parameters
Name In Type Required Description
seed_keywords body array yes One or more seed keywords to expand from.
website_id body string yes UUID of the website this research is for. Always required — every SEO run must belong to a website.
location body string no Country code: AU (default), US, GB, NZ, CA.
language body string no Language code, default en.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-keyword-research.md

GET /seo-research/rank-snapshots Scopes: seo:read

List rank position snapshots for tracked keywords via TrustPager SEO, newest first. Paginated: pagination.total is the real number of snapshots matching the filter, and pagination.next_cursor pages back through older history.

4 parameters
Name In Type Required Description
website_id query string no
tracked_keyword_id query string no
limit query number no Page size, 1 to 100. Defaults to 25.
after query string no Snapshot id from a previous response's pagination.next_cursor, to fetch the next page of older snapshots.

📄 /api/seo/get-seo-research-rank-snapshots.md

GET /seo-research/runs Scopes: seo:read

List past TrustPager SEO research runs (newest first). Filter by website_id or tool.

3 parameters
Name In Type Required Description
website_id query string no
tool query string no keyword_research | competitor_gap | serp_snapshot | backlinks | brand_mentions | ai_visibility | local_seo | site_audit
limit query number no

📄 /api/seo/get-seo-research-runs.md

GET /seo-research/tracked-keywords Scopes: seo:read

List tracked keywords for a website via TrustPager SEO.

1 parameter
Name In Type Required Description
website_id query string no

📄 /api/seo/get-seo-research-tracked-keywords.md

POST /seo-research/llm-visibility Scopes: seo:write

Ask a real LLM (ChatGPT) your prompts and check whether the brand is mentioned or cited in the AI answer via TrustPager SEO. The new frontier beyond Google rankings. Costs credits.

4 parameters
Name In Type Required Description
brand body string no Brand or business name to look for in the AI answer.
topics body string no Newline-separated prompts/questions to ask the LLM.
website_id body string yes UUID of the website this research is for.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-llm-visibility.md

POST /seo-research/local-seo Scopes: seo:write

Audit local search presence for a business via TrustPager SEO. Returns map-pack listings with ratings, addresses, and reviews. Costs credits.

4 parameters
Name In Type Required Description
business_name body string yes Business name to search for.
website_id body string yes UUID of the website this research is for.
location body string no Country code: AU (default), US, GB, NZ, CA.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-local-seo.md

POST /seo-research/site-audit Scopes: seo:write

Start a technical site audit via TrustPager SEO. Crawls up to 100 pages and returns issues (missing titles, broken links, slow pages). Async — poll seo_get_run for results. Costs credits.

3 parameters
Name In Type Required Description
start_url body string yes URL to start crawling from, e.g. https://yoursite.com.
website_id body string yes UUID of the website this audit is for.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-site-audit.md

POST /seo-research/serp-snapshot Scopes: seo:write

Capture the live top organic search results for a keyword in a location via TrustPager SEO. Costs credits. Saved as a run.

5 parameters
Name In Type Required Description
keyword body string yes The search query to snapshot.
website_id body string yes UUID of the website this research is for. Always required — every SEO run must belong to a website.
location body string no Country code: AU (default), US, GB, NZ, CA.
language body string no Language code, default en.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-serp-snapshot.md

POST /seo-research/track-keywords Scopes: seo:write

Add keywords to the Rank Tracker for a website via TrustPager SEO. Triggers an immediate rank check and saves keywords for recurring position monitoring.

4 parameters
Name In Type Required Description
keywords body array yes Keywords to track.
website_id body string yes UUID of the website to track rankings for.
location body string no Country code: AU (default), US, GB, NZ, CA.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/seo/post-seo-research-track-keywords.md

Portals (25 endpoints)

Client portal templates and the live portal instances created from them.

📄 Full markdown: /api/portals.md

POST /portals/:portal_id/members Scopes: portals:write

Add a member to a portal by email and (by default) send them the workspace-branded invite. Adding IS inviting: the backend creates or links a company-less external login (broker, client, site staff who NEVER join your company), sends the invite/access email, and writes a log row. The path is chosen automatically from the person's identity state: a brand-new person gets a set-password link; an un-activated account gets a fresh set-password link re-issued; an already-active platform user gets an 'access granted' notice. Set `send_email: false` to add them silently, with the same access and portal chat but no email. Idempotent per email. Returns `state` (new | pending | active) and `email_sent`. Identical to invite_portal_member.

5 parameters
Name In Type Required Description
portal_id path string yes
email body string yes The person to add / invite. Required.
full_name body string no Optional display name shown in the portal.
send_email body boolean no Send the invite email. Defaults to true. False adds them silently with identical access and portal chat, but someone who has no TrustPager login yet then has no way in until you resend their access link.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-portal-id-members.md

POST /portals/:portal_id/referrer Scopes: portals:write

Connect a referral partner (a contact) to a partner portal as its bound referrer. The referral dashboard and the portal's "Submit a referral now" form both attribute referrals to this contact, so a portal whose referrer is missing cannot accept referrals until this is set. The contact must already exist in the workspace; connecting it also flags it as a referral partner so it appears in the referrer picker. Use this to fix a portal reported as "not fully set up" or to re-point a portal at a different partner.

3 parameters
Name In Type Required Description
portal_id path string yes
contact_id body string yes The contact to bind as this portal's referral partner. Must exist in the workspace.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-portal-id-referrer.md

POST /portals Scopes: portals:write

Create a portal INSTANCE (a live portal). PREFER instantiate_portal_template to create a portal for an opportunity — it stamps a template onto the opportunity, links it, and auto-shares the right records. Use this lower-level call only when you already hold the template id and anchor. config.templateId is REQUIRED: every instance must derive from a Portal Template (the reusable design, in portal_templates; create one with create_portal_template). A portal is the unit of access: members see only records shared into it. Pass config.anchor to link it to the CRM opportunity, plus optional branding / welcome / contact overlay.

4 parameters
Name In Type Required Description
name body string yes Display name, e.g. the opportunity / client name.
type body string no partner | client | doc_collection | stakeholder. Defaults to client. client = a private login for a client to track their project. partner = a referrer/broker portal (adds Referrals & commissions). stakeholder = an external contractor/stakeholder portal (pairs with config.stakeholder.enabled). doc_collection = a document-collection portal.
config body object no Portal config (jsonb). templateId = <portal_templates uuid> is REQUIRED (every instance derives from a template; get ids from list_portal_templates). Prefer instantiate_portal_template (opportunity) or instantiate_partner_portal (contact/referrer) over building an instance by hand. Portal design config (jsonb). REPLACE-not-merge: get the current config, merge your change, PATCH the whole object back — a partial config wipes the omitted keys. Keys: `branding` {logoUrl,primaryColor,secondaryColor,tagline,icon}; `welcome` {headline,body}; `contact` {name,role,email,phone}; `description` (invite-email blurb); `menus` [{id,label,icon,content?,sidebar:[{type,ref?,slug?,label?,icon?,memberCanEdit?}]}] — the top-nav tabs + sidebar entries (entry types: notepad, notepad_folder, scheduler, form, work_orders, signing, documents, invoices, files, referrals, booking, notepads, transcripts, chat); `dataSharing` {<content_type>: {enabled, mode:"all"|"selected", resourceIds?, statusIds?, memberCanEdit?, memberEditableFields?}} — Container 1, auto-share of the ANCHORED OPPORTUNITY's content (content types: work_orders, transcripts, invoices, signing, documents, files, bookings, images, notepads). enabled=false fully protects a type; mode "selected" limits to resourceIds; memberEditableFields (work_orders only) is the allowlist of field SLUGS a member may write — omit it for the original "every field editable" behaviour, or pass [] for status-only so a contractor can accept/decline a job offer without being able to retype the offer amount; memberSelectableStatuses (work_orders only) is the same idea for status — the allowlist of status IDS a member may move a job INTO, omitted meaning every workspace status is offered; requiredFieldsByStatus (work_orders only) {"<status id>":["slug"]} gates a transition until those fields are filled ("_attachments" = at least one photo), so a subcontractor cannot mark a job finished before the work is confirmed; `templateContent` {signing?:[document_template_id], documents?:[document_template_id], files?:[secure_file_id], images?:[company_file_id], notepads?:[notepad_id]} — Container 2, TEMPLATE content proliferated into EVERY instance (signing/documents are rendered per instance with the referrer/opportunity variables). Set this on a TEMPLATE; a create/edit trigger proliferates it. `referral` {enabled,commissions,referrerContactId} — PARTNER portals only (commission dashboard); referrerContactId is pinned at instantiation. `stakeholder` {enabled,contractorContactId}: STAKEHOLDER portals only (type "stakeholder"), the external contractor/subcontractor design. enabled=true adds the "My Jobs" (contractor_jobs) + member-editable work_orders tabs; contractorContactId is pinned at instantiation and scopes the jobs dashboard to that contractor across every opportunity they service. `defaultMembers` [{email,name?}] (TEMPLATE only): the internal team seeded as members onto EVERY portal instantiated from this template, so they get in-portal access without an invite email. `documentsOpportunityId` — PARTNER portals only: the referrer's own opportunity that scopes templateContent signing/document/file candidates + variables. `anchor` {type:"opportunity"|"contact", id} — set by the instantiate endpoints, not by hand. `templateId` — the source template (set at instantiation). `keepInstancesAligned` (TEMPLATE only, boolean, default false) — when true, every instance of this template (existing AND future) keeps its DESIGN (menus, home, branding, welcome, contact, nav, description) matched to the template: any template design edit propagates to all instances automatically, and switching it on aligns the existing instances immediately. Each instance's own opportunity anchor, referrer, members, shared records, and data-sharing rules are always preserved. Set it with set_portal_template_alignment. `lastSyncedAt` (instance only) — stamped by the alignment job when an instance was last matched to its template.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals.md

POST /portals/templates Scopes: portals:write

Create a reusable portal template (design only). Put branding / welcome / contact / pages / tools / nav into config; instantiate_portal_template later stamps it onto an opportunity.

4 parameters
Name In Type Required Description
name body string yes Template name, e.g. "Client Project Portal".
type body string no partner | client | doc_collection | stakeholder. Defaults to client. client = a private login for a client to track their project. partner = a referrer/broker portal (adds Referrals & commissions). stakeholder = an external contractor/stakeholder portal (pairs with config.stakeholder.enabled). doc_collection = a document-collection portal.
config body object no Portal design config (jsonb). REPLACE-not-merge: get the current config, merge your change, PATCH the whole object back — a partial config wipes the omitted keys. Keys: `branding` {logoUrl,primaryColor,secondaryColor,tagline,icon}; `welcome` {headline,body}; `contact` {name,role,email,phone}; `description` (invite-email blurb); `menus` [{id,label,icon,content?,sidebar:[{type,ref?,slug?,label?,icon?,memberCanEdit?}]}] — the top-nav tabs + sidebar entries (entry types: notepad, notepad_folder, scheduler, form, work_orders, signing, documents, invoices, files, referrals, booking, notepads, transcripts, chat); `dataSharing` {<content_type>: {enabled, mode:"all"|"selected", resourceIds?, statusIds?, memberCanEdit?, memberEditableFields?}} — Container 1, auto-share of the ANCHORED OPPORTUNITY's content (content types: work_orders, transcripts, invoices, signing, documents, files, bookings, images, notepads). enabled=false fully protects a type; mode "selected" limits to resourceIds; memberEditableFields (work_orders only) is the allowlist of field SLUGS a member may write — omit it for the original "every field editable" behaviour, or pass [] for status-only so a contractor can accept/decline a job offer without being able to retype the offer amount; memberSelectableStatuses (work_orders only) is the same idea for status — the allowlist of status IDS a member may move a job INTO, omitted meaning every workspace status is offered; requiredFieldsByStatus (work_orders only) {"<status id>":["slug"]} gates a transition until those fields are filled ("_attachments" = at least one photo), so a subcontractor cannot mark a job finished before the work is confirmed; `templateContent` {signing?:[document_template_id], documents?:[document_template_id], files?:[secure_file_id], images?:[company_file_id], notepads?:[notepad_id]} — Container 2, TEMPLATE content proliferated into EVERY instance (signing/documents are rendered per instance with the referrer/opportunity variables). Set this on a TEMPLATE; a create/edit trigger proliferates it. `referral` {enabled,commissions,referrerContactId} — PARTNER portals only (commission dashboard); referrerContactId is pinned at instantiation. `stakeholder` {enabled,contractorContactId}: STAKEHOLDER portals only (type "stakeholder"), the external contractor/subcontractor design. enabled=true adds the "My Jobs" (contractor_jobs) + member-editable work_orders tabs; contractorContactId is pinned at instantiation and scopes the jobs dashboard to that contractor across every opportunity they service. `defaultMembers` [{email,name?}] (TEMPLATE only): the internal team seeded as members onto EVERY portal instantiated from this template, so they get in-portal access without an invite email. `documentsOpportunityId` — PARTNER portals only: the referrer's own opportunity that scopes templateContent signing/document/file candidates + variables. `anchor` {type:"opportunity"|"contact", id} — set by the instantiate endpoints, not by hand. `templateId` — the source template (set at instantiation). `keepInstancesAligned` (TEMPLATE only, boolean, default false) — when true, every instance of this template (existing AND future) keeps its DESIGN (menus, home, branding, welcome, contact, nav, description) matched to the template: any template design edit propagates to all instances automatically, and switching it on aligns the existing instances immediately. Each instance's own opportunity anchor, referrer, members, shared records, and data-sharing rules are always preserved. Set it with set_portal_template_alignment. `lastSyncedAt` (instance only) — stamped by the alignment job when an instance was last matched to its template.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-templates.md

DELETE /portals/:portal_id Scopes: portals:delete

Delete a portal. Cascades to its members and shares (the underlying shared records are NOT deleted).

2 parameters
Name In Type Required Description
portal_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/delete-portals-portal-id.md

DELETE /portals/templates/:template_id Scopes: portals:delete

Delete a portal template. Portals already instantiated from it are unaffected.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/delete-portals-templates-template-id.md

GET /portals/:portal_id Scopes: portals:read

Fetch a portal by UUID.

1 parameter
Name In Type Required Description
portal_id path string yes

📄 /api/portals/get-portals-portal-id.md

GET /portals/templates/:template_id Scopes: portals:read

Fetch a portal template by UUID (its full design config).

1 parameter
Name In Type Required Description
template_id path string yes

📄 /api/portals/get-portals-templates-template-id.md

POST /portals/templates/:template_id/instantiate-for-contact Scopes: portals:write

Create a NEW portal from a template anchored to a CONTACT (a referrer) — the partner-portal path. Pins referral.referrerContactId (commission dashboard scopes to them) and optionally documents_opportunity_id (the referrer's own opportunity that supplies the templateContent signing/document/file candidates + per-instance signing variables). The template's templateContent proliferates into the instance automatically. Use this instead of instantiate_portal_template for partner portals.

6 parameters
Name In Type Required Description
template_id path string yes
contact_id body string yes The referrer contact to anchor the partner portal to (required).
documents_opportunity_id body string no Optional: the referrer's own opportunity that scopes signing/document/file template content + fills per-instance signing variables.
name body string no Portal name. Defaults to the template name.
invite_contact body boolean no Invite the contact as a portal member (branded email). Default true.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-templates-template-id-instantiate-for-contact.md

POST /portals/templates/:template_id/instantiate Scopes: portals:write

Create a NEW portal from a template, anchored to an opportunity. Copies the template design and sets config.anchor to the opportunity; optionally seeds members. Returns the new portal. Share records into it afterwards with share_to_portal.

5 parameters
Name In Type Required Description
template_id path string yes
opportunity_id body string yes The CRM opportunity to anchor the new portal to (required).
name body string no Portal name. Defaults to the template name.
members body array no Optional members to seed: [{ email, user_id?, status? }].
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-templates-template-id-instantiate.md

POST /portals/:portal_id/invite Scopes: portals:write

Invite an external person to a portal by email and send them a workspace-branded invite email. Records them as a company-less member (broker / client / site staff) who NEVER joins your company. Handles all three identity states automatically: a brand-new person gets a set-password link; a person with an un-activated account gets a fresh set-password link re-issued; a person already active on the platform gets an 'access granted' notice and signs in with their existing password. Set `send_email: false` to grant access silently instead. Idempotent per email. Returns `state` (new | pending | active) and `email_sent`.

5 parameters
Name In Type Required Description
portal_id path string yes
email body string yes The person to invite. Required.
full_name body string no Optional display name shown in the portal.
send_email body boolean no Send the invite email. Defaults to true. False grants access and portal chat silently, but someone who has no TrustPager login yet then has no way in until you resend their access link.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-portal-id-invite.md

GET /portals/:portal_id/shares Scopes: portals:read

List the records shared into a portal.

2 parameters
Name In Type Required Description
portal_id path string yes
resource_type query string no

📄 /api/portals/get-portals-portal-id-shares.md

GET /portals/template-content-candidates Scopes: portals:read

List the workspace resources valid to attach as template content of a given type (so you attach real ids, not guesses). signing/documents → document templates; files → secure files; images → company images; notepads → notepads.

1 parameter
Name In Type Required Description
type query string yes One of: signing, documents, files, images, notepads (query param).

📄 /api/portals/get-portals-template-content-candidates.md

GET /portals/templates Scopes: portals:read

List reusable portal templates (designs). A template carries branding / welcome / contact / pages / tools / nav order in config, with no anchor, members, or shares.

📄 /api/portals/get-portals-templates.md

GET /portals Scopes: portals:read

List client/partner portals in the workspace.

2 parameters
Name In Type Required Description
type query string no Filter by portal type: partner | client | doc_collection | stakeholder. Omit for all types.
status query string no Filter by status: active | disabled. Omit for all statuses.

📄 /api/portals/get-portals.md

POST /portals/:portal_id/reconcile-autoshare Scopes: portals:write

Back-fill a live portal: share the anchored opportunity's EXISTING records for every dataSharing type set to enabled+all. New records auto-share via triggers; call this once after enabling a type so content that predates the rule also appears.

2 parameters
Name In Type Required Description
portal_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-portal-id-reconcile-autoshare.md

DELETE /portals/:portal_id/members/:member_id Scopes: portals:write

Remove a member from a portal (revokes their access to it).

3 parameters
Name In Type Required Description
portal_id path string yes
member_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/delete-portals-portal-id-members-member-id.md

DELETE /portals/:portal_id/shares/:share_id Scopes: portals:write

Stop sharing a record into a portal (members lose access to it). Does not delete the underlying record.

3 parameters
Name In Type Required Description
portal_id path string yes
share_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/delete-portals-portal-id-shares-share-id.md

POST /portals/data-sharing Scopes: portals:write

Safely set ONE opportunity-auto-share rule (Container 1) on a portal instance OR a template — server-side merge, so you never replace the whole config. enabled=false fully protects the type; mode "all" auto-shares all of the anchored opportunity's records of that type, "selected" limits to resource_ids.

12 parameters
Name In Type Required Description
portal_id body string no Target a live instance (one of portal_id/template_id).
template_id body string no Target a template (one of portal_id/template_id).
content_type body string yes One of: work_orders, transcripts, invoices, signing, documents, files, bookings, images, notepads.
enabled body boolean no Master switch. false = fully protected (never shared/seen). Defaults true when first set.
mode body string no "all" (auto-share every record) or "selected" (only resource_ids).
resource_ids body array no For mode "selected": the exact record ids.
status_ids body array no work_orders only: filter by status ids.
member_can_edit body boolean no work_orders/notepads: let members edit, not just view.
member_editable_fields body array no work_orders only, alongside member_can_edit: the field SLUGS a member may write. Status is always editable when member_can_edit is true, so this covers the data fields. Omit the key entirely for the original behaviour (every field editable); pass [] for status-only, so a contractor can accept or decline a job but cannot change the offer amount; pass null to clear the allowlist.
member_selectable_statuses body array no work_orders only: the status IDS a member may move a work order INTO — the status equivalent of member_editable_fields. Omit for the original behaviour (every workspace status offered); pass the short list a contractor should see instead of your internal quoting and payment stages; pass null to clear it. NOT the same as status_ids, which decides which work orders are shared into the portal at all.
required_fields_by_status body object no work_orders only: a completion gate, as {"<status id>": ["field_slug", …]}. Every listed slug must be filled before a member may move a work order INTO that status, enforced server-side — so a subcontractor cannot mark a job finished before the work is confirmed. Use the slug "_attachments" to require at least one photo. Pass {} or null to clear the gate.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-data-sharing.md

POST /portals/template-alignment Scopes: portals:write

Turn "keep all instances aligned with this template" on or off for a portal TEMPLATE. When enabled=true, every instance of this template — existing and future — keeps its DESIGN (tabs/pages, page content, branding, welcome, contact) matched to the template: switching it on aligns the existing instances immediately, and every later template design edit propagates to all of them automatically. enabled=false re-freezes them as independent. Each instance's own opportunity anchor, referrer, members, shared records, and data-sharing rules are always preserved.

3 parameters
Name In Type Required Description
template_id body string yes
enabled body boolean yes true = keep all instances matched to this template; false = each instance is independent (default).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-template-alignment.md

POST /portals/template-content Scopes: portals:write

Safely set ONE template-content type (Container 2) on a portal TEMPLATE — server-side merge. This content proliferates into every instance (signing/documents rendered per instance with the referrer/opportunity variables). Pass the full desired id list for the type (replaces just that type's list). Use list_portal_template_content_candidates to find valid ids.

4 parameters
Name In Type Required Description
template_id body string yes
content_type body string yes One of: signing, documents, files, images, notepads. signing/documents take document_template ids; files/images/notepads take the workspace resource ids.
resource_ids body array yes The full id list for this type (empty array clears it).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-template-content.md

POST /portals/:portal_id/shares Scopes: portals:write

Share a workspace record into a portal so its members can see it. This is the explicit access grant - nothing appears in a portal until shared. Idempotent. resource_type is one of: document, file, image, invoice, signing_envelope, booking, scheduled_event_type, form_template, form_submission, work_order, work_order_portal, referral, commission_payment, notepad, notepad_folder, transcript, opportunity_notepad. Scheduler (scheduled_event_type) and form_template surface as Tools the member can act on; documents, invoices and signing surface as Details; opportunity_notepad surfaces as a member-editable notepad in the portal.

4 parameters
Name In Type Required Description
portal_id path string yes
resource_type body string yes The kind of record being shared (e.g. document, invoice, scheduled_event_type, form_template, work_order).
resource_id body string yes UUID of the record to share.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/post-portals-portal-id-shares.md

PATCH /portals/:portal_id Scopes: portals:write

Update a portal. Every field is optional and independent: whatever you omit is left exactly as stored. Set status to disabled to suspend member access. Passing config REPLACES the whole object (get → merge → patch), but omitting name, type, or status does NOT reset them, so do not echo them back unless you mean to change them.

6 parameters
Name In Type Required Description
portal_id path string yes
name body string no New portal name. Omit to leave it unchanged.
type body string no partner | client | doc_collection | stakeholder. OMIT this field to leave the current type unchanged: only supply it when you deliberately want to change the type. client = a private login for a client to track their project. partner = a referrer/broker portal (adds Referrals & commissions). stakeholder = an external contractor/stakeholder portal (pairs with config.stakeholder.enabled). doc_collection = a document-collection portal.
status body string no active | disabled. Omit to leave it unchanged.
config body object no Portal design config (jsonb). REPLACE-not-merge: get the current config, merge your change, PATCH the whole object back — a partial config wipes the omitted keys. Keys: `branding` {logoUrl,primaryColor,secondaryColor,tagline,icon}; `welcome` {headline,body}; `contact` {name,role,email,phone}; `description` (invite-email blurb); `menus` [{id,label,icon,content?,sidebar:[{type,ref?,slug?,label?,icon?,memberCanEdit?}]}] — the top-nav tabs + sidebar entries (entry types: notepad, notepad_folder, scheduler, form, work_orders, signing, documents, invoices, files, referrals, booking, notepads, transcripts, chat); `dataSharing` {<content_type>: {enabled, mode:"all"|"selected", resourceIds?, statusIds?, memberCanEdit?, memberEditableFields?}} — Container 1, auto-share of the ANCHORED OPPORTUNITY's content (content types: work_orders, transcripts, invoices, signing, documents, files, bookings, images, notepads). enabled=false fully protects a type; mode "selected" limits to resourceIds; memberEditableFields (work_orders only) is the allowlist of field SLUGS a member may write — omit it for the original "every field editable" behaviour, or pass [] for status-only so a contractor can accept/decline a job offer without being able to retype the offer amount; memberSelectableStatuses (work_orders only) is the same idea for status — the allowlist of status IDS a member may move a job INTO, omitted meaning every workspace status is offered; requiredFieldsByStatus (work_orders only) {"<status id>":["slug"]} gates a transition until those fields are filled ("_attachments" = at least one photo), so a subcontractor cannot mark a job finished before the work is confirmed; `templateContent` {signing?:[document_template_id], documents?:[document_template_id], files?:[secure_file_id], images?:[company_file_id], notepads?:[notepad_id]} — Container 2, TEMPLATE content proliferated into EVERY instance (signing/documents are rendered per instance with the referrer/opportunity variables). Set this on a TEMPLATE; a create/edit trigger proliferates it. `referral` {enabled,commissions,referrerContactId} — PARTNER portals only (commission dashboard); referrerContactId is pinned at instantiation. `stakeholder` {enabled,contractorContactId}: STAKEHOLDER portals only (type "stakeholder"), the external contractor/subcontractor design. enabled=true adds the "My Jobs" (contractor_jobs) + member-editable work_orders tabs; contractorContactId is pinned at instantiation and scopes the jobs dashboard to that contractor across every opportunity they service. `defaultMembers` [{email,name?}] (TEMPLATE only): the internal team seeded as members onto EVERY portal instantiated from this template, so they get in-portal access without an invite email. `documentsOpportunityId` — PARTNER portals only: the referrer's own opportunity that scopes templateContent signing/document/file candidates + variables. `anchor` {type:"opportunity"|"contact", id} — set by the instantiate endpoints, not by hand. `templateId` — the source template (set at instantiation). `keepInstancesAligned` (TEMPLATE only, boolean, default false) — when true, every instance of this template (existing AND future) keeps its DESIGN (menus, home, branding, welcome, contact, nav, description) matched to the template: any template design edit propagates to all instances automatically, and switching it on aligns the existing instances immediately. Each instance's own opportunity anchor, referrer, members, shared records, and data-sharing rules are always preserved. Set it with set_portal_template_alignment. `lastSyncedAt` (instance only) — stamped by the alignment job when an instance was last matched to its template.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/patch-portals-portal-id.md

PATCH /portals/templates/:template_id Scopes: portals:write

Update a portal template. Every field is optional and independent: whatever you omit is left exactly as stored. Passing config REPLACES the stored design (get → merge → patch the whole object), but omitting name or type does NOT reset them, so do not echo them back unless you mean to change them.

5 parameters
Name In Type Required Description
template_id path string yes
name body string no New template name. Omit to leave it unchanged.
type body string no partner | client | doc_collection | stakeholder. OMIT this field to leave the current type unchanged: only supply it when you deliberately want to change the type. client = a private login for a client to track their project. partner = a referrer/broker portal (adds Referrals & commissions). stakeholder = an external contractor/stakeholder portal (pairs with config.stakeholder.enabled). doc_collection = a document-collection portal.
config body object no Portal design config (jsonb). REPLACE-not-merge: get the current config, merge your change, PATCH the whole object back — a partial config wipes the omitted keys. Keys: `branding` {logoUrl,primaryColor,secondaryColor,tagline,icon}; `welcome` {headline,body}; `contact` {name,role,email,phone}; `description` (invite-email blurb); `menus` [{id,label,icon,content?,sidebar:[{type,ref?,slug?,label?,icon?,memberCanEdit?}]}] — the top-nav tabs + sidebar entries (entry types: notepad, notepad_folder, scheduler, form, work_orders, signing, documents, invoices, files, referrals, booking, notepads, transcripts, chat); `dataSharing` {<content_type>: {enabled, mode:"all"|"selected", resourceIds?, statusIds?, memberCanEdit?, memberEditableFields?}} — Container 1, auto-share of the ANCHORED OPPORTUNITY's content (content types: work_orders, transcripts, invoices, signing, documents, files, bookings, images, notepads). enabled=false fully protects a type; mode "selected" limits to resourceIds; memberEditableFields (work_orders only) is the allowlist of field SLUGS a member may write — omit it for the original "every field editable" behaviour, or pass [] for status-only so a contractor can accept/decline a job offer without being able to retype the offer amount; memberSelectableStatuses (work_orders only) is the same idea for status — the allowlist of status IDS a member may move a job INTO, omitted meaning every workspace status is offered; requiredFieldsByStatus (work_orders only) {"<status id>":["slug"]} gates a transition until those fields are filled ("_attachments" = at least one photo), so a subcontractor cannot mark a job finished before the work is confirmed; `templateContent` {signing?:[document_template_id], documents?:[document_template_id], files?:[secure_file_id], images?:[company_file_id], notepads?:[notepad_id]} — Container 2, TEMPLATE content proliferated into EVERY instance (signing/documents are rendered per instance with the referrer/opportunity variables). Set this on a TEMPLATE; a create/edit trigger proliferates it. `referral` {enabled,commissions,referrerContactId} — PARTNER portals only (commission dashboard); referrerContactId is pinned at instantiation. `stakeholder` {enabled,contractorContactId}: STAKEHOLDER portals only (type "stakeholder"), the external contractor/subcontractor design. enabled=true adds the "My Jobs" (contractor_jobs) + member-editable work_orders tabs; contractorContactId is pinned at instantiation and scopes the jobs dashboard to that contractor across every opportunity they service. `defaultMembers` [{email,name?}] (TEMPLATE only): the internal team seeded as members onto EVERY portal instantiated from this template, so they get in-portal access without an invite email. `documentsOpportunityId` — PARTNER portals only: the referrer's own opportunity that scopes templateContent signing/document/file candidates + variables. `anchor` {type:"opportunity"|"contact", id} — set by the instantiate endpoints, not by hand. `templateId` — the source template (set at instantiation). `keepInstancesAligned` (TEMPLATE only, boolean, default false) — when true, every instance of this template (existing AND future) keeps its DESIGN (menus, home, branding, welcome, contact, nav, description) matched to the template: any template design edit propagates to all instances automatically, and switching it on aligns the existing instances immediately. Each instance's own opportunity anchor, referrer, members, shared records, and data-sharing rules are always preserved. Set it with set_portal_template_alignment. `lastSyncedAt` (instance only) — stamped by the alignment job when an instance was last matched to its template.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/portals/patch-portals-templates-template-id.md

Order Forms (6 endpoints)

Manage payment order forms connected to Stripe for product purchases.

📄 Full markdown: /api/order-forms.md

POST /order-forms Scopes: forms:write

Create an order form configuration: which product categories and products it offers, which contact details it demands, and what happens in the CRM when someone orders.

16 parameters
Name In Type Required Description
website_id body string yes The website this order form belongs to.
is_active body boolean no Whether the form accepts orders. Turn off to take it down without deleting it.
categories body array no Product category IDs to show, in display order. Omit to show every category.
products body array no Product IDs to offer. Omit to offer everything in the chosen categories.
require_email body boolean no Demand an email address before the order can be submitted.
require_phone body boolean no Demand a phone number before the order can be submitted.
require_address body boolean no Demand a delivery address before the order can be submitted.
success_message body string no What the customer reads after ordering.
crm_auto_create_deal body boolean no Create an opportunity in the CRM for every order.
crm_pipeline_id body string no Pipeline the created opportunity lands in. Required when crm_auto_create_deal is on.
crm_initial_stage_id body string no Stage the created opportunity starts at. Must belong to crm_pipeline_id.
crm_default_products body array no Product IDs attached to every created opportunity on top of what was ordered.
email_config_id body string no Sending identity for this form's emails. Omit to use the workspace default.
user_confirmation_template_id body string no Template for the receipt sent to the customer.
staff_notification_template_id body string no Template for the alert sent to your team.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/order-forms/post-order-forms.md

DELETE /order-forms/:order_form_id Scopes: forms:delete

Delete an order form configuration.

2 parameters
Name In Type Required Description
order_form_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/order-forms/delete-order-forms-order-form-id.md

GET /order-forms Scopes: forms:read

List order form configurations.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/order-forms/get-order-forms.md

PATCH /order-forms/:order_form_id Scopes: forms:write

Update an order form configuration: which product categories and products it offers, which contact details it demands, and what happens in the CRM when someone orders.

16 parameters
Name In Type Required Description
order_form_id path string yes
is_active body boolean no Whether the form accepts orders. Turn off to take it down without deleting it.
categories body array no Product category IDs to show, in display order. Omit to show every category.
products body array no Product IDs to offer. Omit to offer everything in the chosen categories.
require_email body boolean no Demand an email address before the order can be submitted.
require_phone body boolean no Demand a phone number before the order can be submitted.
require_address body boolean no Demand a delivery address before the order can be submitted.
success_message body string no What the customer reads after ordering.
crm_auto_create_deal body boolean no Create an opportunity in the CRM for every order.
crm_pipeline_id body string no Pipeline the created opportunity lands in. Required when crm_auto_create_deal is on.
crm_initial_stage_id body string no Stage the created opportunity starts at. Must belong to crm_pipeline_id.
crm_default_products body array no Product IDs attached to every created opportunity on top of what was ordered.
email_config_id body string no Sending identity for this form's emails. Omit to use the workspace default.
user_confirmation_template_id body string no Template for the receipt sent to the customer.
staff_notification_template_id body string no Template for the alert sent to your team.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/order-forms/patch-order-forms-order-form-id.md

Stores (9 endpoints)

Ecommerce storefronts and the products they sell.

📄 Full markdown: /api/stores.md

POST /stores/:store_id/products Scopes: ecommerce:write

Add an existing crm_product to a store, with optional storefront overrides (price_override, storefront_title, images, display_order).

10 parameters
Name In Type Required Description
store_id path string yes
product_id body string yes
price_override body number no
storefront_title body string no
storefront_description body string no
storefront_images body array no
seo body object no
display_order body number no
is_visible body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stores/post-stores-store-id-products.md

POST /stores Scopes: ecommerce:write

Create an ecommerce storefront. Slug auto-derives from name if omitted. Sells crm_products via add_store_product.

17 parameters
Name In Type Required Description
name body string yes
slug body string no
website_id body string no
currency body string no
tax_inclusive body boolean no
tax_rate body number no
is_active body boolean no
branding body object no
shipping_settings body object no Delivery, postage and tax rules. Four optional keys, all set from the store's "Delivery and tax" card. allowed_countries: array of two-letter country codes the buyer may pick as a delivery destination (UI label "Countries you deliver to"); defaults to ["AU"]. domestic_country: two-letter code for where the store is based (UI label "Your home country"); defaults to the first allowed_countries entry, else "AU". export_tax_rate: percentage applied INSTEAD OF tax_rate when an order is delivered outside domestic_country (UI label "Overseas tax rate (%)"). Set export_tax_rate to 0 for a GST-free export, e.g. an Australian store posting goods overseas. Omit export_tax_rate entirely and every order keeps the store-wide tax_rate regardless of destination, which is the pre-existing behaviour. The destination is taken from the order's delivery address: from the `shipping` object your storefront posts on create-checkout when it collects the address itself, otherwise from the address the payment provider collects, in which case the tax is corrected when the payment reconciles. shipping_rates: postage charged as its own line, an object of two-letter country code to amount plus an optional "default" for anywhere without its own rate (UI label "Charge postage as a separate line"), e.g. {"AU": 12.50, "NZ": 24, "default": 30}. Omit shipping_rates and no postage is charged, shipping_total stays 0, and freight has to be built into the item prices, which is the pre-existing behaviour. Postage is taxed at the same destination-aware rate as the items, so a GST-free export pays no tax on its freight either, and it requires collect_shipping_address to be true. A per-country amount is only exact when your storefront posts the delivery address itself; on payment-provider-hosted checkout the destination is not known until after the amount is set, so "default" is charged, and unlike tax it cannot be corrected afterwards.
checkout_settings body object no
collect_shipping_address body boolean no UI label "Collect delivery address at checkout". Ask the buyer for a delivery address at checkout. Turn this on for a store that posts physical goods, so a paid-order automation can print a packing slip; leave it off for a digital store so checkout does not demand an address nobody reads.
fulfillment_pipeline_id body string no
fulfillment_stage_id body string no
auto_create_opportunity body boolean no
email_config_id body string no
opportunity_name_template body string no UI label "Opportunity name". What to call the opportunity created for a paid order. Set on the "Order opportunities" card of the store settings page (/growth/ecommerce/:id, Manage > Settings). Leave it empty and every order card is named "Order ORD-...", which is the pre-existing behaviour and what every store does today. Set it to name the card after something the workspace actually uses, e.g. "{{deal.metadata.job_number}} - {{customer_name}}" for a lab that keys its reports and invoices on a job number. Tokens: {{order_number}}, {{customer_name}}, {{customer_email}}, {{customer_phone}}, {{store_name}}, {{amount}}, {{currency}}, {{item_count}}, {{items_line}} (what was ordered, on one line), {{items_text}} (one item per line, avoid in a name), {{shipping_name}}, {{shipping_text}}, {{shipping_address.city}} and the other address parts, plus {{deal.metadata.<custom_field_id>}} for any opportunity custom field. The same token names the store_order_paid trigger publishes, so a template reads like the paid-order email a workspace has already written. The opportunity custom fields resolve because the name is applied AFTER the opportunity exists, so an Auto Number field with "Generate automatically" on has already minted its number. Applied only to a NEWLY created opportunity: an order matched to an existing opportunity never gets renamed. A token that resolves to nothing renders as empty, and a template that renders to nothing at all falls back to "Order <order_number>" rather than leaving a card unnamed.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stores/post-stores.md

DELETE /stores/:store_id Scopes: ecommerce:delete

Delete an ecommerce store. Fails if it has orders (deactivate instead).

2 parameters
Name In Type Required Description
store_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stores/delete-stores-store-id.md

GET /stores/:store_id Scopes: ecommerce:read

Fetch a single ecommerce store by UUID.

1 parameter
Name In Type Required Description
store_id path string yes

📄 /api/stores/get-stores-store-id.md

GET /stores/:store_id/products Scopes: ecommerce:read

List the catalog (products) for a store.

1 parameter
Name In Type Required Description
store_id path string yes

📄 /api/stores/get-stores-store-id-products.md

GET /stores Scopes: ecommerce:read

List ecommerce storefronts in the workspace.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/stores/get-stores.md

DELETE /stores/:store_id/products/:store_product_id Scopes: ecommerce:delete

Remove a product from a store (does not delete the underlying crm_product).

3 parameters
Name In Type Required Description
store_id path string yes
store_product_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stores/delete-stores-store-id-products-store-product-id.md

PATCH /stores/:store_id Scopes: ecommerce:write

Update an ecommerce store (name, branding, currency, tax, fulfillment pipeline, etc.).

18 parameters
Name In Type Required Description
store_id path string yes
name body string no
slug body string no
is_active body boolean no
currency body string no
tax_inclusive body boolean no
tax_rate body number no
branding body object no
shipping_settings body object no Delivery, postage and tax rules. Four optional keys, all set from the store's "Delivery and tax" card. allowed_countries: array of two-letter country codes the buyer may pick as a delivery destination (UI label "Countries you deliver to"); defaults to ["AU"]. domestic_country: two-letter code for where the store is based (UI label "Your home country"); defaults to the first allowed_countries entry, else "AU". export_tax_rate: percentage applied INSTEAD OF tax_rate when an order is delivered outside domestic_country (UI label "Overseas tax rate (%)"). Set export_tax_rate to 0 for a GST-free export, e.g. an Australian store posting goods overseas. Omit export_tax_rate entirely and every order keeps the store-wide tax_rate regardless of destination, which is the pre-existing behaviour. The destination is taken from the order's delivery address: from the `shipping` object your storefront posts on create-checkout when it collects the address itself, otherwise from the address the payment provider collects, in which case the tax is corrected when the payment reconciles. shipping_rates: postage charged as its own line, an object of two-letter country code to amount plus an optional "default" for anywhere without its own rate (UI label "Charge postage as a separate line"), e.g. {"AU": 12.50, "NZ": 24, "default": 30}. Omit shipping_rates and no postage is charged, shipping_total stays 0, and freight has to be built into the item prices, which is the pre-existing behaviour. Postage is taxed at the same destination-aware rate as the items, so a GST-free export pays no tax on its freight either, and it requires collect_shipping_address to be true. A per-country amount is only exact when your storefront posts the delivery address itself; on payment-provider-hosted checkout the destination is not known until after the amount is set, so "default" is charged, and unlike tax it cannot be corrected afterwards.
checkout_settings body object no
collect_shipping_address body boolean no UI label "Collect delivery address at checkout". Ask the buyer for a delivery address at checkout. Turn this on for a store that posts physical goods, so a paid-order automation can print a packing slip; leave it off for a digital store so checkout does not demand an address nobody reads.
fulfillment_pipeline_id body string no
fulfillment_stage_id body string no
auto_create_opportunity body boolean no
email_config_id body string no
website_id body string no
opportunity_name_template body string no UI label "Opportunity name". What to call the opportunity created for a paid order. Set on the "Order opportunities" card of the store settings page (/growth/ecommerce/:id, Manage > Settings). Leave it empty and every order card is named "Order ORD-...", which is the pre-existing behaviour and what every store does today. Set it to name the card after something the workspace actually uses, e.g. "{{deal.metadata.job_number}} - {{customer_name}}" for a lab that keys its reports and invoices on a job number. Tokens: {{order_number}}, {{customer_name}}, {{customer_email}}, {{customer_phone}}, {{store_name}}, {{amount}}, {{currency}}, {{item_count}}, {{items_line}} (what was ordered, on one line), {{items_text}} (one item per line, avoid in a name), {{shipping_name}}, {{shipping_text}}, {{shipping_address.city}} and the other address parts, plus {{deal.metadata.<custom_field_id>}} for any opportunity custom field. The same token names the store_order_paid trigger publishes, so a template reads like the paid-order email a workspace has already written. The opportunity custom fields resolve because the name is applied AFTER the opportunity exists, so an Auto Number field with "Generate automatically" on has already minted its number. Applied only to a NEWLY created opportunity: an order matched to an existing opportunity never gets renamed. A token that resolves to nothing renders as empty, and a template that renders to nothing at all falls back to "Order <order_number>" rather than leaving a card unnamed.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stores/patch-stores-store-id.md

PATCH /stores/:store_id/products/:store_product_id Scopes: ecommerce:write

Update a store product (price_override, visibility, storefront overrides, display order).

10 parameters
Name In Type Required Description
store_id path string yes
store_product_id path string yes
price_override body number no
storefront_title body string no
storefront_description body string no
storefront_images body array no
seo body object no
display_order body number no
is_visible body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/stores/patch-stores-store-id-products-store-product-id.md

Orders (5 endpoints)

Ecommerce orders and their line items, including status and fulfilment updates.

📄 Full markdown: /api/orders.md

GET /orders/:order_id Scopes: ecommerce:read

Fetch a single ecommerce order by UUID, including its line items.

1 parameter
Name In Type Required Description
order_id path string yes

📄 /api/orders/get-orders-order-id.md

GET /orders/:order_id/items Scopes: ecommerce:read

List the line items for an ecommerce order.

1 parameter
Name In Type Required Description
order_id path string yes

📄 /api/orders/get-orders-order-id-items.md

GET /orders Scopes: ecommerce:read

List ecommerce orders. Filter by status or store_id query params.

3 parameters
Name In Type Required Description
status query string no
store_id query string no
limit query number no

📄 /api/orders/get-orders.md

POST /orders/:order_id/reconcile Scopes: ecommerce:write

Reconcile an order against Stripe (safety net for missed webhooks): pulls the checkout session status with the store's Connect token and marks the order paid only if Stripe confirms payment.

2 parameters
Name In Type Required Description
order_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/orders/post-orders-order-id-reconcile.md

PATCH /orders/:order_id Scopes: ecommerce:write

Update an ecommerce order's status, fulfillment_status, notes, or shipping address.

7 parameters
Name In Type Required Description
order_id path string yes
status body string no
fulfillment_status body string no
payment_status body string no
notes body string no
shipping_address body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/orders/patch-orders-order-id.md

Invoices (13 endpoints)

Native invoices and their line items, optionally linked to an opportunity or company.

📄 Full markdown: /api/invoices.md

POST /invoices/:invoice_id/line-items Scopes: invoices:write

Add one line item to a native invoice. Requires description; line_total and invoice totals are computed.

9 parameters
Name In Type Required Description
invoice_id path string yes
product_id body string no
description body string yes
quantity body number no
unit_price body number no
discount_percent body number no
tax_amount body number no
external_line_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices-invoice-id-line-items.md

POST /invoices/:invoice_id/line-items/bulk Scopes: invoices:write

Add up to 500 line items to a native invoice in one call. Body: { line_items: [...] }, each item the same shape as add_invoice_line_item. Used for invoice-data imports.

3 parameters
Name In Type Required Description
invoice_id path string yes
line_items body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices-invoice-id-line-items-bulk.md

POST /invoices/bulk Scopes: invoices:write

Create up to 100 native invoices in one request, each with inline line_items (header totals computed from the lines). Per-row errors are isolated. Built for high-volume migrations and batch invoicing.

2 parameters
Name In Type Required Description
invoices body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices-bulk.md

POST /invoices Scopes: invoices:write

Create a native invoice, optionally linked to an opportunity and with inline line_items (header totals are computed from the lines). Pass external_order_id to link an ecommerce order.

12 parameters
Name In Type Required Description
opportunity_id body string no
customer_id body string no
external_order_id body string no
invoice_number body string no
status body string no
issue_date body string no
due_date body string no
currency_code body string no
reference body string no
contact_name body string no
line_items body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices.md

POST /invoices/:invoice_id/payment-link Scopes: invoices:write

Generate a Stripe payment link for a native invoice using the workspace's connected Stripe account, and store it on the invoice. The link then appears as the "Pay now" button everywhere the invoice is shown (client portal, invoice emails). Requires Stripe connected under Integrations. One-off charges the outstanding balance; pass recurring_interval (day|week|month|year) to make it a subscription charging the full total each period.

4 parameters
Name In Type Required Description
invoice_id path string yes
recurring_interval body string no
recurring_interval_count body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices-invoice-id-payment-link.md

DELETE /invoices/:invoice_id Scopes: invoices:write

Delete a native invoice by UUID (its line items are removed too). Destructive.

2 parameters
Name In Type Required Description
invoice_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/delete-invoices-invoice-id.md

DELETE /invoices/:invoice_id/line-items/:line_id Scopes: invoices:write

Delete one line item from a native invoice. Invoice totals recompute. Destructive.

3 parameters
Name In Type Required Description
invoice_id path string yes
line_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/delete-invoices-invoice-id-line-items-line-id.md

GET /invoices/:invoice_id Scopes: invoices:read

Fetch a single native invoice by UUID, including its line_items.

1 parameter
Name In Type Required Description
invoice_id path string yes

📄 /api/invoices/get-invoices-invoice-id.md

GET /invoices Scopes: invoices:read

List native invoices. Filter by opportunity_id, customer_id, status, source_platform, external_order_id, or search invoice number / reference.

8 parameters
Name In Type Required Description
limit query number no
after query string no
opportunity_id query string no
customer_id query string no
status query string no
source_platform query string no
external_order_id query string no
search query string no

📄 /api/invoices/get-invoices.md

POST /invoices/:invoice_id/resend Scopes: invoices:write

Send an invoice that already exists, again: a branded email with the invoice PDF attached and a "Pay now" link. Unlike send_invoice this also works on invoices held in a connected accounting platform, fetching the current invoice and PDF from it without altering it, so chasing an overdue invoice needs the invoices:write scope rather than a login to the accounting file. Requires the invoice to be approved/open, not draft or voided.

5 parameters
Name In Type Required Description
invoice_id path string yes
to body string no Optional. Send to this address instead of the contact the invoice is addressed to. Use it to chase an accounts-payable inbox without changing the invoice itself.
attach_pdf body boolean no Optional, defaults to true. Attach the invoice PDF to the email.
recipient_contact_id body string no Optional. UUID of another contact on this workspace to send to instead, e.g. a bookkeeper. Ignored when "to" is given.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices-invoice-id-resend.md

POST /invoices/:invoice_id/send Scopes: invoices:write

Email a native invoice to its linked contact (or an explicit "to" address) via TrustPager Mail. The email includes the line items, amount due, and a "Pay now" button when the invoice has a payment link (run create_invoice_payment_link first for Stripe card payment); otherwise it shows the workspace bank/BPAY details.

3 parameters
Name In Type Required Description
invoice_id path string yes
to body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/post-invoices-invoice-id-send.md

PATCH /invoices/:invoice_id Scopes: invoices:write

Update a native invoice header (status, dates, reference, amount_paid, etc.). amount_due is recomputed. Pass only the fields you want to change.

7 parameters
Name In Type Required Description
invoice_id path string yes
status body string no
due_date body string no
reference body string no
amount_paid body number no
amount_credited body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/patch-invoices-invoice-id.md

PATCH /invoices/:invoice_id/line-items/:line_id Scopes: invoices:write

Update one line item on a native invoice. line_total and invoice totals recompute when pricing fields change.

8 parameters
Name In Type Required Description
invoice_id path string yes
line_id path string yes
description body string no
quantity body number no
unit_price body number no
discount_percent body number no
tax_amount body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/invoices/patch-invoices-invoice-id-line-items-line-id.md

Recurring Invoices (5 endpoints)

Recurring invoice schedules that generate invoices automatically on a cadence.

📄 Full markdown: /api/recurring-invoices.md

POST /recurring-invoices Scopes: recurring_invoices:write

Set up a recurring invoice: pick a schedule (interval_unit week|month|year + interval_count) and line_items, optionally linked to an opportunity/contact. Each period TrustPager generates a fresh native invoice, attaches a Stripe 'Pay now' link (attach_payment_link, needs Stripe connected), and emails it (auto_send). Optional end_date or max_occurrences stop the series. Starts active by default.

19 parameters
Name In Type Required Description
name body string no
opportunity_id body string no
contact_id body string no
customer_id body string no
contact_name body string no
currency_code body string no
reference body string no
interval_unit body string no
interval_count body number no
start_date body string no
next_run_at body string no
end_date body string no
max_occurrences body number no
due_days body number no
auto_send body boolean no
attach_payment_link body boolean no
status body string no
line_items body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/recurring-invoices/post-recurring-invoices.md

DELETE /recurring-invoices/:recurring_invoice_id Scopes: recurring_invoices:write

Stop a recurring invoice schedule permanently (no more invoices are generated). Already-generated invoices are kept. Destructive.

2 parameters
Name In Type Required Description
recurring_invoice_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/recurring-invoices/delete-recurring-invoices-recurring-invoice-id.md

GET /recurring-invoices/:recurring_invoice_id Scopes: recurring_invoices:read

Fetch one recurring invoice schedule by UUID, including its template line items, next run date, and how many invoices it has generated.

1 parameter
Name In Type Required Description
recurring_invoice_id path string yes

📄 /api/recurring-invoices/get-recurring-invoices-recurring-invoice-id.md

GET /recurring-invoices Scopes: recurring_invoices:read

List recurring invoice schedules. Filter by status (active|paused|stopped|completed) or opportunity_id. Each schedule auto-generates a native invoice every period.

3 parameters
Name In Type Required Description
status query string no
opportunity_id query string no
limit query number no

📄 /api/recurring-invoices/get-recurring-invoices.md

PATCH /recurring-invoices/:recurring_invoice_id Scopes: recurring_invoices:write

Update a recurring invoice schedule (line items, interval, dates, toggles) OR change its status to pause/resume/stop it. status='paused' stops generating, status='active' resumes, status='stopped' ends it. Pass only the fields you want to change.

17 parameters
Name In Type Required Description
recurring_invoice_id path string yes
name body string no
opportunity_id body string no
contact_id body string no
currency_code body string no
reference body string no
interval_unit body string no
interval_count body number no
next_run_at body string no
end_date body string no
max_occurrences body number no
due_days body number no
auto_send body boolean no
attach_payment_link body boolean no
status body string no
line_items body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/recurring-invoices/patch-recurring-invoices-recurring-invoice-id.md

Files (15 endpoints)

Unified file storage endpoint for all file types. Use ?type=document (private PDFs), ?type=image (public CDN/R2 images), or ?type=secure (confidential private files). Single-resource routes (/files/:id) auto-detect the type.

📄 Full markdown: /api/files.md

POST /files/bundle Scopes: files:read

Bundle up to 50 files (documents, images, or secure files) into a single ZIP. Auto-detects each file's type. Two response modes: default returns binary application/zip with Content-Disposition: attachment (best for direct browser downloads). Pass ?response=url to instead stage the ZIP in private storage and receive a 10-minute signed download URL — the right mode for API/MCP agents that can't consume large binary bodies. Max 50 files / 200MB total. Skipped files (storage errors) are listed in _manifest.txt inside the ZIP.

3 parameters
Name In Type Required Description
ids body array yes File UUIDs to bundle (1-50). Mix of document / image / secure types is fine — each is auto-detected.
filename body string no Optional ZIP filename (without extension). Defaults to "attachments_<YYYY-MM-DD>.zip".
response body string no Response mode. "binary" (default): streams the ZIP back in the response body. "url": stages the ZIP and returns a JSON body with a signed download URL good for 10 minutes. Pass as a query string (?response=url) — body field is also accepted.

📄 /api/files/post-files-bundle.md

POST /files/folders Scopes: files:write

Create a new file folder.

2 parameters
Name In Type Required Description
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/post-files-folders.md

DELETE /files/:file_id Scopes: files:delete

Delete a file by UUID. Destructive.

2 parameters
Name In Type Required Description
file_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/delete-files-file-id.md

DELETE /files/folders/:folder_id Scopes: files:delete

Delete a file folder by UUID.

2 parameters
Name In Type Required Description
folder_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/delete-files-folders-folder-id.md

GET /files/:file_id/download Scopes: files:read

Download a workspace file by UUID.

1 parameter
Name In Type Required Description
file_id path string yes

📄 /api/files/get-files-file-id-download.md

GET /files/:file_id Scopes: files:read

Fetch a single file metadata record by UUID.

1 parameter
Name In Type Required Description
file_id path string yes

📄 /api/files/get-files-file-id.md

GET /files/:file_id/signed-url Scopes: files:read

Get a signed playback URL for a private file.

1 parameter
Name In Type Required Description
file_id path string yes

📄 /api/files/get-files-file-id-signed-url.md

GET /files Scopes: files:read

List files in workspace storage. `type` is REQUIRED and selects which store to read: document, image or secure. Then optionally filter by folder, tag, category, document_type, file_category, or free-text search. Every file carries a `tags` array of {name, color} — the same tags shown on the file in the Files page — so `tag` is how you pull back, say, only the "Before" photos.

9 parameters
Name In Type Required Description
type query string yes REQUIRED. Which file store to list: document (PDFs and docs), image (images/media), or secure (private files). Omitting it returns a 400.
limit query number no
after query string no
search query string no Free-text search across file names.
folder query string no
tag query string no Return only files carrying this tag, matched on the tag name (e.g. "Before"). Case-sensitive, one tag per request.
category query string no
document_type query string no
file_category query string no

📄 /api/files/get-files.md

POST /files/:file_id/make-private Scopes: files:write

Make a file private.

2 parameters
Name In Type Required Description
file_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/post-files-file-id-make-private.md

POST /files/:file_id/make-public Scopes: files:write

Make a file publicly accessible.

2 parameters
Name In Type Required Description
file_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/post-files-file-id-make-public.md

POST /files/:file_id/publish Scopes: files:write

Publish a document (make it generally accessible).

2 parameters
Name In Type Required Description
file_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/post-files-file-id-publish.md

POST /files/:file_id/unpublish Scopes: files:write

Unpublish a document.

2 parameters
Name In Type Required Description
file_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/post-files-file-id-unpublish.md

PUT /files/:file_id Scopes: files:write

Update a file metadata record: rename it, change its description, move it to another folder, or set its tags. Only the keys you send are changed.

8 parameters
Name In Type Required Description
file_id path string yes REQUIRED. The file id.
name body string no The file name as shown in the Files page, including its extension.
description body string no Free-text description stored with the file.
folder body string no The folder the file sits in on the Files page. This is the folder NAME, not an id.
tags body array no Full replace of the file's tags — the coloured chips shown on the file in the Files page (e.g. ["Before"] on a job photo). Accepts names (["Before"]) or objects ([{"name":"Before","color":"#f97316"}]). Send [] to clear every tag; omit the key to leave tags untouched. Max 10.
document_type body string no Document files only — the document category.
file_category body string no Secure files only — the file category.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/put-files-file-id.md

POST /files/upload Scopes: files:write

Upload a file to workspace storage. Pass type=document (PDF), type=image, or type=secure (private files — the default for spreadsheets, CSVs, Office docs, and anything else). Non-PDF files sent as type=document are auto-filed as secure files instead of rejected (the response meta returns auto_filed_as:"file"); attach those to an opportunity with add_opportunity_file, not add_opportunity_document.

11 parameters
Name In Type Required Description
type body string yes REQUIRED. The kind of file: "document" (PDF), "image", or "secure" (private files — spreadsheets, CSVs, Office docs, and anything else). This is the top-level field that selects how the file is stored; it is NOT the same as "category" or "document_type".
base64 body string yes REQUIRED. The file content as base64. A leading "data:...;base64," prefix is accepted and stripped automatically.
name body string yes REQUIRED. The filename including its extension (e.g. "briefing.pdf").
mime_type body string no Optional MIME type (e.g. "application/pdf"). Defaults to a value derived from the filename extension.
folder body string no Optional folder/label to file the upload under.
description body string no Optional description stored with the file.
document_type body string no Optional. Only used when type="document" — categorises the document record.
category body string no Optional. Only used when type="image" — sets the storage path prefix and image category. Does NOT set the file type; use the "type" field for that.
file_category body string no Optional. Only used when type="secure" — categorises the secure file (defaults to a value derived from the MIME type).
tags body array no Optional tags to classify the file, shown as coloured chips on the file in the Files page (e.g. ["Before"] on a job photo). Accepts names (["Before"]) or objects ([{"name":"Before","color":"#f97316"}]); a name with no colour gets the workspace default. Max 10.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/files/post-files-upload.md

Images (1 endpoint)

Image optimisation: resize a stored image and generate fast WebP variants.

📄 Full markdown: /api/images.md

POST /images/optimize Scopes: files:write

Optimize a stored image — resize and generate WebP variants for fast delivery.

3 parameters
Name In Type Required Description
file_id body string yes
max_width body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/images/post-images-optimize.md

Notepads (18 endpoints)

Manage rich-text notepads organized in folders. Supports markdown input, iterative editing (append/prepend/section patches), per-record visibility, and ACL-based access control for restricted notes.

📄 Full markdown: /api/notepads.md

POST /notepads/:notepad_id/acl Scopes: notepads:write

Grant access to a notepad (user or role principal).

5 parameters
Name In Type Required Description
notepad_id path string yes
principal_type body string yes
principal_id body string yes
permission body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/post-notepads-notepad-id-acl.md

POST /notepads/folders/:folder_id/acl Scopes: notepads:write

Grant access to a notepad folder (user or role principal).

5 parameters
Name In Type Required Description
folder_id path string yes
principal_type body string yes
principal_id body string yes
permission body string no read or write
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/post-notepads-folders-folder-id-acl.md

POST /notepads Scopes: notepads:write

Create a new notepad. Supports markdown content. Set is_public=true to publish it to the public blog (a slug is derived from the title); notepads are private by default. Set meta_title / meta_description to control the published post's SEO tags.

10 parameters
Name In Type Required Description
title body string yes
content body string no
folder_id body string no
is_public body boolean no Publish to the public blog. Private by default. The post only appears publicly when it is also in a website's designated blog folder.
slug body string no Optional public URL slug. Derived from the title when omitted.
cover_image body string no Cover image URL — shown on the Notepads card grid and at the top of the public blog post.
meta_title body string no SEO title tag for the published post. Keep it to about 60 characters. When omitted the website falls back to the notepad title.
meta_description body string no SEO meta description for the published post. Keep it to about 160 characters. When omitted the website falls back to an auto-generated excerpt of the body.
og_image body string no Social share image URL (og:image) for the published post. Falls back to cover_image when omitted.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/post-notepads.md

POST /notepads/folders Scopes: notepads:write

Create a new notepad folder. Set is_public=true to mark it a public content collection that can be integrated as a section on a website (the public notepads inside it then appear there).

3 parameters
Name In Type Required Description
name body string yes
is_public body boolean no Mark the folder as a public content collection (integratable on websites).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/post-notepads-folders.md

DELETE /notepads/:notepad_id Scopes: notepads:delete

Delete a notepad by UUID. Destructive.

2 parameters
Name In Type Required Description
notepad_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/delete-notepads-notepad-id.md

DELETE /notepads/folders/:folder_id Scopes: notepads:delete

Delete a notepad folder by UUID.

2 parameters
Name In Type Required Description
folder_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/delete-notepads-folders-folder-id.md

GET /notepads/:notepad_id Scopes: notepads:read

Fetch a notepad by UUID, including its full content.

1 parameter
Name In Type Required Description
notepad_id path string yes

📄 /api/notepads/get-notepads-notepad-id.md

POST /notepads/:notepad_id/deals Scopes: notepads:write

Link a notepad to an opportunity.

3 parameters
Name In Type Required Description
notepad_id path string yes
deal_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/post-notepads-notepad-id-deals.md

GET /notepads Scopes: notepads:read

List notepads in the workspace. Filter by folder, folder_id, visibility, is_favorite, is_public, or free-text search.

8 parameters
Name In Type Required Description
limit query number no
after query string no
search query string no Free-text search across notepad titles and content.
folder query string no
folder_id query string no
visibility query string no
is_favorite query boolean no
is_public query boolean no Filter to public (blog-published) notepads only.

📄 /api/notepads/get-notepads.md

DELETE /notepads/acl/:acl_id Scopes: notepads:write

Revoke a notepad ACL entry by UUID.

2 parameters
Name In Type Required Description
acl_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/delete-notepads-acl-acl-id.md

DELETE /notepads/:notepad_id/deals/:deal_id Scopes: notepads:write

Unlink a notepad from an opportunity.

3 parameters
Name In Type Required Description
notepad_id path string yes
deal_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/delete-notepads-notepad-id-deals-deal-id.md

PATCH /notepads/:notepad_id Scopes: notepads:write

Update the title and/or content of a notepad. Set is_public=true to publish it to the public blog, or false to unpublish; a slug is derived from the title on first publish. Set meta_title / meta_description to control the published post's SEO tags.

10 parameters
Name In Type Required Description
notepad_id path string yes
title body string no
content body string no
is_public body boolean no Publish (true) or unpublish (false) to the public blog.
slug body string no Optional public URL slug. Derived from the title when omitted.
cover_image body string no Cover image URL (shown on the card grid + public post). Pass null to clear.
meta_title body string no SEO title tag for the published post. Keep it to about 60 characters. Pass null to clear and fall back to the notepad title.
meta_description body string no SEO meta description for the published post. Keep it to about 160 characters. Pass null to clear and fall back to an auto-generated excerpt of the body.
og_image body string no Social share image URL (og:image) for the published post. Pass null to clear and fall back to cover_image.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/patch-notepads-notepad-id.md

PATCH /notepads/folders/:folder_id Scopes: notepads:write

Rename or update a notepad folder. Set is_public to mark it (true) or unmark it (false) as a public content collection integratable on websites.

4 parameters
Name In Type Required Description
folder_id path string yes
name body string no
is_public body boolean no Public content collection flag.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/notepads/patch-notepads-folders-folder-id.md

Whiteboards (8 endpoints)

Whiteboards and their canvas contents, optionally linked to an opportunity.

📄 Full markdown: /api/whiteboards.md

POST /whiteboards/:whiteboard_id/elements Scopes: whiteboards:write

Append elements to the current whiteboard canvas without wiping what is already there.

3 parameters
Name In Type Required Description
whiteboard_id path string yes
elements body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whiteboards/post-whiteboards-whiteboard-id-elements.md

POST /whiteboards Scopes: whiteboards:write

Create a whiteboard. Starts empty; use set_whiteboard_content to add a diagram.

4 parameters
Name In Type Required Description
name body string yes
description body string no
opportunity_id body string no Optional opportunity to link the whiteboard to.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whiteboards/post-whiteboards.md

DELETE /whiteboards/:whiteboard_id Scopes: whiteboards:delete

Delete a whiteboard and its canvas.

2 parameters
Name In Type Required Description
whiteboard_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whiteboards/delete-whiteboards-whiteboard-id.md

POST /whiteboards/:whiteboard_id/duplicate Scopes: whiteboards:write

Clone a whiteboard and its current canvas into a new board.

3 parameters
Name In Type Required Description
whiteboard_id path string yes
name body string no Optional name for the copy.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whiteboards/post-whiteboards-whiteboard-id-duplicate.md

GET /whiteboards/:whiteboard_id Scopes: whiteboards:read

Fetch a whiteboard with its current canvas elements, appState and files.

1 parameter
Name In Type Required Description
whiteboard_id path string yes

📄 /api/whiteboards/get-whiteboards-whiteboard-id.md

GET /whiteboards Scopes: whiteboards:read

List whiteboards in the workspace. Filter by opportunity_id or search by name.

2 parameters
Name In Type Required Description
opportunity_id query string no
search query string no

📄 /api/whiteboards/get-whiteboards.md

PUT /whiteboards/:whiteboard_id/content Scopes: whiteboards:write

Replace the entire whiteboard canvas with an array of Excalidraw elements (rectangle, ellipse, diamond, arrow, line, text). Minimal elements are auto-completed. NOTE: an open builder tab reads content on load and auto-saves over external changes — close/reopen the board to see the result.

5 parameters
Name In Type Required Description
whiteboard_id path string yes
elements body array yes Excalidraw elements. Each needs type + x + y + width + height; text/colors/points optional.
appState body object no
files body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whiteboards/put-whiteboards-whiteboard-id-content.md

PATCH /whiteboards/:whiteboard_id Scopes: whiteboards:write

Update a whiteboard name, description, or linked opportunity.

6 parameters
Name In Type Required Description
whiteboard_id path string yes UUID of the whiteboard to update. Get ids from list_whiteboards.
opportunity_id body string no UUID of the opportunity this whiteboard hangs off. Pass null to make it standalone.
name body string no Whiteboard name shown in the Whiteboards list.
description body string no What this whiteboard is for. Internal note for your team.
settings body object no Whiteboard canvas settings (grid, snapping, background, default tool). Full-replace on write.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/whiteboards/patch-whiteboards-whiteboard-id.md

Spreadsheets (16 endpoints)

Manage spreadsheet templates (column definitions) and populated spreadsheets (row data). Spreadsheets can be linked to opportunities and are also created automatically when a form with a spreadsheet field is submitted. Scopes: spreadsheets:read, spreadsheets:write, spreadsheets:delete.

📄 Full markdown: /api/spreadsheets.md

POST /spreadsheets/:spreadsheet_id/rows Scopes: spreadsheets:write

Append a row to a spreadsheet.

3 parameters
Name In Type Required Description
spreadsheet_id path string yes
cells body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/post-spreadsheets-spreadsheet-id-rows.md

POST /spreadsheets/:spreadsheet_id/rows/bulk Scopes: spreadsheets:write

Bulk-append rows.

3 parameters
Name In Type Required Description
spreadsheet_id path string yes
rows body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/post-spreadsheets-spreadsheet-id-rows-bulk.md

POST /spreadsheets Scopes: spreadsheets:write

Create a spreadsheet from a template.

3 parameters
Name In Type Required Description
template_id body string yes
name body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/post-spreadsheets.md

POST /spreadsheets/templates Scopes: spreadsheets:write

Create a spreadsheet template.

3 parameters
Name In Type Required Description
name body string yes
columns body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/post-spreadsheets-templates.md

DELETE /spreadsheets/:spreadsheet_id Scopes: spreadsheets:delete

Delete a spreadsheet.

2 parameters
Name In Type Required Description
spreadsheet_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/delete-spreadsheets-spreadsheet-id.md

DELETE /spreadsheets/:spreadsheet_id/rows/:row_id Scopes: spreadsheets:delete

Delete a row.

3 parameters
Name In Type Required Description
spreadsheet_id path string yes
row_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/delete-spreadsheets-spreadsheet-id-rows-row-id.md

DELETE /spreadsheets/templates/:template_id Scopes: spreadsheets:delete

Delete a spreadsheet template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/delete-spreadsheets-templates-template-id.md

POST /spreadsheets/:spreadsheet_id/import_from_document Scopes: spreadsheets:write

Extract rows from a PDF via a document mapper.

4 parameters
Name In Type Required Description
spreadsheet_id path string yes
mapper_id body string yes
file_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/post-spreadsheets-spreadsheet-id-import-from-document.md

GET /spreadsheets Scopes: spreadsheets:read

List spreadsheets in the workspace.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/spreadsheets/get-spreadsheets.md

PATCH /spreadsheets/:spreadsheet_id Scopes: spreadsheets:write

Update a spreadsheet.

5 parameters
Name In Type Required Description
spreadsheet_id path string yes UUID of the spreadsheet to update. Get ids from list_spreadsheets.
name body string no Spreadsheet name shown in the Spreadsheets list.
opportunity_id body string no UUID of the opportunity this spreadsheet hangs off. Pass null to make it standalone.
is_archived body boolean no Archive the spreadsheet. Archived spreadsheets stay readable but are hidden from the default list.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/patch-spreadsheets-spreadsheet-id.md

PATCH /spreadsheets/:spreadsheet_id/rows/:row_id Scopes: spreadsheets:write

Update a row.

4 parameters
Name In Type Required Description
spreadsheet_id path string yes
row_id path string yes
cells body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/patch-spreadsheets-spreadsheet-id-rows-row-id.md

PATCH /spreadsheets/templates/:template_id Scopes: spreadsheets:write

Update a spreadsheet template.

8 parameters
Name In Type Required Description
template_id path string yes UUID of the spreadsheet template to update. Get ids from list_spreadsheet_templates.
name body string no Template name shown in the Spreadsheets list.
description body string no What this template is for. Internal note for your team.
columns body array no Ordered column definitions. Each column: { id, label, type, options? }. Validated on write — an unknown column type is rejected. Full-replace array.
merge_rules body object no How rows from different sources are matched and merged into one row. Validated on write. Full-replace on write.
default_sort body object no Default sort applied when the spreadsheet opens, e.g. { "column_id": "...", "direction": "asc" }. Validated on write.
is_archived body boolean no Archive the template. Archived templates stay readable but are hidden from the picker.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/spreadsheets/patch-spreadsheets-templates-template-id.md

Reports (18 endpoints)

Query engine, dashboard CRUD, card CRUD, and funnel configuration for the workspace reporting system. Dashboards support per-record visibility (all_users or restricted) with ACL-based access grants.

📄 Full markdown: /api/reports.md

POST /report-dashboards/:dashboard_id/cards Scopes: opportunities:read

Add a card to a dashboard. Standard cards carry a query_spec (same shape as query_report). A funnel card (visualization_type "funnel") measures pipeline pass-through conversion from the stage-move log: omit query_spec and pass display_config.funnel = { pipeline_id, steps: [{ name, stage_ids }] } instead.

8 parameters
Name In Type Required Description
dashboard_id path string yes Dashboard UUID
title body string yes Card title
visualization_type body string no stat, bar, horizontal_bar, line, area, donut, pie, table, composed, or funnel
query_spec body object no Query spec (same shape as query_report). Omit for funnel cards. For a drilldown table card set mode:"drilldown" and list the columns you want in dimensions[] (in order, custom fields included as cf_<id>); the emailed digest table renders up to 8 of them.
display_config body object no Display overrides. Funnel cards: { funnel: { pipeline_id, steps: [{ name, stage_ids }] } }. Table cards: { columns, max_rows }. max_rows caps how many rows render in the emailed digest table (default 25, max 100) — raise it if rows are being dropped from the digest.
size body string no sm, md, lg
position body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/post-report-dashboards-dashboard-id-cards.md

POST /report-dashboards/:dashboard_id/acl Scopes: opportunities:read

Grant dashboard access.

4 parameters
Name In Type Required Description
dashboard_id path string yes
principal_type body string yes
principal_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/post-report-dashboards-dashboard-id-acl.md

PUT /report-funnels Scopes: opportunities:read

Configure a funnel for a pipeline.

3 parameters
Name In Type Required Description
pipeline_id body string yes
steps body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/put-report-funnels.md

POST /report-dashboards Scopes: opportunities:read

Create a report dashboard.

5 parameters
Name In Type Required Description
name body string no
description body string no
template body string no Dashboard template key to seed cards from.
pipeline_id body string no Scope the seeded cards to one pipeline.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/post-report-dashboards.md

DELETE /report-dashboards/:dashboard_id Scopes: opportunities:read

Delete a dashboard.

2 parameters
Name In Type Required Description
dashboard_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/delete-report-dashboards-dashboard-id.md

GET /report-funnels Scopes: opportunities:read

Get funnel config for a pipeline.

1 parameter
Name In Type Required Description
pipeline_id query string yes

📄 /api/reports/get-report-funnels.md

POST /reports/query Scopes: opportunities:read

Run a report query against the workspace. Free read. In aggregate mode (default) dimensions[] are the grouping keys. In drilldown mode (mode:"drilldown") dimensions[] instead names the columns to return and their order — any dimension or measure field from list_report_sources, including per-workspace custom fields (cf_<id>); omit it to get the source default column set. The "deals" source excludes pipelines flagged exclude_from_lead_reporting by default; pass include_excluded_pipelines:true to include them.

5 parameters
Name In Type Required Description
source body string yes
measures body array no
dimensions body array no
filters body array no
include_excluded_pipelines body boolean no Deals source only. Include pipelines flagged exclude_from_lead_reporting (excluded by default).

📄 /api/reports/post-reports-query.md

DELETE /report-cards/:card_id Scopes: opportunities:read

Delete a card.

2 parameters
Name In Type Required Description
card_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/delete-report-cards-card-id.md

POST /reports/render-preview Scopes: opportunities:read

Server-side render a dashboard to HTML for preview.

1 parameter
Name In Type Required Description
dashboard_id body string yes

📄 /api/reports/post-reports-render-preview.md

PUT /report-dashboards/:dashboard_id/reorder Scopes: opportunities:read

Reorder cards on a dashboard.

3 parameters
Name In Type Required Description
dashboard_id path string yes
card_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/put-report-dashboards-dashboard-id-reorder.md

POST /reports/send Scopes: opportunities:read

Send a dashboard digest email.

3 parameters
Name In Type Required Description
dashboard_id body string yes
to body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/post-reports-send.md

PATCH /report-cards/:card_id Scopes: opportunities:read

Update a card.

2 parameters
Name In Type Required Description
card_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/patch-report-cards-card-id.md

PATCH /report-dashboards/:dashboard_id Scopes: opportunities:read

Update a dashboard.

2 parameters
Name In Type Required Description
dashboard_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reports/patch-report-dashboards-dashboard-id.md

AI Knowledge (7 endpoints)

Manage company AI Knowledge entries with semantic search powered by Voyage AI embeddings. Use for policies, FAQs, agent instructions, and product documentation.

📄 Full markdown: /api/knowledge.md

POST /knowledge Scopes: knowledge:write

Create a new knowledge base entry. Requires title and content.

5 parameters
Name In Type Required Description
title body string yes
content body string yes
category body string no
tags body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge/post-knowledge.md

DELETE /knowledge/:knowledge_id Scopes: knowledge:delete

Delete a knowledge base entry by UUID. Destructive.

2 parameters
Name In Type Required Description
knowledge_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge/delete-knowledge-knowledge-id.md

GET /knowledge/:knowledge_id Scopes: knowledge:read

Fetch a single knowledge base entry by UUID. Returns full content.

1 parameter
Name In Type Required Description
knowledge_id path string yes

📄 /api/knowledge/get-knowledge-knowledge-id.md

GET /knowledge Scopes: knowledge:read

List entries in the workspace knowledge base. Supports filtering by category, tag, and text search.

5 parameters
Name In Type Required Description
limit query number no
after query string no
category query string no
tag query string no Exact match against one of the entry's tags.
search query string no Free-text search on the entry title.

📄 /api/knowledge/get-knowledge.md

POST /knowledge/search Scopes: knowledge:read

Semantic search across the workspace knowledge base. Use to find relevant context before answering a customer question. Pass kb_ids to scope to specific knowledge bases, or agent_type + agent_id to auto-scope to the knowledge bases attached to that agent.

5 parameters
Name In Type Required Description
query body string yes Search query
limit body number no Max results (default 5)
kb_ids body array no Optional: restrict search to these knowledge base IDs
agent_type body string no Optional: with agent_id, auto-scope to the KBs attached to this agent
agent_id body string no Optional: the agent whose attached KBs scope the search

📄 /api/knowledge/post-knowledge-search.md

POST /knowledge/sync-from-products Scopes: knowledge:write

Refresh the knowledge base entries that auto-generate from the product catalog.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge/post-knowledge-sync-from-products.md

PATCH /knowledge/:knowledge_id Scopes: knowledge:write

Update a knowledge base entry. Pass only the fields you want to change.

6 parameters
Name In Type Required Description
knowledge_id path string yes
title body string no
content body string no
category body string no
tags body array no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/knowledge/patch-knowledge-knowledge-id.md

Agent Memory (7 endpoints)

Cross-run persistent state for managed agents. Each row records what an agent learned, decided, or intends to revisit about a subject. Supports semantic search via vector embeddings. Required scopes: memory:read (GET/search), memory:write (POST/PATCH/DELETE).

📄 Full markdown: /api/memory.md

DELETE /memory/:memory_id Scopes: memory:write

Soft-delete a memory. Sets deleted_at; the row is preserved for audit but no longer surfaces in list / search / get calls. Reversible only by admin SQL.

2 parameters
Name In Type Required Description
memory_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/memory/delete-memory-memory-id.md

GET /memory/:memory_id Scopes: memory:read

Fetch a single agent memory by its uuid.

1 parameter
Name In Type Required Description
memory_id path string yes

📄 /api/memory/get-memory-memory-id.md

GET /memory Scopes: memory:read

List agent memories for this workspace, filterable by subject, kind, agent, tag, linked entity, and time. Cursor-paginated. Use this for keyed lookup before composing new actions (e.g. "what have I already said to this contact?"); use search_memory for fuzzy / semantic lookup.

11 parameters
Name In Type Required Description
subject_type query string no Filter by subject type — e.g. "contact", "opportunity", "company", "user", "self".
subject_id query string no Filter by subject id (use with subject_type).
kind query string no Filter by kind — e.g. "pitch", "objection", "preference", "next_steps".
agent_registry_id query string no Filter by owning agent.
visibility query string no Filter by visibility.
tag query array no Tag filter (matches any of the provided tags). Pass as repeated `tag` query params or array.
linked_entity_type query string no Find memories linked to an entity of this type.
linked_entity_id query string no Find memories linked to this entity id (must be combined with linked_entity_type).
since query string no ISO timestamp — return memories created after this time.
limit query number no
after query string no

📄 /api/memory/get-memory.md

POST /memory/purge Scopes: memory:delete

Bulk-retract agent memories matching a filter, in one call. Soft-deletes by default (reversible, audit-preserving); pass hard:true to physically remove rows for PII / right-to-be-forgotten. This is the "forget everything about this contact / opportunity / company" primitive — filter by subject, agent, kind, tag, or linked entity. Refuses to run with no filter unless you set all:true. Requires the memory:delete scope.

10 parameters
Name In Type Required Description
subject_type body string no Purge memories about this subject type — e.g. "contact", "opportunity", "company", "user", "self".
subject_id body string no Purge memories about this specific subject id (use with subject_type for "forget this contact").
agent_registry_id body string no Purge memories owned by this agent.
kind body string no Purge memories of this kind.
tag body string no Purge memories carrying this tag.
linked_entity_type body string no Purge memories linked to an entity of this type (combine with linked_entity_id).
linked_entity_id body string no Purge memories linked to this entity id (combine with linked_entity_type).
hard body boolean no Default false (soft-delete). true physically removes the rows — irreversible.
all body boolean no Set true to purge EVERY memory in the workspace. Required when no filter is provided; ignored otherwise.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/memory/post-memory-purge.md

POST /memory/search Scopes: memory:read

Semantic search over agent memories. Pass a natural-language query; returns the top-K most similar memories ranked by cosine similarity. Use when you need fuzzy / topic-based lookup ("have I discussed pricing with this contact?") rather than exact filter by subject_id. Use list_memory for keyed lookup ("what have I said to contact X about kind Y?").

8 parameters
Name In Type Required Description
query body string yes Natural language query.
subject_type body string no
subject_id body string no
kind body string no
agent_registry_id body string no
visibility body string no
limit body number no Default 10, max 50.
threshold body number no Cosine similarity floor (0.0–1.0). Default 0.3.

📄 /api/memory/post-memory-search.md

PATCH /memory/:memory_id Scopes: memory:write

Update a memory in place — change content, metadata, tags, links, confidence, expiry, or visibility. Re-embeds automatically if content changes. For upsert semantics, prefer write_memory with the same key.

9 parameters
Name In Type Required Description
memory_id path string yes
content body string no
metadata body object no
linked_entities body array no
tags body array no
confidence body number no
expires_at body string no
visibility body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/memory/patch-memory-memory-id.md

POST /memory Scopes: memory:write

Write a memory for an agent. If `key` is provided, behaves as upsert on (agent, subject, kind, key) — re-running the same key UPDATES the existing memory rather than creating a duplicate. Use this to record what you have learned, decided, or intend to revisit. Content is natural-language; metadata is structured. Embedding generated automatically for semantic search.

16 parameters
Name In Type Required Description
agent_registry_id body string no The owning agent id. For agent-private state.
visibility body string no Default "private". Set "shared" to make this memory readable by other agents in the workspace.
subject_type body string yes What this memory is about. Canonical values: "contact", "opportunity", "company", "user" (a workspace user — the person the agent is helping), "self". Agent-defined values also work.
subject_id body string no The id of the subject (the contact uuid, opportunity uuid, user uuid, etc.). Null for global/self memories.
kind body string yes The category of memory — e.g. "pitch", "objection", "preference", "observation", "next_steps". Free-form; agents define their own taxonomy.
key body string no Optional unique key within (agent, subject, kind) — enables upsert. Example: an article_slug for a pitch memory means re-pitching the same slug UPDATES rather than duplicates.
content body string yes The memory itself, in natural language.
metadata body object no Structured payload alongside the content.
linked_entities body array no Other entities this memory references. e.g. [{type:"opportunity", id:"..."}, {type:"article", id:"voice-agents-setup"}].
tags body array no Free-form semantic facets. e.g. ["competitor:Twilio", "objection:pricing", "feature:voice_agents"].
confidence body number no 0.0–1.0. Default 1.0. Decreases as the memory ages or gets contradicted.
source_kind body string no Where this memory came from — e.g. "email_send", "transcript", "tool_observation", "manual".
source_id body string no Pointer back to the source event (e.g. email_logs.id).
parent_memory_id body string no Link to an earlier memory this one updates or continues.
expires_at body string no ISO timestamp. Memory becomes inactive after this time.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/memory/post-memory.md

Company (33 endpoints)

View and manage company settings, users, and CRM configuration.

📄 Full markdown: /api/company.md

GET /our-company/dispatcher-config Scopes: company:read

Get the workspace dispatcher settings — retry policy, pacing/concurrency, and the business-hours CALLING WINDOWS used for scheduled sends and the AI dialler. business_hours.windows is keyed by day (mon…sun); each day is a list of ["HH:MM","HH:MM"] ranges. A null/empty config means the workspace is on the platform defaults (Mon–Fri 09:00–17:00, per-lead timezone). Configured in the UI at https://app.trustpager.com/settings/inbox (Dispatcher).

📄 /api/company/get-our-company-dispatcher-config.md

GET /our-company Scopes: company:read

Get OUR Company — the workspace's own organisation profile (the business that runs this CRM), shown at https://app.trustpager.com/settings/company. NOT a CRM account/customer — for those use get_company / list_companies.

📄 /api/company/get-our-company.md

GET /our-company/pipeline-card-config Scopes: company:read

Get the pipeline (Workflows) opportunity-card configuration. Returns: available_sections (toggleable popout sections with labels + defaults); popout_sections (resolved on/off per section for the hover/popout panel); custom_field_ids (which opportunity custom fields show when the popout "custom_fields" section is on); and card_face ({ opportunity_type, custom_field_ids }) for what shows on the card FACE itself (the opportunity name, customer and value always show; the type and chosen custom fields are opt-in). Popout: notes/next_action/tasks default ON, custom_fields OFF. Card face: all default OFF.

📄 /api/company/get-our-company-pipeline-card-config.md

GET /our-company/referral-settings Scopes: company:read

Get the workspace referral settings: referral_form_template_id (the form pinned onto every referral link, where referrers/clients submit a referral) and referrer_portal_template_id (the portal template instantiated for a referrer). Configured in the UI at https://app.trustpager.com/settings/tools.

📄 /api/company/get-our-company-referral-settings.md

POST /our-company/users/invite Scopes: users:write

Invite a new user to the workspace.

3 parameters
Name In Type Required Description
email body string yes
role body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/post-our-company-users-invite.md

GET /our-company/ai-fill-prompts Scopes: company:read

List every "Fill with AI" form in the workspace with its label, what it controls, the built-in default master prompt, and the current workspace override (if any). Call this first when configuring how AI Fill writes fields — it returns the valid form_ids to pass to set_ai_fill_prompt. The create-opportunity form is form_id "create-deal-multi-step"; per-entity custom fields are "custom-fields-deal" / "custom-fields-contact" / "custom-fields-account".

📄 /api/company/get-our-company-ai-fill-prompts.md

DELETE /our-company/users/:user_id Scopes: users:delete

Remove a user from the workspace.

2 parameters
Name In Type Required Description
user_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/delete-our-company-users-user-id.md

POST /our-company/users/:user_id/resend-invite Scopes: users:write

Resend the workspace invitation to a user who was invited but has not accepted yet (status "pending"), shown at https://app.trustpager.com/settings/team. Keeps the SAME user id, so existing report recipients, task and work-order assignments stay intact. Never use remove_user plus invite_user to re-invite someone: that mints a new id and silently breaks those references. Get user_id from list_company_users. Fails if the user has already accepted and is active.

2 parameters
Name In Type Required Description
user_id path string yes UUID of the pending workspace user to re-invite. Get it from list_company_users (their status will be "pending").
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/post-our-company-users-user-id-resend-invite.md

DELETE /our-company/ai-fill-prompts/:form_id Scopes: company:write

Remove the workspace master-prompt override for one "Fill with AI" form, reverting it to the built-in default. Get valid form_ids from list_ai_fill_prompts.

2 parameters
Name In Type Required Description
form_id path string yes Form to reset to its built-in default.
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/delete-our-company-ai-fill-prompts-form-id.md

PUT /our-company/ai-fill-prompts/:form_id Scopes: company:write

Set the master prompt for one "Fill with AI" form. The master prompt is prepended to the AI Fill system prompt for that form, so it steers tone, format, and field rules every time AI Fill runs there (e.g. set form_id "create-deal-multi-step" to enforce a consistent Opportunity Title format). Get valid form_ids from list_ai_fill_prompts. Overrides only the named form; other forms are untouched.

3 parameters
Name In Type Required Description
form_id path string yes Form to configure. Get valid ids from list_ai_fill_prompts (e.g. "create-deal-multi-step").
master_prompt body string yes Instruction prepended to the AI Fill system prompt for this form.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/put-our-company-ai-fill-prompts-form-id.md

PUT /our-company/birthday-messages Scopes: company:write

Replace the reusable birthday message templates a user can pick from when sending a contact a birthday greeting. FULL REPLACE, not a merge: call get_birthday_messages first and send the existing templates back along with any new ones, or the omitted templates are removed.

2 parameters
Name In Type Required Description
messages body array yes The complete set of templates the workspace should have after this call.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/put-our-company-birthday-messages.md

PATCH /our-company/crm-settings Scopes: company:write

Update workspace CRM settings. Includes payment_details (bank-transfer / BPAY remittance details printed on invoices when there is no online pay link) and approval_routing_config (the ordered chain that decides who a queued approval — auto-responder reply or API write — is assigned to). Also covers list_view_defaults (default grouping per CRM list, which surfaces the left-nav bucket sub-list), detail_layout_config (detail-page card order/visibility), product_bucket_labels, approval_sla_config (approval breach SLA), auto_queue_config (Auto Queue guards, including the minimum gap between automated messages to the same contact), and notetaker_config / transcription_config (meeting notetaker + transcription settings).

38 parameters
Name In Type Required Description
lead_sources body array no Available lead sources for opportunities. Full-replace array — send the complete list you want kept.
lost_reasons body array no Available reasons when marking an opportunity as lost. Full-replace array.
won_reasons body array no Available reasons when marking an opportunity as won. Full-replace array.
referral_categories body array no Workspace referral categories (modality for radiology, service type for trades, partner type for property services). Renders as the category dropdown on the public referral form at /refer/{token} and surfaces as a chip on the Referrers leaderboard; submissions are validated against this list when it is set. Empty array = no dropdown, any category accepted. Full-replace array, e.g. ["Trade Partner","Supplier"].
custom_fields body object no REPLACES the entire stored value on write — always send the COMPLETE set (call get_crm_settings first, modify, send all of deal/account/contact back); anything omitted is removed. Custom field definitions keyed by entity: { deal: [...], account: [...], contact: [...] }. Each field: { id, label, type, options?, section?, show_on_detail, show_in_table, required?, fill_with_ai?, hidden?, conditional_logic? }. Types: text | textarea | url | dropdown | number | datetime | checkbox. Omit `id` and a slug is generated from the label. Values are read/written per record via the `metadata` parameter on contacts / companies / opportunities.
custom_fields_title body string no Custom label for the "Additional Information" custom-fields section on detail pages.
custom_field_sections body object no Section definitions that group custom fields on detail pages, keyed by entity: { deal: [...], account: [...], contact: [...] }. Each section: { name (must match the `section` string stamped on its member fields), default_state?: "open" | "collapsed" | "pinned" (default "collapsed"), description?, order? }. Full-replace per write — send the complete object.
opportunity_type_options body array no Available opportunity type options (e.g. New Business, Upsell, Renewal, Referral). Full-replace array. Requires opportunity_type_enabled.
account_type_options body array no Available company/account type options (e.g. Client, Supplier, Partner, Referrer). Full-replace array.
contact_type_options body array no Available contact type options (e.g. Accountant, Lawyer, Decision Maker, Referrer). Full-replace array.
transcript_types body array no Transcript type categories (e.g. Sales, Fulfilment, Support). Full-replace array.
transcript_sources body array no Transcript sources (e.g. Zoom, Loom, Manual). Full-replace array.
birthday_messages body array no Reusable birthday message templates selectable when sending a contact a birthday greeting. Each entry: { label, channels: string[] ("email" and/or "sms"), email_subject, email_body, sms_body }. Full-replace array.
form_completion_notify_emails body array no Workspace-wide default email addresses notified when any form is completed. Overridable per form template. Full-replace array.
automation_error_notify_emails body array no Email addresses notified when an automation action fails. Must be valid email addresses. Notifications are throttled to one per error signature per hour. Full-replace array; pass null to clear.
automation_error_notify_phones body array no Phone numbers in E.164 format (e.g. +61431377068) notified by SMS when an automation action fails. Requires an active phone number in the workspace. Throttled to one per error signature per hour. Full-replace array; pass null to clear.
quick_links body array no Workspace-wide Quick Link TYPES — buttons in the right-rail sidebar of opportunity, company and contact pages, each opening a per-record URL in a new tab. Read-modify-write: call get_crm_settings, append, send the whole array back. Per-record URLs live on the entity under metadata.quick_links keyed by the type id.
ai_fill_prompts body object no Per-FORM "Fill with AI" master prompts. Prefer the dedicated list_ai_fill_prompts / set_ai_fill_prompt / reset_ai_fill_prompt actions — they validate form ids and write the correct shape. Shape, for reference: { "<form_id>": { "master_prompt": "...", "updated_at": "ISO" } } keyed by formId (e.g. "create-deal-multi-step"), NOT by custom-field id. Shallow-merges.
accounts_enabled body boolean no Enable the Companies/Accounts feature in this workspace.
contacts_enabled body boolean no Enable the Contacts feature in this workspace.
opportunity_type_enabled body boolean no Show the Opportunity Type field on opportunities. Turn on before relying on opportunity_type_options.
enable_work_orders body boolean no Enable Work Orders on opportunities.
opportunity_value_default_mode body string no How NEW opportunities determine their value. 'auto' (default) sums the value from the opportunity's products; 'manual' means the value is set by the user/automation and products never overwrite it. Overridable per-opportunity via update_opportunity value_is_manual.
needs_analysis_config body object no Workspace-wide config for the Proposal Builder / ai_needs_analysis. Shallow-merges — only the keys you pass change. UI editor: /settings/crm?section=needs-analysis.
referral_statement_template_id body string no document_templates UUID of the Document Builder template used to render referrer commission statements (chosen in the UI at /growth/referrals). Get ids from list_document_templates. Pass null to clear.
payment_details body object no Bank-transfer / BPAY details shown on invoices that have no online pay link. Replaces the whole object on write — send the complete set of fields you want kept.
email_template_settings body object no Workspace-wide email chrome defaults applied to form / signing / document / work-order invite emails. Per-template overrides (form_templates.email_template_settings, document_templates.email_template_settings) take precedence. Replaces the whole object on write.
approval_routing_config body array no Ordered approval-routing chain — who a queued approval (auto-responder reply, API write) is assigned to. Walked top-to-bottom; the first rule that resolves a user wins. Full-replace array. e.g. [{"type":"pipeline_user","map":{"<pipeline_id>":"<user_id>"}},{"type":"specific_user","user_id":"<user_id>"}].
list_view_defaults body object no Default grouping per CRM list, applied for everyone in the workspace (it also surfaces that list's bucket sub-list in the left nav). Each user can still change/turn off grouping on their own screen. Keyed by tableId: "all-deals-table" (Opportunities), "crm-contacts-table" (Contacts), "crm-customers-table" (Companies). Each value is { groupKey } where groupKey is a groupable column on that list — Opportunities: stage.name | opportunity_type | lead_source | contact.contact_type; Contacts: contact_type; Companies: account_type | industry. Shallow-merges per tableId (pass only the lists you want to change). e.g. { "crm-contacts-table": { "groupKey": "contact_type" } }.
detail_layout_config body object no Detail-page card order + hidden cards per surface, workspace-wide (the Opportunity / Contact / Company detail pages). Keyed by surface: opportunity.main, opportunity.side, contact.main, contact.side, company.main, company.side. Each value is { order: string[] (card keys top-to-bottom), hidden: string[] (card keys removed from the page) }. Shallow-merges per surface.
product_bucket_labels body array no Labels for the product grouping buckets used across the Products UI. Full-replace array — send the complete ordered list you want kept.
file_tag_options body array no The workspace file tag palette shown at https://app.trustpager.com/dashboard/files — the quick-pick tags anyone can put on a file. By default a tag is ALSO a photo bucket a contractor uploads into from their portal work order (e.g. Before / After on a job); set portal_bucket false on a tag that is only for the office, so it stays a quick-pick and a filter without appearing on a contractor screen. Full-replace array — send the complete ordered list you want kept. e.g. [{"name":"Before","color":"#f97316"},{"name":"After","color":"#22c55e"},{"name":"Listing","color":"#3b82f6","portal_bucket":false}].
approval_sla_config body object no Approval SLA: notify the assignee once when a pending approval has waited longer than the threshold. Shallow-merges.
auto_queue_config body object no Auto Queue guards shown at https://app.trustpager.com/settings/auto (Auto Queues section). Shallow-merges. min_send_gap spaces out automated messages to the same contact across every Auto Queue and channel: a contact can be enrolled in two queues at once, and each queue times its steps from its own enrolment date, so two messages can otherwise land a minute apart. When a step would fire inside the gap it is rescheduled to just after the previous message rather than skipped, so nothing is dropped.
notetaker_config body object no Workspace defaults for the meeting Notetaker. Shallow-merges (pass only the keys you want to change).
transcription_config body object no Workspace call-transcription settings (configured at /settings/inbox, Transcripts section). Shallow-merges; pass only the keys you want to change.
portal_on_anchor_delete body string no What happens to a portal when the record it hangs off is deleted (its referrer contact, or its anchor opportunity). "keep" leaves the portal alone (default, today's behaviour). "delete" permanently removes the portal and its chat history. "delete_unless_chat" does the same but blocks the parent delete when the portal has a chat. "disable" switches the portal off reversibly.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-crm-settings.md

PATCH /our-company/dispatcher-config Scopes: company:write

Update the workspace dispatcher settings shown at https://app.trustpager.com/settings/inbox (Dispatcher). Pass any of business_hours, retry, concurrency, channel_defaults, failure; each section shallow-merges over the current config. business_hours.windows sets the calling windows per day and, when provided, fully replaces the day set — use minute-precise ranges like { "mon": [["08:30","09:30"],["15:30","17:30"]], "sun": [["10:00","11:00"]] }, and omit a day to skip calling it. Times are evaluated in each lead's local timezone.

6 parameters
Name In Type Required Description
business_hours body object no Calling windows + timezone resolution for business-hours-aware sends and the dialler.
retry body object no Per-channel retry policy (email/sms/voice).
concurrency body object no Pacing / concurrency caps.
channel_defaults body object no Default respect-business-hours per channel.
failure body object no What to do on final failure.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-dispatcher-config.md

PATCH /our-company/settings/embeddings Scopes: company:write

Update embedding-pipeline settings.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-settings-embeddings.md

PATCH /our-company Scopes: company:write

Update OUR Company — the workspace's own organisation profile (branding, contact info, address) shown at https://app.trustpager.com/settings/company. NOT a CRM account/customer — to edit a customer record use update_company.

20 parameters
Name In Type Required Description
name body string no Trading name of the business that runs this workspace. Appears on invoices, documents and branded emails.
slug body string no URL-safe short name used in public links for this workspace. Lowercase letters, numbers and hyphens.
description body string no Short description of what the business does. Used as context by AI features and on some public surfaces.
contact_name body string no Primary contact person for the business, as customers should see it.
contact_email body string no Primary contact email for the business. Shown on invoices and public pages; this is NOT the sending address (that lives on the email config).
phone body string no Primary business phone number as customers should see it.
logo_url body string no Absolute URL of the business logo. Used on invoices, documents, portals and branded emails.
primary_color body string no Brand primary colour as a hex value, e.g. "#3b82f6". Must be a hex colour: it is spliced into branded email styles, so anything else is rejected.
secondary_color body string no Brand secondary colour as a hex value, e.g. "#f97316". Same hex-only rule as primary_color.
address_line1 body string no Street address line 1 of the business.
address_line2 body string no Street address line 2 (unit, level, PO box).
city body string no City or suburb of the business address.
state body string no State or territory of the business address, e.g. "VIC".
postal_code body string no Postcode of the business address.
country body string no Country of the business address. Defaults to Australia for new workspaces.
timezone body string no IANA timezone the business operates in, e.g. "Australia/Melbourne". Drives scheduling, business hours and date display.
industry body string no Industry the business operates in. Used as context by AI features.
website_url body string no Absolute URL of the business website, e.g. "https://example.com".
abn body string no Australian Business Number, printed on invoices. Digits only or spaced; stored as given.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company.md

PATCH /our-company/pipeline-card-config Scopes: company:write

Configure the opportunity card on the pipeline (Workflows) board. Two independent surfaces, pass either or both. Card POPOUT (hover panel): popout_sections as a partial map of section_key -> boolean (only keys you pass change; valid keys notes, next_action, tasks, custom_fields), plus custom_field_ids (opportunity custom-field ids from get_crm_settings.custom_fields.deal) shown when the custom_fields section is on. Card FACE (the card itself): card_face as { opportunity_type?: boolean, custom_field_ids?: string[] } to show/hide the opportunity type and chosen custom fields on the card (name, customer and value always show); partial, only keys you pass change. e.g. { "card_face": { "opportunity_type": true, "custom_field_ids": ["broker_name"] } } or { "popout_sections": { "custom_fields": true }, "custom_field_ids": ["lot_number"] }.

4 parameters
Name In Type Required Description
popout_sections body object no Partial map of popout section_key -> show(boolean). e.g. { "tasks": false, "custom_fields": true }.
custom_field_ids body array no Opportunity custom-field ids to show in the POPOUT when the custom_fields section is on. e.g. ["lot_number","slab_type"].
card_face body object no What shows on the card FACE. { "opportunity_type": true, "custom_field_ids": ["broker_name"] }.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-pipeline-card-config.md

PATCH /our-company/referral-settings Scopes: company:write

Set the workspace referral form and/or referrer portal. referral_form_template_id is a form_templates UUID (the public form referrers/clients submit to start a referral; get ids from list_form_templates); referrer_portal_template_id is a portal_templates UUID (the portal a referrer logs into; get ids from list_portal_templates). Pass either or both; pass null to clear one.

3 parameters
Name In Type Required Description
referral_form_template_id body string no form_templates UUID of the workspace referral form, or null to clear.
referrer_portal_template_id body string no portal_templates UUID of the referrer portal, or null to clear.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-referral-settings.md

PATCH /our-company/settings/tag-palette Scopes: company:write

Replace the workspace tag colour palette. FULL REPLACE, not a merge: call get_tag_palette first and send the existing tags back along with any new ones, or the omitted tags are removed. Tag names are de-duplicated case-insensitively, last one wins.

2 parameters
Name In Type Required Description
tags body array yes The complete palette. Every tag the workspace should have after this call.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-settings-tag-palette.md

PATCH /our-company/users/:user_id/workspace-user-roles Scopes: users:write

Update a user role.

3 parameters
Name In Type Required Description
user_id path string yes
role body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-users-user-id-workspace-user-roles.md

PATCH /our-company/users/:user_id/workspace-user-preferences Scopes: users:write

Update a user preferences.

2 parameters
Name In Type Required Description
user_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-users-user-id-workspace-user-preferences.md

PATCH /our-company/users/:user_id/workspace-user-profile Scopes: users:write

Update a user workspace profile.

2 parameters
Name In Type Required Description
user_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/company/patch-our-company-users-user-id-workspace-user-profile.md

CRM Templates (5 endpoints)

Manage reusable CRM templates for emails, messages, and automated communications.

📄 Full markdown: /api/crm-templates.md

POST /crm-templates Scopes: crm-templates:write

Create a CRM template.

5 parameters
Name In Type Required Description
type body string yes
name body string yes
category body string no
content body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/crm-templates/post-crm-templates.md

DELETE /crm-templates/:template_id Scopes: crm-templates:delete

Delete a CRM template by UUID.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/crm-templates/delete-crm-templates-template-id.md

GET /crm-templates Scopes: crm-templates:read

List workspace CRM templates (default custom-field templates for entities).

1 parameter
Name In Type Required Description
type query string no

📄 /api/crm-templates/get-crm-templates.md

PATCH /crm-templates/:template_id Scopes: crm-templates:write

Update a CRM template.

4 parameters
Name In Type Required Description
template_id path string yes
name body string no
content body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/crm-templates/patch-crm-templates-template-id.md

Integrations (5 endpoints)

Read, query, and execute actions on native integrations (Xero, MYOB, etc.). Connecting and disconnecting integrations is done via the platform UI (OAuth browser flows).

📄 Full markdown: /api/integrations.md

POST /integrations/:integration_id/action Scopes: integrations:write

Execute an action on a connected third-party platform (e.g. post Slack message, add calendar event).

4 parameters
Name In Type Required Description
integration_id path string yes
action_type body string yes Platform action to run, e.g. "slack_post_message".
params body object yes Arguments for the action.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/integrations/post-integrations-integration-id-action.md

GET /integrations/:integration_id Scopes: integrations:read

Fetch a single integration by UUID, including its status and capabilities.

1 parameter
Name In Type Required Description
integration_id path string yes

📄 /api/integrations/get-integrations-integration-id.md

POST /integrations/:integration_id/query Scopes: integrations:read

Read data from a connected third-party platform (e.g. list channels, get profile).

3 parameters
Name In Type Required Description
integration_id path string yes
query body string yes
args body object no

📄 /api/integrations/post-integrations-integration-id-query.md

POST /integrations/:integration_id/sync-receivables Scopes: invoices:write

Backfill / reconcile the outstanding-invoices (accounts receivable) ledger from a connected Xero integration. Pages all sales invoices into the workspace and powers the Invoices / Receivables report source. Idempotent — safe to re-run.

2 parameters
Name In Type Required Description
integration_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/integrations/post-integrations-integration-id-sync-receivables.md

Webhooks (17 endpoints)

Manage incoming and outgoing webhooks for external system integration.

📄 Full markdown: /api/webhooks.md

POST /webhooks/incoming Scopes: webhooks:write

Create an incoming webhook URL.

6 parameters
Name In Type Required Description
service_type body string yes Which external service posts to this endpoint. Determines how the payload is parsed and normalised.
service_name body string yes Human label for this incoming webhook in the Webhooks list.
config_data body object no Service-specific settings: field mappings, secrets the sender includes, payload shape hints. Full-replace on write.
crm_pipeline_id body string no Pipeline a newly-created opportunity lands in when a payload arrives. Falls back to the workspace default when unset.
crm_initial_stage_id body string no Stage within that pipeline the new opportunity starts at.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/post-webhooks-incoming.md

POST /webhooks/outgoing Scopes: webhooks:write

Create an outgoing webhook.

9 parameters
Name In Type Required Description
name body string yes Label for this outgoing webhook in the Webhooks list.
url body string yes Absolute HTTPS endpoint we POST to when a trigger event fires.
enabled body boolean no Whether the webhook fires. False keeps it configured but dormant.
headers body object no Extra HTTP headers sent with every request, as { "Header-Name": "value" }. Use for auth tokens the receiver expects. Full-replace on write.
body_template body object no Custom JSON body to send instead of the default payload. Supports template tokens for record fields. Full-replace on write; omit to send the standard payload.
trigger_events body array no Which events fire this webhook, e.g. ["deal_created","form_submitted"]. Full-replace array.
include_trigger_data body boolean no Whether the full trigger_data snapshot is included in the POST body alongside the record.
website_id body string no Scope the webhook to one website's events. Null fires for the whole workspace.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/post-webhooks-outgoing.md

POST /webhooks/subscribe Scopes: webhooks:write

Subscribe a URL to API event notifications.

4 parameters
Name In Type Required Description
url body string yes
events body array yes
secret body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/post-webhooks-subscribe.md

DELETE /webhooks/incoming/:webhook_id Scopes: webhooks:delete

Delete an incoming webhook.

2 parameters
Name In Type Required Description
webhook_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/delete-webhooks-incoming-webhook-id.md

DELETE /webhooks/outgoing/:webhook_id Scopes: webhooks:delete

Delete an outgoing webhook.

2 parameters
Name In Type Required Description
webhook_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/delete-webhooks-outgoing-webhook-id.md

DELETE /webhooks/subscriptions/:subscription_id Scopes: webhooks:delete

Delete a webhook subscription.

2 parameters
Name In Type Required Description
subscription_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/delete-webhooks-subscriptions-subscription-id.md

POST /webhooks/outgoing/:webhook_id/test Scopes: webhooks:write

Send a test payload to an outgoing webhook.

2 parameters
Name In Type Required Description
webhook_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/post-webhooks-outgoing-webhook-id-test.md

PATCH /webhooks/incoming/:webhook_id Scopes: webhooks:write

Update an incoming webhook.

7 parameters
Name In Type Required Description
webhook_id path string yes UUID of the incoming webhook to update. Get ids from list_incoming_webhooks.
service_type body string no Which external service posts to this endpoint. Determines how the payload is parsed and normalised.
service_name body string no Human label for this incoming webhook in the Webhooks list.
config_data body object no Service-specific settings: field mappings, secrets the sender includes, payload shape hints. Full-replace on write.
crm_pipeline_id body string no Pipeline a newly-created opportunity lands in when a payload arrives. Falls back to the workspace default when unset.
crm_initial_stage_id body string no Stage within that pipeline the new opportunity starts at.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/patch-webhooks-incoming-webhook-id.md

PATCH /webhooks/outgoing/:webhook_id Scopes: webhooks:write

Update an outgoing webhook.

10 parameters
Name In Type Required Description
webhook_id path string yes UUID of the outgoing webhook to update. Get ids from list_outgoing_webhooks.
name body string no Label for this outgoing webhook in the Webhooks list.
url body string no Absolute HTTPS endpoint we POST to when a trigger event fires.
enabled body boolean no Whether the webhook fires. False keeps it configured but dormant.
headers body object no Extra HTTP headers sent with every request, as { "Header-Name": "value" }. Use for auth tokens the receiver expects. Full-replace on write.
body_template body object no Custom JSON body to send instead of the default payload. Supports template tokens for record fields. Full-replace on write; omit to send the standard payload.
trigger_events body array no Which events fire this webhook, e.g. ["deal_created","form_submitted"]. Full-replace array.
include_trigger_data body boolean no Whether the full trigger_data snapshot is included in the POST body alongside the record.
website_id body string no Scope the webhook to one website's events. Null fires for the whole workspace.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/patch-webhooks-outgoing-webhook-id.md

PATCH /webhooks/subscriptions/:subscription_id Scopes: webhooks:write

Update a webhook subscription.

6 parameters
Name In Type Required Description
subscription_id path string yes UUID of the webhook subscription to update. Get ids from list_webhook_subscriptions.
url body string no Absolute HTTPS endpoint that receives the event POST.
events body array no Event names this subscription listens for. Full-replace array — send the complete set you want kept.
secret body string no Shared secret used to sign the payload so your endpoint can verify it came from us. Treat as a credential.
is_active body boolean no Whether the subscription delivers. False pauses delivery without deleting it.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/webhooks/patch-webhooks-subscriptions-subscription-id.md

AI (15 endpoints)

AI-powered features including text editing, call coaching, needs analysis, form filling, pipeline generation, image generation, reference-guided image editing, text-to-speech generation, and AI tool generators (form, document, whiteboard, website page) that create fully-structured workspace assets from a plain-language prompt.

📄 Full markdown: /api/ai.md

POST /ai/call-coaching Scopes: ai:use

Analyze a phone call transcript for coaching feedback. Costs credits.

2 parameters
Name In Type Required Description
transcript_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-call-coaching.md

POST /ai/edit-image Scopes: ai:use

Edit an image based on a prompt. Costs credits.

8 parameters
Name In Type Required Description
prompt body string yes How to edit the reference image. 2 to 3000 characters.
reference_image_url body string yes Public http(s) URL of the image to edit. Provide this or reference_image_urls.
reference_image_urls body array no Up to 3 public http(s) image URLs, as an alternative to reference_image_url.
width body number no Output width. Defaults to 1024; must form a supported width/height pair.
height body number no Output height. Defaults to 1024; must form a supported width/height pair.
seed body number no Optional seed for reproducible output.
output_format body string no Output image format.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-edit-image.md

POST /ai/edit-text Scopes: ai:use

Rewrite, refine, or transform a block of text. Use for "make this more formal", "shorten this", "fix grammar". Costs credits.

4 parameters
Name In Type Required Description
text body string yes
instruction body string yes
tone body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-edit-text.md

POST /ai/fill-form Scopes: ai:use

Auto-fill a form template from natural-language input. Pass template_id (the form template to fill) and prompt (the source text / instructions to extract field values from). The workspace master prompt configured for this template (via set_ai_fill_prompt) is applied automatically; pass master_prompt to override it for this one call. Costs credits.

4 parameters
Name In Type Required Description
template_id body string yes UUID of the form template to fill. Get ids from list_form_templates.
prompt body string yes Natural-language source text / instructions the AI extracts field values from.
master_prompt body string no Optional one-off override of the system steer for this call. Leave unset to use the workspace master prompt configured via set_ai_fill_prompt (or the built-in default).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-fill-form.md

POST /ai/generate-document Scopes: ai:usedocuments:write

Generate a new document from a prompt — proposals, scopes, summaries. Returns a document UUID. Costs credits.

5 parameters
Name In Type Required Description
prompt body string yes
opportunity_id body string no
contact_id body string no
title body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-document.md

POST /ai/generate-embedding Scopes: ai:use

Generate a vector embedding for a text string. Free.

1 parameter
Name In Type Required Description
text body string yes

📄 /api/ai/post-ai-generate-embedding.md

POST /ai/generate-form Scopes: ai:useforms:write

Generate a form template from a natural-language prompt.

2 parameters
Name In Type Required Description
prompt body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-form.md

POST /ai/generate-image Scopes: ai:use

Generate an image from a prompt. Costs credits.

3 parameters
Name In Type Required Description
prompt body string yes
aspect_ratio body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-image.md

POST /ai/generate-music Scopes: ai:use

Generate music audio from a prompt. Costs credits.

3 parameters
Name In Type Required Description
prompt body string yes
duration_ms body number no Track length in MILLISECONDS. Defaults to 30000 (30s).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-music.md

POST /ai/generate-pipeline Scopes: ai:usepipelines:write

Generate a new pipeline (with stages) from a natural-language description.

7 parameters
Name In Type Required Description
description body string yes Natural-language description of the process the pipeline should model.
business_type body string no Optional business type, to tune the generated stages.
industry body string no Optional industry, to tune the generated stages.
success_criteria body string no Optional definition of what a won opportunity looks like.
lost_criteria body string no Optional definition of what a lost opportunity looks like.
additional_context body string no Optional extra context for the generator.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-pipeline.md

POST /ai/generate-speech Scopes: ai:use

Generate speech audio from text. Costs credits.

3 parameters
Name In Type Required Description
text body string yes
voice body string no Voice to speak with.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-speech.md

POST /ai/generate-whiteboard Scopes: ai:use

Generate a whiteboard layout from a prompt.

2 parameters
Name In Type Required Description
prompt body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-generate-whiteboard.md

POST /ai/needs-analysis Scopes: ai:use

Analyse an opportunity — activities, transcripts, notes — to surface needs, objections, next steps. Costs credits.

3 parameters
Name In Type Required Description
opportunity_id body string yes
focus body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-needs-analysis.md

POST /ai/transcript-summary Scopes: ai:use

Summarise a call or meeting transcript — key topics, decisions, action items. Costs credits.

3 parameters
Name In Type Required Description
transcript_id body string yes
focus body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-transcript-summary.md

POST /ai/upscale-image Scopes: ai:use

Upscale an image to higher resolution. Costs credits.

4 parameters
Name In Type Required Description
image_url body string yes Public http(s) URL of the image to upscale.
upscale_factor body number no How much to enlarge by. Defaults to 2.
output_format body string no Output image format.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/ai/post-ai-upscale-image.md

Billing (4 endpoints)

View billing plans, credit balance, and pricing.

📄 Full markdown: /api/billing.md

Service Requests (8 endpoints)

Submit and manage platform improvement requests. Designed for AI agents to report missing capabilities, suggest new features, and flag issues with the MCP, API, or platform. Supports listing, filtering, note threads, inline note editing, and two-way ticket linking.

📄 Full markdown: /api/service-requests.md

POST /service-requests/:request_id/notes Scopes: service-requests:write

Add a note to a service request.

3 parameters
Name In Type Required Description
request_id path string yes
content body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/service-requests/post-service-requests-request-id-notes.md

POST /service-requests Scopes: service-requests:write

File a platform improvement / capability request. Use when you hit a missing tool, missing field, confusing error, or bug.

5 parameters
Name In Type Required Description
title body string yes
description body string yes
category body string no
priority body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/service-requests/post-service-requests.md

POST /service-requests/:request_id/links Scopes: service-requests:write

Link (or unlink) service requests to each other. Links are two-way: adding B to A also adds A to B. Provide at least one of "add" or "remove".

4 parameters
Name In Type Required Description
request_id path string yes The service request to update links on.
add body array no Service request UUIDs to link to this one (two-way).
remove body array no Service request UUIDs to unlink from this one.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/service-requests/post-service-requests-request-id-links.md

GET /service-requests Scopes: service-requests:read

List platform improvement / capability requests submitted by AI agents.

2 parameters
Name In Type Required Description
status query string no
limit query number no

📄 /api/service-requests/get-service-requests.md

POST /service-requests/search Scopes: service-requests:read

Semantic search across this workspace's service requests using vector embeddings. Use to find duplicates before filing, group related open requests, or find historical resolutions. Returns ranked SRs by cosine similarity.

4 parameters
Name In Type Required Description
query body string yes Natural-language description of what you're looking for
status body string no Optional: restrict to a single status
limit body number no Max results, 1-50 (default 10)
threshold body number no Minimum cosine similarity 0-1 (default 0.5)

📄 /api/service-requests/post-service-requests-search.md

PATCH /service-requests/:request_id/notes/:note_id Scopes: service-requests:write

Update a note on a service request.

4 parameters
Name In Type Required Description
request_id path string yes
note_id path string yes
content body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/service-requests/patch-service-requests-request-id-notes-note-id.md

PATCH /service-requests/:request_id Scopes: service-requests:write

Update a service request's status, e.g. mark it completed/resolved after shipping the fix, or reopen a completed one.

3 parameters
Name In Type Required Description
request_id path string yes
status body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/service-requests/patch-service-requests-request-id.md

Approvals (6 endpoints)

Manage API actions queued for human approval. When an API key has a "with Approval" permission level, write operations are held here until a team member reviews them.

📄 Full markdown: /api/approvals.md

POST /approvals/:approval_id/approve Scopes: approvals:write

Approve a pending action and execute it. Destructive — runs the underlying queued operation.

2 parameters
Name In Type Required Description
approval_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/approvals/post-approvals-approval-id-approve.md

POST /approvals/:approval_id/assign Scopes: approvals:reassign

Reassign a pending approval to a different reviewer. Does not approve or reject.

4 parameters
Name In Type Required Description
approval_id path string yes
primary_assignee_id body string yes
secondary_assignee_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/approvals/post-approvals-approval-id-assign.md

GET /approvals/:approval_id Scopes: approvals:read

Fetch a single approval by UUID — full action details, request body, status, reviewer assignment.

1 parameter
Name In Type Required Description
approval_id path string yes

📄 /api/approvals/get-approvals-approval-id.md

GET /approvals Scopes: approvals:read

List pending approvals — actions queued for human review. Use after a 202 to check what is waiting.

3 parameters
Name In Type Required Description
status query string no pending (default), approved, rejected, expired, executed, failed
resource query string no Resource the queued action targets, e.g. sms or phone-numbers.
limit query number no

📄 /api/approvals/get-approvals.md

POST /approvals/:approval_id/reject Scopes: approvals:write

Reject a pending action. Cancels the queued operation.

3 parameters
Name In Type Required Description
approval_id path string yes
reason body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/approvals/post-approvals-approval-id-reject.md

POST /approvals/:approval_id/edit Scopes: approvals:edit

Rewrite the request_body of a pending approval. Lets agents iterate on AI-drafted content (e.g. fix an email body) without approving.

3 parameters
Name In Type Required Description
approval_id path string yes
request_body body object yes New request body to replace the queued one
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/approvals/post-approvals-approval-id-edit.md

AI Instructions (1 endpoint)

Structured behavioral instructions for AI agents. Call once per session, cache the result. Free (0 credits).

📄 Full markdown: /api/ai-instructions.md

Voices (8 endpoints)

Manage saved workspace voices and browse platform-recommended voices. Workspace voices are saved ElevenLabs voices scoped to your company. Platform voices are pre-seeded recommended voices available to all workspaces (read-only). Use these with POST /ai/generate-speech.

📄 Full markdown: /api/voices.md

POST /voices Scopes: voices:write

Add a voice to the workspace (resolves metadata from provider on create).

3 parameters
Name In Type Required Description
provider_voice_id body string yes
name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voices/post-voices.md

DELETE /voices/:voice_id Scopes: voices:delete

Delete a workspace voice.

2 parameters
Name In Type Required Description
voice_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voices/delete-voices-voice-id.md

GET /voices/:voice_id Scopes: voices:read

Fetch a workspace voice by UUID.

1 parameter
Name In Type Required Description
voice_id path string yes

📄 /api/voices/get-voices-voice-id.md

GET /voices Scopes: voices:read

List workspace voices.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/voices/get-voices.md

POST /voices/:voice_id/provider-mapping Scopes: voices:write

Map a workspace voice to a provider voice id so agent creation uses the right voice.

3 parameters
Name In Type Required Description
voice_id path string yes
retell_voice_id body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voices/post-voices-voice-id-provider-mapping.md

POST /voices/sync-provider-catalog Scopes: voices:write

Auto-map every catalogue voice to a workspace voice row.

1 parameter
Name In Type Required Description
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voices/post-voices-sync-provider-catalog.md

PATCH /voices/:voice_id Scopes: voices:write

Update a workspace voice.

3 parameters
Name In Type Required Description
voice_id path string yes
name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/voices/patch-voices-voice-id.md

Agent Proposals (6 endpoints)

Agent action proposals submitted by AI agents for human review and approval. Agents submit proposals when they identify an action that should be taken but requires a human decision. Proposals surface in the Agent Hub at /auto/agent-hub?tab=proposals.

📄 Full markdown: /api/agent-proposals.md

POST /agent-proposals/:proposal_id/approve Scopes: agent-ops:write

Approve an agent proposal — EVE handler executes it.

2 parameters
Name In Type Required Description
proposal_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-proposals/post-agent-proposals-proposal-id-approve.md

POST /agent-proposals Scopes: agent-ops:write

Create a new agent action proposal for human review.

6 parameters
Name In Type Required Description
agent_name body string yes
category body string yes
title body string yes
proposed_action body object yes
rationale body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-proposals/post-agent-proposals.md

GET /agent-proposals Scopes: agent-ops:read

List agent action proposals. Filter by status (pending, approved, rejected) and agent_name.

4 parameters
Name In Type Required Description
status query string no
agent_name query string no
category query string no
limit query number no

📄 /api/agent-proposals/get-agent-proposals.md

POST /agent-proposals/:proposal_id/reject Scopes: agent-ops:write

Reject an agent proposal with optional reason.

3 parameters
Name In Type Required Description
proposal_id path string yes
reason body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-proposals/post-agent-proposals-proposal-id-reject.md

POST /agent-proposals/:proposal_id/execute-result Scopes: agent-ops:write

EVE handler reports the result of executing an approved proposal.

4 parameters
Name In Type Required Description
proposal_id path string yes
status body string yes
result body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-proposals/post-agent-proposals-proposal-id-execute-result.md

Lead Generation (10 endpoints)

Search for businesses via Google Maps (powered by Apify), match against existing CRM records, save search configurations, and import results as contacts, customers, and deals. Requires lead-gen:read, lead-gen:write, or lead-gen:delete scopes.

📄 Full markdown: /api/lead-gen.md

POST /lead-gen/searches/:search_id/cancel Scopes: lead-gen:write

Force-cancel a running lead-gen search and refund any credits that were charged. Use this to clear searches stuck in "running" — typically because the dispatch edge function timed out / was killed before it could mark the row completed or failed, leaving the row orphaned and the user's credits locked up. Only searches in status="running" can be cancelled; completed/failed/cancelled rows return a 400. On success the row flips to status="cancelled" with error_message="Cancelled by user" and credits_charged is refunded via a "refund" ledger transaction. Response includes credits_refunded and credit_balance_after for confirmation.

2 parameters
Name In Type Required Description
search_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen/post-lead-gen-searches-search-id-cancel.md

POST /lead-gen/saved-searches Scopes: lead-gen:write

Save a lead-gen search query for reuse.

4 parameters
Name In Type Required Description
name body string yes
search_query body string yes
location body string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen/post-lead-gen-saved-searches.md

DELETE /lead-gen/saved-searches/:saved_search_id Scopes: lead-gen:delete

Archive a saved lead-gen search.

2 parameters
Name In Type Required Description
saved_search_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen/delete-lead-gen-saved-searches-saved-search-id.md

POST /lead-gen/import Scopes: lead-gen:write

Convert lead_gen_results into CRM contacts + customers (+ optional pipeline opportunity). Every conversion requires a per-result contact mapping — first_name is mandatory for each row so the CRM contact has a real person attached, not the business name. Find-or-create semantics: existing customers matched by name and contacts matched by email are reused instead of duplicated. Importing a lead that's already fully in CRM is a no-op; partial/zombie imports (imported flag flipped but contact record never created) are retried automatically.

6 parameters
Name In Type Required Description
contacts body array yes Required. Per-result contact mapping. Each entry creates or reuses a contact with the supplied name + email + phone, links to the lead's customer record (by business name), and optionally creates a deal in the named pipeline + stage.
pipeline_id body string no Optional. When set with stage_id, creates a deal per imported lead and places it in this pipeline.
stage_id body string no Optional. Required when pipeline_id is provided.
lead_source body string no Defaults to "Lead Generation".
tags body array no Optional tags applied to the created deal(s).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen/post-lead-gen-import.md

POST /lead-gen/search Scopes: lead-gen:write

Start a new lead-gen search via Apify Google Maps. Costs credits.

4 parameters
Name In Type Required Description
query body string yes
location body string yes
limit body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen/post-lead-gen-search.md

PATCH /lead-gen/saved-searches/:saved_search_id Scopes: lead-gen:write

Update a saved lead-gen search.

3 parameters
Name In Type Required Description
saved_search_id path string yes
name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen/patch-lead-gen-saved-searches-saved-search-id.md

Lead Gen Initiatives (12 endpoints)

Lead generation results and the multi-step outreach initiatives that work them.

📄 Full markdown: /api/lead-gen-initiatives.md

POST /lead-gen/initiatives/:initiative_id/steps Scopes: lead-gen:write

Add a step to an initiative. Quick mode: pass action_type + action_config + delay. Bring-your-own mode: pass automation_id.

9 parameters
Name In Type Required Description
initiative_id path string yes
action_type body string no send_gmail_email | send_sms | notify_assigned_staff
action_config body object no Config matching the chosen action type (subject/body/etc.)
automation_id body string no Alternative to action_type+config — reuse an existing automation
delay_days body number no
delay_hours body number no
delay_minutes body number no
name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/post-lead-gen-initiatives-initiative-id-steps.md

POST /lead-gen/initiatives Scopes: lead-gen:write

Create an outreach initiative (multi-step sequence) for lead-gen leads. Send-cadence fields are optional — sensible defaults apply (40 emails/day, 09:00-17:00 Mon-Fri Sydney, 90s minimum gap). Override only if the user needs a specific pace.

10 parameters
Name In Type Required Description
name body string yes
description body string no
is_active body boolean no Active initiatives run their dispatcher; paused initiatives queue no new sends. Default true.
daily_send_cap body integer no Max email-channel sends per calendar day in the initiative timezone. Default 40. Personal email accounts typically get flagged above ~50/day for cold outreach.
send_window_start body string no 24-hour HH:MM start of the daily send window in send_window_timezone. Default "09:00".
send_window_end body string no 24-hour HH:MM end of the daily send window in send_window_timezone. Default "17:00".
send_window_timezone body string no IANA timezone for the send window (e.g. "Australia/Sydney"). Default "Australia/Sydney".
send_window_days body array no ISO weekdays the initiative is allowed to send on (1=Mon … 7=Sun). Default [1,2,3,4,5] (weekdays).
min_gap_seconds body integer no Minimum seconds between consecutive successful sends on this initiative. Default 90 — spreads 40 sends across ~60 minutes minimum.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/post-lead-gen-initiatives.md

POST /lead-gen/results Scopes: lead-gen:write

Manually insert a lead_gen_result (hand-curated lead, CSV import, smoke fixture).

9 parameters
Name In Type Required Description
business_name body string yes
email body string no
phone body string no
website body string no
city body string no
state body string no
country_code body string no
search_id body string no Optional — if omitted a wrapper search is created
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/post-lead-gen-results.md

DELETE /lead-gen/initiatives/:initiative_id Scopes: lead-gen:delete

Delete an initiative and all its steps + underlying automations.

2 parameters
Name In Type Required Description
initiative_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/delete-lead-gen-initiatives-initiative-id.md

DELETE /lead-gen/initiatives/:initiative_id/steps/:step_id Scopes: lead-gen:delete

Delete a step from an initiative and its underlying automation.

3 parameters
Name In Type Required Description
initiative_id path string yes
step_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/delete-lead-gen-initiatives-initiative-id-steps-step-id.md

POST /lead-gen/initiatives/:initiative_id/enrol Scopes: lead-gen:write

Enrol one or more lead_gen_results into an initiative. Schedules the first step task and tracks the rest as the dispatcher advances each enrolment.

3 parameters
Name In Type Required Description
initiative_id path string yes
lead_gen_result_ids body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/post-lead-gen-initiatives-initiative-id-enrol.md

POST /lead-gen/initiatives/dispatcher/run Scopes: lead-gen:write

Run the initiative dispatcher synchronously for this workspace. Fires any pending step tasks whose scheduled_for has passed. Same code path as the cron tick.

3 parameters
Name In Type Required Description
max_tasks body number no Cap on how many tasks to claim+run (default 10, max 50)
only_enrollment_id body string no Restrict to a specific enrolment (smoke testing)
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/post-lead-gen-initiatives-dispatcher-run.md

PATCH /lead-gen/initiatives/:initiative_id Scopes: lead-gen:write

Update an initiative — name, description, active state, or send-cadence (daily cap, send window, days, min-gap). Only present fields are written.

11 parameters
Name In Type Required Description
initiative_id path string yes
name body string no
description body string,null no
is_active body boolean no
daily_send_cap body integer no Max email-channel sends per calendar day. Personal email accounts typically get flagged above ~50/day.
send_window_start body string no 24-hour HH:MM (e.g. "09:00").
send_window_end body string no 24-hour HH:MM (e.g. "17:00").
send_window_timezone body string no IANA timezone (e.g. "Australia/Sydney").
send_window_days body array no ISO weekdays (1=Mon … 7=Sun).
min_gap_seconds body integer no Minimum seconds between consecutive successful sends.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/patch-lead-gen-initiatives-initiative-id.md

PATCH /lead-gen/initiatives/:initiative_id/steps/:step_id Scopes: lead-gen:write

Update an initiative step (delay, ordering, is_active).

3 parameters
Name In Type Required Description
initiative_id path string yes
step_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/lead-gen-initiatives/patch-lead-gen-initiatives-initiative-id-steps-step-id.md

Playbooks (8 endpoints)

Manage Playbooks and their cards. Playbooks are drag-and-drop boards of cards that can embed YouTube videos, external links, iframes, notepads, PDFs, images, and secure files.

📄 Full markdown: /api/training.md

POST /playbooks/:playbook_id/cards Scopes: resources:write

Add a card to a Playbook.

5 parameters
Name In Type Required Description
playbook_id path string yes
title body string no
content body string no
position body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/training/post-playbooks-playbook-id-cards.md

POST /playbooks Scopes: resources:write

Create a new Playbook. Optional template: "blank" or "getting_started".

3 parameters
Name In Type Required Description
name body string yes
template body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/training/post-playbooks.md

DELETE /playbooks/:playbook_id Scopes: resources:delete

Delete a Playbook by UUID.

2 parameters
Name In Type Required Description
playbook_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/training/delete-playbooks-playbook-id.md

DELETE /playbook-cards/:card_id Scopes: resources:delete

Delete a Playbook card.

2 parameters
Name In Type Required Description
card_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/training/delete-playbook-cards-card-id.md

GET /playbooks/:playbook_id Scopes: resources:read

Fetch a Playbook by UUID with its cards.

1 parameter
Name In Type Required Description
playbook_id path string yes

📄 /api/training/get-playbooks-playbook-id.md

GET /playbooks Scopes: resources:read

List Playbooks in the workspace. Free read.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/training/get-playbooks.md

PATCH /playbooks/:playbook_id Scopes: resources:write

Update a Playbook.

3 parameters
Name In Type Required Description
playbook_id path string yes
name body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/training/patch-playbooks-playbook-id.md

PATCH /playbook-cards/:card_id Scopes: resources:write

Update a Playbook card.

4 parameters
Name In Type Required Description
card_id path string yes
title body string no
content body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/training/patch-playbook-cards-card-id.md

Roles & Permissions (9 endpoints)

Workspace roles with their scopes and data scope, and the effective permissions a member resolves to.

📄 Full markdown: /api/roles.md

POST /roles/:role_id/users Scopes: permissions:write

Assign a workspace member to a role. You cannot assign a role that grants scopes you do not hold (unless you have admin). The member's prior role is remembered so removal can restore it.

3 parameters
Name In Type Required Description
role_id path string yes
user_id body string yes UUID of the member to assign
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/roles/post-roles-role-id-users.md

POST /roles Scopes: permissions:write

Create a custom role. You can only grant scopes you hold yourself (unless you have the admin scope). Scopes are strings like "contacts:write".

6 parameters
Name In Type Required Description
name body string yes Role name, unique within the workspace
description body string no
scopes body array no Scope strings, e.g. ["contacts:read","contacts:write","opportunities:read"]
data_scope body string no Default data scope (e.g. "all")
visibility body object no Per-resource visibility filters, e.g. {"tasks":["assigned_to","created_by"]}
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/roles/post-roles.md

DELETE /roles/:role_id Scopes: permissions:write

Delete a custom role. Fails if any users are still assigned (unassign them first). Preset roles cannot be deleted.

2 parameters
Name In Type Required Description
role_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/roles/delete-roles-role-id.md

GET /roles/effective Scopes: permissions:read

Resolve a workspace member's live effective permissions (is_admin, scopes, data_scope) via the same engine RLS uses. Pass ?user_id=<uuid>; omit to resolve the calling key's creator. Use this to verify what a user can actually do.

1 parameter
Name In Type Required Description
user_id query string no UUID of the member to resolve; omit for the caller

📄 /api/roles/get-roles-effective.md

GET /roles/:role_id Scopes: permissions:read

Fetch a single role by UUID with its resolved scopes, visibility, and assigned-user count.

1 parameter
Name In Type Required Description
role_id path string yes

📄 /api/roles/get-roles-role-id.md

GET /roles/:role_id/users Scopes: permissions:read

List the workspace members currently assigned to a role.

1 parameter
Name In Type Required Description
role_id path string yes

📄 /api/roles/get-roles-role-id-users.md

GET /roles Scopes: permissions:read

List all roles in this workspace (preset and custom) with their resolved scopes, data scope, visibility, and assigned-user counts.

📄 /api/roles/get-roles.md

DELETE /roles/:role_id/users/:user_id Scopes: permissions:write

Remove a workspace member from a role, restoring their previous role (or viewer if none).

3 parameters
Name In Type Required Description
role_id path string yes
user_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/roles/delete-roles-role-id-users-user-id.md

PATCH /roles/:role_id Scopes: permissions:write

Update a custom role (name, description, scopes, data_scope, visibility). Preset roles cannot be edited. You can only set scopes you hold yourself unless you have the admin scope. Renaming keeps existing assignments intact.

7 parameters
Name In Type Required Description
role_id path string yes
name body string no
description body string no
scopes body array no
data_scope body string no
visibility body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/roles/patch-roles-role-id.md

Scheduled Communications (7 endpoints)

Queue deferred emails, SMS, and AI voice calls for future dispatch. The communications_scheduler_tick cron (runs every minute) claims pending rows, enforces business-hours windows, retries with exponential backoff, and dispatches via the automation pipeline. Row lifecycle: pending -> dispatching -> dispatched | failed | cancelled | skipped.

📄 Full markdown: /api/scheduled-communications.md

POST /scheduled-communications/bulk-cancel Scopes: dispatcher:write

Cancel every PENDING scheduled communication for a contact, opportunity, or customer. Use it to stop an AI voice follow-up cadence or a queued SMS/email sequence when a lead is handed to a human. Provide at least one of contact_id, deal_id, customer_id; supplying more than one narrows the match (they are ANDed). Already-sent items are unaffected.

4 parameters
Name In Type Required Description
contact_id body string no Cancel pending items for this contact.
deal_id body string no Cancel pending items for this opportunity.
customer_id body string no Cancel pending items for this customer.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduled-communications/post-scheduled-communications-bulk-cancel.md

DELETE /scheduled-communications/:scheduled_id Scopes: dispatcher:write

Soft-cancel a scheduled communication.

2 parameters
Name In Type Required Description
scheduled_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduled-communications/delete-scheduled-communications-scheduled-id.md

POST /scheduled-communications/:scheduled_id/dispatch-now Scopes: dispatcher:write

Dispatch a pending scheduled communication immediately.

2 parameters
Name In Type Required Description
scheduled_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduled-communications/post-scheduled-communications-scheduled-id-dispatch-now.md

POST /scheduled-communications Scopes: dispatcher:write

Schedule a deferred email, SMS or voice call for future dispatch.

6 parameters
Name In Type Required Description
channel body string yes
scheduled_for body string yes
payload body object yes
contact_id body string no
deal_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduled-communications/post-scheduled-communications.md

PATCH /scheduled-communications/:scheduled_id Scopes: dispatcher:write

Update a pending scheduled communication (only while status=pending).

4 parameters
Name In Type Required Description
scheduled_id path string yes
scheduled_for body string no
payload body object no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/scheduled-communications/patch-scheduled-communications-scheduled-id.md

Schemas (2 endpoints)

Discoverable reference data for automation trigger types. Returns the shape of trigger_data each trigger publishes, the {{variable}} tokens available in action templates, and CRM-enriched variable namespaces. Free -- 0 credits, no scope required.

📄 Full markdown: /api/schemas.md

GET /schemas/triggers/:trigger_type

Fetch a single trigger schema by trigger_type (e.g. contact_created). Free read.

1 parameter
Name In Type Required Description
trigger_type path string yes Trigger type identifier

📄 /api/schemas/get-schemas-triggers-trigger-type.md

Reputation (22 endpoints)

Public B2B reputation profiles, verified reviews, and case studies. Build credibility with a public reputation page at trustpager.com/reputation/<slug>. Includes a companion anonymous image upload endpoint for reviewer logos and avatars.

📄 Full markdown: /api/reputation.md

POST /reputation/reviews/:review_id/approve Scopes: reputation:write

Approve a pending review for publication.

2 parameters
Name In Type Required Description
review_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-reviews-review-id-approve.md

POST /reputation/case-studies/:case_study_id/archive Scopes: reputation:write

Archive a case study.

2 parameters
Name In Type Required Description
case_study_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-case-studies-case-study-id-archive.md

POST /reputation/reviews/:review_id/archive Scopes: reputation:write

Archive a review.

2 parameters
Name In Type Required Description
review_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-reviews-review-id-archive.md

POST /reputation/case-studies Scopes: reputation:write

Create a case study.

19 parameters
Name In Type Required Description
profile_id body string yes UUID of the reputation profile this case study belongs to.
review_id body string no UUID of a review to attach to this case study, so the testimonial shows alongside the story.
title body string yes Case study headline.
slug body string yes URL-safe segment for the public case study page. Changing it breaks links already shared.
client_name body string yes Name of the client the work was done for, as shown publicly.
client_company body string no Client company name, when different from client_name.
client_logo body string no Absolute URL of the client logo.
problem body string no The situation before the work: what the client was struggling with.
solution body string no What you did about it.
outcome body string no What changed as a result, ideally with concrete numbers.
summary body string no Short summary shown on the case study card in listings.
key_metrics body object no Headline result figures rendered as stat tiles, e.g. { "Revenue": "+38%" }. Full-replace on write.
images body object no Images used on the case study page. Full-replace on write.
tags body array no Tags used to filter case studies on the public profile. Full-replace array.
featured body boolean no Pin this case study to the top of the public profile.
sort_order body number no Manual position in the case study list. Lower sorts first.
source_type body string no Where the case study came from, e.g. authored in-app or imported.
source_reference body object no Provenance details for the source. Full-replace on write.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-case-studies.md

POST /reputation/reviews Scopes: reputation:write

Create a reputation review.

24 parameters
Name In Type Required Description
profile_id body string yes UUID of the reputation profile this review belongs to.
reviewer_name body string yes Full name of the person giving the review, as shown publicly.
reviewer_email body string no Reviewer email. Used for verification and follow-up; never shown publicly.
reviewer_company body string no Company the reviewer works for, shown under their name.
reviewer_company_logo body string no Absolute URL of the reviewer's company logo.
reviewer_role body string no Reviewer job title, shown under their name.
reviewer_avatar body string no Absolute URL of the reviewer photo shown beside the review.
reviewer_linkedin_url body string no Absolute URL of the reviewer's LinkedIn profile.
reviewer_linkedin_verified body boolean no Whether the LinkedIn identity has been verified. Drives the verified badge on the public review.
reviewer_company_size body string no Size band of the reviewer company, used for filtering on the public profile.
reviewer_industry body string no Industry of the reviewer company, used for filtering on the public profile.
rating body number yes Star rating given, 1 to 5.
testimonial_text body string yes The review body as written by the reviewer.
service_category body string no Which service the review is about, used for filtering.
engagement_type body string no Shape of the engagement being reviewed, e.g. project or retainer.
engagement_value_band body string no Value band of the engagement. A band rather than an exact figure so it can be shown publicly.
vendor_response body string no Your public reply to the review, shown beneath it.
featured body boolean no Pin this review to the top of the public profile.
source_type body string no Where the review came from, e.g. collected by request or imported.
source_reference body object no Provenance details for the source, e.g. the original request or import record. Full-replace on write.
consent_given body boolean no Whether the reviewer consented to public display. Publishing without consent is what this field exists to prevent.
consent_method body string no How consent was captured, e.g. via the review form or in writing.
consent_date body string no ISO 8601 timestamp of when consent was given.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-reviews.md

DELETE /reputation/case-studies/:case_study_id Scopes: reputation:delete

Delete a case study.

2 parameters
Name In Type Required Description
case_study_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/delete-reputation-case-studies-case-study-id.md

DELETE /reputation/profile Scopes: reputation:delete

Delete the reputation profile.

1 parameter
Name In Type Required Description
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/delete-reputation-profile.md

DELETE /reputation/reviews/:review_id Scopes: reputation:delete

Delete a reputation review.

2 parameters
Name In Type Required Description
review_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/delete-reputation-reviews-review-id.md

GET /reputation/reviews Scopes: reputation:read

List reputation reviews.

2 parameters
Name In Type Required Description
status query string no
limit query number no

📄 /api/reputation/get-reputation-reviews.md

POST /reputation/case-studies/:case_study_id/publish Scopes: reputation:write

Publish a case study to the public profile.

2 parameters
Name In Type Required Description
case_study_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-case-studies-case-study-id-publish.md

POST /reputation/reviews/:review_id/publish Scopes: reputation:write

Publish a review to the public profile.

2 parameters
Name In Type Required Description
review_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-reviews-review-id-publish.md

POST /reputation/reviews/:review_id/reject Scopes: reputation:write

Reject a review.

2 parameters
Name In Type Required Description
review_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-reviews-review-id-reject.md

POST /reputation/request-review Scopes: reputation:write

Send a tokenised review request to a contact.

3 parameters
Name In Type Required Description
contact_id body string no
email body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-request-review.md

PATCH /reputation/case-studies/:case_study_id Scopes: reputation:write

Update a case study.

20 parameters
Name In Type Required Description
case_study_id path string yes UUID of the case study to update. Get ids from list_reputation_case_studies.
profile_id body string no UUID of the reputation profile this case study belongs to.
review_id body string no UUID of a review to attach to this case study, so the testimonial shows alongside the story.
title body string no Case study headline.
slug body string no URL-safe segment for the public case study page. Changing it breaks links already shared.
client_name body string no Name of the client the work was done for, as shown publicly.
client_company body string no Client company name, when different from client_name.
client_logo body string no Absolute URL of the client logo.
problem body string no The situation before the work: what the client was struggling with.
solution body string no What you did about it.
outcome body string no What changed as a result, ideally with concrete numbers.
summary body string no Short summary shown on the case study card in listings.
key_metrics body object no Headline result figures rendered as stat tiles, e.g. { "Revenue": "+38%" }. Full-replace on write.
images body object no Images used on the case study page. Full-replace on write.
tags body array no Tags used to filter case studies on the public profile. Full-replace array.
featured body boolean no Pin this case study to the top of the public profile.
sort_order body number no Manual position in the case study list. Lower sorts first.
source_type body string no Where the case study came from, e.g. authored in-app or imported.
source_reference body object no Provenance details for the source. Full-replace on write.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/patch-reputation-case-studies-case-study-id.md

PATCH /reputation/profile Scopes: reputation:write

Partially update the reputation profile.

12 parameters
Name In Type Required Description
category_id body string no UUID of the reputation category this profile is listed under.
slug body string no URL-safe segment for the public profile page. Changing it changes the public URL and breaks links already shared.
display_name body string no Brand name shown at the top of the public reputation profile.
tagline body string no One-line positioning statement shown under the display name.
description body string no Longer "about" copy for the public profile.
logo_url body string no Absolute URL of the brand logo shown on the profile.
cover_image_url body string no Absolute URL of the banner image across the top of the profile.
website_url body string no Absolute URL of the brand website, linked from the profile.
linkedin_url body string no Absolute URL of the brand LinkedIn page, linked from the profile.
settings body object no Profile display settings (section visibility, ordering, theme). Full-replace on write.
is_published body boolean no Whether the profile is publicly visible. False keeps it a draft.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/patch-reputation-profile.md

PATCH /reputation/reviews/:review_id Scopes: reputation:write

Update a reputation review.

25 parameters
Name In Type Required Description
review_id path string yes UUID of the review to update. Get ids from list_reputation_reviews.
profile_id body string no UUID of the reputation profile this review belongs to.
reviewer_name body string no Full name of the person giving the review, as shown publicly.
reviewer_email body string no Reviewer email. Used for verification and follow-up; never shown publicly.
reviewer_company body string no Company the reviewer works for, shown under their name.
reviewer_company_logo body string no Absolute URL of the reviewer's company logo.
reviewer_role body string no Reviewer job title, shown under their name.
reviewer_avatar body string no Absolute URL of the reviewer photo shown beside the review.
reviewer_linkedin_url body string no Absolute URL of the reviewer's LinkedIn profile.
reviewer_linkedin_verified body boolean no Whether the LinkedIn identity has been verified. Drives the verified badge on the public review.
reviewer_company_size body string no Size band of the reviewer company, used for filtering on the public profile.
reviewer_industry body string no Industry of the reviewer company, used for filtering on the public profile.
rating body number no Star rating given, 1 to 5.
testimonial_text body string no The review body as written by the reviewer.
service_category body string no Which service the review is about, used for filtering.
engagement_type body string no Shape of the engagement being reviewed, e.g. project or retainer.
engagement_value_band body string no Value band of the engagement. A band rather than an exact figure so it can be shown publicly.
vendor_response body string no Your public reply to the review, shown beneath it.
featured body boolean no Pin this review to the top of the public profile.
source_type body string no Where the review came from, e.g. collected by request or imported.
source_reference body object no Provenance details for the source, e.g. the original request or import record. Full-replace on write.
consent_given body boolean no Whether the reviewer consented to public display. Publishing without consent is what this field exists to prevent.
consent_method body string no How consent was captured, e.g. via the review form or in writing.
consent_date body string no ISO 8601 timestamp of when consent was given.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/patch-reputation-reviews-review-id.md

POST /reputation/profile Scopes: reputation:write

Create or replace the workspace reputation profile.

12 parameters
Name In Type Required Description
category_id body string no UUID of the reputation category this profile is listed under.
slug body string no URL-safe segment for the public profile page. Changing it changes the public URL and breaks links already shared.
display_name body string no Brand name shown at the top of the public reputation profile.
tagline body string no One-line positioning statement shown under the display name.
description body string no Longer "about" copy for the public profile.
logo_url body string no Absolute URL of the brand logo shown on the profile.
cover_image_url body string no Absolute URL of the banner image across the top of the profile.
website_url body string no Absolute URL of the brand website, linked from the profile.
linkedin_url body string no Absolute URL of the brand LinkedIn page, linked from the profile.
settings body object no Profile display settings (section visibility, ordering, theme). Full-replace on write.
is_published body boolean no Whether the profile is publicly visible. False keeps it a draft.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/reputation/post-reputation-profile.md

Referrals (18 endpoints)

Track the referrer -> referred contact -> opportunity chain. Includes workspace-defined category picklist, a leaderboard endpoint, a public token-based submission form, and a create_referral automation action for pipeline-driven partner registration. Every write to the referrals table fires the referral_attributed automation trigger (see GET /schemas/triggers/referral_attributed). Attribution is also cached on the opportunity: crm_deals.primary_referrer_contact_id and crm_deals.primary_referrer_category are maintained by a Postgres trigger and surface in GET /opportunities/:id (including the expand=referrer expansion).

📄 Full markdown: /api/referrals.md

POST /referrals/:referral_id/commissions Scopes: referrals:write

Add a commission instalment to a referral. amount is required; status defaults to scheduled. The cached commission summary (paid-to-date / pending / next-payment) on the referral updates automatically.

7 parameters
Name In Type Required Description
referral_id path string yes
amount body number yes
status body string no scheduled | paid | cancelled. Defaults to scheduled.
due_date body string no ISO date (YYYY-MM-DD) the instalment is expected.
paid_date body string no ISO date (YYYY-MM-DD) the instalment was paid.
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/post-referrals-referral-id-commissions.md

POST /referrals Scopes: referrals:write

Create a referral entry. Requires referrer_contact_id.

5 parameters
Name In Type Required Description
referrer_contact_id body string yes
referred_contact_id body string no
notes body string no
deal_id body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/post-referrals.md

POST /referrals/links Scopes: referrals:write

Create a stable referral/affiliate link for a referrer contact so every signup through the link is attributed to them. The form it opens is the workspace referral form (Settings -> Tools -> Referrals), resolved automatically — not set per link. slug (the public handle) defaults to the referrer's name. Returns link_url to share.

4 parameters
Name In Type Required Description
referrer_contact_id body string yes Contact UUID of the referrer/partner. Required.
slug body string no Optional public handle for the link (e.g. 'aiafy'). Defaults to a slug of the referrer's name; must be unique in the workspace.
active body boolean no Defaults to true.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/post-referrals-links.md

DELETE /referrals/:referral_id Scopes: referrals:delete

Delete a referral.

2 parameters
Name In Type Required Description
referral_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/delete-referrals-referral-id.md

DELETE /referrals/:referral_id/commissions/:payment_id Scopes: referrals:write

Delete a commission instalment from a referral. The cached commission summary on the referral updates automatically.

3 parameters
Name In Type Required Description
referral_id path string yes
payment_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/delete-referrals-referral-id-commissions-payment-id.md

DELETE /referrals/links/:link_id Scopes: referrals:delete

Delete a referral link. Prefer setting active=false to disable a partner link while keeping its history.

2 parameters
Name In Type Required Description
link_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/delete-referrals-links-link-id.md

GET /referrals/links/:link_id Scopes: referrals:read

Fetch a referral link by UUID (includes link_url).

1 parameter
Name In Type Required Description
link_id path string yes

📄 /api/referrals/get-referrals-links-link-id.md

GET /referrals/:referral_id/commissions Scopes: referrals:read

List the commission instalments (scheduled / paid / cancelled) attached to a referral, ordered by due date.

1 parameter
Name In Type Required Description
referral_id path string yes

📄 /api/referrals/get-referrals-referral-id-commissions.md

GET /referrals/links Scopes: referrals:read

List referral links — a referrer's stable, reusable referral/affiliate links. Each carries link_url (the shareable app.trustpager.com/r/{workspace}/{handle} link). Filter by referrer_contact_id or active.

2 parameters
Name In Type Required Description
referrer_contact_id query string no
active query boolean no

📄 /api/referrals/get-referrals-links.md

GET /referrals Scopes: referrals:read

List referrals in the workspace.

1 parameter
Name In Type Required Description
limit query number no

📄 /api/referrals/get-referrals.md

POST /referrals/request Scopes: referrals:write

Ask a contact to refer someone — sends the referral-request flow.

3 parameters
Name In Type Required Description
contact_id body string yes
channel body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/post-referrals-request.md

POST /referrals/attribute Scopes: referrals:write

Set, reassign, or clear the primary referrer on an opportunity. Pass referrer_contact_id to attribute it to a contact, or null to clear. Updates the referral graph in place so commission tracking and history survive a reassignment, and leaves form/automation-sourced referrals intact.

4 parameters
Name In Type Required Description
opportunity_id body string yes Opportunity (deal) UUID to attribute. Required.
referrer_contact_id body string,null yes Contact UUID of the referrer. Pass null to clear the referrer.
category body string no Optional referral category (modality, service type, lead source).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/post-referrals-attribute.md

PATCH /referrals/:referral_id Scopes: referrals:write

Update a referral.

4 parameters
Name In Type Required Description
referral_id path string yes
status body string no
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/patch-referrals-referral-id.md

PATCH /referrals/:referral_id/commissions/:payment_id Scopes: referrals:write

Update a commission instalment (amount, status, due_date, paid_date, notes). Setting status to paid auto-stamps paid_date when none is supplied.

8 parameters
Name In Type Required Description
referral_id path string yes
payment_id path string yes
amount body number no
status body string no
due_date body string no
paid_date body string no
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/patch-referrals-referral-id-commissions-payment-id.md

PATCH /referrals/links/:link_id Scopes: referrals:write

Update a referral link — change its handle (slug) or active state (deactivate to disable a partner link without deleting it). The form it opens is a workspace setting, not per-link.

4 parameters
Name In Type Required Description
link_id path string yes
slug body string no
active body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/referrals/patch-referrals-links-link-id.md

CRM Export (1 endpoint)

One-shot export of CRM data across contacts, companies and opportunities.

📄 Full markdown: /api/crm-export.md

GET /crm/export

Export CRM data (contacts, companies, deals, work-orders) to xlsx or csv. Pass `type` and optional filters via query string. Returns a downloadable file.

9 parameters
Name In Type Required Description
type query string yes contacts, customers, deals, or work-orders
format query string no xlsx (default) or csv
search query string no
status query string no
pipeline_id query string no
stage_id query string no
customer_id query string no
contact_id query string no
archived query string no Archive scope (contacts/companies/deals). "false" (default) = active only, "true" = archived only, "all" = both.

📄 /api/crm-export/get-crm-export.md

Export Templates (13 endpoints)

Reusable export templates and the field catalog they draw on, for pulling workspace data out as CSV or XLSX.

📄 Full markdown: /api/export-templates.md

POST /exports/templates Scopes: exports:write

Create an export template.

7 parameters
Name In Type Required Description
name body string yes Template name, shown in the Spreadsheets list.
root_entity body string yes What one row represents.
description body string no Optional note about what this spreadsheet is for.
columns body array no Columns, left to right. Defaults to none, which produces an empty grid.
filters body array no Filters limiting which records appear. Defaults to none.
output body object no File output settings: { "format": "csv" | "xlsx", "bom": boolean, "filename_template": string }. filename_template accepts the tokens {name}, {YYYY-MM-DD}, {YYYY}, {MM}, {DD}. Defaults to { "format": "csv", "bom": true }.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/export-templates/post-exports-templates.md

POST /exports/templates/:template_id/views Scopes: exports:write

Create a view on an export template. A view holds its own filters and sort, so one template can carry several saved cuts of the same data.

6 parameters
Name In Type Required Description
template_id path string yes
name body string yes View name, shown in the view picker.
description body string no Optional note about what this view shows.
filters body array no Filters for this view. A view holds its own filters, so one template can carry several saved cuts of the same data.
sort body array no Sort order for this view. Only root scalar columns sort at query time.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/export-templates/post-exports-templates-template-id-views.md

DELETE /exports/templates/:template_id Scopes: exports:delete

Delete an export template.

2 parameters
Name In Type Required Description
template_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/export-templates/delete-exports-templates-template-id.md

DELETE /exports/templates/:template_id/views/:view_id Scopes: exports:delete

Delete a view.

3 parameters
Name In Type Required Description
template_id path string yes
view_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/export-templates/delete-exports-templates-template-id-views-view-id.md

POST /exports/templates/:template_id/preview Scopes: exports:read

Preview an export template (free read). Returns the first rows as formatted cells, so it is the fastest way to check a column or filter change did what you meant.

5 parameters
Name In Type Required Description
template_id path string yes
view_id body string no Run against this saved view. Defaults to the most recently updated view on the template.
filters body array no Replace the view filters for this run only. Nothing is saved.
extra_filters body array no Append to the view filters for this run only. Ignored when `filters` is also sent.
sort body array no Override the view sort for this run only. Send null to run unsorted.

📄 /api/export-templates/post-exports-templates-template-id-preview.md

POST /exports/templates/:template_id/run Scopes: exports:read

Run an export template and return the file (CSV or XLSX, per the template output settings).

5 parameters
Name In Type Required Description
template_id path string yes
view_id body string no Run against this saved view. Defaults to the most recently updated view on the template.
filters body array no Replace the view filters for this run only. Nothing is saved.
extra_filters body array no Append to the view filters for this run only. Ignored when `filters` is also sent.
sort body array no Override the view sort for this run only. Send null to run unsorted.

📄 /api/export-templates/post-exports-templates-template-id-run.md

PATCH /exports/templates/:template_id Scopes: exports:write

Update an export template. Send the full columns / filters list, not a partial one.

9 parameters
Name In Type Required Description
template_id path string yes
name body string no Rename the template.
description body string no Replace the note. Send null to clear it.
columns body array no Replaces the whole column list. Send the full set, not a partial one.
filters body array no Replaces the whole filter list. Send the full set, not a partial one.
output body object no File output settings: { "format": "csv" | "xlsx", "bom": boolean, "filename_template": string }. filename_template accepts the tokens {name}, {YYYY-MM-DD}, {YYYY}, {MM}, {DD}. Defaults to { "format": "csv", "bom": true }.
is_archived body boolean no Archive the template (hides it from the Spreadsheets list) or restore it.
delivery body object no Scheduled-delivery settings. Send null to clear.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/export-templates/patch-exports-templates-template-id.md

PATCH /exports/templates/:template_id/views/:view_id Scopes: exports:write

Update a view.

7 parameters
Name In Type Required Description
template_id path string yes
view_id path string yes
name body string no Rename the view.
description body string no Replace the note. Send null to clear it.
filters body array no Replaces the whole filter list for this view.
sort body array no Replaces the sort order. Send null to clear it.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/export-templates/patch-exports-templates-template-id-views-view-id.md

Evie (In-App Agent) (2 endpoints)

Evie is the conversational AI assistant embedded in the TrustPager CRM sidebar. These endpoints sit outside the standard /api/v1 gateway and use OAuth tokens minted specifically for the in-app agent.

📄 Full markdown: /api/evie.md

POST /evie-grant

Mint an Evie OAuth token for the authenticated user. The caller must supply a Supabase JWT (portal session token) as the Bearer credential. The endpoint verifies workspace membership and returns a tp_oauth_* token scoped to the intersection of the client max-scopes and the user role scopes. Idempotent: re-calling revokes any prior Evie token for the same (user, company) pair and issues a fresh one.

1 parameter
Name In Type Required Description
company_id body uuid yes Target workspace company ID. Must be a workspace the authenticated user belongs to.

📄 /api/evie/post-evie-grant.md

GET /api/v1/_meta/tools

Return the list of CRM tools available to the authenticated API key holder. Each tool entry includes: name (snake_case), description, input_schema (JSON Schema), preferred_model, api_path, required_scopes, is_write, and portal_path. Tools are filtered by the caller scopes, so a tp_live_* key with only contacts:read sees only read-scoped contact tools. Used internally by Evie to populate her tool catalog, and useful for building your own agent on top of the TrustPager API.

📄 /api/evie/get-api-v1-meta-tools.md

Agent Ops (28 endpoints)

Observability and management for AI agent infrastructure. Covers: registry, run log, signals, metrics, tool log, report runs, alert rules, fired alerts, and the aggregated dashboard. All routes require agent-ops:read (reads) or agent-ops:write (writes/actions).

📄 Full markdown: /api/agent-ops.md

POST /agent-ops/alerts/:alert_id/acknowledge Scopes: agent-ops:write

Acknowledge a fired agent alert.

2 parameters
Name In Type Required Description
alert_id path string yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-alerts-alert-id-acknowledge.md

POST /agent-ops/alerts Scopes: agent-ops:write

Record a fired agent alert.

6 parameters
Name In Type Required Description
rule_id body string no UUID of the alert rule that fired. Null for an alert raised directly rather than by a rule.
agent_name body string yes Machine name of the agent the alert is about.
alert_type body string yes What kind of alert this is.
message body string yes Human-readable alert text.
context body object no Supporting detail for the alert: the run, the values that tripped the rule. Full-replace on write.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-alerts.md

POST /agent-ops/alert-rules Scopes: agent-ops:write

Create an agent alert rule.

7 parameters
Name In Type Required Description
agent_name body string no Machine name of the agent this rule watches. Null watches every agent.
rule_type body string yes What the rule checks for, e.g. a failed run or a run that took too long.
threshold body object yes The condition that trips the rule. A JSON object, not a bare number, because the shape depends on rule_type.
notify_channel body string no How to notify when the rule trips, e.g. chat or email.
notify_target body string no Where to send the notification: the room, address or user for the chosen channel.
enabled body boolean no Whether the rule is active. False keeps it configured but silent.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-alert-rules.md

POST /agent-ops/registry Scopes: agent-ops:write

Register a new agent.

18 parameters
Name In Type Required Description
name body string yes Stable machine name for the agent, used as the key in run logs and signals. Lowercase, no spaces.
display_name body string yes Human-readable agent name shown in the UI.
description body string no What this agent does and when it runs.
icon body string no Icon key for the agent card.
color body string no Accent colour for the agent card, as a hex value.
agent_type body string no Category of agent, used to group it in the console.
status body string no Lifecycle state of the agent, e.g. active or paused. A paused agent stays registered but is not scheduled.
capabilities body array no What this agent is allowed to do, used for routing work to it. Full-replace array.
allowed_tools body array no Tool names this agent may call. Full-replace array; an empty list means no restriction is recorded.
schedule body string no Cron expression for when the agent runs. Null means it only runs when triggered.
timezone body string no IANA timezone the schedule is evaluated in, e.g. "Australia/Melbourne".
upstream_agents body array no Agent names whose output this agent consumes. Full-replace array.
downstream_agents body array no Agent names that consume this agent output. Full-replace array.
configuration body object no Agent-specific settings. Shape depends on agent_type. Full-replace on write.
template_notepad_id body string no UUID of the notepad used as the output template for this agent runs.
runtime body string no Where the agent executes. Determines which worker picks up its runs.
kickoff_message_template body string no Message template used to start a run, with placeholders filled from the run context.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-registry.md

POST /agent-ops/reports Scopes: agent-ops:write

Create an agent report-run entry.

9 parameters
Name In Type Required Description
eve_id body string no Identifier of the host that ran the report.
report_name body string yes Which scheduled report this run is for.
run_date body string yes Date the report covers, as YYYY-MM-DD.
status body string no Outcome of the report run, e.g. running, complete or failed.
started_at body string no ISO 8601 timestamp the report started.
completed_at body string no ISO 8601 timestamp the report finished. Null while still running.
notepad_id body string no UUID of the notepad the report was written to.
error body string no Failure reason when the report run failed.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-reports.md

POST /agent-ops/runs Scopes: agent-ops:write

Log a new agent run.

17 parameters
Name In Type Required Description
eve_id body string no Identifier of the host that executed the run.
agent_name body string yes Machine name of the agent that ran. Matches agent_registry.name.
task_type body string no What kind of work the run performed.
status body string no Outcome of the run, e.g. running, complete or failed.
model body string no Model identifier the run used.
started_at body string no ISO 8601 timestamp the run started.
completed_at body string no ISO 8601 timestamp the run finished. Null while still running.
duration_ms body number no Wall-clock duration of the run in milliseconds.
output_summary body string no Short summary of what the run produced.
notepad_id body string no UUID of the notepad the run wrote its output to.
slack_sent body boolean no Whether the run posted its summary to the team chat room.
prompt_chars body number no Characters of prompt sent, for cost tracking.
output_chars body number no Characters of output produced, for cost tracking.
exit_code body number no Process exit code. 0 means success.
error_message body string no One-line failure reason when the run failed.
error_detail body string no Full error text or stack trace for debugging.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-runs.md

POST /agent-ops/signals Scopes: agent-ops:write

Send an inter-agent signal.

10 parameters
Name In Type Required Description
eve_id body string no Identifier of the host that raised the signal.
for_agent body string yes Machine name of the agent this signal is addressed to.
created_by body string yes Who raised the signal: an agent machine name, or a person.
signal body string yes The signal name, i.e. what happened. Text, not an object.
detail body string no Free-text context for the receiving agent.
expires_at body string no ISO 8601 timestamp after which the signal is stale and should be ignored.
actioned_at body string no ISO 8601 timestamp the signal was consumed. Set this to mark it handled.
report_type body string no Which report the signal relates to, when it came from a scheduled report.
contact_id body string no UUID of the CRM contact the signal is about, when it concerns one.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-signals.md

POST /agent-ops/tool-log Scopes: agent-ops:write

Log an agent tool call.

10 parameters
Name In Type Required Description
eve_id body string no Identifier of the host that made the tool call.
tool_name body string yes Name of the tool that was called.
caller body string no Which agent or process made the call.
args body object no Arguments the tool was called with. Full-replace on write.
status body string no Outcome of the call, e.g. ok or error.
duration_ms body number no How long the call took in milliseconds.
http_status body number no HTTP status returned, for tools that make a request.
response_size body number no Size of the response in bytes.
error body string no Error text when the call failed.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-tool-log.md

DELETE /agent-ops/alert-rules/:rule_id Scopes: agent-ops:delete

Delete an agent alert rule.

2 parameters
Name In Type Required Description
rule_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/delete-agent-ops-alert-rules-rule-id.md

DELETE /agent-ops/registry/:registry_id Scopes: agent-ops:delete

Delete an agent registry entry.

2 parameters
Name In Type Required Description
registry_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/delete-agent-ops-registry-registry-id.md

POST /agent-ops/dispatch Scopes: agent-ops:write

Dispatch a workflow-agent run on the Cloudflare engine and return its run id. The agent runs as durable, cheap-model steps (routed per role); poll get_agent_run for the per-step trace + cost. mode:"test" (default) runs in Demo Company only; mode:"live" runs in the current workspace. Steps, tool_catalog, and routing fall back to the agent's saved configuration when omitted; omit everything to fire a one-step engine health check.

8 parameters
Name In Type Required Description
agent_id body string yes agent_registry id to run.
mode body string no test = Demo Company only (default); live = current workspace.
input body object no Run input, threaded into the first step.
steps body array no Optional StepSpec[]; falls back to the agent's configuration.steps, else a one-step health check.
task_type body string no Label shown as the Sessions row Task.
tool_catalog body array no Optional tool definitions for tool_loop / gather steps (falls back to configuration.tool_catalog).
routing body object no Optional role->model routing override { byRole, byStepId } (falls back to configuration.routing).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-dispatch.md

GET /agent-ops/runs/:run_id Scopes: agent-ops:read

Fetch one agent run with its full per-step execution trace (each step's role, model, status, tokens, tool calls, output) from the workflow-agent ledger. Accepts the run id returned by dispatch_agent_run, or an agent_run_log row id.

1 parameter
Name In Type Required Description
run_id path string yes Run id from dispatch_agent_run, or an agent_run_log row id.

📄 /api/agent-ops/get-agent-ops-runs-run-id.md

GET /agent-ops/runs Scopes: agent-ops:read

List agent execution runs.

2 parameters
Name In Type Required Description
agent_name query string no
limit query number no

📄 /api/agent-ops/get-agent-ops-runs.md

GET /agent-ops/tool-log Scopes: agent-ops:read

List agent tool-call log entries. Filter by caller, tool_name, or since.

5 parameters
Name In Type Required Description
limit query number no
after query string no
caller query string no Which agent made the call.
tool_name query string no
since query string no ISO timestamp. Only entries at or after this time.

📄 /api/agent-ops/get-agent-ops-tool-log.md

PATCH /agent-ops/alert-rules/:rule_id Scopes: agent-ops:write

Update an agent alert rule.

8 parameters
Name In Type Required Description
rule_id path string yes UUID of the alert rule to update.
agent_name body string no Machine name of the agent this rule watches. Null watches every agent.
rule_type body string no What the rule checks for, e.g. a failed run or a run that took too long.
threshold body object no The condition that trips the rule. A JSON object, not a bare number, because the shape depends on rule_type.
notify_channel body string no How to notify when the rule trips, e.g. chat or email.
notify_target body string no Where to send the notification: the room, address or user for the chosen channel.
enabled body boolean no Whether the rule is active. False keeps it configured but silent.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/patch-agent-ops-alert-rules-rule-id.md

PATCH /agent-ops/registry/:registry_id Scopes: agent-ops:write

Update an agent registry entry.

19 parameters
Name In Type Required Description
registry_id path string yes UUID of the agent registry entry to update.
name body string no Stable machine name for the agent, used as the key in run logs and signals. Lowercase, no spaces.
display_name body string no Human-readable agent name shown in the UI.
description body string no What this agent does and when it runs.
icon body string no Icon key for the agent card.
color body string no Accent colour for the agent card, as a hex value.
agent_type body string no Category of agent, used to group it in the console.
status body string no Lifecycle state of the agent, e.g. active or paused. A paused agent stays registered but is not scheduled.
capabilities body array no What this agent is allowed to do, used for routing work to it. Full-replace array.
allowed_tools body array no Tool names this agent may call. Full-replace array; an empty list means no restriction is recorded.
schedule body string no Cron expression for when the agent runs. Null means it only runs when triggered.
timezone body string no IANA timezone the schedule is evaluated in, e.g. "Australia/Melbourne".
upstream_agents body array no Agent names whose output this agent consumes. Full-replace array.
downstream_agents body array no Agent names that consume this agent output. Full-replace array.
configuration body object no Agent-specific settings. Shape depends on agent_type. Full-replace on write.
template_notepad_id body string no UUID of the notepad used as the output template for this agent runs.
runtime body string no Where the agent executes. Determines which worker picks up its runs.
kickoff_message_template body string no Message template used to start a run, with placeholders filled from the run context.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/patch-agent-ops-registry-registry-id.md

PATCH /agent-ops/reports/:report_id Scopes: agent-ops:write

Update an agent report-run.

10 parameters
Name In Type Required Description
report_id path string yes UUID of the report-run entry to update.
eve_id body string no Identifier of the host that ran the report.
report_name body string no Which scheduled report this run is for.
run_date body string no Date the report covers, as YYYY-MM-DD.
status body string no Outcome of the report run, e.g. running, complete or failed.
started_at body string no ISO 8601 timestamp the report started.
completed_at body string no ISO 8601 timestamp the report finished. Null while still running.
notepad_id body string no UUID of the notepad the report was written to.
error body string no Failure reason when the report run failed.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/patch-agent-ops-reports-report-id.md

PATCH /agent-ops/runs/:run_id Scopes: agent-ops:write

Update an agent run.

18 parameters
Name In Type Required Description
run_id path string yes UUID of the run log entry to update.
eve_id body string no Identifier of the host that executed the run.
agent_name body string no Machine name of the agent that ran. Matches agent_registry.name.
task_type body string no What kind of work the run performed.
status body string no Outcome of the run, e.g. running, complete or failed.
model body string no Model identifier the run used.
started_at body string no ISO 8601 timestamp the run started.
completed_at body string no ISO 8601 timestamp the run finished. Null while still running.
duration_ms body number no Wall-clock duration of the run in milliseconds.
output_summary body string no Short summary of what the run produced.
notepad_id body string no UUID of the notepad the run wrote its output to.
slack_sent body boolean no Whether the run posted its summary to the team chat room.
prompt_chars body number no Characters of prompt sent, for cost tracking.
output_chars body number no Characters of output produced, for cost tracking.
exit_code body number no Process exit code. 0 means success.
error_message body string no One-line failure reason when the run failed.
error_detail body string no Full error text or stack trace for debugging.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/patch-agent-ops-runs-run-id.md

PATCH /agent-ops/signals/:signal_id Scopes: agent-ops:write

Update a signal (e.g. mark as consumed).

11 parameters
Name In Type Required Description
signal_id path string yes UUID of the signal to update.
eve_id body string no Identifier of the host that raised the signal.
for_agent body string no Machine name of the agent this signal is addressed to.
created_by body string no Who raised the signal: an agent machine name, or a person.
signal body string no The signal name, i.e. what happened. Text, not an object.
detail body string no Free-text context for the receiving agent.
expires_at body string no ISO 8601 timestamp after which the signal is stale and should be ignored.
actioned_at body string no ISO 8601 timestamp the signal was consumed. Set this to mark it handled.
report_type body string no Which report the signal relates to, when it came from a scheduled report.
contact_id body string no UUID of the CRM contact the signal is about, when it concerns one.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/patch-agent-ops-signals-signal-id.md

POST /agent-ops/metrics Scopes: agent-ops:write

Upsert a metric row.

5 parameters
Name In Type Required Description
agent_name body string yes Machine name of the agent the metrics belong to.
run_date body string yes Date the metrics cover, as YYYY-MM-DD. Together with agent_name this is the upsert key.
data body object no The metric values for that agent and date. Full-replace on write.
run_log_id body string no UUID of the run these metrics came from.
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/agent-ops/post-agent-ops-metrics.md

Auto Responders (6 endpoints)

Per-identity AI reply automation for email and SMS (AI Auto-Responders). Each config binds one phone number or email address to a reply behaviour: enabled on/off, draft-for-review vs auto-send, persona/instructions, tone, and knowledge base grounding. Use test_auto_responder to dry-run the triage+draft pipeline before enabling. All routes require agent-ops:read (reads) or agent-ops:write / agent-ops:delete (writes/deletes). The actual send/queue decision at runtime happens server-side and is not exposed here — this surface is pure config CRUD plus a dry-run test.

📄 Full markdown: /api/auto-responders.md

POST /auto-responders Scopes: agent-ops:write

Create or update (upsert by identity) an auto-responder config. identity_kind "phone" needs identity_ref = a phone_numbers.id; "email_config" needs identity_ref = an email_config.id. Defaults: enabled=false, mode="draft" (queues replies for human approval, never auto-sends unless mode="auto_send" is explicitly set).

11 parameters
Name In Type Required Description
channel body string yes
identity_kind body string yes
identity_ref body string yes phone_numbers.id or email_config.id matching identity_kind
enabled body boolean no
mode body string no draft (default) queues for approval; auto_send sends immediately
instructions body string no
tone body string no
knowledge_base_id body string no
business_hours_only body boolean no
config body object no What the AI is told about the customer, what it can do, and how it handles each type of inbound. context_modules: array of opportunity, contact, customer_account, products, work_orders, bookings, invoices, a CRM record snapshot funnelled into the draft as reference only (the AI does not proactively volunteer it). tools: object keyed by tool name (lookup_account, work_order_status, check_pricing, check_availability, book_appointment, cancel_booking, reschedule_booking, request_callback, take_message, unsubscribe, create_invoice_payment_link) with { enabled: boolean, requires_approval?: boolean }. requires_approval only applies to write tools (book_appointment, cancel_booking, reschedule_booking, request_callback, take_message, unsubscribe, create_invoice_payment_link) and defaults to true for customer-visible actions; when true the action queues into /settings/approvals instead of executing immediately. triage_actions: object keyed by inbound category (new_enquiry, existing_customer, general_question, booking_request, complaint, billing_account, sales_pitch, vendor_supplier, recruitment_partnership, automated_notification) mapping each to one of auto_respond, escalate, do_nothing — auto_respond drafts a reply, escalate drafts but always queues for approval, do_nothing ignores it. Unset categories use sensible defaults (enquiries auto-respond, complaint/billing escalate, sales pitches/vendor/machine mail do nothing).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-responders/post-auto-responders.md

DELETE /auto-responders/:id Scopes: agent-ops:delete

Delete an auto-responder config. The identity (number/email) still appears in the Hub list, just unconfigured.

2 parameters
Name In Type Required Description
id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-responders/delete-auto-responders-id.md

GET /auto-responders Scopes: agent-ops:read

List per-identity AI auto-responder configs for the workspace (email/SMS reply automation). Optional filters: channel (sms|email), enabled (true|false).

2 parameters
Name In Type Required Description
channel query string no
enabled query boolean no

📄 /api/auto-responders/get-auto-responders.md

POST /auto-responders/:id/test Scopes: agent-ops:write

Fire a synthetic message through the auto-responder's triage and draft pipeline (TrustPager AI) WITHOUT sending or queuing anything for approval. A dry run to verify behaviour before enabling. Returns the triage category (new_enquiry, sales_pitch, complaint, etc.), the resolved action (auto_respond | escalate | do_nothing), whether the reply would be forced to the approval queue, and the drafted text when one is produced.

5 parameters
Name In Type Required Description
id path string yes
message_body body string yes The synthetic inbound message to test
from body string no Optional synthetic sender address/number
subject body string no Optional synthetic subject (email only)
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-responders/post-auto-responders-id-test.md

PATCH /auto-responders/:id Scopes: agent-ops:write

Update an auto-responder config (enable/disable, change mode, edit persona/instructions/tone/knowledge base, context modules, tools, per-category triage actions).

5 parameters
Name In Type Required Description
id path string yes
enabled body boolean no
mode body string no
config body object no context_modules: array of opportunity, contact, customer_account, products, work_orders, bookings, invoices. tools: object keyed by tool name (lookup_account, work_order_status, check_pricing, check_availability, book_appointment, cancel_booking, reschedule_booking, request_callback, take_message, unsubscribe, create_invoice_payment_link) with { enabled: boolean, requires_approval?: boolean }. triage_actions: object keyed by inbound category (new_enquiry, existing_customer, general_question, booking_request, complaint, billing_account, sales_pitch, vendor_supplier, recruitment_partnership, automated_notification) → one of auto_respond, escalate, do_nothing (auto_respond | escalate | do_nothing).
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/auto-responders/patch-auto-responders-id.md

INVENTORY (14 endpoints)

inventory endpoints.

📄 Full markdown: /api/inventory.md

POST /inventory/batches Scopes: products:write

Create an inventory batch/lot for a product. Stock is added separately by recording a receive movement.

9 parameters
Name In Type Required Description
product_id body string yes
batch_number body string yes
initial_quantity body number yes
received_date body string no
expiry_date body string no
supplier_name body string no
purchase_cost body number no
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/post-inventory-batches.md

POST /inventory/locations Scopes: products:write

Create an inventory location (warehouse / stockroom). Requires name.

9 parameters
Name In Type Required Description
name body string yes
address_line1 body string no
city body string no
state body string no
postal_code body string no
country body string no
is_default body boolean no
is_active body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/post-inventory-locations.md

DELETE /inventory/batches/:batch_id Scopes: products:delete

Delete an inventory batch by UUID. Destructive.

2 parameters
Name In Type Required Description
batch_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/delete-inventory-batches-batch-id.md

DELETE /inventory/locations/:location_id Scopes: products:delete

Delete an inventory location by UUID. Destructive.

2 parameters
Name In Type Required Description
location_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/delete-inventory-locations-location-id.md

GET /inventory/stock/summary Scopes: products:read

Per-product stock summary (total on hand, batch count, earliest expiry) for inventory-tracked products. Filter by product_id.

1 parameter
Name In Type Required Description
product_id query string no

📄 /api/inventory/get-inventory-stock-summary.md

GET /inventory/batches Scopes: products:read

List inventory batches/lots. Filter by product_id or search by batch_number.

4 parameters
Name In Type Required Description
limit query number no
after query string no
product_id query string no
search query string no

📄 /api/inventory/get-inventory-batches.md

GET /inventory/locations Scopes: products:read

List inventory locations (warehouses / stockrooms) in the workspace.

4 parameters
Name In Type Required Description
limit query number no
after query string no
search query string no
is_active query boolean no

📄 /api/inventory/get-inventory-locations.md

GET /inventory/movements Scopes: products:read

List inventory stock movements (the ledger). Filter by product_id, batch_id, or reference.

6 parameters
Name In Type Required Description
limit query number no
after query string no
product_id query string no
batch_id query string no
reference_type query string no
reference_id query string no

📄 /api/inventory/get-inventory-movements.md

GET /inventory/stock Scopes: products:read

List current stock on hand (per batch, per location). Filter by batch_id or location_id. Maintained automatically from the movements ledger.

4 parameters
Name In Type Required Description
limit query number no
after query string no
batch_id query string no
location_id query string no

📄 /api/inventory/get-inventory-stock.md

POST /inventory/movements Scopes: products:write

Record a stock movement (receive, ship, transfer, adjust_in, adjust_out, dispose). Stock on hand updates automatically. receive/adjust_in need to_location_id; ship/adjust_out/dispose need from_location_id; transfer needs both. The ledger is append-only — correct mistakes with an offsetting movement.

10 parameters
Name In Type Required Description
batch_id body string yes
movement_type body string yes
quantity body number yes
from_location_id body string no
to_location_id body string no
reference_type body string no
reference_id body string no
reason body string no
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/post-inventory-movements.md

PATCH /inventory/batches/:batch_id Scopes: products:write

Update an inventory batch. The product it belongs to cannot be changed.

6 parameters
Name In Type Required Description
batch_id path string yes
batch_number body string no
expiry_date body string no
supplier_name body string no
notes body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/patch-inventory-batches-batch-id.md

PATCH /inventory/locations/:location_id Scopes: products:write

Update an inventory location. Pass only the fields you want to change.

5 parameters
Name In Type Required Description
location_id path string yes
name body string no
is_default body boolean no
is_active body boolean no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/inventory/patch-inventory-locations-location-id.md

COMPONENTS (12 endpoints)

components endpoints.

📄 Full markdown: /api/components.md

POST /component-instances/bulk Scopes: products:write

Create up to 500 component instances in one call. Body: { instances: [...] }, each item the same shape as create_component_instance (product_id + opportunity_id required). Used for sample-data imports.

2 parameters
Name In Type Required Description
instances body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/post-component-instances-bulk.md

POST /product-components/bulk Scopes: products:write

Create up to 500 product template components in one call. Body: { components: [...] }, each item the same shape as create_product_component.

2 parameters
Name In Type Required Description
components body array yes
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/post-product-components-bulk.md

POST /component-instances Scopes: products:write

Create a component instance (a unit / lab sample) for a job. REQUIRES both product_id and opportunity_id — an instance always belongs to a product and a specific opportunity. Carry result data in attributes.

8 parameters
Name In Type Required Description
product_id body string yes
opportunity_id body string yes
label body string no
status body string no
attributes body object no
external_ref body string no
source body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/post-component-instances.md

POST /product-components Scopes: products:write

Add a template component (a BOM part/bundle) to a product. Product-level, not tied to any opportunity. Requires product_id.

9 parameters
Name In Type Required Description
product_id body string yes
type body string no
label body string no
status body string no
attributes body object no
sort_order body number no
external_ref body string no
source body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/post-product-components.md

DELETE /component-instances/:instance_id Scopes: products:delete

Delete a component instance by UUID. Destructive.

2 parameters
Name In Type Required Description
instance_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/delete-component-instances-instance-id.md

DELETE /product-components/:product_component_id Scopes: products:delete

Delete a product template component by UUID. Destructive.

2 parameters
Name In Type Required Description
product_component_id path string yes
require_approval query boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/delete-product-components-product-component-id.md

GET /component-instances Scopes: products:read

List component instances (the actual units / lab samples processed for jobs), carrying result data in attributes. Filter by opportunity_id, product_id, status, or search by label.

6 parameters
Name In Type Required Description
limit query number no
after query string no
opportunity_id query string no
product_id query string no
status query string no
search query string no

📄 /api/components/get-component-instances.md

GET /product-components Scopes: products:read

List a product's template components (bill-of-materials parts/bundles). Filter by product_id, type, or search by label. These are product-level and reused across opportunities — for the actual lab samples/units of a job use list_component_instances.

5 parameters
Name In Type Required Description
limit query number no
after query string no
product_id query string no
type query string no
search query string no

📄 /api/components/get-product-components.md

PATCH /component-instances/:instance_id Scopes: products:write

Update a component instance. The product and opportunity it belongs to cannot be changed. Pass only the fields you want to change (e.g. status, attributes).

7 parameters
Name In Type Required Description
instance_id path string yes
label body string no
status body string no
attributes body object no
external_ref body string no
source body string no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/patch-component-instances-instance-id.md

PATCH /product-components/:product_component_id Scopes: products:write

Update a product template component. The product it belongs to cannot be changed.

7 parameters
Name In Type Required Description
product_component_id path string yes
type body string no
label body string no
status body string no
attributes body object no
sort_order body number no
require_approval body boolean no Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly.

📄 /api/components/patch-product-components-product-component-id.md