Skip to main content

Allow cookies so we can count page views, see which pages and campaigns bring people here, and measure our ads on Meta, Google and LinkedIn. Cookie policy

How do I list, inspect and load a VARTA agent?

An agent is what you built in the VARTA studio: a language model, a speech recogniser, a speech synthesiser, a voice and a conversation flow, bundled under one id. GET /v1/agents and GET /v1/agents/{agent_id} read that configuration back; POST /v1/agents/{agent_id}/load is where a conversation actually begins — it opens a session and returns the opening line with its audio already synthesised, so your code never assembles a pipeline or a greeting itself.

Tenant isolation on this page applies in enforce mode. The scoping described below — "visible to your tenant", and an id belonging to another tenant reported as not_found — is enforced only when the instance runs with auth_mode: "enforce". On a default instance that setting is "audit" (backend/app/core/config.py:26), and in audit mode require_tenant returns the resource without comparing tenants at all (backend/app/security/ownership.py:51-52). Object-level isolation is then observed but not enforced: because GET /v1/agents filters purely on that check (backend/app/api/v1/agents.py:90-102), on a default instance it lists every tenant's agents, not just yours. See Authentication.

List agents

GET /v1/agents

Returns every agent visible to your tenant, sorted by id.

curl "$VARTA_BASE_URL/agents" \
  -H "Authorization: Bearer $VARTA_API_KEY"
{
  "data": [
    {
      "id": "ag_412",
      "name": "Collections — Hindi",
      "language": "hi",
      "voice_id": "voice_7a1",
      "agent_name": "Priya",
      "agent_gender": "female",
      "llm": { "provider": "openai", "model": "gpt-4o-mini", "source": "agent" },
      "stt": { "provider": null, "source": "deployment_default" },
      "tts": { "provider": "elevenlabs", "voice_id": "voice_7a1", "source": "agent" },
      "steps": 9
    }
  ],
  "has_more": false,
  "next_cursor": null
}

llm, stt and tts each carry a source: "agent" when the agent overrides that provider, "deployment_default" when it falls back to whatever this deployment runs by default. A null provider with source: "deployment_default" is normal, not a misconfiguration — it means the agent doesn't pin one.

has_more and next_cursor are always false / null today: this endpoint does not yet paginate.

Errors: none specific to this request.

Get an agent

GET /v1/agents/{agent_id}
curl "$VARTA_BASE_URL/agents/ag_412" \
  -H "Authorization: Bearer $VARTA_API_KEY"

Returns the same shape as one item in the GET /v1/agents list above.

Errors: workflow_not_found when agent_id isn't a value this API ever issued, not_found when it's a well-formed id that doesn't exist for your tenant — including one that belongs to another tenant, which is deliberately reported the same way so a cross-tenant id can't be distinguished from a missing one.

Load an agent

POST /v1/agents/{agent_id}/load

Loading an agent is one call. It resolves the agent's model, speech recognition, speech synthesis, voice and flow, opens a session, and returns the opening line — already synthesised — along with filler clips and the resolved runtime stack.

curl -X POST "$VARTA_BASE_URL/agents/ag_412/load" \
  -H "Authorization: Bearer $VARTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customer_name": "Rahul", "context": {"order_id": "SO-4821"}}'

Every field in the body is optional. context is passed through to the pre-call context initialiser, so the opening line can already name the caller.

{
  "session_id": "se_9021",
  "agent_id": "ag_412",
  "opening": {
    "text": "Namaste Rahul, main Priya baat kar rahi hoon...",
    "audio_url": "https://.../opening_9021.mp3",
    "clips": [
      {
        "intent_key": "opening_greeting",
        "display_order": 0,
        "text": "Namaste Rahul, main Priya baat kar rahi hoon...",
        "audio_url": "https://.../opening_9021.mp3",
        "livekit_wav_url": null,
        "requires_user_input": false
      }
    ]
  },
  "filler_clips": {},
  "behavior_clips": {},
  "runtime": {
    "agent_name": "Priya",
    "language": "hi",
    "llm": { "provider": "openai", "model": "gpt-4o-mini", "source": "agent" },
    "stt": { "provider": null, "source": "deployment_default" },
    "tts": { "provider": "elevenlabs", "voice_id": "voice_7a1", "source": "agent" },
    "steps": 9
  },
  "ended": false
}

Hold on to session_id — it's what you send to every endpoint on the Sessions page next. filler_clips and behavior_clips are pre-synthesised clips your client can play opportunistically (a filler while waiting on a turn, a scenario-specific reaction); both are commonly empty objects and that's not an error, it just means this agent has none configured.

A clip object's documented fields are intent_key, display_order, text, audio_url, livekit_wav_url and requires_user_input. livekit_wav_url is a WAV-format rendition of the same clip — the telephony path plays this one — but it is populated for every caller regardless of channel, not only for SIP calls; it may be null. The runtime attaches other fields to clips internally (for example _played) — anything not listed here is implementation detail, not part of the contract.

Like every state-changing call under /v1, this endpoint honours an Idempotency-Key header — see Idempotency for the replay semantics; Calls explains why it matters most for a call that actually dials.

Errors: invalid_request when the body isn't a JSON object or context isn't, workflow_not_found when agent_id is malformed, not_found when it's a well-formed id this tenant doesn't own.