Changelog
Every change to the /v1 contract. Additive only — see the versioning policy for what that guarantees.
Changes are additive: nothing listed here removes or retypes anything you already receive. See Versioning for what that commits us to.
Subscribe by watching openapi.json —
it is regenerated from the code and is the machine-readable record of everything
below.
2026-10-14 — Transfers to a person
Added
- An agent can hand a live call to a person at your business. Set up who may
be rung with
/v1/transfer-destinations(each one verified by a call that speaks a code), and when, withcallSettings.transferon the agent. Runs on Plivo and Exotel numbers. See Transfers to a person. transferon the call —GET /v1/calls/{id}, the call list and every call webhook carry the latest attempt: status, outcome, destination label, times, how long the person talked and the brief they heard.nullwhen the agent never tried.GET /v1/calls/{id}/transferslists every attempt.- Three webhook events:
call.transfer_started,call.transferredandcall.transfer_failed, each with the attempt asdata.transferand alinks.handoffpage for the person taking the call. See Webhooks. GET /v1/calls/{id}/transfers/{transferId}/recordingand…/return-recording— the person's part of the call, and the agent's part after an attempt nobody took, each recorded separately.- A transcript role,
human_agent, for the person's lines after a handoff. - Warm handoff:
callSettings.transfer.handoff: "warm"keeps the caller with the agent until the person has pressed 1, on Plivo numbers. Such an attempt ismode: "consult", passes through the statusaccepted, and carriesacceptedAt. See Warm handoff. - A second person:
destinations[].fallbackDestinationIdnames who to try when nobody at a destination takes the call, rung at once on Plivo numbers. See A second person. - Transfers on your own SIP trunk: the person is rung over the call's own trunk, always warm, and their minutes bill at ₹1.50. Their part is recorded and transcribed as on Plivo. See On your own SIP trunk.
- Transfers on BYO calls: your bot asks with a
transferframe on its Tone Media Streams socket and is told how the attempt goes;trigger: "byo"on the attempt.POST /v1/calls/{id}/transfertakeshandofffor a BYO call. See Handing the call to a person. POST /v1/calls/{id}/transfer— your backend asks the agent on a live call to hand it to a person;trigger: "api"on the attempt. A new error code,call_not_live, when no agent is on the call.
Nothing you already receive changed. On a transferred call, the time the caller and the person talk bills at ₹2.00 a minute; see Billing.
2026-10-11 — New agents default to a Murf voice
Changed
- An agent created without
ttsModelandttsVoicenow gets a Murf voice that speaks every language in itslanguages, female like the previous default. If no Murf voice speaks them all, it getsbulbul:v3/simranas before. An agent that names its voice is unaffected. See Voices.
2026-10-11 — Lower per-minute prices: Developer and Enterprise plans
Changed
- The list rate is ₹5.00/min (was ₹6.00): agent ₹3.00 + telephony ₹0.50 + platform ₹1.50. This is the Developer plan, which every organization is on unless it has an Enterprise rate.
- Enterprise, from ₹4.00/min and lower at higher volume, is a rate agreed per
organization.
ratePaisePerMinuteonGET /v1/walletreports the rate you are on. - The component rates moved with it: bring your own voice ₹2.00/min (was ₹2.50), your own SIP trunk ₹4.50/min (was ₹5.50), your own trunk with your own voice ₹1.50/min (was ₹2.00). See Billing.
Nothing in the API's shape changed. Calls already billed keep the rate they were
billed at — every call records its own ratePaisePerMinute.
2026-10-06 — A readable evidence PDF
Changed
GET /v1/calls/{id}/evidence.pdfis redesigned as one page: a verdict, a timeline of what happened when (in IST, to the second), what each compliance check found, the call's details, and the tamper-evident seal. It is still read only from the sealed record.GET /v1/calls/{id}/evidenceis unchanged.
2026-10-06 — Promotional calls are checked against India's DND register
Added
dnd_register, a pre-dial check that can block. A promotional call to a number on India's DND register is refused withblocked_dnd, unless an explicit consent for that number is on record. Transactional and service calls are not checked: DND does not govern them, and their numbers are never sent to the lookup. A lookup that cannot answer records a warning and the call goes ahead. See Compliance.source: "vendor"on check rows answered by the third-party DND lookup.- Promotional campaigns have their list checked at launch. Listed numbers are excluded and
counted under
dnd_scrub.
Changed
dnd_registerreplacescarrier_dndon calls from today.carrier_dndrows on earlier calls keep their meaning: advisory, never a block.- The
a2p(robocall declaration) check applies to promotional calls only, for now. Transactional, service and collections calls record it asnot_applicable, and a call'scomplianceis no longerflaggedfor it. Calls placed earlier keep their recordedwarn, but it no longer flags them either. - In test mode, only
+915555000005is on the DND register. Before, every number ending in 0 also read as listed. That was harmless while the check only warned, but would now block one test number in ten. See Test mode.
2026-10-06 — Transactional campaigns skip the frequency cap
Changed
- The 7-day frequency cap no longer applies to transactional campaigns. Before, a
transactional campaign left out anyone your organization had reached in the last 7 days, so a
customer who ordered twice in a week missed the second confirmation call. Promotional and service
campaigns are still capped, and their recipients still land in the
frequency_capbucket of the pre-flight. See Campaigns.
2026-10-05 — GST tax invoices for top-ups
Added
- A GST tax invoice for every top-up, emailed as a PDF to your organization's owners and admins and listed on the dashboard's Billing page. It carries your billing name, address and GSTIN, and charges CGST and SGST inside Madhya Pradesh or IGST anywhere else. Its QR code opens a page where anyone holding the invoice can check it and download the original. See Billing.
billing_details_required(422): a top-up started before your organization saved the billing name, address and state the invoice needs. Top-ups are started from the dashboard, which asks for them the first time. See the error catalog.
2026-10-05 — Calls stop at an empty wallet, campaigns stay inside your quota
Fixed
POST /v1/callsrefuses a live call the wallet cannot pay for, with402 insufficient_funds: when the balance is below ₹12, or while the wallet is on hold for a payment dispute. The error catalog and the billing page already said a call fails rather than being placed at zero; it is now true.detailscarriesbalancePaiseandminBalancePaise. Test-mode calls are unaffected.- A campaign pauses instead of failing recipients when the wallet runs dry. It
pauses with
pausedReason: "low_balance"(and emitscampaign.paused) even if you set noautoPauseBelowPaise, and the recipient it was about to call keeps its attempt. - A campaign never dials past your concurrency quota. Each tick it dials at most
the agent calls
GET /v1/limitssays are free, counting everything else running for your organization. Before, amaxConcurrentabove the quota had its overflow refused and those recipients settledfailed.
2026-10-02 — List totals, and searching calls by number
Added
-
searchonGET /v1/callsandGET /v1/calls/export.csv— digits of a phone number, found at either end of a call: the number it came from or the one it went to. Part of a number matches anywhere in it, and formatting is ignored —+91 98765 43210,09876543210and4321all work. -
meta.pagination.totalon the first page of every list — calls, campaigns and their recipients, compliance checks, evidence records, consent records, the suppression list and the wallet statement: how many results match your filters, counted up to 10,000. Until now only the suppression list and number search sent one. -
meta.pagination.totalCapped, sent withtotal:truewhen more than 10,000 results match. The suppression list's total is now counted the same way. -
Paging on two lists that stopped at a fixed number.
GET /v1/integrations/webhooks/deliveriesreturned the newest 50 deliveries andGET /v1/campaigns/{id}/compliancethe newest 500 checks, with no way to read further. Both takelimitandcursornow and carry a total. Called without them, they return what they always did.
Fixed
- Paging through rows created together. Rows written by one request — a bulk suppression upload, a campaign's recipient list — could be skipped by the next page (newest-first lists) or shown again (a campaign's recipients, oldest first). Every page now continues exactly where the last one stopped. See Pagination.
2026-10-01 — Choosing and buying numbers
Added
GET /v1/numbers/carriers— the carriers selling numbers right now. Pass one'sprovidertoGET /v1/numbers/availableorGET /v1/numbers/regionsto see that carrier alone.- A count on number search. The first page of
GET /v1/numbers/availablecarriesmeta.pagination.totalwhen every carrier searched can count what it lists. - When a number renews. Every offer carries
renewalCycleandrenewsAt, and every numberrenewalCycle.anniversaryrenews monthly on the day it was bought;calendar_month— VoiceLink, for numbers bought from today — runs its first period to the end of the month it was bought in, at the full monthly rental, and renews on the 1st. See Rent. confirmedTotalPaiseonPOST /v1/numbers/purchase, and the error it can return,price_changed: send the total your customer reviewed, and a price that has moved since is refused instead of charged.
2026-08-25 — First published
The initial /v1 contract: 92 operations an API key can call, 12 webhook
events, and 32 error codes.
Added
- Agents — create, publish, roll back, and read any published version. Every call pins the version that ran it.
- Phone numbers — search carrier inventory, buy, route to a Tone agent or your own stack, and read the rental state.
- Calls — place outbound, receive inbound, and read the detail record, transcript and recording.
- Campaigns — 20 operations covering recipients, pre-flight, launch, pacing, retries and outcomes.
- Compliance — the pre-dial gate as a standalone verdict API, a consent ledger, suppression lists, outcome ingestion and evidence packs.
- Knowledge bases — documents an agent answers from, with a retrieval preview that runs the same path a live turn runs.
- Wallet — balance, ledger and usage by category.
- Webhooks — endpoint management, per-endpoint secrets with 24-hour rotation overlap, delivery history and replay.
- Limits — request budget and both concurrency pools.
Conventions established
Idempotency-Key, required on number purchase and campaign launch.- Rate-limit headers on every keyed response, successes included.
doc_urlon every error, pointing at the catalog.- Every enum published as an open set — see Versioning.
How an entry gets written
The contract is diffed on every change:
pnpm --filter backend openapi:diff --markdownThat produces the mechanical half — what was added, and whether anything was
breaking. The prose is written by hand, because "new field agentVersion" is
not the same as "a call now records which version of the agent ran it, so a
finished call stays explainable after the prompt changes".