What you need
Everything below is regional. An agent, a number, a batch and a credit balance created against
https://api.in.talqing.com do not exist in https://api.us.talqing.com; the same token reaches both. See regions.
The build
1
Write the agent for an outbound conversation
An outbound call is a stranger’s phone ringing. The prompt has to carry three things a support agent’s prompt does not: who is calling, why, and how the person gets off the phone without a fight.Writes replace the whole config, so read the current one and send it back changed rather than sending the field you want to alter. See agents overview.
2
Personalize each call with the recipient's own userdata
Each row of a batch carries A field that is not in userdata resolves to nothing, so put the token where an empty value still leaves a sentence. Attach it as
to plus a flat map of strings that becomes that call’s session state, and {{userdata.field}} in the prompt and the greeting is substituted from it when the agent starts. One published agent, a different opening line per lead."Hi {{userdata.first_name}} — this is Maya from Northwind Tools" still reads if the name is missing; "Hi, am I speaking to {{userdata.first_name}}?" does not. Values are strings on purpose — a spreadsheet cell reading 007 is a reference number, not the integer seven. See userdata.Branching the opening on the call direction
If the same agent also answers inbound calls on that number, the greeting has to differ: outbound says who is calling and why, inbound does not. A greeting is one verbatim line and has no conditionals, so put the branch in anon_enter hook, which finishes before the greeting and whose writes to userdata the greeting then reads.Create this tool, publish it, and set the agent’s greeting to "{{userdata.opening}}":"on_enter": { "tool_id": "7a2e5b91-0c34-4d6f-8a12-b93f5c7e2d61" }.{{system_vars.direction}} is inbound or outbound and is empty on web calls and text conversations. See variables.3
Write the qualification back to your CRM
One tool, one capability. The model supplies what it learned as arguments; the tree posts them and says one line. The CRM’s token is a workspace secret, so the model never sees it and cannot put it in an argument.Two details worth understanding.
silent: true on the http operation hides the CRM’s response from the model — and because no operation in the tree can then hand the model anything, the tool is derived silent: the say line plays and the agent does not improvise a second sentence on top of it. And {{system_vars.now}} and {{system_vars.agent_phone_number}} are filled in by the platform, so the model is never asked to know the time or the number it called from. See the operation tree and templating.Attach it with "tools": [{ "tool_id": "3f8b0f4c-9a1e-4a7d-9c2b-1d5e6f70a821" }] and leave tool_version out — publishing the agent fills it in.4
Turn on post-call analysis
The tool writes what the agent was told. Analysis writes what a reader infers from the finished transcript, which is what makes a campaign readable without listening to four hundred calls. Add it to the agent’s config:Analysis is voice and video only and runs on the agent’s own LLM, so it needs no second provider key. It adds roughly 5% to the cost of a call and runs during call finalize, so its tokens land in the same bill. A call is skipped rather than analysed when it ended on a failure reason, when fewer than two caller turns happened, or when the spec produces nothing. See call analysis.
Analysis fields and userdata answer different questions, and one must not be used for the other.
userdata is what the agent knew — seeded from the recipient row, written by a tool, confirmed on the call. Analysis fields are what a model inferred afterwards by reading the transcript. Analysis results are never merged into userdata, deliberately: a guess must not overwrite a tool-confirmed value.So budget_band on the CRM write is an argument the model filled in while the person was on the line, and it is what you act on. budget in the analysis fields is a sentence a reader can scan. If a value has to be right, make it a tool argument. If it only has to be readable, make it an analysis field.5
Publish the agent
Publishing freezes the draft as an immutable version and pins each attached tool to the tool version live at that moment. Republishing the tool afterwards changes nothing until you publish the agent again.
6
Pick the number you dial from, and check its outbound flag
A batch dials from one number, named by The number the campaign dials from is also what decides how each
from_phone_number_id. That number has to be active on a carrier account that is ready, and it has to have can_outbound set — a number imported for inbound only is refused at create with this number is not enabled for outbound.to is parsed: numbers are normalized against the region of the dialling number, not a global default.7
Place one real call to yourself
Before the list, one call. This rings a real phone and is billed. There is no dry run. Use a number you own, and use a
POST /v1/calls/outbound runs the same published agent with the same userdata a batch row would carry, so it exercises the greeting, the tool and the analysis in one go.crm_id your CRM will accept and you can delete afterwards.8
Create the batch
Now the list. One request carries the policy and up to 10,000 recipients.In the dashboard this is Telephony → Outbound Calling → New batch, which takes the same fields and a pasted or uploaded list.The four numbers that decide how it behaves:
timezone is the batch’s own clock, and it interprets calling_window — so the window is the recipients’ working day, not the working day of whoever pressed the button.Test it
Before the list runs, prove each piece separately on the single call you placed.- The transcript.
GET /v1/calls/{session_id}returns the transcript with every tool call and its output, plus per-stage latency. Check the greeting was substituted, that the agent gave the way out inside the first three sentences, and thatrecord_qualificationwas called once rather than twice. - The CRM row. Look in your CRM, not at the tool’s response. The
httpoperation issilent, so a 200 with the wrong body looks identical to a correct write from the agent’s side. - The analysis. Read
analysis.status,analysis.outcomeandanalysis.fieldson the same call. If a field came back vague, that is the field’sdescriptionfailing, not the model — rewrite it and usePOST /v1/calls/{session_id}/analysis/previewto try new wording against the same transcript. Preview writes nothing and still costs a real LLM call. - A two-row batch to phones you own. Create the campaign with two of your own numbers and
max_concurrency: 1before you create it with four hundred. Everything about scheduling, retries and counters is the same shape at two rows as at four thousand.
Running it
next_dial_at is the field that tells “waiting for Monday” apart from “stuck”. It is null while the batch is actually dialling, while a person has it paused, and once it is over — all three of which status already tells you.
- Pausing stops claiming new recipients; calls already ringing or connected run to their end. Resuming carries on, and a batch whose
start_atis still in the future goes back toscheduledrather thanrunning— pausing and resuming is never a way to start early. - Adding rows to a running batch works:
POST /v1/calls/batches/{batch_id}/recipientsappends, and numbers the batch already holds are silently skipped and reported rather than rejected. Re-uploading the same CRM export never calls anyone twice. - The circuit breaker stops a batch after ten consecutive setup-style failures — a carrier fault, an unpublished agent, an expired credential. The count is rolling and any success resets it, and busy signals and unanswered phones never count towards it: a run of those is a phone list, not a fault.
- Running out of credit pauses the campaign rather than failing it. No attempt is spent on anybody,
failure_reasonsays the workspace is out of credits, and it resumes on its own once you top up. There is no button to press. - Cancel is final and there is no delete. A batch is the record of money spent.
What to watch
Turning the campaign into a qualified list, then, is two filters and a fetch: list the batch’s calls with
outcome=success, fetch each one, and keep the rows whose fit is strong or possible. The next_step field is what a salesperson reads first.
Where it falls short
- No answering-machine detection. Say it again because it shapes your numbers: voicemail is a completed, billed, never-retried call, and some fraction of your
completedcount is machines. Nothing on the platform can tell you which. - One batch is one agent, one number, one clock. There are no per-recipient overrides of anything but
userdata. Half a list needing a different agent, a different caller ID or a different language is a second batch. - The batch runs as the person who created it. Every dialling pass re-authorizes as that user. If they leave the workspace or drop below the EDITOR role, their campaign records a configuration failure on the next pass, and ten of those trip the breaker. Hand running campaigns over before somebody leaves.
- Calling law is yours to know. Consent, do-not-call registers, permitted calling hours, disclosure requirements and recording law differ by country and by state, and Talqing enforces none of them.
calling_windowis a scheduling feature, not a compliance one — it does not know a public holiday from a Tuesday. - Analysis is a reading, not a record. It is one LLM call over the transcript, with a 30-second timeout, three-valued on purpose so that a wrong number comes back
unknownrather than being forced into a verdict. Back a business decision with what a tool confirmed, not with what a summary suggested.
Next
Batch calling
Every status, the retry table, policy edits and pinning a version.
Call analysis
Outcome, fields, preview and backfilling calls you already have.
Webhooks
Get each finished call, with its analysis, pushed to your own system.