Developers
REST API
Every SIGNL tool is also an HTTP endpoint, with the same inputs and scopes as the MCP server. This page is read from the OpenAPI contract the API serves, so the two always agree.
117 tools
The contract
SIGNL Developer API 1.0.0
OpenAPI 3.1
Authentication
Keys are minted under the client's Integrations page (API keys), or organisation Settings → API Keys.
Bearer key
SIGNL API key
GET /api/keys/me
Describe the key you are holding
Scopes
A key can do what its scopes allow and nothing else. Each tool below names the scope it needs.
ingest:write
scope
read
scope
write
scope
write:sensitive
scope
write:builder
scope
write:ads
scope
write:agency
scope
write:finance
scope
recordings:write
scope
Calling a tool
Send the tool's input as a JSON body. Workspace tools also take workspace, a workspace slug, which an organisation-wide key uses to name the workspace it acts in.
GET /api/v1/tools
List the tools the calling key can use
POST /api/v1/tools/<name>
run a tool
Responses and errors
Every status code a tool can answer with, and what the contract says about each.
200
status
- The tool result.
201
status
- Created.
- A client was created.
400
status
- Invalid input, named field by field. Unknown fields are refused.
- Invalid input, or the request was refused (plan limit, unknown client). Unknown fields are refused.
401
status
- Missing, malformed, unknown or revoked API key. A valid key never gets 401 — a missing scope is 403.
403
status
- The key lacks read; the body names both.
- The key lacks write; the body names both.
- The key lacks write:sensitive; the body names both.
- The key lacks write:ads; the body names both.
- The key lacks write:builder; the body names both.
- The key lacks read, or is pinned to one workspace and so has no portfolio.
- The key lacks the tool’s scope (write:agency, or write:finance for statements; some also need write:sensitive), or is pinned to one workspace and so has no agency to run.
404
status
- A referenced record was not found in this workspace.
409
status
- The request is still running (honour Retry-After), or its outcome is unknown and requires reconciliation before another write.
422
status
- This Idempotency-Key was already used with a different tool or body.
429
status
- Request limit exceeded.
insufficient_scope
403 body
errorstring, requiredmessagestring, requiredkey_scopesarray of one of: ingest:write, read, write, write:sensitive, write:builder, write:ads, write:agency, write:finance, recordings:write, requiredrequiredarray of one of: ingest:write, read, write, write:sensitive, write:builder, write:ads, write:agency, write:finance, recordings:write, requiredfixstring, required
Tools
Grouped by the scope each one needs. The same tools over MCP are on the MCP page.
Tools: read
63
get_client_snapshot
Get client snapshot
Compact 30-day KPI snapshot for this client: leads, calls, deals, pipeline, top leads, cadences. Start here for open-ended questions.
POST /api/v1/tools/get_client_snapshot · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_leads
List leads
Leads (visitors) for this client, most recently seen first. Each lead has name (full) plus firstName and lastName, which are null when unknown (never guessed from the full name). Filter by free-text search, tag, minimum intent score, or customer status.
POST /api/v1/tools/list_leads · scope read
workspacestring, optionalsearchstring, optional. Match against name, email, or phone.tagstring, optional. Only leads carrying this tag.min_intent_scoreinteger, optional. Only leads at or above this intent score.is_customerboolean, optional. Filter to customers (true) or non-customers (false).limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_lead
Get lead detail
Full detail for one lead plus their recent journey events, notes, and calls.
POST /api/v1/tools/get_lead · scope read
workspacestring, optionallead_idstring, uuid, required. Lead id from list_leads.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_calls
List calls
Calls for this client, most recent first. Filter by lead, closer, outcome, type or a date window. Each call carries leadId, callType, repId and setterId so it can be joined to a lead or rep without a get_call per row.
POST /api/v1/tools/list_calls · scope read
workspacestring, optionalstatusone of: booked, showed, no_show, cancelled, completed, optional. Filter by call status.whenone of: past, upcoming, optional. "past": calls already due, newest first (use this to find calls needing an outcome). "upcoming": still to come, soonest first. Omit for both, newest first.lead_idstring, uuid, optional. Only this lead's calls. The `leadId` on each call; also the id from list_leads.talent_idstring, uuid, optional. Only calls assigned to this closer. From list_talent.outcomeone of: won, lost, follow_up, no_decision, pending, disqualified, no_pitch_dq, optionalcall_typeone of: discovery, closing, consult, follow_up, optionalsincestring, optional. Scheduled at or after this ISO 8601 date or timestamp.untilstring, optional. Scheduled on or before this ISO 8601 date or timestamp.limitinteger, optional. Max results, default 25, capped at 50.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_pipelines
List pipelines and stages
CRM pipelines with their ordered stages. Call this to get stage ids before creating or moving a deal.
POST /api/v1/tools/list_pipelines · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_deals
List deals
CRM deals for this client, most recently updated first.
POST /api/v1/tools/list_deals · scope read
workspacestring, optionalstatusone of: open, won, lost, optional. Filter by deal status.pipeline_idstring, uuid, optional. Restrict to one pipeline.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_tasks
List tasks
Tasks for this client, soonest due first, or newest first with sort "newest".
POST /api/v1/tools/list_tasks · scope read
workspacestring, optionalstatusone of: open, done, optional. Filter by task status.sortone of: due, newest, optional. "due" (default) or "newest" by creation time.lead_idstring, uuid, optional. Only tasks about this lead.assignee_member_idstring, uuid, optional. Only tasks assigned to this team member. The `member_id` on a list_talent row, or `assigneeMemberId` on a task.overdueboolean, optional. Only open tasks already past their due date.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_commissions_summary
Get commissions summary
Pending, approved, and paid commission totals (integer pence) for this client.
POST /api/v1/tools/get_commissions_summary · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
get_affiliate_summary
Get affiliate summary
Affiliate/JV partner totals for this client: active partners, verified postback conversions, and outstanding payout (integer pence).
POST /api/v1/tools/get_affiliate_summary · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
get_leaderboard
Get leaderboard
Rep leaderboard for this client: paid commission, total calls and close rate (won over calls with a recorded outcome), ranked. Includes every rep with a call or a paid commission.
POST /api/v1/tools/get_leaderboard · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
get_attribution_summary
Get attribution summary
Multi-touch revenue attribution by source/medium for this client.
POST /api/v1/tools/get_attribution_summary · scope read
workspacestring, optionalmodelone of: first_touch, last_touch, linear, u_shaped, time_decay, optional. Attribution model, default first_touch.daysinteger, optional. Lookback window in days, default 30.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_funnel_summary
Get funnel summary
Funnel for this client over a window: page views, leads captured, applied and qualified (only when the client has a form with qualification rules; `applicationForms` counts them), booked, showed, won, with stage-to-stage conversion, booked/showed/won by source, and the worst leak priced in money. Use it for "where am I losing people".
POST /api/v1/tools/get_funnel_summary · scope read
workspacestring, optionaldaysinteger, optional. Lookback window in days, default 30.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_metric_figures
Get metric figures
Named figures SIGNL has already worked out for this client, the same ones the dashboards show (collected revenue, show rate, close rate and the rest), each with its value as displayed, the period before it, the change and how it was reached. Call it with no `metrics` to list the keys and what each counts, then with up to 12 keys to read them. Quote these figures in an answer; do not state a number that none of them gives.
POST /api/v1/tools/get_metric_figures · scope read
workspacestring, optionalmetricsarray of string, optional. Metric keys from the catalogue. Leave out to list the catalogue.rangeone of: today, 7d, 30d, 90d, mtd, qtd, ytd, all, optional. today, 7d, 30d, 90d, mtd, qtd, ytd or all. Default 30d. Days follow the client time zone.compareboolean, optional. Also read the period before, for the change. Not for all time.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_vsl_summary
Get VSL summary
Every VSL video with views, completed views, average watch time and the 15-second stretch where the most viewers stop watching (needs 50 views). All-time; up to 20 videos.
POST /api/v1/tools/get_vsl_summary · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
get_tracking_summary
Get tracking summary
Visitor behaviour over a window (page views by hour and weekday in UTC, device, browser, country, median time on page, scroll depth, returning visitors) and, per tracking source (see list_sources), visitors, net revenue, revenue per visitor and share of revenue over the same window, by first or last touch.
POST /api/v1/tools/get_tracking_summary · scope read
workspacestring, optionaldaysinteger, optional. Lookback window in days, default 30, max 90.modelone of: first_touch, last_touch, optional. Which touch gets the revenue, default first_touch.
Responds 200 · 400 · 401 · 403 · 404 · 429
check_tracking_install
Check tracking install
Fetch one page of the client's site and check the SIGNL tag on it: present, this workspace's id, loaded from SIGNL, async, not doubled, held by a consent tool, plus events from that host in the last 24 hours and 14 days. Reads the HTML only (no JavaScript on the page is run), so a page built in the browser answers status unknown. Returns status (ok, degraded, broken, not_installed, unknown) and findings, each with an explanation and a fix. Ten checks a minute per workspace.
POST /api/v1/tools/check_tracking_install · scope read
workspacestring, optionalurlstring, required. The page to check, e.g. https://yoursite.com/apply. Public http(s) addresses only.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_email_stats
Get email stats
Email performance from the client's connected Kit account: sent, opened and clicked with open and click rates over Kit's last 90 days, subscriber growth, and per-broadcast stats for recent broadcasts. Says so when Kit is not connected.
POST /api/v1/tools/get_email_stats · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_ad_campaigns
List ad campaigns
Ad campaigns SIGNL has seen for this client, newest first: platform, status, objective and currency, and whether pause, resume and budget can act on it (`controllable`: Meta and Whop today). The ids are what pause_ad_campaign, resume_ad_campaign and update_ad_campaign_budget take.
POST /api/v1/tools/list_ad_campaigns · scope read
workspacestring, optionalplatformone of: meta, google, tiktok, youtube, linkedin, whop, other, optional. Only campaigns on this platform.limitinteger, optional. Max results, default 50, capped at 100.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_talent
List talent
Sales roster (closers, setters, managers) for this client. Use these ids to assign calls.
POST /api/v1/tools/list_talent · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_automations
List automations
Automations for this client with trigger type, active state, and run counts.
POST /api/v1/tools/list_automations · scope read
workspacestring, optionallimitinteger, optional. Max results, default 100, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_cadences
List cadences
Outbound follow-up cadences for this client. Use these ids with enroll_lead_in_cadence.
POST /api/v1/tools/list_cadences · scope read
workspacestring, optionallimitinteger, optional. Max results, default 100, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_tracked_links
List tracked links
Tracked links with clicks, conversions, and attributed revenue (integer pence), each with its five UTMs, its source key (see list_sources) and the content item it sits under.
POST /api/v1/tools/list_tracked_links · scope read
workspacestring, optionallimitinteger, optional. Max results, default 100, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_sources
List traffic sources
Every traffic source a tracked link can sit under: the built-in ones (YouTube, Instagram, Kit, Email…) and this client’s own, with each one’s key, default utm_source and utm_medium, whether it is hidden in the Source tab, and how many content items it has. Pass a key as create_tracked_link’s `source`.
POST /api/v1/tools/list_sources · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
get_content_performance
Get content performance
One row per content item in the Source tab (a video, a post, a broadcast or a campaign filed under a source such as YouTube, Instagram, Email or your own), with the numbers that tab shows: the item's links, their clicks, and the forms, calls booked and revenue (integer pence) of people whose first tracked link was one of them, plus their calls that showed (shows), calls won (wins) and ledger cash by currency in minor units (cash). All time by default; days counts one window, with clicks and revenue from the dated click ledger (ledgerCovers.note says when the window starts before it). A YouTube video is one item however many links it has. Pass a source key from list_sources to see one source.
POST /api/v1/tools/get_content_performance · scope read
workspacestring, optionalsourcestring, optional. Only items under this source key (see list_sources): youtube, instagram, tiktok, email, x, or one of your own.sortone of: newest, revenue, bookings, forms, clicks, name, optional. Order: revenue (default), bookings, forms, clicks, newest or name.daysinteger, optional. Count only the last N days (1 to 365). Leave out for all time.limitinteger, optional. Max results, default 50, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_forms
List forms
Forms for this client with view, start, submission counts and completion rate.
POST /api/v1/tools/list_forms · scope read
workspacestring, optionallimitinteger, optional. Max results, default 100, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_form_submissions
List form submissions
Recent form submissions with answers, most recent first.
POST /api/v1/tools/list_form_submissions · scope read
workspacestring, optionalform_idstring, uuid, optional. Restrict to one form.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_form
Get form
One form in full: fields with their stable ids, pages, endings, qualification rules and settings. Read this before update_form, and send the ids back, so rules keep matching.
POST /api/v1/tools/get_form · scope read
workspacestring, optionalform_idstring, uuid, required
Responds 200 · 400 · 401 · 403 · 404 · 429
list_booking_pages
List booking pages
Booking pages (calendars) for this client with status, duration and booking count.
POST /api/v1/tools/list_booking_pages · scope read
workspacestring, optionallimitinteger, optional. Max results, default 100, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_booking_page
Get booking page
One booking page with every setting that changes how it behaves: duration, buffer, notice, window, weekly hours, intake questions, location, hosts and endings.
POST /api/v1/tools/get_booking_page · scope read
workspacestring, optionalpage_idstring, uuid, required
Responds 200 · 400 · 401 · 403 · 404 · 429
list_availability_schedules
List availability schedules
Shared weekly-hours schedules a booking page can use instead of its own hours, with their time zones.
POST /api/v1/tools/list_availability_schedules · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
get_call
Get call detail
One call in full: lead, rep, status, outcome, objection, notes, recording summary and the post-call record.
POST /api/v1/tools/get_call · scope read
workspacestring, optionalcall_idstring, uuid, required. From list_calls.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_deal
Get deal detail
One deal in full, including notes and custom fields.
POST /api/v1/tools/get_deal · scope read
workspacestring, optionaldeal_idstring, uuid, required. From list_deals.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_call_transcript
Get call transcript
The recording transcript of one call, up to 20,000 characters per response. Check `hasMore` and send `nextOffset` back as `offset` to read the rest. Personal data: read it to answer a question about a call, not to copy it elsewhere. Empty until transcription has run (see `transcriptionStatus`).
POST /api/v1/tools/get_call_transcript · scope read
workspacestring, optionalcall_idstring, uuid, required. From list_calls.offsetinteger, optional. Character offset; `nextOffset` from the previous slice.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_ad_performance
Get ad performance
Ad campaigns over the last N days (default 30, at most 90): spend (integer pence, `null` when no spend row exists, which is unmeasured and not free), impressions, clicks, CTR and CPC, highest spend first. Same numbers as the Ads page.
POST /api/v1/tools/get_ad_performance · scope read
workspacestring, optionaldaysinteger, optional. Lookback window in days, default 30, max 90.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_offers
List offers
What this client sells: name, description, price (integer minor units in `currency`) and whether it is active. Offer ids link calls and deals to what was sold.
POST /api/v1/tools/list_offers · scope read
workspacestring, optionalactiveboolean, optional. Only active (true) or inactive (false) offers.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_contracts
List contracts
Agreements sent for e-signature, newest first: status, signed total (integer minor units), the lead it is for (`leadId`, null for someone kept out of the CRM), the linked deal (often null: a contract need not have one) and dates. `get_contract` has the text and each signer.
POST /api/v1/tools/list_contracts · scope read
workspacestring, optionallead_idstring, uuid, optional. Only this lead’s contracts (a lead id from list_leads).statusone of: draft, sent, viewed, signed, declined, expired, voided, optional. Only contracts in this status: draft, sent, viewed, signed, declined, expired or voided. A fully signed contract is "signed".limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_contract
Get contract
One contract with its text (first 20,000 characters), its sections, the template version it was drafted from, the fields the signer fills in (key, type, label, required) with the values they entered once signed, and each signer’s name, email, role and status. Signing links and drawn signatures are never returned.
POST /api/v1/tools/get_contract · scope read
workspacestring, optionalcontract_idstring, uuid, required. From list_contracts.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_contract_templates
List contract templates
This workspace’s active contract templates, newest edit first: id, name, current version, whether it is a copy of an agency template and when it last changed. `get_contract_template` has the sections.
POST /api/v1/tools/list_contract_templates · scope read
workspacestring, optionallimitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_contract_template
Get contract template
One contract template at its current version: its sections (key, heading, text, whether locked) and line items. Templates are written in the app.
POST /api/v1/tools/get_contract_template · scope read
workspacestring, optionalidstring, uuid, required. From list_contract_templates.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_webinars
List webinars
Webinars for this client, newest first (deleted ones excluded): title, slug, mode, status and timezone.
POST /api/v1/tools/list_webinars · scope read
workspacestring, optionalstatusstring, optional. Only webinars in this status.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_webinar_registrations
List webinar registrations
Who registered for one webinar, newest first: name, email, status, session time, how much they watched and whether they clicked the call to action.
POST /api/v1/tools/list_webinar_registrations · scope read
workspacestring, optionalwebinar_idstring, uuid, required. From list_webinars.statusstring, optional. Only registrations in this status.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_custom_fields
List custom fields
The custom fields this client added, with key, label, type, choices and what they attach to (leads, calls or deals).
POST /api/v1/tools/list_custom_fields · scope read
workspacestring, optionaltargetstring, optional. Only fields on this object, e.g. "lead" or "deal".
Responds 200 · 400 · 401 · 403 · 404 · 429
list_dni_numbers
List tracking numbers
The client’s call-tracking phone numbers: number, name, where it forwards, country and status.
POST /api/v1/tools/list_dni_numbers · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_data_tables
List data tables
The client’s own tables (the Data page): name, description, field definitions and whether the rows come from a form, booking page or report or are entered by hand. Use the ids with list_data_records.
POST /api/v1/tools/list_data_tables · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_data_records
List data records
Rows of one data table, newest first. `values` is keyed by the table’s field ids from list_data_tables.
POST /api/v1/tools/list_data_records · scope read
workspacestring, optionaltable_idstring, uuid, required. From list_data_tables.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_dashboards
List dashboards
The client’s custom dashboards: name, description, which is the default, whether the client portal shows it, and how many widgets it has.
POST /api/v1/tools/list_dashboards · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
list_import_runs
List import runs
Imports and syncs, newest first: mode, status, file name, rows total, processed and failed, per-kind counts, any error, and whether it was undone.
POST /api/v1/tools/list_import_runs · scope read
workspacestring, optionalstatusstring, optional. Only runs in this status, e.g. "failed" or "completed".limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_training_assignments
List training assignments
Role-play practice assigned to reps, newest first: who, against which persona, status, due date and note.
POST /api/v1/tools/list_training_assignments · scope read
workspacestring, optionalstatusstring, optional. Only assignments in this status.talent_idstring, uuid, optional. Only this rep, from list_talent.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_task
Get task detail
One task by id.
POST /api/v1/tools/get_task · scope read
workspacestring, optionaltask_idstring, uuid, required. From list_tasks.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_payments
List payments
Payments received from connected providers (Stripe, Whop and others), newest first. Amounts are integer minor units in the currency returned beside them; refunds point at the payment they reverse.
POST /api/v1/tools/list_payments · scope read
workspacestring, optionalsincestring, optional. ISO 8601 timestamp; only payments on or after it.kindstring, optional. Filter by kind, e.g. "charge" or "refund".limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_payment_plans
List payment plans
Payment plans with every instalment, what is paid, and what is due. Use for "who is behind on their plan".
POST /api/v1/tools/list_payment_plans · scope read
workspacestring, optionalstatusone of: active, completed, defaulted, optionallimitinteger, optional. Max results, default 25, capped at 100.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_eod_reports
List EOD reports
End-of-day reports from the sales team, newest first: calls taken, shows, offers, closes, cash collected and the template answers.
POST /api/v1/tools/list_eod_reports · scope read
workspacestring, optionaltalent_idstring, uuid, optional. From list_talent.sincestring, optional. ISO 8601 date; only reports submitted on or after it.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_commission_entries
List commission entries
The individual commission rows behind get_commissions_summary, with the call or deal each came from.
POST /api/v1/tools/list_commission_entries · scope read
workspacestring, optionalstatusone of: pending, approved, paid, disputed, optionaltalent_idstring, uuid, optional. From list_talent.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_recordings
List recordings
Screen and video recordings in this workspace. Share links are not returned.
POST /api/v1/tools/list_recordings · scope read
workspacestring, optionallimitinteger, optional. Max results, default 25, capped at 100.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_sops
List SOPs
Standard operating procedures, with their section and a short excerpt of each. Use get_sop for the full text.
POST /api/v1/tools/list_sops · scope read
workspacestring, optionallimitinteger, optional. Max results, default 25, capped at 100.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_sop
Get SOP
One SOP with its full body.
POST /api/v1/tools/get_sop · scope read
workspacestring, optionalsop_idstring, uuid, required. From list_sops.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_cadence_enrollments
List cadence enrolments
Leads enrolled in cadences: which step they are on, when the next action runs, and whether they replied or failed.
POST /api/v1/tools/list_cadence_enrollments · scope read
workspacestring, optionalcadence_idstring, uuid, optional. From list_cadences.statusone of: active, paused, completed, replied, failed, optionallimitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_messages
List a lead's messages
One lead's texts, WhatsApp messages and emails, newest first: what SIGNL sent (a subject or the first 80 characters, with delivery status) and what the lead replied by text or WhatsApp. Inbound email is not recorded yet.
POST /api/v1/tools/list_messages · scope read
workspacestring, optionallead_idstring, uuid, required. From list_leads.channelone of: sms, whatsapp, email, optionaldirectionone of: in, out, optional. in = the lead wrote, out = SIGNL sent.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
get_usage
Get credit usage
What this workspace has spent in credits, and what the caller has left: credits used in a window (default this month, UTC), split by vendor (AI, texts and calls, transcription, email, Meeting Bots) and by feature, optionally by day, plus the caller's own balance (credits belong to each person). Use it for "what have I spent on texts this month?". The balance is null when no person is calling.
POST /api/v1/tools/get_usage · scope read
workspacestring, optionalfromstring, optional. Start of the window, ISO date. Default: the first of this month (UTC).tostring, optional. End of the window, ISO date, exclusive. Default: now. At most 366 days from `from`.vendorone of: anthropic, twilio, deepgram, resend, recall, optional. anthropic = AI, twilio = texts and calls, deepgram = transcription, resend = email, recall = Meeting Bots.by_dayboolean, optional. Add a per-day breakdown.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_lead_history
List a lead's owner history
The recorded changes to one lead's owner, newest first: who it was, who it became, who changed it (a member, the Agent with the member who approved it, an API key) and when. History starts on 5 Oct 2026; earlier changes are not reconstructed.
POST /api/v1/tools/list_lead_history · scope read
workspacestring, optionallead_idstring, uuid, required. From list_leads.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
list_deal_history
List a deal's stage history
The recorded stage moves of one deal, newest first: from, to, who moved it (a member, the Agent with the member who approved it, an automation, an API key) and when, plus the time spent in each stage. History starts on 5 Oct 2026; earlier moves are not reconstructed.
POST /api/v1/tools/list_deal_history · scope read
workspacestring, optionaldeal_idstring, uuid, required. From list_deals.limitinteger, optional. Max results, default 25, capped at 100.offsetinteger, optional. Skip this many results. Pass `nextOffset` from the previous page; the response says `hasMore`.
Responds 200 · 400 · 401 · 403 · 404 · 429
whoami
Who am I
Which workspace this connection is working in and who it is acting as: the workspace name and slug, whether it acts as a team member or an API key or connector (and its name), and the time zone dates are read in. Call it first when you start a task with no context. It returns no ids, keys or permissions.
POST /api/v1/tools/whoami · scope read
workspacestring, optional
Responds 200 · 400 · 401 · 403 · 404 · 429
Tools: write
13
create_lead
Create lead
Create a lead for this client. Deduplicates on email then phone — if a matching lead exists it is returned instead of creating a duplicate.
POST /api/v1/tools/create_lead · scope write
workspacestring, optionalnamestring, optional. Full name. Kept as sent; never split into first and last.first_namestring, optional. Given name, when known. Stored as an explicit value.last_namestring, optional. Family name, when known. Stored as an explicit value.emailstring, email, optionalphonestring, optionaltagsarray of string, optionalintent_scoreinteger, optionalsourcestring, optional. First-touch source, default "mcp".mediumstring, optional. First-touch medium, default "api".campaignstring, optional
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_lead
Update lead
Update a lead. Tag changes are additive/subtractive via add_tags and remove_tags — existing tags are never blindly overwritten.
POST /api/v1/tools/update_lead · scope write
workspacestring, optionallead_idstring, uuid, requirednamestring, optional. Full name. Changing it alone clears first_name and last_name when they no longer match it.first_namestring or null, optional. Given name. Omit to keep; null or empty clears. The full name follows first and last unless name is also sent.last_namestring or null, optional. Family name. Omit to keep; null or empty clears.emailstring, email, optionalphonestring, optionalintent_scoreinteger, optionalis_customerboolean, optionaladd_tagsarray of string, optionalremove_tagsarray of string, optional
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
add_lead_note
Add lead note
Append a timestamped note to a lead. Attributed to the API key that wrote it.
POST /api/v1/tools/add_lead_note · scope write
workspacestring, optionallead_idstring, uuid, requiredbodystring, required
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_call
Create call
Log a booked call for this client.
POST /api/v1/tools/create_call · scope write
workspacestring, optionallead_namestring, requiredscheduled_atstring, required. ISO 8601 timestamp.lead_emailstring, email, optionallead_phonestring, optionalcall_typeone of: discovery, closing, consult, follow_up, optionaltalent_idstring, uuid, optional. Rep to assign, from list_talent. Must be active.setter_talent_idstring, uuid, optional. The active setter who booked it, from list_talent. Setter commission reads this.offer_idstring, uuid, optional. What the call is selling, from list_offers.lead_idstring, uuid, optional. Link to an existing lead.duration_minutesinteger, optionalnotesstring, optional
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_call
Update call
Update a call — typically logging the outcome after it happened, or pushing its transcript or recording link from any call recorder. Money is integer pence. Does not create commission entries; the commissions engine derives those from rules.
POST /api/v1/tools/update_call · scope write
workspacestring, optionalcall_idstring, uuid, requiredstatusone of: booked, showed, no_show, cancelled, completed, optionaloutcomeone of: won, lost, follow_up, no_decision, pending, disqualified, no_pitch_dq, optionaldeal_value_penceinteger, optional. Integer pence, never a decimal amount.objectionstring, optionalnotesstring, optionaltalent_idstring, uuid, optionalsetter_talent_idstring, uuid, optional. The active setter who booked it, from list_talent.offer_idstring, uuid, optional. What was sold, from list_offers.cancel_reasonstring, optional. Why it was cancelled; use with status "cancelled".recording_transcriptstring, optional. The call transcript as plain text, from any recorder. Feeds call scoring. Refused if the call already has one, unless replace_transcript is true.replace_transcriptboolean, optional. Set true to replace a transcript the call already has.recording_urlstring, uri, optional. The recording link, stored on the call. A Fathom, Fireflies or Zoom link also imports the transcript from that tool when it is connected.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_deal
Create deal
Create a CRM deal. Call list_pipelines first to get a valid stage_id.
POST /api/v1/tools/create_deal · scope write
workspacestring, optionaltitlestring, requiredcontact_namestring, requiredstage_idstring, uuid, required. Stage id from list_pipelines.contact_emailstring, email, optionalvalue_penceinteger, optional. Integer pence.probabilityinteger, optionalexpected_close_datestring, optional. ISO date, e.g. 2026-09-01.lead_idstring, uuid, optionaloffer_idstring, uuid, optional. What the deal is for. Offer id from list_offers.notesstring, optional
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_deal
Update deal
Update a deal — move stage, change value, or mark won/lost (with a loss_reason when lost). Moving stage keeps the pipeline consistent automatically. A stage can require fields before a deal enters it (value, close date, offer, custom fields): a move that leaves any empty is refused and names them, so set them in the same call or first.
POST /api/v1/tools/update_deal · scope write
workspacestring, optionaldeal_idstring, uuid, requiredstage_idstring, uuid, optionalstatusone of: open, won, lost, optionaltitlestring, optionalvalue_penceinteger, optional. Integer pence.probabilityinteger, optionalexpected_close_datestring, optionaloffer_idstring, uuid or null, optional. Offer id from list_offers, or null to clear it.notesstring, optionalloss_reasonone of: price, timing, no_budget, competitor, not_a_fit, no_response, other or null, optional. Why a lost deal was lost: price, timing, no_budget, competitor, not_a_fit, no_response or other. Needs the deal to be lost (set status to lost in the same call). null clears it. Reopening or winning a deal clears it automatically.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_task
Create task
Create a task, optionally linked to a lead.
POST /api/v1/tools/create_task · scope write
workspacestring, optionaltitlestring, requireddescriptionstring, optionaldue_atstring, optional. ISO 8601 timestamp, or a date. Stored as that instant in UTC; include an offset if the time matters.lead_idstring, uuid, optionalassignee_member_idstring, uuid, optional. Who does it: the `member_id` on a list_talent row. Must be a team member of this workspace.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_task
Update task
Update or complete a task. Setting status to done stamps the completion time.
POST /api/v1/tools/update_task · scope write
workspacestring, optionaltask_idstring, uuid, requiredstatusone of: open, done, optionaltitlestring, optionaldescriptionstring, optionaldue_atstring, optionalassignee_member_idstring, uuid or null, optional. A team member (list_talent `member_id`), or null to unassign.lead_idstring, uuid or null, optional. Link the task to a lead, or null to unlink.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_tracked_link
Create tracked link
Create a tracked link, optionally under a traffic source and content item (list_sources). Returns the code, the short URL (`short_url`) and the native URL (`native_url`: the destination with `sg=<code>` and the UTMs). With a source, a UTM you leave out takes its default: source and medium from the source, campaign from the content item’s name, content from the link’s name.
POST /api/v1/tools/create_tracked_link · scope write
workspacestring, optionalnamestring, requireddestination_urlstring, uri, required. Absolute http(s) URL.sourcestring, optional. A source key from list_sources.content_item_idstring, uuid, optional. An existing content item. Its own source is used.content_item_namestring, optional. A content item under `source`: the live one with this name, else a new one.codestring, optional. A custom code: 3 to 64 letters, numbers, dashes or underscores, unique across SIGNL. Omit for a generated one.utm_sourcestring, optionalutm_mediumstring, optionalutm_campaignstring, optionalutm_contentstring, optionalutm_termstring, optional
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_source
Create traffic source
Add a traffic source of this client’s own (up to 40). Its key is its name as a slug; a built-in source’s name is refused. Links and content items go under it with create_tracked_link.
POST /api/v1/tools/create_source · scope write
workspacestring, optionalnamestring, requiredutm_sourcestring, optional. Default utm_source for its links. Defaults to the key.utm_mediumstring, optional. Default utm_medium, e.g. bio, story, email, dm.iconstring, optional. brand:<id> for a logo or lucide:<Name> for an icon. Defaults to lucide:Link.default_destination_urlstring, uri, optional. Where its new links point by default.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_sop
Create SOP
Write a new standard operating procedure. role_scope labels who it is for, e.g. ["closer"]; it does not restrict who can read it.
POST /api/v1/tools/create_sop · scope write
workspacestring, optionaltitlestring, requiredbodystring, optional. Markdown.role_scopearray of string, optionalsectionstring or null, optional. Group label such as "Sales"; blank or null leaves it unsectioned.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_sop
Update SOP
Change an SOP. Only the fields you send change; body replaces the whole text.
POST /api/v1/tools/update_sop · scope write
workspacestring, optionalsop_idstring, uuid, required. From list_sops.titlestring, optionalbodystring, optionalrole_scopearray of string, optionalsectionstring or null, optional. Group label such as "Sales"; blank or null removes it from its section.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
Tools: write:sensitive
2
enroll_lead_in_cadence
Enrol a lead in a cadence
Start an outbound follow-up cadence for a lead. This sends real messages to a real person — requires the write:sensitive scope. Refuses a lead who has bounced, complained or unsubscribed when the cadence sends email.
POST /api/v1/tools/enroll_lead_in_cadence · scope write:sensitive
workspacestring, optionallead_idstring, uuid, required. Lead id from list_leads.cadence_idstring, uuid, required. Cadence id from list_cadences.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
set_automation_status
Activate or pause an automation
Turn an automation on or off. An active automation can contact leads, so this requires the write:sensitive scope. Switching on is refused when the published version cannot do anything (the same check as the Active toggle in SIGNL), and steps that will skip are returned as warnings. Editing the automation node graph is intentionally not exposed here.
POST /api/v1/tools/set_automation_status · scope write:sensitive
workspacestring, optionalautomation_idstring, uuid, requiredis_activeboolean, required
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
Tools: write:ads
3
pause_ad_campaign
Pause ad campaign
Pause a running ad campaign on the platform it is connected to. Spends real money if left running, so requires the write:ads scope. Meta and Whop today — a Google or TikTok campaign, or one only ever seen as a UTM string, is refused with the reason (roadmap E2).
POST /api/v1/tools/pause_ad_campaign · scope write:ads
workspacestring, optionalcampaign_idstring, uuid, required. ad_campaigns id from list_ad_campaigns, not the platform’s own campaign id.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
resume_ad_campaign
Resume ad campaign
Resume a paused ad campaign on the platform it is connected to. This starts real spend again, so requires the write:ads scope. Meta and Whop today (roadmap E2).
POST /api/v1/tools/resume_ad_campaign · scope write:ads
workspacestring, optionalcampaign_idstring, uuid, required. ad_campaigns id from list_ad_campaigns.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_ad_campaign_budget
Change ad campaign daily budget
Change a running ad campaign’s daily budget on the platform it is connected to. Changes real spend, so requires the write:ads scope. Meta and Whop today; refused when the campaign’s currency is unset or is not what SIGNL displays, the same guard ad-spend import uses. Capped at 10000 USD/day — a higher figure is refused rather than sent, to catch a fat-fingered amount (e.g. typing pounds where pence, or dollars where cents, were meant) before it reaches the platform.
POST /api/v1/tools/update_ad_campaign_budget · scope write:ads
workspacestring, optionalcampaign_idstring, uuid, required. ad_campaigns id from list_ad_campaigns.daily_budget_penceinteger, required. Integer pence, SIGNL’s convention everywhere — converted to the account’s own currency before it reaches the platform. Hard-capped at 1000000 (10000 USD/day); a larger value is refused, not clamped.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
Tools: write:builder
5
create_form
Create form (draft)
Create a form as a DRAFT: fields, pages, endings and qualification rules. Nothing goes live; a person publishes it in SIGNL. Give an id to any field or option a rule refers to. Branching logic from another platform is never imported automatically; if you are migrating a form, list the rules you could not express and tell the operator.
POST /api/v1/tools/create_form · scope write:builder
workspacestring, optionalnamestring, requireddescriptionstring, optional. Shown in link previews, under the name on a classic form, and as the start screen of a one-question-at-a-time form (a blank line splits its heading from its text).modeone of: classic, paged, typeform, optional. classic: every question on one page. paged: one page per screen, with Next and Back (use pages and each field's pageId). typeform: one question at a time.fieldsarray of object, optional. The questions, in order. On update this REPLACES the list — read get_form first and send every field you want to keep, with its id.pagesarray of object, optionalendingsarray of object, optional. Screens a lead lands on: { id, kind: "thank_you" | "redirect" | "calendar", title?, body?, redirect_url?, booking_page_id? }. Defaults to one thank-you ending.qualification_rulesarray of object, optional. { id, match: "all" | "any", conditions: [{ field_id, operator, value }], outcome: "qualified" | "disqualified", ending_id }. Operators: equals, not_equals, contains, not_contains, greater_than, less_than, is_empty, is_not_empty.default_ending_idstring, optionalredirect_urlstring, uri, optionalnotification_emailstring, email, optionalthemeone of: dark, light, optional
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_form
Update draft form
Edit a form. A draft is edited directly. A published form keeps its live version: the edit goes to its working copy and reaches visitors only when a person presses Publish changes in SIGNL. Refuses an archived form. `fields` replaces the whole list, so call get_form first and send every field you want to keep, with its id.
POST /api/v1/tools/update_form · scope write:builder
workspacestring, optionalform_idstring, uuid, requirednamestring, optionaldescriptionstring, optional. Shown in link previews, under the name on a classic form, and as the start screen of a one-question-at-a-time form (a blank line splits its heading from its text).modeone of: classic, paged, typeform, optional. classic: every question on one page. paged: one page per screen, with Next and Back (use pages and each field's pageId). typeform: one question at a time.fieldsarray of object, optional. The questions, in order. On update this REPLACES the list — read get_form first and send every field you want to keep, with its id.pagesarray of object, optionalendingsarray of object, optional. Screens a lead lands on: { id, kind: "thank_you" | "redirect" | "calendar", title?, body?, redirect_url?, booking_page_id? }. Defaults to one thank-you ending.qualification_rulesarray of object, optional. { id, match: "all" | "any", conditions: [{ field_id, operator, value }], outcome: "qualified" | "disqualified", ending_id }. Operators: equals, not_equals, contains, not_contains, greater_than, less_than, is_empty, is_not_empty.default_ending_idstring, optionalredirect_urlstring, uri, optionalnotification_emailstring, email, optionalthemeone of: dark, light, optionalpaginatestring, optional. "one_per_page" re-pages the form so each screen is its own page: one question each, a contact block or question group kept together, a statement on its own. It replaces `pages` and every field's pageId.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
import_form
Import form from Typeform (draft)
Import a Typeform from its public link as a DRAFT: questions, choices, endings and jumps. Returns `unmapped`, the list of what could not come across (score or variable logic, dropped screens). Always tell the operator what is in `unmapped` before they publish; never imply the logic came across when it did not.
POST /api/v1/tools/import_form · scope write:builder
workspacestring, optionalurlstring, required. The public Typeform link, e.g. https://yourname.typeform.com/to/AbC123.namestring, optional. Defaults to the Typeform title.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
create_booking_page
Create booking page (draft)
Create a booking page (calendar) as a DRAFT: duration, buffer, notice, booking window, weekly hours and time zone (or a shared schedule), hosts (one, or a round-robin pool from list_talent), intake questions, location and look. It takes no bookings until a person activates it in SIGNL.
POST /api/v1/tools/create_booking_page · scope write:builder
workspacestring, optionalnamestring, requiredduration_minutesinteger, requireddescriptionstring, optionalbuffer_minutesinteger, optional. Gap kept free after each call. Default 10.min_notice_minutesinteger, optional. How soon ahead a lead can book.booking_window_daysinteger, optional. How far ahead a lead can book. Default 90.weekly_hoursobject, optional. Bookable hours per day, e.g. { "mon": [{ "start": "09:00", "end": "17:00" }] }. Replaces the whole week: a day left out is closed.time_zonestring, optional. IANA zone the weekly hours are in, e.g. Europe/London. Gives the page its own zone, which stays put when the workspace timezone changes.follow_account_timezoneboolean, optional. true: the page follows the workspace timezone and moves when it changes (not with time_zone). false: keep the zone it has as its own. A new page follows the workspace by default.availability_schedule_idstring, uuid or null, optional. Use a shared schedule (list_availability_schedules) for the hours instead of weekly_hours. null clears it.send_confirmation_emailboolean, optionalmax_attendeesinteger, optional. Seats per slot: how many people can book the same time. 1 (the default) is one-to-one; more makes a group event and the page shows "N seats left".first_slot_onlyboolean, optional. true: the page offers only its earliest open time, and the confirm step refuses any other. false: the whole calendar.assignment_modeone of: single, round_robin, optional. single: one host. round_robin: rotate across talent_pool.host_talent_idstring, uuid or null, optional. The host for single mode, from list_talent.talent_poolarray of string, uuid, optional. Hosts to rotate across in round_robin mode, from list_talent.questionsarray of object, optional. Intake questions. Defaults to name, email and phone. On update this REPLACES the list.name_formatone of: full, split, optional. "full": one name box. "split": first name and last name boxes, both required. Switches which of the name questions shows and keeps the wording of each; applies to questions when sent too.bullet_pointsarray of string, optional. What the call covers, shown beside the calendar.consent_textstring, optionallocationobject, optionalthemeone of: dark, light, optionalaccent_colorstring, optional. Hex, e.g. #2334d1.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
update_booking_page
Update draft booking page
Edit a DRAFT booking page. Refuses an active or inactive page. `questions` replaces the whole list.
POST /api/v1/tools/update_booking_page · scope write:builder
workspacestring, optionalpage_idstring, uuid, requirednamestring, optionalduration_minutesinteger, optionaldescriptionstring, optionalbuffer_minutesinteger, optional. Gap kept free after each call. Default 10.min_notice_minutesinteger, optional. How soon ahead a lead can book.booking_window_daysinteger, optional. How far ahead a lead can book. Default 90.weekly_hoursobject, optional. Bookable hours per day, e.g. { "mon": [{ "start": "09:00", "end": "17:00" }] }. Replaces the whole week: a day left out is closed.time_zonestring, optional. IANA zone the weekly hours are in, e.g. Europe/London. Gives the page its own zone, which stays put when the workspace timezone changes.follow_account_timezoneboolean, optional. true: the page follows the workspace timezone and moves when it changes (not with time_zone). false: keep the zone it has as its own. A new page follows the workspace by default.availability_schedule_idstring, uuid or null, optional. Use a shared schedule (list_availability_schedules) for the hours instead of weekly_hours. null clears it.send_confirmation_emailboolean, optionalmax_attendeesinteger, optional. Seats per slot: how many people can book the same time. 1 (the default) is one-to-one; more makes a group event and the page shows "N seats left".first_slot_onlyboolean, optional. true: the page offers only its earliest open time, and the confirm step refuses any other. false: the whole calendar.assignment_modeone of: single, round_robin, optional. single: one host. round_robin: rotate across talent_pool.host_talent_idstring, uuid or null, optional. The host for single mode, from list_talent.talent_poolarray of string, uuid, optional. Hosts to rotate across in round_robin mode, from list_talent.questionsarray of object, optional. Intake questions. Defaults to name, email and phone. On update this REPLACES the list.name_formatone of: full, split, optional. "full": one name box. "split": first name and last name boxes, both required. Switches which of the name questions shows and keeps the wording of each; applies to questions when sent too.bullet_pointsarray of string, optional. What the call covers, shown beside the calendar.consent_textstring, optionallocationobject, optionalthemeone of: dark, light, optionalaccent_colorstring, optional. Hex, e.g. #2334d1.
Responds 200 · 201 · 400 · 401 · 403 · 404 · 409 · 422 · 429
Agency tools: read
10
list_clients
List clients
Every client workspace in the organisation: id, slug, name, status, type and the name of its current package (null when it has none). Use the slug as the `workspace` argument of client tools.
POST /api/v1/tools/list_clients · scope read · organisation-wide key only
statusone of: active, inactive, prospect, churned, optional. Only clients with this status.
Responds 200 · 400 · 401 · 403 · 429
get_portfolio_overview
Portfolio overview
The whole agency at a glance, over the last 30 days: totals across active clients, clients by status, average measured close and show rates, clients below their ROAS target, top performers, daily revenue trend and the team leaderboard. The same figures the agency dashboard shows. Package retainers are per client, each in its own currency — never totalled across clients. Start portfolio questions here.
POST /api/v1/tools/get_portfolio_overview · scope read · organisation-wide key only
No body fields.
Responds 200 · 400 · 401 · 403 · 429
compare_clients
Compare clients
Side-by-side performance for several clients over the last 30 days, sorted. Omit `workspaces` to compare every active client. Rates are null when no calls were measured. Each client carries its current package (name, currency, monthly value) as /clients shows it.
POST /api/v1/tools/compare_clients · scope read · organisation-wide key only
workspacesarray of string, optional. Client slugs to compare. Omit for every active client.sort_byone of: collected_revenue, contracted_value, roas, close_rate, show_rate, optional. Default collected_revenue, highest first.
Responds 200 · 400 · 401 · 403 · 429
get_client_health
Client health
One client's performance over the last 30 days with plain flags for what deserves a look (below ROAS target, no calls, cash collected far below contracted), and its current package in its own currency. For detail inside the client, follow up with its client tools.
POST /api/v1/tools/get_client_health · scope read · organisation-wide key only
workspacestring, required. The client slug (from list_clients).
Responds 200 · 400 · 401 · 403 · 429
list_packages
List packages
The packages this agency sells its clients: name, kind (core or add-on), status, terms in their own currency (retainer, setup fee and instalments, revenue share) and how many clients are on each today.
POST /api/v1/tools/list_packages · scope read · organisation-wide key only
statusone of: draft, active, archived, optional. Only packages with this status.
Responds 200 · 400 · 401 · 403 · 429
list_statements
List agency statements
What each client owes the agency, month by month, newest first: client, period, status, total and paid (integer minor units in the statement’s currency) and the engine’s warnings. Read only: issuing, voiding and recording payment stay in SIGNL.
POST /api/v1/tools/list_statements · scope read · organisation-wide key only
workspacestring, optional. Only this client (slug).statusstring, optional. Only statements in this status, e.g. "draft", "issued" or "paid".limitinteger, optional. Max results, default 50, capped at 100.
Responds 200 · 400 · 401 · 403 · 429
list_event_templates
List event templates
Managed booking-page templates defined once and pushed to clients: name, duration, how many fields are locked and how many client pages are linked. Owners and admins only.
POST /api/v1/tools/list_event_templates · scope read · organisation-wide key only
No body fields.
Responds 200 · 400 · 401 · 403 · 429
list_agency_skills
List agency skills
Agent skills the agency wrote once and pushed to clients: title, version, the tools each names, and for every client carrying a still-linked copy whether it is locked and whether it has the latest version. Owners and admins only.
POST /api/v1/tools/list_agency_skills · scope read · organisation-wide key only
No body fields.
Responds 200 · 400 · 401 · 403 · 429
list_org_members
List team members
Everyone with a SIGNL login in the organisation: name, email, role, the one client they are pinned to (if any) and when they were last active.
POST /api/v1/tools/list_org_members · scope read · organisation-wide key only
No body fields.
Responds 200 · 400 · 401 · 403 · 429
list_agency_talent
List talent across clients
Setters, closers and other talent across every client, with the client each works in and their paid commission, total calls and close rate from the agency leaderboard. Filter by workspace or role.
POST /api/v1/tools/list_agency_talent · scope read · organisation-wide key only
workspacestring, optional. Only talent in this client (slug).rolestring, optional. Only this role, e.g. closer or setter.include_inactiveboolean, optional. Include deactivated talent. Default false.
Responds 200 · 400 · 401 · 403 · 429
Agency tools: write:agency
19
create_client
Create a client
Create a new client workspace in the organisation, with the starter pipeline and report templates for its type. Counts against the plan’s client limit, and is refused at the limit exactly as Add Client is. Commercial terms are not set here: assign a package in SIGNL. Returns the new client’s id and slug, the workspace to use in every other tool.
POST /api/v1/tools/create_client · scope write:agency · organisation-wide key only
namestring, required. The client’s name. The URL slug is derived from it.typeone of: coaching, agency, saas, ecom, info, optional. coaching (default), agency, saas, ecom or info. Picks the starter pipeline.primary_contactstring, optional. Who you deal with at the client.primary_emailstring, optional. Their email address.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
update_client
Edit a client
Change a client’s name, contact, type, status or target ROAS. Send only the fields to change. Retainer and rev share belong to the client’s package and cannot be set here.
POST /api/v1/tools/update_client · scope write:agency · organisation-wide key only
workspacestring, required. The client to edit: slug, id or exact name (list_clients).namestring, optionalprimary_contactstring, optionalprimary_emailstring, optional. An empty string clears it.typeone of: coaching, agency, saas, ecom, info, optionalstatusone of: active, inactive, prospect, churned, optionaltarget_roasnumber, optional
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
archive_client
Archive a client
Archive a client: it leaves every agency list, aggregate and Login As, and its workspace becomes read-only. Reversible with restore_client. Its package assignment is left alone, so restoring brings it back on the terms it left with. Archiving again is a no-op.
POST /api/v1/tools/archive_client · scope write:agency · organisation-wide key only
workspacestring, required. The client to archive: slug, id or exact name.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
restore_client
Restore an archived client
Bring an archived client back. Counts against the plan’s client limit again, and is refused at the limit. Takes the client’s id or slug as shown when it was archived.
POST /api/v1/tools/restore_client · scope write:agency · organisation-wide key only
clientstring, required. The archived client’s slug or id.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
create_package
Create a package
Add a package to the catalogue: a core offer (or an add-on) with its setup fee, retainer and/or rev share. Created as a draft unless `status` says otherwise; only an active package can be assigned to a client. Money is integer pence of the stated currency.
POST /api/v1/tools/create_package · scope write:agency · organisation-wide key only
namestring, requireddescriptionstring or null, optionalkindone of: core, add_on, required. core is what a client is on; add_on rides under a core package.group_keystring or null, optional. Groups alternative packages together in the catalogue.sort_orderinteger, optionalstatusone of: draft, active, archived, optional. Default draft. Only an active package can be assigned.deliverablesarray of object, optionalinternal_notesstring or null, optionaltermsobject, required. Commercial terms. At least one of a setup fee, a retainer or a rev share is required.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
update_package
Edit a package
Replace a package’s details and terms (send the whole package, as the edit form does; list_packages shows the current one). Clients already assigned keep the terms they were assigned on.
POST /api/v1/tools/update_package · scope write:agency · organisation-wide key only
package_idstring, required. The package id (list_packages).namestring, requireddescriptionstring or null, optionalkindone of: core, add_on, required. core is what a client is on; add_on rides under a core package.group_keystring or null, optional. Groups alternative packages together in the catalogue.sort_orderinteger, optionalstatusone of: draft, active, archived, optional. Default draft. Only an active package can be assigned.deliverablesarray of object, optionalinternal_notesstring or null, optionaltermsobject, required. Commercial terms. At least one of a setup fee, a retainer or a rev share is required.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
set_package_status
Activate, draft or archive a package
Move a package between draft, active and archived. Archiving hides it from new assignments; existing assignments are untouched.
POST /api/v1/tools/set_package_status · scope write:agency · organisation-wide key only
package_idstring, requiredstatusone of: draft, active, archived, required
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
duplicate_package
Duplicate a package
Copy a package as a new draft named “… (copy)”.
POST /api/v1/tools/duplicate_package · scope write:agency · organisation-wide key only
package_idstring, required
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
delete_package
Delete a draft package
Permanently delete a package. Only a draft that has never been assigned can be deleted; anything else is refused (archive it instead).
POST /api/v1/tools/delete_package · scope write:agency · organisation-wide key only
package_idstring, required
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
assign_package
Put a client on a package
Assign an active core package (and optional add-ons) to a client from a date, with the terms that apply to that client. This sets what the client will be billed from `effective_from`. Refused if the client already has a current package (use switch_package) or the date falls inside a period with an issued statement.
POST /api/v1/tools/assign_package · scope write:agency · organisation-wide key only
workspacestring, required. The client: slug, id or exact name.package_idstring, requiredeffective_fromstring, required. YYYY-MM-DD.termsobject, required. Commercial terms. At least one of a setup fee, a retainer or a rev share is required.add_onsarray of object, optionalnotesstring or null, optional
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
switch_package
Switch a client to another package
Move a client from its current core package to another from a date: the current package (and its add-ons) ends the day before and the new one starts, in one step that is rolled back if it cannot complete. Switching to the same package is a re-price and does not charge the setup fee again. Refused inside a period with an issued statement.
POST /api/v1/tools/switch_package · scope write:agency · organisation-wide key only
workspacestring, required. The client: slug, id or exact name.package_idstring, requiredeffective_fromstring, required. YYYY-MM-DD.termsobject, required. Commercial terms. At least one of a setup fee, a retainer or a rev share is required.add_onsarray of object, optionalnotesstring or null, optional
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
end_package_assignment
End a client’s package
End an assignment (and its add-ons) on a date. Cannot end before it started, or before the period covered by an issued statement.
POST /api/v1/tools/end_package_assignment · scope write:agency · organisation-wide key only
assignment_idstring, requiredeffective_tostring, required. YYYY-MM-DD.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
create_event_template
Create an event template
Define booking-page settings once for the agency: duration, buffer, questions, location, branding and rules. `locked_fields` names what clients cannot change on pages made from it. Nothing reaches a client until push_event_template.
POST /api/v1/tools/create_event_template · scope write:agency · organisation-wide key only
namestring, requiredduration_minutesinteger, requireddescriptionstring or null, optionalbuffer_minutesinteger, optionalquestionsarray of object, optionalquestion_flowone of: inline, grouped, single, optionalbullet_pointsarray of string, optionalconsent_textstring or null, optionallocationone of: google_meet, zoom, phone or null, optional. google_meet, zoom or phone.min_notice_minutesinteger or null, optionalbooking_horizon_daysinteger or null, optionalsend_confirmation_emailboolean, optionalreminder_1h_enabledboolean, optionalthemeone of: dark, light, optionalaccent_colorstring or null, optional. Hex like #2334d1.accent_color_secondarystring or null, optionallogo_urlstring or null, optional. Absolute http(s) URL.prevent_duplicate_bookingsboolean, optionalreschedule_with_same_hostboolean, optionallocked_fieldsarray of one of: name, description, duration, buffer, questions, highlights, consent, location, booking_window, notifications, branding, booking_rules, optional. Which groups of settings clients cannot change on pages from this template.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
update_event_template
Edit an event template
Change an event template; send only the fields to change. Saving propagates its LOCKED fields to every booking page already made from it, so this can change live client pages. The result says how many pages were updated.
POST /api/v1/tools/update_event_template · scope write:agency · organisation-wide key only
template_idstring, required. The template id (list_event_templates).namestring, optionalduration_minutesinteger, optionaldescriptionstring or null, optionalbuffer_minutesinteger, optionalquestionsarray of object, optionalquestion_flowone of: inline, grouped, single, optionalbullet_pointsarray of string, optionalconsent_textstring or null, optionallocationone of: google_meet, zoom, phone or null, optional. google_meet, zoom or phone.min_notice_minutesinteger or null, optionalbooking_horizon_daysinteger or null, optionalsend_confirmation_emailboolean, optionalreminder_1h_enabledboolean, optionalthemeone of: dark, light, optionalaccent_colorstring or null, optional. Hex like #2334d1.accent_color_secondarystring or null, optionallogo_urlstring or null, optional. Absolute http(s) URL.prevent_duplicate_bookingsboolean, optionalreschedule_with_same_hostboolean, optionallocked_fieldsarray of one of: name, description, duration, buffer, questions, highlights, consent, location, booking_window, notifications, branding, booking_rules, optional. Which groups of settings clients cannot change on pages from this template.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
push_event_template
Push an event template to clients
Create a draft booking page from the template in each named client (slug, id or exact name). Clients that already have a page from it are skipped. Pages start as drafts; publishing stays a human action in SIGNL.
POST /api/v1/tools/push_event_template · scope write:agency · organisation-wide key only
template_idstring, requiredworkspacesarray of string, required. Clients to push to.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
detach_event_template_page
Unlink a booking page from its template
Stop a booking page following its template. It keeps its current values and becomes fully editable by the client.
POST /api/v1/tools/detach_event_template_page · scope write:agency · organisation-wide key only
page_idstring, required. The booking page id.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
delete_event_template
Delete an event template
Delete a template. Pages already made from it stay as they are, with their current values, and become fully editable.
POST /api/v1/tools/delete_event_template · scope write:agency · organisation-wide key only
template_idstring, required
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
set_client_setup_brief
Set a client’s setup brief
Shape the AI setup chat a client sees at their first login (replaces the brief; send all of it). `enabled: false` turns the chat off for that client. `notes` is private to the agency (server-only, never shown to the client) but the setup guide reads it and may act on it, so write nothing you would regret the client hearing paraphrased. `prefill` answers questions the agency already knows, in the setup profile’s own values; these ARE shown to the client, because the chat confirms each in one line instead of asking: business_model (one_to_one, group, course, agency, community, other), offers ([{ name, price_band: under_1k | 1k_3k | 3k_10k | 10k_plus, delivery }]), sales_motion (application_call, direct_booking, webinar, vsl, dm_setting, checkout, referrals), team_shape (solo, with_setter, setters_closers, sales_team), stack ([{ category, provider }]), alert_channel, alert_events, automations_before, notes. `allowed` names the kinds the chat may propose (pipeline, form, event, automation, integration; any left out stay allowed). `include_event_template_ids` puts up to 20 of the agency’s event templates on the client’s plan as draft booking pages. Refused once the client’s setup has been planned, built or skipped. A client with no setup yet gets one, opened at their next login.
POST /api/v1/tools/set_client_setup_brief · scope write:agency · organisation-wide key only
workspacestring, required. The client: slug, id or exact name.enabledboolean, required. False turns the setup chat off for this client.notesstring, optionalprefillobject, optional. Setup profile answers the agency already knows (see the description for the keys and values).allowedobject, optionalinclude_event_template_idsarray of string, optional. Event template ids (list_event_templates).
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
invite_client_member
Invite someone to one client’s workspace
Email an invitation to join ONE client’s workspace as a member. Always the member role, pinned to that client: inviting an admin, someone with the whole organisation or a custom role is done in SIGNL. Emails a real person, so the key needs write:sensitive as well as write:agency. Resending to a pending address replaces its earlier link.
POST /api/v1/tools/invite_client_member · scope write:agency and write:sensitive · organisation-wide key only
workspacestring, required. The client they will work in: slug, id or exact name.emailstring, requirednamestring, optional. Who they are; used in confirmations.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
Agency tools: write:finance
2
generate_statement_drafts
Generate the month’s statement drafts
Compute what each client owes the agency for a month from its packages and collected cash, and create or refresh the DRAFT statements. Drafts are working copies: nothing is issued to a client. Issuing, voiding and recording payment stay in SIGNL. Returns how many drafts were created, refreshed and skipped (already issued).
POST /api/v1/tools/generate_statement_drafts · scope write:finance · organisation-wide key only
period_startstring, required. The first day of the month, YYYY-MM-DD.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
add_statement_adjustment
Add an adjustment to a draft statement
Add a manual line to a DRAFT statement: a positive amount adds to what the client owes, a negative one is a credit. Amount is integer pence of the statement’s currency. Refused once the statement is issued: put it on next month’s draft instead.
POST /api/v1/tools/add_statement_adjustment · scope write:finance · organisation-wide key only
statement_idstring, required. The draft statement id (list_statements).labelstring, required. What the adjustment is for; shown on the statement.amount_penceinteger, required. Non-zero. Negative for a credit.
Responds 200 · 201 · 400 · 401 · 403 · 409 · 422 · 429
Also in the contract
The other endpoints in the OpenAPI contract, beyond the tools.
POST /api/ingest/server
ingest:write
POST /api/webhooks/inbound
ingest:write
POST /api/mcp
read
GET /api/builder/forms
read
POST /api/builder/forms
write:builder
PATCH /api/builder/forms
write:builder
GET /api/builder/booking-pages
read
POST /api/builder/booking-pages
write:builder
PATCH /api/builder/booking-pages
write:builder
POST /api/builder/forms/import
write:builder
GET /api/keys/me
Keys