2026-10-23: Auto-recharge can buy the Bronze pack
Update agency auto-recharge now takesBRONZE as its planCode, as it takes
SILVER, GOLD and DIAMOND. Bronze is on self-serve price lists only, so a
plan your price list does not include answers PLAN_NOT_FOUND. Auto-recharge
is still available on paid plans only (FREE_PLAN_NO_AUTO_RECHARGE). See
Balances, spend and sub-account wallets.
2026-10-23: TFU Live agents book on Calendly calendars
Look up TFU Live resources forcalendars now also lists the calendars of the
Calendly account the sub-account has connected, with source calendly and
ids such as calendly:<event type uuid>, and Find slots and Cancel appointment
steps take them. Calendly books through its API only on a paid Calendly plan. A
booking sends the location the event type asks for and answers its required
phone question from the contact on file; an event type that needs any other
answer from the caller is refused on the call, and nothing is booked. As on
Cal.com, a workflow that books on Calendly needs a Collect information step
that saves the caller’s email (below). See
Build a TFU Live agent.
2026-10-23: Cal.com bookings need a Collect information step for the email
A TFU Live workflow that books on a Cal.com calendar now needs a Collect information step before its Book appointment, with a required item that saves the caller’s email tocontact.email. A save refuses a new or changed workflow
without one (invalid_workflow, with stepId pointing at the Book
appointment). The step reuses an email already on the contact without asking.
The agent no longer asks for the email while booking: Find slots asks only for
the time, and for the caller’s timezone when times are offered in it and none
is on file, as on GoHighLevel and native calendars. Its contact_email
argument is gone. A workflow saved before this change is not refused until it
is changed, but on a call where the contact has no email it now books nothing,
so add the step to it. Cal.com bookings now also carry the contact’s phone
number, when it is in international form, as the attendee’s phone. See
Build a TFU Live agent.
2026-10-22: Campaigns can share a number, and each number has one answering campaign
Campaigns of your agency can now share a number, in any of its sub-accounts. They must all be TFU Live agents, or all Standard agents. A refused number answers409, and NumberOnAnotherCampaign is no longer sent. It is replaced
by one of these:
NumberInAnotherAgency: another agency uses the number.NumberOnTfuLiveCampaign: a TFU Live agent uses it, and this is a Standard agent.NumberOnNonTfuLiveCampaign: a Standard agent uses it, and this is a TFU Live agent.NumberRegisteredToOneBusiness: it is registered to another business in the Trust Center.NumberCannotBeShared: a Standard agent on a different voice account uses it.
answeredBy on every number, not only on TFU
Live numbers. campaigns lists that campaign first, then the rest, oldest
first. Each campaign has canAnswer, true for a TFU Live campaign or an
Inbound agent. The new answeringNow is the campaign in
answeredBy while it can take calls. Otherwise it is null. Send
locationId and engine, and campaignId for a campaign you edit, and each
number’s unavailableReason says why that campaign can’t use it. It is null
when it can.
A campaign you add a number to answers it if nobody else does. It must be able
to answer calls. If another campaign answers the number, that campaign keeps
it. To take it over, list the number in answerCalls. Assign
phone number, Move phone number and Update campaign now take answerCalls. A
listed number that is not on the campaign after the save gets 400
AnswerCallsNotOnCampaign. A campaign that can’t answer calls gets 422
CampaignCannotAnswerCalls. When the answering campaign leaves the number,
the next campaign on it that can answer calls takes over, oldest first. See
Phone numbers and caller ID.
2026-10-22: TFU Live agents book on Cal.com calendars
Look up TFU Live resources forcalendars now also lists the calendars of the
Cal.com account the sub-account has connected, on GoHighLevel and native
sub-accounts alike, with source calcom and ids such as calcom:4711.
sources reports each system on its own, so one that cannot be read is
unavailable while the rest are listed. Find slots and Cancel appointment
steps take those ids. A save refuses, with invalid_workflow, a workflow whose
calendars come from more than one system. A calendar the sub-account’s CRM
cannot book on, such as a GoHighLevel calendar on a native sub-account (going
live refuses it with calendar_not_on_crm), is left out of that count, so such
calendars can be replaced one at a time. Cal.com needs the caller’s email to
book: when the contact has none, the agent asks for it on the call and saves it
to the contact.
An email already on the contact is always used and never replaced. Calendly
calendars are not listed yet, and a save refuses one. See
Build a TFU Live agent.
2026-10-21: Connecting Cal.com or Calendly checks the key first
Connect a calendar system now uses a pasted Cal.com key or Calendly token for one read in that product before it saves anything. A key the product refuses answers400 with CalendarKeyRefused, where it used to be saved and fail at
the first booking. A product that cannot be reached answers 503 with
CalendarKeyCheckUnavailable. Either way nothing is saved, and a connection
already there stays as it was. See Calendars.
2026-10-20: Date filters can follow your time zone
List calls and List contacts now taketz, an IANA zone such as
America/Los_Angeles. With it, a plain YYYY-MM-DD in dateFromUTC or
dateToUTC covers that day from midnight to midnight in that zone, instead of
the UTC day. Timestamps are read exactly as before. A request without tz, or
with a zone the platform does not know, reads plain dates as UTC days, as it
always has. The window on the response shows the instants the filter used.
See Dates and times.
2026-10-17: Set up a TFU Live rep’s campaign by API
Get campaign and Update campaign now work for a TFU Live rep, with itstfu_live: id and
locationId, so API keys and MCP clients can set its start and stop tags, its calling hours
and switches, its cadence of calls and texts, and the number its texts come from, through the
same checks as every campaign. Start tags also give the rep a tag start when it has none.
What the rep sets itself is refused with TFU_LIVE_CAMPAIGN_SETTING_ELSEWHERE, and
details.use names the operation to use instead: its workflows, its numbers, Go live and
Pause, its master family and its test links. Changing needs campaigns:write and
agents:write. Every campaign also takes smsFromNumber, the number its texts come from.
See Set up a TFU Live rep’s campaign.
2026-10-17: After-call steps can save the caller’s name
The post-call AI now saves the name the caller gave for themselves on the call with its summary. After-call steps read it ascall.caller_first_name and
call.caller_last_name, in text, in a Condition or in a Webhook with response
field. Both are empty when the caller gave no name; they never come from the
contact on file. A Set field whose value names a call fact that comes back empty
is now skipped instead of clearing the field, so contact.firstName set to
{{call.caller_first_name}} keeps the contact’s name when the caller gave none.
See TFU Live workflows.
2026-10-17: Take a TFU Live rep live, or pause it, by API
API keys and MCP clients can now switch a TFU Live rep’s campaign on and off the way the dashboard’s Go live and pause buttons do, with Go live with TFU Live agent and Pause TFU Live agent. Going live is judged by the same go-live check: while it lists anything, the call is refused withTFU_LIVE_GO_LIVE_BLOCKED and every blocker, and the
campaign stays paused. Going live adds no start rule or tag; an outbound rep with start
tags begins calling matching contacts once live. Both need campaigns:write and
agents:write, and asking for what already is changes nothing. Check go-live readiness
now also takes campaignId. See Take a TFU Live rep live, or pause it.
2026-10-17: A retest clears what an earlier test booked or stopped
Before a campaign test runs again on a contact that only test runs have reached, the upcoming appointments its test calls booked are cancelled, without the calendar’s notifications, and an opt-out it gave on a test call is lifted. An opt-out given any other way, or a contact a real call has reached, is left as it is. A booking made by a test call now starts the confirmation campaign as a test run, so it no longer counts as a real lead. See TFU Live authoring.2026-10-17: A test link can test the same number again
A campaign test runs for real, so a test that booked, parked or passed on its contact used to leave tags that refused every later test of that number. A share link now takes those tags off when only test runs have reached the contact, and starts the run. A contact that a real run already finished with is refused with its own message,CampaignContactFinished. The kill switch, Do Not Disturb,
opt-out tags and the client’s own stop tags still refuse as before. A start that
is refused no longer counts against the link’s start limits. See
TFU Live authoring.
2026-10-16: Buy or connect a TFU Live rep’s number by API
API keys and MCP clients can now give a TFU Live rep its phone number the way the dashboard’s Get a number dialog does: connect a number the agency already has for free, or search, quote and buy one. The purchase is the payer’s yes to the quoted price, needs a billing card on file, and charges the agency wallet once. Reads needagents:read; quoting, buying and connecting need agents:write. Assign phone number
and the campaign number move now also work for a TFU Live campaign, with a key that has
agents:write as well. See
Give a TFU Live rep a phone number.
2026-10-15: MCP browser sign-in guidance
The MCP connection guide is readable before authentication. Discovery metadata links to the guide, and the initial authentication challenge tells clients to start browser sign-in and resume after approval. Existing API keys and OAuth permissions are unchanged. See Connect an AI assistant.2026-10-15: TFU Live saves through the API take effect at once
Every save through the API or MCP now sets the saved version up straight away: an edit, a restore, or a workflow change. A test link opened after a save uses that version without a separate Prepare call. A draft that still has setup items is set up for test calls only. If a save cannot be set up, its response carriessetupError. A test link opened while setup is still running now says the agent is
still being set up, instead of a general failure. See
TFU Live authoring.
2026-10-15: TFU Live test links and GHL connection
The MCP handoff gives you the ready rep’s browser test link before phone setup. Scoped clients can request a GoHighLevel install link and check its status through TFU Live authoring. You still approve installation in GHL and choose where the rep should move.TFU Live customer guides
TFU Live now groups the visible builder controls into focused guides, with a simple diagram of conversation, Brain and actions. Developer contracts keep their existing URLs under API Reference. The updated guides are available in the customer documentation.TFU Live manual saves and explicit workflow sync (local development)
Saving your own instructions does not invoke AI or charge for generation. Sync workflows is an explicit action when you want the saved instructions reflected in workflows. Review and test the result before using it with leads. See Instructions and the authoring contract. This change has not been deployed.TFU Live agency-owner dashboard authoring (local development)
Agency owners can create and edit TFU Live agents in their own sub-accounts using manual configuration or typed and spoken Build with AI. New agents receive a paused campaign. Roleplay and test flows retain resource readiness checks; project users and cross-agency access remain blocked. API keys continue to use scoped public operations. This change is local and has not been deployed. See Build a TFU Live agent.TFU Live customer authoring (local development)
The local development API adds tenant-scoped TFU Live creation, reads, revision-checked edits, explicit preparation and capability/resource discovery through dedicated TFU Live operations and TFU Live authoring. See Build a TFU Live agent. This change has not been deployed to the production API. Use this page to track public API changes that affect integrations.October 2026
-
Every error has a code in
errorand a sentence inmessage(local development). All endpoints now answer a failure with the same envelope:erroris a stable code to branch on,messageis one plain sentence for a person, and the optionalerrors,detailsandrefsay which fields to fix, carry data for your code, and give support a reference. Native Calendar, Native Contacts, Contacts, TFU Live and the power dialer operations under Campaigns used to put a sentence inerror; they now put a code there and the sentence inmessage. Contacts and the power dialer no longer send a separatecodefield; read the code fromerror. Existing codes keep their spelling, and fields such asrequiredScopeare still sent.messageis English for API keys and OAuth apps; its wording can change, so never parse it. See Conventions. -
Validation refusals list their fields in
errors(local development). AVALIDATIONrefusal from Agents, Calls, Campaigns or Contacts used to list the fields indetails, as[{ field, message }]. It now lists them inerrors, as[{ field, code, message }], like every other refusal:codeis stable andmessageis for a person.detailsis now an object of data for your code, or absent. When a field must be one of a set, Agents and Campaigns put the choices indetails.allowed, by field. List calls still sendsdetailsas[{ field }], withoutmessage. See Conventions. -
Native Calendar and Native Contacts list refused fields as objects (local
development). Their
errorsused to be a list of sentences. Each entry is now{ field, code, message }, as on every other refusal.errors[].codeis a specific code for the rule that was broken, such asContactEmailInvalid,ContactFieldValueNotNumber,TimezoneNameInvalidorCalendarLengthInvalid, not only the generalField...codes, andfieldnames the field (customFields.<key>for a custom field value). A refusal’smessagesays what happened, such as a phone number another contact already has or a field a campaign starts on, whileerror(andcodeon Native Contacts) keeps the status code it had, such asConflictorBadRequest. -
Calls answers a code in
error(local development). The call recording downloads used to put a sentence inerror, such asCall not found. They now send a code, such asCallNotFound,RecordingUnavailable,CombinedRecordingUnavailableorTransferRecordingUnavailable, and the sentence is inmessage. Get call still answersNotFoundfor a call that is not there or not yours. -
A role refusal no longer names the role (local development). A
Forbiddenfrom a role check used to carryrequiredRole. It is no longer sent.requiredScopeonInsufficientScopeis unchanged. -
messageis in the reader’s language (local development). Every refusal’smessage, and eachmessageinerrors, is written in the language of the person reading it: the dashboard asks for the language the person chose. Requests made with an API key or an OAuth app, MCP included, always get English, whateverAccept-Languagethey send.error,codeand every other field stay the same in every language. See Conventions. - TFU Live has a focused customer guide. Start with TFU Live to learn where to edit Instructions, Conversation Style, Workflows, Chat and Call handling, then test and go live. Developer contracts remain in API Reference.
-
A TFU Live campaign’s browser test link uses a contact already on the
number (local development). For
scope: "campaign", the web link from Issue TFU Live test links no longer refuses a number that belongs to a contact a test link did not make. It finds the contact by the number the tester enters, as the phone link does, and runs the campaign for it. In GoHighLevel the contact takes the name the tester enters. A contact the web link creates in GoHighLevel still carries the sourceTFU AI Test Link. The tester’s page now says why a run did not start for their contact: Do Not Disturb, calling stopped, or a number that changed in the CRM. See Build a TFU Live agent. -
TFU Live campaign test links run in the browser (local development).
For
scope: "campaign", Issue TFU Live test links no longer answersweb.available: falsewith the blockerWEB_CAMPAIGN_PHONE_ONLY. The web link now runs the real campaign for the contact made from the name and phone the tester enters, in their browser, with no calling line needed, and it is charged nothing, as the phone test run is. The web link takes a number only when no contact holds it yet, or when a test link’s browser run made the contact on it. That contact stays usable for 30 days after its last browser run through a test link, and each run that uses it starts the 30 days again. Any other number is refused and its contact is left untouched. A contact the web link creates in GoHighLevel carries the sourceTFU AI Test Link. The response carrieswebin two cases: with the blockerWEB_CRM_UNSUPPORTEDwhen the sub-account’s CRM is not one TFU Live runs on, and with the new blockerWEB_LINK_PHONE_ONLYwhen a reused link was issued before this change. That link’s phone side works as before, androtate: trueissues one that runs in the browser. See Build a TFU Live agent. - Transcript search (local development). The API and MCP add literal words and phrases with AND/OR, bounded excerpts and signed continuation. Search covers saved transcripts, including older calls. Counts are matching calls, with optional coverage of how many calls were searchable. See Transcript search.
-
Large MCP tools list a lighter schema. Ten tools whose bodies nest
several objects deep, such as
patch_agent_builder_agents_by_idandupdate_agent_campaign, now appear in the tool list with shorter field descriptions, and some list their deepest objects by key name, so every client can read the whole schema. Before this, Codex stripped the descriptions from oversized schemas and showed four of these tools with no body fields at all. Every field is still accepted and checked against the full schema, and search mode still returns the full schemas. The MCP handshake instructions are also shorter, with the rules about confirming writes and untrusted text first. See Large tools. -
Every MCP write tool is marked destructive. All write tools now carry
destructiveHint: true, creates included, so a client that honours the hint asks before each one, including placing a call, running the dialler and buying a number. Reads are unchanged. See Reads and writes. -
Search mode for MCP clients that limit tools. Add
mode=searchto the MCP URL andtools/listreturnssearch_tools,list_tools,call_read_toolandcall_write_toolinstead of every tool. Everything stays reachable and listable, with the same checks. See Search mode. -
The MCP tool list matches your role.
tools/listnow leaves out tools your role cannot use, as well as those your credential lacks the scope for. A role without agency admin rights, such as a sales rep (rep), sees the call, contact, analytics and Power Dialer tools instead of every customer tool. See Tool visibility. -
Two MCP tools have shorter names, so AI clients that limit tool name
length show them:
post_agent_builder_phone_number_campaign_moveanddelete_agent_builder_phone_number_campaign, for moving and unassigning a campaign’s phone number. Their operation IDs in this reference are unchanged.
September 2026
-
A refused TFU Live campaign says so. When
Create TFU Live agent saves
the agent but its campaign is refused, the response keeps the refusal’s
status and message with the code
TFU_LIVE_CAMPAIGN_REFUSED, instead of reading as an unconfirmed campaign to retry. Like the rest of TFU Live authoring, this is a local development contract. See TFU Live authoring. -
Analytics by lead age.
Get analytics by lead age
returns the analytics summary split into
freshleads (sent within 5 minutes of being created in the CRM),warm(under 3 days) anddbr(3 days or more), plusunknownfor leads whose times cannot place them, withunknownReasonssaying why. The segments add up to the summary. See By lead age. -
A contact now says how old the lead was when it arrived.
List contacts and
Get contact return
leadGeneratedAtInCrm, when the sub-account’s CRM created the lead, withleadGeneratedAtInCrmPrecisionsaying whether that is an exacttimeor only aday, andleadReceivedByTfuAi, the exact moment the lead reached the platform.dateAddedis unchanged. See How old a lead was when it arrived. -
A TFU Live agent’s orb has its own colours.
Set TFU Live agent orb colour
picks one of four kinds:
default(it follows the voice),curated, one of 17presetpairs (each a published palette’s first real colour as the main colour and the next colour that differs from it as the glow), or twocustomcolours (the orb’s own colour, then its glow). Every agent read, starting with Get TFU Live agent, now returnsorb, and{"style": "default"}when none was chosen. Choosing a colour takes noifVersionand saves no revision. Like the rest of TFU Live authoring, this is a local development contract. The orb colour explains each kind. -
A campaign workflow can post one outcome to your system.
send-webhookis now a published node type on Add actions to an outcome and Replace the entire workflow, with its receiver inconfig.url. The node already worked in the builder; the reference left it out, and Add actions to an outcome refused it. It sends the signedcall_endedevent only when its outcome fires. Outcome webhooks covers the body, signing and retries. -
Contacts and calendars without a CRM are in the API. Twenty-one
operations under
/api/native-contactsand nineteen under/api/native-calendarcover what a sub-account that keeps its contacts here needs: create, read, update and delete contacts, define the custom fields your prompts read, import a CSV, enrol contacts into a campaign, set do-not-call, and read or rotate the lead link; then the calendars themselves, their free slots, and booking, rescheduling, confirming and cancelling on them. Contacts use thecontacts:readandcontacts:writescopes an existing key already carries; calendars useprojects:readandprojects:write. Contacts without a CRM and Calendars and booking are the guides. -
Native cadences can send webhooks.
api-eventactions on Update campaign schedule (not published on this branch; the cadence is edited undercalling.cadenceon Update campaign) send a signed HTTPS event with contact and cadence details plus static custom JSON. Event-only steps do not place a call. Destinations and data read back on Get campaign schedule (not published on this branch; readcalling.cadenceon Get campaign). Send webhooks covers the fields and delivery behaviour. The step is called Send webhook in the builder;api-eventremains its stored type, so nothing you send changes. -
An agent can wait for hello.
config.llmon Update agent takesstartingSpeaker(agentgreets first,userwaits for the person) andbeginAfterUserSilenceMs(how long a waiting agent gives a quiet person before it speaks,1000to15000). Both read back on Get agent. Who speaks first explains the choice. -
Billing changes are in the API. Ten operations under
/api/billingswitch auto-recharge on or off and pick its plan, buy a plan, turn a sub-account’s rebilling on or off, link or unlink its Stripe customer, set its auto-recharge and Credit Guard, and charge its client’s card. Anything that charges a card needs the newbilling:chargescope and anIdempotency-Key, and is not available over MCP. Every sub-account change needs rebilling on your plan and Stripe Connect connected. Set up rebilling for a sub-account walks through it. -
Billing is in the API, read-only. Six endpoints under
/api/billinganswer where your agency stands: a summary of balance, auto-recharge, subscription, this month’s spend and what needs attention; one history of everything that moved your wallet; usage by sub-account or by day; invoices and receipts; and every sub-account’s wallet. They need thebilling:readscope and an agency admin’s key, and cover only the agency the key belongs to. Balances, spend and sub-account wallets explains every figure. -
A cadence step can say its own words. A step’s
callnow also takesopeningMessage,screeningPurpose,voicemailandvoicemailMessage, so each touch can open differently, give its own reason when a phone screens the call, and leave its own voicemail. Leave one out and the agent’s own opening and purpose, and the campaign’s voicemail, apply.voicemail: truewithout avoicemailMessagereturns422. Cadences, steps and the queue has the detail. -
An agent’s
config.voicemailis documented. It reports the agent’s own voicemail handling:enabled,messageanddetectionPrompt.timeoutMsstays in the shape and isnull, because no detection timeout is reported any more. It is read-only, and separate from the campaign’s voicemail below. Get agent shows it. -
One voicemail switch per campaign.
config.voicemail,config.voicemailMessageand the optionalconfig.voicemailDetectionPromptleave one voicemail per cadence touch, on its last dial: the second dial when the touch double dials. Callbacks and inbound calls never leave one.dropVoicemailOnDoubleDial,doubleDialVoicemailMessageanddoubleDialVoicemailDetectionPromptare deprecated and still read while the new keys are absent. What a campaign is has the detail. -
Your agency’s voice library is in the API. Five operations joined
Voices: List added voices,
Search for a voice to add,
Add a voice,
Preview removing a voice and
Remove a voice. Search, add and
remove need the new
voices:writescope. List voices now also returns your own and shared voices, each row with asourceofown,sharedorcurated. An add can be refused with409andVOICE_ALLOWANCE,VOICE_CAPACITYorVOICE_ALREADY_SHARED. Voices has the detail. -
Trigger tags are stored in lowercase. On GoHighLevel sub-accounts
activeTagsandinactiveTagsare saved in lowercase, the way GoHighLevel sends them, and tags that differ only in case are merged. A trigger saved asHot Leadnow fires on thehot leadGoHighLevel sends. Who gets called has the detail. -
A master agent can be split tested. Converting a master agent campaign no
longer returns
409. Run the split from the parent, and every linked project applies the weights to its own leads. Converting or adding a variant through a child returns409. Agent split tests has the detail. -
A split test variant can sit out of the cycle.
Update split weights now
accepts
weight: 0for any variant but the primary. The variant comes back withsplitDraft: true, takes no calls, and stays testable. While it is out, one live variant covers the calls owed to its leads, the same one every call, and including it again hands those leads straight back. Covering calls count in the campaign’s totals but not in any variant’s own numbers. Agent split tests has the detail. -
A campaign’s name follows its agent’s name. A live campaign’s name is kept in step
with its agent’s, so a
namesent on Update campaign or Update project campaign does not last. Rename the agent with Update agent to rename both. A campaign running an active split test, or whose agent’s name another campaign in the project already has, keeps its own. What a campaign is has the detail. -
Corrected: a split test does not return
startedAt, so the guides no longer mention it. The List voices filters never hid your own or shared voices, though the reference said they did. Preview removing a voice never returns404. A cadence step’scallignores keys it does not know rather than refusing them. An excluded split variant does not keep its in-flight leads; a live variant covers them, as described above. -
Project selectors require Location IDs. Use
locationIdfor one project orlocationIdsfor several.projectNameandprojectsare display labels; name-only selections return400. Conventions explains the identity fields. -
Get voice answers only for voices in your
voice list. That’s the catalogue, your own voices and shared ones. Any other
id is a
404. A voice from your list that is not in the catalogue comes back withisCustom: trueand itsgender,accentandage, withvoiceNameempty. Voices has the detail. -
Billing access is separate from subscription status. Read
AccessSubscriptionRequiredrather than inferring access from subscription state: an agency can have software access without one. Agency boundaries, user roles and API key scopes still apply. Existing billing records and provider subscriptions remain unchanged. Conventions explains billing access errors. - The docs now cover every published concept, and the two tabs link both ways. The Documentation sidebar mirrors the API reference groups one to one, with a guide for each module that had none: Call records, Contacts and leads, Metrics and how they are calculated, Cadences, steps and the queue, Campaign workflows, Phone numbers and caller ID, Voices, GoHighLevel resources, Agencies, projects and sub-accounts, Agent split tests and Master Agent. Every reference group opens with a landing page that links its guide, and every guide ends with the endpoints behind it. A Glossary defines every field and enum value, and the docs are checked on every build for a broken link, an orphaned page, or an enum value the docs do not mention.
- New: Quickstart, Test your agent, Clone an agent, Run a split test and Backfill existing leads.
-
Conventions now carries the numbers. Rate limits with
their defaults and the
RateLimit-*headers, every error code that appears in published responses, which id to use for what, the four operations that acceptIdempotency-Key, the concurrency tokens, and the legacy aliases. -
POST /api/agent-builder/agents/{id}/web-version/sessionis documented. The reference now describes the browser test session: theaccessToken,callIdandagentNameit returns, the billing gates that answer409, and the502VoiceProviderUnavailablewhen the voice provider refuses to start. No behaviour changed. - Corrected: outcomes follow capabilities, not the campaign type. The after-the-call guide said which outcomes exist depends on the agent’s type. It depends on the installed capabilities, as the agent-types guide already said. Corrected: the introduction claimed billing, agency settings, access subscriptions and events were published modules. They are not.
- Moved: the skills-for-voice-ai concept page is merged into Skills and tools. The old URL redirects.
-
The deprecated project-scoped campaign workflow paths left this reference.
/api/agent-builder/projects/{locationId}/campaigns/{campaignId}/workflowand its digest and node paths are no longer listed here, so the reference shows only the agent-scoped paths to move to. They still work and still send aDeprecationheader. The whole-workflowDELETEis the exception: it needs a dashboard session and refuses API keys, and it never appeared here. -
Corrected:
Idempotency-Keyon Add split variant. The operation described the header but never listed it, so a generated client had no way to send the one thing that makes the call replay-safe. The header is now a documented parameter. The request body no longer advertises anidempotencyKeyfield: the route strips it and reads the header only, so sending it in the body never guarded a retry. No behaviour changed.
August 2026
- The
outreachcampaign type is now labelled “Outbound”. Only the display name changed:GET /api/agent-builder/agent-typesreturnslabel: "Outbound"where it used to return"Outreach", and the same wording appears in the validation message you get back when you omitcapabilityIds. The type id is stilloutreacheverywhere (inagentType, in stored campaigns and in the legacysystemmapping), so nothing you send or store needs to change. If you display our label rather than your own, your UI will follow. - The MCP action endpoint advertises every published operation. Placing
calls, buying or releasing numbers, running the power dialler, deleting
projects, clearing a do-not-call flag and enrolling leads are all reachable as
tools with a broad enough credential: the MCP surface is exactly what this
reference publishes, filtered only by the credential’s scopes. If your client
auto-approves tools, note that
destructiveHintdoes not flag these: placing a call, running the dialler, buying a number and creating an agent are all creates, and creates are annotateddestructiveHint: false. Scope the credential accordingly. See MCP action tools. - Contacts can be marked as your own test leads.
POST /api/contacts/internalmarks a contact internal andDELETE /api/contacts/internalclears the mark; both takelocationIdwith eithercontactIdorphoneNumber, and report how many records the identity resolved to. List contacts takes a matchinginternalfilter:all(the default) lists them withisInternalon each row,onlynarrows to them,excludehides them. The default lists them. taggedis now a disposition you can filter on. It was previously only a breakdown figure, so a tagged count on the dashboard could not be turned into a list of which contacts. It reads as one option rather than one per tag, since which tag was applied is the breakdown’s question and the tags differ per client.taggednever masks another outcome: tagged plus booked readsappointment.POST /api/power-dialer/moveis now published. The route existed but was missing from this reference. It moves waiting leads to a different step of their schedule and recomputes the next call time from the target step in each lead’s own timezone. Only waiting leads move; one that is mid-dial, pinned to a callback, on an appointment-reminder schedule, or whose schedule has no such step comes back inskippedwith a reason instead of failing the request.- Corrected: the scope table described several scopes wrongly. Nothing
changed in the API; the Authentication table was wrong, and
a key scoped from it could come back 403 with no clue why. The worst of it:
outcome prompts are covered by
campaigns:readandcampaigns:write, notagents:readandagents:writeas the table claimed. Also corrected:calls:readandcontacts:readno longer claim to cover CSV exports, andcalls:readno longer claims execution history, none of which this reference publishes;contacts:writenow mentions marking a contact as a test lead and names the do-not-call flag rather than an internal “kill switch” spelling;ghl:readno longer claims pipelines and workflows, which it does not reach;power_dialer:writenames moving leads between steps rather than a “requeue” that does not exist;projects:writeno longer claims to create projects, which it cannot; and theagents:*rows now mention the agent’s skills and tools, which they do cover and did not say. webhooks:readandwebhooks:writeare documented. Both scopes were already issuable and enforced; the Authentication scope table omitted them.
July 2026
- Breaking:
agentTypeon the Agents module is now a campaign type, not a combined template id. Create agent, theagentTypefilter on List agents, and the agent responses accept and returnoutreach,inbound, orappointment. What the agent can do moved to a separate field,capabilityIdson create, which takes one or more ofappointment_booking,live_transfer, andadd_tag. The seven combined ids listed under “Agent types are now a fixed, validated set” below are no longer accepted asagentType; sending one now returns a 400 listing the three valid types. Integrations that send a combined id assystem, with noagentType, are unaffected and keep working. See Campaign types and capabilities for the mapping from each old id to its type and capability set. - A campaign’s installed capabilities are now readable. Agent responses
carry
capabilitieson the campaign facet, so you can tell what an agent can do without inferring it from a template id. Capabilities also gate outcomes: a call can only end inTRANSFERwhen Live Transfer is installed, and inSUCCESSorRESCHEDULEwhen Appointment Booking is. GET /api/agent-builder/agent-typesreturns three entries, not seven. Outreach and Inbound each carry atemplatesarray listing the starting capabilities you can pass ascapabilityIds. Reminder resolves to a single fixed template.- The Campaigns and V2 Projects modules still speak the seven template ids.
Their
agentTypeis unchanged and still validated against the original set. It names the template a campaign was cloned from, not what the agent can do, and on an agent created with several capabilities it reflects only the first. These modules will be migrated separately; until then, treatagentTypeon the Agents module andagentTypeon Campaigns/Projects as different fields that happen to share a name. - Appointment Booking is now a documented skill type. It was already
installable and has been all along, but the reference omitted it from the
skill type set and from
GET /api/agent-builder/agents/{id}/skills/library. Both now list it. No behaviour changed; the documentation was wrong. - Breaking: call records answer with the canonical field names. A call’s
identifier is
idand its agent type isagentType. No other spelling of either field is returned. The list payload also no longer carriescached,queryTime, andgeneratedAt. Those described the server’s own caching, not your data, and were never something to build on. - Breaking: execution-history responses nest under
dataand use camelCase. The run summary, node history, runs list, timeline and graph endpoints now return{ "success": true, "data": { … } }with the same camelCase names the rest of the API uses. - Campaign workflows can now be addressed by the agent that owns them. A
workflow is reachable at
/api/agent-builder/agents/{id}/campaign/workflow, alongside endpoints to read a digest, append an action to an outcome, switch an outcome, and delete a node. The project-scoped equivalents under/api/agent-builder/projects/{locationId}/campaigns/{campaignId}/…still work and are unchanged, but they are deprecated: they now carry aDeprecationresponse header (RFC 9745). They will be removed in a future release, so move to the agent-scoped paths. - Fixed: fetching a call by its platform call id.
GET /api/call-history/by-call-id/{callId}returned 404 for every call, including ones that exist. It now returns the call. - Fixed:
excludeReviewed=falseno longer excludes. The value was coerced in a way that read any present value as true, so passingfalsedid the opposite of what it says.excludeReviewednow takes exactlytrueorfalse, and any other value is a validation error rather than a guess.dispositionis also accepted as a repeated parameter again, not only as a comma-separated string. - A campaign’s
agentTypeanddialingare validated wherever a campaign is written. The project-scoped campaign routes accepted any string for either field and stored it, after which the campaign read back withagentType: nulland no way to tell from the write that anything was wrong. Both fields are now checked against the published sets on those routes too, and an unknown value is rejected with a 400 that lists the valid ones. - Agent types are now a fixed, validated set.
agentTypeaccepts onlyappointment_booking,appointment_confirmation,live_transfer,live_transfer_and_tag,live_transfer_and_booking,add_tag, andinbound_receptionist. An unrecognised value is now rejected up front as a validation error listing the valid types, instead of failing later as a not-found. The same set applies to theagentTypefilter on List agents. The agent type is also always present on an agent response now. It isnullwhen none can be resolved, where it was previously left out of the object. - Breaking: the
confirmationandreactivationdispatch modes are retired. Neither can be set on a campaign any more: creating or updating with"dialing": "reactivation"(or"confirmation") is rejected with a 400, and the writable modes are nows2l,pd, ands2l_pd. Campaigns created before this still work: they keep their stored mode, keep dialling exactly as before, and still report"dialing": "reactivation"on a read, which is why that value remains in the response schema. What they cannot do is have their dispatch mode re-sent: an update that includes the retired value is refused, so change the mode to a supported one in the same request if you need to edit such a campaign.confirmationis no longer accepted on a write. A read still returns it for a Reminder campaign, and List agents reports the same campaign aspd. - Breaking: a campaign’s
dialingno longer acceptsnull. Sending"dialing": nullwhen creating or updating a campaign is now rejected with a 400. Omit the field to leave a campaign’s current dispatch mode alone, or, on create, to take the default for the agent type (outbound types default topd). There is no “clear the dispatch mode” operation, because a campaign without one is inert: it never dials, and it also hides the controls you would use to set it, so it cannot be repaired from the dashboard. A campaign storingnullis given its correct mode on its next write. - Breaking: three campaign-workflow action types have been removed.
post-webhook,enroll-in-campaign, andrequeue-pdare no longer valid values for a workflow nodetype, and are rejected on write. The supported actions areadd-tag,remove-tag,set-field,move-stage,add-note,send-sms,send-email, andbook-appointment, plus theifandswitchbranch nodes. Re-dialling a contact who did not answer is handled by the engine itself and never needed a node. The webhook node’surl,payload,headers,auth, andretryconfig fields are gone with it. - Workflow configs are rejected if they contain an unreplaced placeholder.
A node config carrying a stand-in value (
REPLACE-WITH-…,CHANGE-ME, or a URL on a reserved documentation host such asexample.com) now fails to save. An empty config is still accepted: an unfinished draft is fine, a value that only looks finished is not. - Post-call analysis fields are now protected on update. When you update an agent, platform-managed analysis fields (the standard call outcomes and other system-managed fields) are always retained, even if your request omits them. A partial update that sends only your own custom fields no longer removes the managed ones. Only the custom fields you send are replaced.
- Added public API documentation for launched customer-facing modules.
- Added bearer API key authentication guidance.
- Added standard API response and error conventions.
