Skip to main content
VARTA

Is there runnable example code for the VARTA API?

Yes. Four runnable examples live in this repository's examples/ directory, one per major shape of /v1 usage: a plain-text conversation, a phone call that actually dials, telephony provisioning, and a browser voice widget. Each is a complete, working project — fetch and the Node or browser standard library only, no @varta/* package to install — that you can download as a zip and run against your own VARTA instance in well under sixty seconds. The zips below are built from this same source at every deploy of this site, not hand-assembled once and left to drift, so what you download always matches what this page shows.

Prerequisites

Every example below needs the same three things:

  • A reachable VARTA instance and its base URL, including the /v1 prefix — e.g. https://your-varta-host/v1. Set it as VARTA_BASE_URL in each example's .env.
  • An agent id from the VARTA studio (VARTA_AGENT_ID). See Quickstart if you haven't built one yet.
  • Node 20 or later.

Each example also has its own .env.example to copy to .env, and its own README.md with a verified transcript of what happens when you run it — including what it prints when VARTA_BASE_URL is unset or unreachable, with no backend required to see that part.

01 — Text conversation CLI

Download varta-example-01-text-conversation-cli.zip

The fastest way to see the /v1 API work end to end: load an agent, type replies at a prompt, end the session. No audio, no telephony — proves the three-call shape from Quickstart (loadturnend) actually works against a real agent, with trace.layer (which engine layer decided each reply) and cost.total_inr (that turn's spend) printed next to every line the agent says.

for await (const rawLine of rl) {
  const text = rawLine.trim()
  if (text === '/quit') break
  if (!text) continue

  const turn = (await api(`/sessions/${sessionId}/turn`, {
    method: 'POST',
    body: JSON.stringify({ text }),
  })) as TurnResponse

  // trace.layer names which decision layer of the engine produced the reply (a keyword match,
  // a rule, the LLM) -- see /docs/api/sessions. cost is this turn's spend.
  console.log(`agent [${turn.trace.layer}, ${fmtCost(turn.cost)}]: ${turn.text}`)

  if (turn.ended) {
    console.log('\n(the agent ended the session on this turn)')
    break
  }
}

02 — Outbound call

Download varta-example-02-outbound-call.zip

Places a real phone call (POST /v1/calls with "dial": true) and polls it to completion. What it actually proves is idempotency: a --ref you pass on the command line becomes a stable Idempotency-Key, so running the script twice with the same --ref replays the first call's response (Idempotency-Replayed: true) instead of dialling the same person twice — and the same key with a different request body comes back 409 idempotency_key_reuse rather than silently merging or redialling. Read this one before you write any retry logic near POST /v1/calls.

const idempotencyKey = `outbound-call:${ref}`

console.log(`Placing call to ${TO} (Idempotency-Key: ${idempotencyKey})`)

// "dial": true is set explicitly here -- POST /v1/calls is prepare-only by default (it loads
// the agent, pre-fetches context and pre-synthesises the opening line, but never rings
// anyone). Only "dial": true, against a deployment with a configured trunk, places the real
// SIP dial. This example exists to show that path, so it always sets it.
const body: Record<string, unknown> = { agent_id: AGENT_ID, to: TO, dial: true }
if (FROM) body.from = FROM
if (TRUNK_ID) body.trunk_id = TRUNK_ID

const placed = (await api('/calls', {
  method: 'POST',
  headers: { 'Idempotency-Key': idempotencyKey },
  body: JSON.stringify(body),
})) as CallResponse

03 — Telephony provisioning

Download varta-example-03-provision-telephony.zip

Registers a SIP trunk, registers a DID number with VARTA, and binds that number to an agent for inbound — the dial plan a deployment needs before POST /v1/calls can place a real call, or before it can answer one. It also proves the distinction that trips up first-time integrators: POST /v1/numbers registers a number you already hold with a carrier, it does not purchase or provision anything — buy the DID from your carrier first.

const trunk = (await api('/trunks', {
  method: 'POST',
  headers: { 'Idempotency-Key': uuid() },
  body: JSON.stringify(trunkBody),
})) as Trunk
console.log(`  trunk id=${trunk.id} has_credentials=${trunk.has_credentials}`)

const numberRecord = (await api('/numbers', {
  method: 'POST',
  headers: { 'Idempotency-Key': uuid() },
  body: JSON.stringify({ number: NUMBER, trunk_id: trunk.id }),
})) as NumberRecord
console.log(`  number id=${numberRecord.id}`)

const bound = (await api(`/numbers/${encodeURIComponent(NUMBER!)}/bind`, {
  method: 'POST',
  headers: { 'Idempotency-Key': uuid() },
  body: JSON.stringify({ agent_id: AGENT_ID }),
})) as NumberRecord
console.log(`  ${bound.number} now bound to agent_id=${bound.agent_id}`)

04 — Browser voice widget

Download varta-example-04-browser-voice-widget.zip

A single web page with a mic button: press it, speak, hear the agent reply. It proves two things at once. First, that POST /v1/sessions/{id}/turn takes transcribed text, not audio — VARTA does not do speech recognition on this path, so this widget uses the browser's own Web Speech API to produce a transcript itself, and is careful about a real gotcha in doing so: Chrome commonly reports confidence: 0 on a final result, which is not the same signal as "no confidence available" to the engine's low-confidence gate, so a bare 0 is never forwarded as stt_confidence. Second, that a browser client has to keep its API key server-side: server.mjs is a small allowlisted proxy that attaches Authorization to exactly the three routes this widget calls — the browser itself never holds the key.

const sttConfidence = typeof confidence === 'number' && Number.isFinite(confidence) && confidence > 0
  ? confidence
  : undefined
void submitTurn(text, sttConfidence)

Download all four

Download varta-examples.zip — all four examples in one archive, each nested under its own directory inside a single top-level varta-examples/ folder (varta-examples/01-text-conversation-cli/, varta-examples/02-outbound-call/, and so on), so extracting it doesn't scatter four projects' worth of files into wherever you extracted it.