Skip to main content
VARTA

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.