Vanira/Docs
v1.0

API Reference

v1.0

Build next-gen voice AI products on the Vanira Sovereign Engine. Manage agents, trigger outbound traffic, and embed real-time conversational intelligence with zero effort.

Start in 2 minutes

Live voice demo

Try a live voice demo

Production demos with embedded Vanira voice agents — same sites shown in our , plus our on-site refund workflow at .

To test with your agent: open the dashboard, copy your pk_live_* key, and use the API Playground panel on the right — or paste it into a starter repo.

Template agents

Clone a pre-built agent into your account. Make your own agents public via Agent → Share to share with other developers.

Refund & Returns Agent

E-commerce
web

Live camera inspection, guided return UI, and multimodal refund confirmation.

Kisan Support Agent

Agriculture
react-native · web

Farmer-facing welfare intake — live camera, forms, regional languages.

Live demo

Maths Tutor Agent

Education
web

Board-first tutoring with screen share, camera, and upload.

Live demo

Citizen Services Agent

Citizen access
web

Voice-guided portal navigation — search, dates, and forms in regional language.

Live demo

Starter repos

vanira-starter-web

Vite + React + VaniraCallBox — voice pill and presets in minutes.

vanira-starter-rn

React Native + PresetHostProvider + createReactNativeAI.

About the SDK

#
The Vanira SDK adds live AI voice, chat, presets, and client tools to your product.

Two paths — pick one

PathWhen to use
Widget embedNo-code / marketing sites — paste a script tag, Vanira renders the UI
npm SDKDevelopers building React, Next.js, Vue, or vanilla apps with their own UI

npm integration surfaces

SurfaceImportWhat you get
VaniraCallBox@vanira/sdkVoice pill + presets + custom tool hook
Headless@vanira/sdk/headlessVaniraClient + PresetRenderer — you build the call UI

What you need

  • Agent ID from the dashboard
  • Publishable key pk_live_* for browser code (or token inside the Vanira dashboard)
  • No backend URL — the SDK uses Vanira's cloud API automatically

Read next (in order)

1. Widget — script-tag embed
2. SDK Installationnpm install @vanira/sdk
3. API Keys & Configuration — keys and props reference
4. VaniraCallBox — drop-in React voice pill
5. Build Your Own UI — headless VaniraClient
6. Preset Handler — built-in UI tools (forms, calendar, navigate, …)
7. Custom Tool Handler — your own client-side tools
8. Client-Side Events / Server-Side Events — lifecycle and data-channel events
9. Session Continuity — resume calls across refresh

React Native

Mobile apps use a separate package — see React Native SDK section below (starts with About the RN SDK).

Widget Embed

#
Use the widget embed when you want Vanira's full floating UI — chat, voice, presets — with zero npm install.
Copy the snippet from Agent → Widget → Embed in the dashboard:
Code examplehtml
1<script2  src="https://unpkg.com/@vanira/sdk@latest/dist/vanira-sdk.js"3  data-widget-id="YOUR_WIDGET_ID"4  data-pk-key="pk_live_YOUR_PUBLISHABLE_KEY"5  defer6></script>
The script bootstraps a <vanira-convai> custom element on document.body. It survives SPA route changes because it lives outside your React/Vue tree.

SPA navigation

If your agent uses the vanira_navigate preset, add a listener so in-app routing stays in-SPA:
Code examplejavascript
1// Add once on your site (same page as the Vanira widget).2// Required when your agent uses the vanira_navigate preset.3window.addEventListener('vanira:navigate', (event) => {4  const path = event.detail.path; // e.g. "/pricing" or "/docs#section"5 6  // Option A — multi-page site or simple fallback:7  window.location.assign(path);8 9  // Option B — SPA router (pick one that matches your stack):10  // router.push(path);              // React Router: useNavigate()11  // navigate(path);                 // Vue Router12  // router.push(path);              // Next.js App Router13 14  event.detail.handled = true; // required — tells the SDK navigation succeeded15});
When the agent calls vanira_navigate, the SDK dispatches a browser event instead of forcing a full page reload:
TargetSDK behavior
Same-origin path (e.g. /pricing, /docs#faq)Fires vanira:navigate with detail.pathyour site must handle it
External URL (different origin)Opens in a new tab automatically — no listener needed
  • *SPA sites (React, Vue, Next.js, etc.) must register a vanira:navigate listener** that routes with your framework and sets event.detail.handled = true. Without it, same-origin navigation fails with status: cancelled and the console shows: No SPA listener handled vanira:navigate.
  • *Blocking tool:** the AI pauses until the SDK sends client_tool_result. Success payload: { status: 'success', navigated_to, target_url }. Server interrupt (clearAudio / client_tool_cancel): { status: 'interrupted', reason, target_url }.
  • *Multi-page sites** can use window.location.assign(event.detail.path) in the listener, or the same pattern as a fallback.

When to use npm instead

Choose VaniraCallBox or headless `VaniraClient` when you need your own call button, layout, or styling — not Vanira's floating widget chrome.

Powered by Vanira

Free-tier widget chat shows "Technology Powered by Vanira AI" in the UI — a discovery path for other developers. Paid plans can request branding removal.

SDK Installation

#
Install @vanira/sdk when you want VaniraCallBox or a headless integration with your own UI.
Code examplebash
1npm install @vanira/sdk2# or3yarn add @vanira/sdk

Imports

Use caseImport
Drop-in voice pillimport { VaniraCallBox } from '@vanira/sdk'
Your own call UIimport { VaniraClient, PresetRenderer } from '@vanira/sdk/headless'
Low-level (same class)import { VaniraClient } from '@vanira/sdk'

Requirements

  • Agent ID + publishable key pk_live_*
  • HTTPS in production (microphone access)
  • Start calls from a user click on mobile browsers
> For a no-build script-tag embed, see Widget Embed — no npm install needed.

API Keys & Configuration

#

API keys

KeyWhereUse
pk_live_*Browser, widget embed, VaniraCallBoxWeb calls only — safe for frontend
sk_live_*Your backend onlyFull API access — never expose in browser code
Pass apiKey: 'pk_live_…' in browser integrations. The SDK provisions the call and opens WebRTC — no backend URL, no manual REST calls.
For the script-tag widget, use data-pk-key. Inside the Vanira dashboard, VaniraCallBox can use token (Bearer JWT) instead of apiKey.

VaniraCallBox props

PropRequiredDescription
agentIdYesAgent UUID from dashboard
apiKeyYes*pk_live_* for external sites
tokenYes*Dashboard Bearer JWT (*one of apiKey or token)
onNavigateRecommendedSPA router hook for vanira_navigate preset
onCustomToolAs neededHandler for custom client tools (not presets)
sessionBehaviorNo'new' (default) or 'continue'
autoStartNoDefault false — tap-to-talk
onMinimize / onCloseNoHost UI callbacks

VaniraClient props

PropRequiredDescription
agentIdYesAgent UUID
apiKey or tokenYes*Auth (*unless serverUrl + callId + iceServers pre-supplied)
sessionBehaviorNo'new' or 'continue'
prospectId / callIdNoManual session resume
trackRouteContextNoDefault true — auto page-route context sync
onConnected / onDisconnected / onErrorRecommendedLifecycle callbacks
onClientToolCallAs neededAll client tool calls (presets + custom)
onTranscriptionNoUser speech-to-text stream
Use constructor callbacks or .on(event) + start() — same class, two styles.

Example

Code exampletypescript
1// Browser2const client = new VaniraClient({3  agentId: 'YOUR_AGENT_ID',4  apiKey: 'pk_live_<uuid>',5  onConnected: () => setStatus('connected'),6});7await client.connect();

VaniraCallBox

#
VaniraCallBox is the fastest npm integration — voice pill, presets, and a hook for custom tools.
Only agentId + apiKey required. Mount above your router so SPA navigation does not tear down the call.
Code exampletypescript
1import { VaniraCallBox } from '@vanira/sdk';2import { useNavigate } from 'react-router-dom';3 4function AppShell() {5  const navigate = useNavigate();6 7  return (8    <>9      <YourRoutes />10      <VaniraCallBox11        agentId={import.meta.env.VITE_VANIRA_AGENT_ID}12        apiKey={import.meta.env.VITE_VANIRA_PK_KEY}13        onNavigate={(path) => navigate(path)}14        onCustomTool={(call, client) => {15          if (call.name === 'say_hi') {16            showGreetingPopup();17            if (call.execution_mode !== 'fire_and_forget') {18              client.sendToolResult(call.tool_call_id, { status: 'success' });19            }20          }21        }}22      />23    </>24  );25}

Rules

  • Presets (form, calendar, navigate, …) — automatic, no code
  • Custom tools — implement in onCustomTool only
  • Do not mount inside a single page behind {showCall && …} on multi-route SPAs

Custom call button (optional)

Code exampletypescript
1<VaniraCallBox agentId="..." apiKey="...">2  {({ status, startCall, endCall }) =>3    status === 'connected'4      ? <button onClick={endCall}>Hang up</button>5      : <button onClick={startCall}>Talk to us</button>6  }7</VaniraCallBox>

Build Your Own UI

#
Use the headless path when you want full control over buttons, layout, and status UI.
Import from @vanira/sdk/headless:
Code exampletypescript
1import { useRef } from 'react';2import {3  VaniraClient,4  PresetRenderer,5  type PresetRendererHandle,6} from '@vanira/sdk/headless';7 8const presetRef = useRef<PresetRendererHandle>(null);9let client: VaniraClient | null = null;10 11async function startCall() {12  client = new VaniraClient({13    agentId: 'YOUR_AGENT_ID',14    apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',15    onConnected: () => setStatus('connected'),16    onDisconnected: () => setStatus('idle'),17    onClientToolCall: (raw) => presetRef.current?.enqueueToolCall(raw),18  });19  await client.connect();20}
Code exampletypescript
1<PresetRenderer ref={presetRef} client={client} onCustomTool={handleCustomTool} />

Callbacks or events

Code exampletypescript
1// Style A — constructor callbacks + connect()2await client.connect();3 4// Style B — .on() listeners + start()5client.on('connected', () => setStatus('connected'));6client.on('tool_call', (tc) => presetRef.current?.enqueueToolCall(tc));7await client.start();
Start from a button click. Show live UI on onConnected / connected — not on onSessionStarted (provisioning only).

Preset Handler

#
  • *Presets** are built-in client tools the SDK renders automatically — forms, calendars, uploads, navigation, DOM actions, and more.
With VaniraCallBox, presets work with zero code. With headless VaniraClient, mount PresetRenderer and enqueue tool calls via presetRef.enqueueToolCall() or onClientToolCall.
  • *Dashboard: Agent → Tools → Create tool → Client → pick a preset tile. Full `POST /tools` bodies are in the Tools → Preset Tools** doc.
Preset IDUIMode
vanira_formData Collection Formblocking
vanira_calendarDate & Time Pickerblocking
vanira_uploadFile Uploadblocking
vanira_cameraCamera Capturefire_and_forget
vanira_navigateNavigate to Route — requires vanira:navigate listener on SPAsblocking
vanira_highlight_elementHighlight Elementblocking
vanira_click_elementClick Elementblocking
vanira_select_optionSelect Dropdown Optionblocking
vanira_set_dateSet Date Fieldblocking
vanira_type_textDOM Typing Simulationblocking
vanira_erase_textWhiteboard / DOM Eraseblocking
vanira_erase_drawErase Drawing Boardblocking
vanira_drawChalkboard Shape Drawingblocking
vanira_live_visionLive Vision (Streaming Camera)fire_and_forget
vanira_close_live_cameraStop Live Camerablocking
vanira_live_screenLive Screen Sharefire_and_forget
vanira_close_live_screenStop Live Screen Shareblocking
vanira_clip_regionPage Region Clipblocking
vanira_tab_screenshotTab Screenshotblocking
vanira_screen_inkScreen Inkblocking
vanira_screen_cursorScreen Cursorblocking
vanira_screen_clickScreen Clickblocking
vanira_clear_screen_overlayClear Screen Overlayblocking
vanira_page_scanPage Scanblocking
vanira_point_atPoint Atblocking
vanira_outline_targetsOutline Targetsblocking
vanira_clear_guideClear Guideblocking
  • *Blocking presets (most): the AI waits until the SDK calls `sendToolResult()`. fire_and_forget**: vanira_camera, vanira_live_vision.
Unknown tool calls (no matching preset) go to onCustomTool.

Navigate preset — host-site setup

When the agent calls vanira_navigate, the SDK dispatches a browser event instead of forcing a full page reload:
TargetSDK behavior
Same-origin path (e.g. /pricing, /docs#faq)Fires vanira:navigate with detail.pathyour site must handle it
External URL (different origin)Opens in a new tab automatically — no listener needed
  • *SPA sites (React, Vue, Next.js, etc.) must register a vanira:navigate listener** that routes with your framework and sets event.detail.handled = true. Without it, same-origin navigation fails with status: cancelled and the console shows: No SPA listener handled vanira:navigate.
  • *Blocking tool:** the AI pauses until the SDK sends client_tool_result. Success payload: { status: 'success', navigated_to, target_url }. Server interrupt (clearAudio / client_tool_cancel): { status: 'interrupted', reason, target_url }.
  • *Multi-page sites** can use window.location.assign(event.detail.path) in the listener, or the same pattern as a fallback.

DOM presets — route field

For vanira_click_element, vanira_select_option, vanira_set_date, vanira_type_text, and vanira_erase_text, set client_fields.route to the SPA path where the target element lives (e.g. /checkout). If the user is on a different page, the SDK dispatches vanira:navigate first, waits for the route (and element when possible), then clicks/types/erases. Requires the same vanira:navigate listener as the Navigate preset on SPA sites.
> API bodies: see Tools → Preset Tools for copy-paste POST /tools JSON for every preset.

React Integration Example

Code exampletypescript
1import { useEffect, useState } from 'react';2import { VaniraClient, PresetRenderer } from '@vanira/sdk';3 4function App() {5  const [client] = useState(() => new VaniraClient({6    agentId: 'YOUR_AGENT_ID',7    apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY'8  }));9  const [activeToolCall, setActiveToolCall] = useState(null);10 11  useEffect(() => {12    client.on('tool_call', (toolCall) => {13      setActiveToolCall(toolCall);14    });15    16    client.start();17    return () => client.stop();18  }, [client]);19 20  return (21    <div>22      <MainDashboard />23 24      {/* Mount the PresetRenderer to automatically handle forms, calendars, etc. */}25      {activeToolCall && (26        <PresetRenderer27          client={client}28          toolCall={activeToolCall}29          onCustomTool={(toolCall) => {30            console.log('Handle your custom tool:', toolCall.name);31          }}32        />33      )}34    </div>35  );36}

Custom Tool Handler

#
Custom client tools are actions you implement in app code — popups, navigation side-effects, API calls from the browser. They are not SDK presets (form, calendar, navigate, etc.).
Create them in the dashboard: Agent → Tools → New tool → Client → Custom.

Two data layers (do not confuse them)

LayerDashboard sectionWho fills itWhere it lands in code
1. Agent parameters*Agent parameters*The AI extracts from the conversationTool schema only — tells the AI what to collect
2. Frontend payload*Frontend payload*You map keys → {{param}} or static valuescall.arguments in onCustomTool
  • *Agent parameters** define the conversation contract (e.g. customer_name, order_id).
  • *Frontend payload** (client_fields in the API) defines what your app receives. Use {{param_name}} for dynamic agent values or plain strings for static fields.

Dashboard example

  • *Agent parameters**
  • customer_name (string, required) — "Person's name from the conversation"
  • *Frontend payload**
Payload keyValue
name{{customer_name}}
sourcewebsite
  • *At runtime** your handler receives:
Code examplejson
1{2  "name": "Teja",3  "source": "website"4}
If you omit custom payload rows, each agent parameter is auto-mapped to the same key in call.arguments.

Execution mode

Set in the dashboard when creating the tool:
ModeAI behaviorYour code
blockingPauses until sendToolResult()Must call client.sendToolResult(tool_call_id, result)
fire_and_forgetKeeps speakingNo result required

VaniraCallBox handler

Code exampletypescript
1<VaniraCallBox2  agentId="YOUR_AGENT_ID"3  apiKey="pk_live_YOUR_PUBLISHABLE_KEY"4  onCustomTool={(call, client) => {5    const { name, arguments: args, tool_call_id, execution_mode } = call;6 7    if (name === 'greet_user') {8      openGreetingModal(args.name); // args.name from frontend payload mapping9 10      if (execution_mode !== 'fire_and_forget' && tool_call_id) {11        client.sendToolResult(tool_call_id, {12          status: 'success',13          message: 'Greeting shown',14        });15      }16    }17  }}18/>

API equivalent (POST /tools)

Code examplejson
1{2  "name": "greet_user",3  "description": "Show a personalized greeting popup when the user says hello",4  "type": "client",5  "execution_mode": "blocking",6  "channels": ["voice_web"],7  "parameters": [8    {9      "name": "customer_name",10      "type": "string",11      "description": "The person's name from the conversation",12      "required": true13    }14  ],15  "client_fields": {16    "name": "{{customer_name}}",17    "source": "website"18  }19}
Presets use client_fields.preset_id — handled automatically by PresetRenderer, not onCustomTool.

Tool call payload

FieldDescription
nameTool name or ref_code
argumentsResolved frontend payload your app reads
tool_call_idID for sendToolResult() / sendToolError()
execution_modeblocking or fire_and_forget
The SDK auto-sends client_tool_ack within ~2.3s — you do not ack manually.

On error or cancel

For blocking tools, call sendToolError(tool_call_id, message) when the operation fails so the agent can recover:
Code exampletypescript
1try {2  await bookSlot(args.date);3  client.sendToolResult(tool_call_id, { status: 'success' });4} catch (e) {5  client.sendToolError(tool_call_id, e.message || 'Booking failed');6}

Client-Side Events

#
  • *Client-side events** are callbacks the SDK fires in your browser — connection lifecycle, transcription, tool calls, and media tracks.
Use constructor callbacks (onConnected, …) or .on('connected', …) + start() — same events either way.
Event / callbackWhen it fires
onSessionStarted / session_startedSession provisioned — not live yet
onConnected / connectedWebRTC live — show your "connected" UI here
onDisconnected / disconnectedCall ended
onError / errorConnection or permission failure
onTranscription / transcriptionUser speech-to-text (isFinal flag)
onLocalStreamMicrophone stream ready
onRemoteTrackAgent audio/video track arrives
onClientToolCall / tool_callAI requested a browser action
> Common mistake: Showing "connected" on onSessionStarted. Wait for onConnected.

VaniraClient Example

Code exampletypescript
1const client = new VaniraClient({2  agentId: 'YOUR_AGENT_ID',3  apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',4 5  onSessionStarted: ({ prospectId, callId, serverUrl }) => {6    // Phase 1 — provisioned, still connecting to worker7    console.log('Provisioned:', { prospectId, callId, serverUrl });8    setStatus('connecting');9  },10 11  onConnected: () => {12    // Phase 2 — live (Talk to Agent connected state)13    setStatus('connected');14  },15 16  onDisconnected: () => setStatus('idle'),17 18  onError: (error) => {19    console.error('Connection error:', error);20    setStatus('error');21  },22 23  onTranscription: (text, isFinal) => {24    // isFinal = true means committed utterance.25    setTranscript(text);26  },27 28  onLocalStream: (stream) => {29    localAudioDebugRef.current.srcObject = stream;30  },31 32  onRemoteTrack: (track, stream) => {33    if (track.kind === 'audio') {34      audioElement.srcObject = stream;35      audioElement.play();36    }37  },38 39  onClientToolCall: (toolCall) => {40    // See "Client Tool Calls" section for full usage41    console.log('AI wants to:', toolCall.name, toolCall.arguments);42  }43});

Server-Side Events

#
  • *Server-side events are messages your app sends to the agent** over the WebRTC data channel.

High-level methods (preferred)

MethodPurpose
sendContextUpdate(data)Silent UI state sync (page, cart, map location)
sendActionTrigger(name, data)User action that should interrupt and get a spoken response
triggerActionInterrupt()Cut agent speech before an action trigger
sendToolResult(id, result)Reply to a blocking client tool
sendToolError(id, message)Report tool failure to the agent
uploadMedia(file, reason)Vision upload during a live call
Route changes during a call are synced automatically (trackRouteContext, default on).

Low-level: sendEvent()

For protocol-level signals without a wrapper:
Code exampletypescript
1client.sendEvent('client_live_camera_started', { resolution: '720p' });2client.sendEvent('client_live_camera_stopped');
ParameterRequiredDescription
eventYesEvent name string
dataNoJSON payload merged into the message

Session Continuity

#
### Why Session Continuity?
WebRTC connections end when a page refreshes or a component unmounts. Session continuity lets you reconnect with the same user identity and conversation context instead of creating a completely unrelated call.
The SDK stores prospectId and callId in browser storage after a call starts. With sessionBehavior: 'continue', the next connect() reuses that context.

Storage Keys

KeyMeaning
vanira_prospect_idThe user/prospect identity used across chat and voice
vanira_latest_call_idThe latest web-call session ID
Both keys are written to sessionStorage and localStorage when the SDK creates a call.

Configuration Reference

  • sessionBehavior: 'new': start a fresh call. This is the default.
  • sessionBehavior: 'continue': reuse stored or explicitly supplied prospectId and callId.
  • prospectId: pass this when you want to bind the call to your own user/contact record.
  • callId: pass this if your app stores and restores call sessions manually.
  • onSessionStarted: use this callback to persist or display the resolved prospectId, callId, and serverUrl.

React Integration Example

Below is a complete, production-ready React component handling WebRTC initialization, session continuation, and cleaning up state on component unmount.
Code exampletypescript
1import React, { useEffect, useState, useRef } from 'react';2import { VaniraClient } from '@vanira/sdk';3 4export function VoiceCallWidget() {5  const [status, setStatus] = useState<'idle' | 'connecting' | 'connected' | 'disconnected'>('idle');6  const [sessionInfo, setSessionInfo] = useState<{ callId: string; prospectId: string } | null>(null);7  const clientRef = useRef<VaniraClient | null>(null);8 9  const startCall = async () => {10    setStatus('connecting');11    12    clientRef.current = new VaniraClient({13      agentId: 'YOUR_AGENT_ID',14      apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY', // Browser-safe publishable key15      sessionBehavior: 'continue',           // Attempt to continue session on page load/refresh16      17      onSessionStarted: ({ callId, prospectId }) => {18        setSessionInfo({ callId, prospectId });19        console.log('Provisioned (Phase 1):', { callId, prospectId });20      },21      onConnected: () => {22        setStatus('connected');23      },24      onDisconnected: () => {25        setStatus('disconnected');26        setSessionInfo(null);27      },28      onError: (err) => {29        console.error('Call Error:', err);30        setStatus('idle');31      }32    });33 34    try {35      await clientRef.current.connect();36    } catch (e) {37      console.error('Failed to start call', e);38      setStatus('idle');39    }40  };41 42  const endCall = () => {43    if (clientRef.current) {44      clientRef.current.disconnect();45      clientRef.current = null;46    }47    setStatus('idle');48  };49 50  // Safe cleanup when component unmounts51  useEffect(() => {52    return () => {53      if (clientRef.current) {54        clientRef.current.disconnect();55      }56    };57  }, []);58 59  return (60    <div className="p-4 border rounded-lg bg-zinc-900 text-white">61      <p>Status: {status}</p>62      {sessionInfo && (63        <p className="text-xs text-zinc-400">Call ID: {sessionInfo.callId}</p>64      )}65      {status === 'connected' ? (66        <button onClick={endCall} className="bg-red-500 px-4 py-2 rounded">End Call</button>67      ) : (68        <button onClick={startCall} disabled={status === 'connecting'} className="bg-emerald-500 px-4 py-2 rounded">69          {status === 'connecting' ? 'Connecting...' : 'Start / Resume Call'}70        </button>71      )}72    </div>73  );74}

Context Update

#
Use context updates for passive state sync. They tell the agent what the user is currently seeing or doing without interrupting the agent's current speech.
Good context updates are small, factual snapshots: current page, selected product, cart total, active map location, form step, account status, or the visible error message. The agent uses this context the next time it responds.
Use sendContextUpdate() or the updateContext() alias on VaniraClient.

Automatic page route sync (built-in)

When a call is live, the SDK automatically sends client_context_update for page navigation — no extra code required:
EventPayload highlights
Call connectsuser_action: call_started_on_page, current_route, current_page
User navigatesuser_action: user_navigated, previous_route, current_route
Detection covers history.pushState / replaceState, popstate, hashchange, vanira:navigate, and a lightweight location poll for SPA routers.
Set trackRouteContext: false on VaniraClient to disable. Default is on.

Code Example

Code exampletypescript
1// User navigated to a pricing page.2client.sendContextUpdate({3  active_page: '/dashboard/pricing',4  customer_tier: 'gold',5  last_viewed_item: 'Premium Plan'6});7 8// Map demo: user panned the map. Debounce this in production.9map.on('moveend', async () => {10  const center = map.getCenter();11  const placeName = await reverseGeocode(center.lat, center.lng);12 13  client.sendContextUpdate({14    active_map_location: placeName,15    user_action: 'panning_map'16  });17});18 19// Alias:20client.updateContext({21  active_page: '/checkout',22  cart_total: 149.9923});

Action Trigger

#
Use action triggers when the user does something important and the agent should respond immediately.
With VaniraClient, call triggerActionInterrupt() first to cut current agent speech, then call sendActionTrigger() with an action name and a structured payload. Or use triggerInterrupt(actionName, data) — it sends both events in the correct order.
Do not call this immediately after uploadMedia(). Media uploads already notify the agent through client_media_update, and sending another interrupt can make the agent respond twice.

When to use this

  • User clicks an important CTA
  • User selects a product, location, plan, or appointment
  • User submits a form outside a preset
  • Your app navigates to a new page and you want an immediate spoken response

Code Example

Code exampletypescript
1// VaniraClient: interrupt, then send the action.2client.triggerActionInterrupt();3client.sendActionTrigger('map_click', {4  location: 'Tokyo, Japan',5  prompt: 'User clicked on Tokyo. Tell them 2 interesting facts about Tokyo immediately.'6});7 8// Or use the combined alias:9client.triggerInterrupt('plan_selected', {10  plan: 'Enterprise',11  prompt: 'The user selected Enterprise. Explain the next onboarding step.'12});

Interrupt Audio Only

#

Interrupt Audio Only

Use this capability when you want to immediately cut off the AI agent's active speech *without* sending a client action event trigger.
This is extremely useful when the user is about to take an action where the SDK or another flow will notify the agent automatically (such as performing a media upload or triggering a system-level transfer), and you want to prevent the agent from talking over the user or creating double response loops.
Call triggerActionInterrupt() to cut current agent speech, or interruptAudioOnly() for audio-only interrupt.

Code Example

Code exampletypescript
1// Cut agent speech right before initiating a custom file upload flow2document.getElementById('upload-area').addEventListener('dragenter', () => {3  client.interruptAudioOnly();4});5 6// Or the lower-level interrupt:7client.triggerActionInterrupt();

Ending a Call

#
End the live session when the user hangs up, closes your call UI, or navigates away.
Call disconnect() or stop() — both release the microphone, close the data channel, close the peer connection, and emit a disconnected event.

Code Example

Code exampletypescript
1client.disconnect();2client = null;3 4// React cleanup5useEffect(() => {6  return () => {7    clientRef.current?.disconnect();8    clientRef.current = null;9  };10}, []);

Error Handling

#
Most SDK failures happen before the call is fully connected: invalid keys, blocked microphone permission, missing serverUrl, failed /calls/create (Phase 1), or WebRTC/ICE failure reaching the worker (Phase 2).
If you only see POST /calls/create in the network tab, Phase 1 succeeded but Phase 2 did not — check onError, microphone permission, and worker POST …/webrtc responses.
Always implement onError and treat it as a user-facing state. Also clean up the client when a connection attempt fails so the next retry starts from a fresh peer connection.

Common Errors

SymptomLikely causeWhat to do
Only POST /calls/create in network tabPhase 2 failed (mic, worker SDP, ICE)Check onError; call connect() from button click; allow microphone
onSessionStarted fires but never onConnectedStuck in Phase 2Check worker /webrtc POST response and ICE; see console [WebRTC] logs
serverUrl is missingNo apiKey and no manual worker URLPass apiKey, or pass serverUrl and callId from your backend
createCall failed (401/403)Invalid key, wrong scope, or origin mismatchCheck key type and origin setting
Microphone permission deniedBrowser blocked mic accessStart from a user click and show permission guidance
DataChannel not openSending too early or after disconnectWait for onConnected before calling context/actions/uploads
Audio autoplay blockedBrowser policyStart calls from a user gesture and keep audio element playback user-initiated

Retry Pattern

Code exampletypescript
1import { VaniraClient } from '@vanira/sdk';2 3let client: VaniraClient | null = null;4 5async function startCall() {6  client?.disconnect();7 8  client = new VaniraClient({9    agentId: 'YOUR_AGENT_ID',10    apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',11    onConnected: () => setStatus('connected'),12    onDisconnected: () => setStatus('idle'),13    onError: (error) => {14      console.error('Vanira call failed:', error);15      setStatus('error');16      client?.disconnect();17      client = null;18    },19  });20 21  setStatus('connecting');22  await client.connect();23}

Best Practices

  • Disable your "Start call" button while status is connecting or connected.
  • Call disconnect() or stop() during React unmount.
  • Do not call connect() twice on the same client.
  • Do not call context, action, or upload methods before the connection is open.
  • Keep sk_live_* keys out of browser code.

Preset Session Continuity

#
### Why Preset Session Continuity?
Voice session continuity restores the call identity, but a browser refresh still clears React component state. If a form, calendar, or upload dialog is active when the page refreshes, store the active tool-call payload yourself and restore it on mount.
This pattern stores the latest preset tool call in sessionStorage. It restores the dialog shell after reload; for fully restoring half-filled form inputs, store those form values separately in your app state.

React Continuity Implementation

Use this alongside sessionBehavior: 'continue' for the voice session.
Code exampletypescript
1import { useEffect, useState } from 'react';2import { VaniraClient, PresetRenderer } from '@vanira/sdk';3 4function App() {5  const [client] = useState(() => new VaniraClient({ 6    agentId: 'YOUR_AGENT_ID',7    apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',8    sessionBehavior: 'continue'9  }));10 11  // 1. Initialize activeToolCall from sessionStorage if it exists12  const [activeToolCall, setActiveToolCall] = useState(() => {13    const saved = sessionStorage.getItem('vanira_active_preset');14    return saved ? JSON.parse(saved) : null;15  });16 17  useEffect(() => {18    client.on('tool_call', (toolCall) => {19      // 2. Cache the active tool call in sessionStorage20      sessionStorage.setItem('vanira_active_preset', JSON.stringify(toolCall));21      setActiveToolCall(toolCall);22    });23    24    client.start();25    return () => client.stop();26  }, [client]);27 28  const clearPreset = () => {29    // 3. Clear when your flow is complete, or when the user dismisses your restored UI30    sessionStorage.removeItem('vanira_active_preset');31    setActiveToolCall(null);32  };33 34  return (35    <div>36      <MainDashboard />37 38      {activeToolCall && (39        <button onClick={clearPreset}>Clear restored preset</button>40      )}41 42      {activeToolCall && (43        <PresetRenderer44          client={client}45          toolCall={activeToolCall}46        />47      )}48    </div>49  );50}

Full Example (Map)

#
A complete integration example using all advanced SDK features together — client tool calls, context updates, and action triggers — based on the Vanira Map Assistant demo.
The agent can:
  • Navigate the map via show_location_map tool call (AI to UI)
  • Receive click context via action trigger (UI to AI, interrupts)
  • Track pan context via context update (UI to AI, silent)

Code Example

Code exampletypescript
1import { VaniraClient } from '@vanira/sdk';2 3let client: VaniraClient | null = null;4 5async function startMapSession(agentId: string) {6  // agentId + apiKey: the SDK handles call creation and WebRTC setup.7  client = new VaniraClient({8    agentId,9    apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',10    onConnected:     () => setStatus('connected'),11    onDisconnected:  () => setStatus('idle'),12    onTranscription: (text, isFinal) => updateTranscript(text, isFinal),13 14    // AI to UI: agent wants to show a location on the map.15    onClientToolCall: (toolCall) => {16      if (toolCall.name === 'show_location_map') {17        geocode(toolCall.arguments.query).then(success => {18          if (toolCall.execution_mode === 'blocking') {19            client?.sendToolResult(toolCall.tool_call_id, { success });20          }21        });22      }23    }24  });25 26  await client.connect(); // pre-flight + WebRTC handled internally27 28  // 3. UI to AI (silent): sync map viewport to agent every second after pan.29  map.on('moveend', debounce(async () => {30    const place = await reverseGeocode(map.getCenter());31    client?.sendContextUpdate({ active_map_location: place, user_action: 'panning' });32  }, 1000));33 34  // 4. UI to AI (interrupt): map click forces immediate AI response.35  map.on('click', async (e) => {36    const place = await reverseGeocode(e.latlng);37    client?.triggerActionInterrupt();38    client?.sendActionTrigger('map_click', {39      location: place,40      prompt: `User clicked ${place}. Tell them 2 facts about it immediately.`41    });42  });43}

Agent & Human Transfers

#
Vanira supports two common handoff patterns for live conversations.
### 1. Human Transfer (SIP Referral)
In telephony calls, the Human Transfer tool triggers a standard SIP REFER to your configured fallback number. The AI agent immediately disconnects once the transfer is initiated.
### 2. Agent Transfer (Context Switch)
Switch the user to a different AI agent without ending the session. This is perfect for multi-stage workflows (e.g., qualifying a lead with one agent, then switching to a "Closing" agent).
For web calls, the old WebRTC session should be treated as ended. When onDisconnected fires, create a new VaniraClient with the next agent ID returned by your transfer flow and call connect() again.

Upload Media (Vision)

#

Live Multimodal Vision

During an active voice call, users can upload an image or PDF with client.uploadMedia(). The SDK uploads the file to the active media server and then sends a client_media_update event over the WebRTC data channel so the agent can process the new visual context.
Do not send a separate action trigger after upload. The media update is the notification the backend expects.

Parameters

ArgumentTypeRequiredDescription
file`FileBlob`YesThe file object to upload. Supported by the high-level SDK: JPEG, PNG, GIF, WEBP, BMP, and PDF up to 50 MB.
reasonstringYesCategory tag (e.g. 'kyc_document', 'error_screenshot'). Tells your backend webhook how to process this upload.
messagestringNoOptional text question or message to accompany the file (e.g. "What does this line item mean?").
interruptFirstbooleanNoAvailable on VaniraClient.uploadMedia(). Cuts current audio before upload without sending a duplicate action trigger.

Critical Anti-Patterns to Avoid

> [!WARNING]
> Do NOT trigger manual action interrupts after calling `uploadMedia()`.
>
> The SDK already notifies the AI with client_media_update. If you manually call client.triggerActionInterrupt() or client.sendActionTrigger() immediately after uploading, you can create duplicate responses.

React File Upload Example

Here is how to implement a drag-and-drop or file input upload element during an active voice session:
Code exampletypescript
1import React, { useRef, useState } from 'react';2import { VaniraClient } from '@vanira/sdk';3 4interface UploadProps {5  client: VaniraClient | null;6}7 8export function VisionUploadButton({ client }: UploadProps) {9  const [isUploading, setIsUploading] = useState(false);10  const fileInputRef = useRef<HTMLInputElement>(null);11 12  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {13    const file = e.target.files?.[0];14    if (!file || !client) return;15 16    try {17      setIsUploading(true);18      19      // Upload the document and let the media pipeline notify the AI.20      const response = await client.uploadMedia(21        file,22        'kyc_verification', // Routing reason23        'Please review this document and tell me if my name matches.' // Message context24      );25      26      console.log('Media uploaded successfully:', response.url);27    } catch (error) {28      console.error('Failed to upload vision context:', error);29    } finally {30      setIsUploading(false);31      if (fileInputRef.current) fileInputRef.current.value = ''; // Reset input32    }33  };34 35  return (36    <div className="flex items-center gap-2">37      <input38        type="file"39        ref={fileInputRef}40        onChange={handleFileChange}41        accept="image/*,application/pdf"42        className="hidden"43      />44      <button45        disabled={isUploading || !client}46        onClick={() => fileInputRef.current?.click()}47        className="px-4 py-2 text-sm bg-white text-black font-semibold rounded-lg hover:bg-zinc-200 disabled:opacity-50 disabled:cursor-not-allowed"48      >49        {isUploading ? 'Uploading...' : 'Upload Image / PDF'}50      </button>51    </div>52  );53}

Body Parameters

fileREQUIRED
string

The image or document to upload (JPEG, PNG, GIF, WEBP, BMP, PDF).

reasonREQUIRED
string

The routing category configured in the Dashboard (e.g. kyc_photo, general).

message
string

Optional text context to send alongside the image.

Media Webhook

#

Processing Uploaded Media

When a user calls client.uploadMedia(), Vanira can forward the uploaded file and metadata to your configured Media Webhook for custom processing.
Use this when you need OCR, identity checks, invoice parsing, damage assessment, database lookup, or any domain-specific processing before the result is injected back into the agent's context.

### Step 1: Webhook Payload Format
Vanira forwards the uploaded file to your webhook as a POST request with multipart/form-data containing:
  • media: The uploaded binary file (for example, image or PDF).
  • reason: The tag identifier sent by the client (e.g., 'kyc_upload').
  • message: (Optional) User's textual query or message.
  • session_id: The active WebRTC callId session.

### Step 2: Expected JSON Response
Your webhook must return a JSON response matching the following structure:
Code examplejson
1{2  "interrupt": true,3  "result_text": "OCR Result: PAN Card verified. Name: Jane Doe. PAN: ABCDE1234F."4}
  • interrupt: Set to true if the agent should react immediately to the processed media.
  • result_text: The text content that the LLM will receive and verbally respond to.

Backend Integration Example (Express.js)

Below is a complete Node.js / Express handler using multer to process the incoming file upload and return the structured result back to Vanira:
Code examplejavascript
1const express = require('express');2const multer = require('multer');3const upload = multer({ limits: { fileSize: 50 * 1024 * 1024 } }); // 50MB limit4 5const app = express();6 7app.post('/api/vanira-media-webhook', upload.single('media'), async (req, res) => {8  try {9    const file = req.file; // The uploaded file buffer and metadata10    const { reason, message, session_id } = req.body;11 12    console.log(`Processing media for call ${session_id}. Reason: ${reason}`);13 14    let processedTextResult = '';15 16    if (reason === 'kyc_verification') {17      // 1. Call your KYC verification pipeline or OCR service18      // const kycResult = await verifyDocument(file.buffer);19      processedTextResult = 'Document verified successfully. Name: Jane Doe.';20    } else {21      processedTextResult = 'Generic document received. Please ask the user to clarify.';22    }23 24    // 2. Return the expected payload to Vanira25    return res.status(200).json({26      interrupt: true, // Cut off agent's speech to process this event instantly27      result_text: processedTextResult28    });29 30  } catch (error) {31    console.error('Webhook processing failure:', error);32    return res.status(500).json({33      interrupt: false,34      result_text: 'Failed to process document due to a server error.'35    });36  }37});38 39app.listen(3000, () => console.log('Media Webhook active on port 3000'));

### Setup In Dashboard
1. Go to your Vanira Dashboard.
2. Select your agent under Agents.
3. Navigate to Media Handlers tab.
4. Paste your public webhook URL in the input field and save.

Body Parameters

mediaREQUIRED
string

The raw multipart/form-data file blob uploaded by the user.

reasonREQUIRED
string

The routing category.

message
string

Optional context string.

session_idREQUIRED
string

The active WebRTC call ID.

About the RN SDK

#
The React Native SDK adds live AI voice, interactive presets, and client tools to iOS and Android apps.
> Web apps use [@vanira/sdk](https://www.npmjs.com/package/@vanira/sdk). This package is React Native only — do not import the web SDK in mobile apps.

Package

npm@vanira/sdk-react-native
Importimport { createReactNativeAI, PresetHostProvider } from '@vanira/sdk-react-native'

What you get

  • Voice calls over WebRTC (createReactNativeAI)
  • Built-in preset UI — forms, calendar, upload, camera, navigation, live vision
  • Same agent protocol as web (client_tool_call, uploadMedia, session continuity)

What you need

  • Agent ID from the dashboard
  • Publishable key pk_live_* in app code
  • Native modules for WebRTC (see RN Installation and Native Setup)

Read next (in order)

1. RN Installationnpm install @vanira/sdk-react-native
2. Native Setup — WebRTC globals, permissions, peer deps
3. Quick StartPresetHostProvider + createReactNativeAI
4. Preset Handler (RN) — route tool calls with setActiveToolCall()
5. RN Events — lifecycle callbacks
6. Session Continuity (RN) — resume calls with AsyncStorage

RN Installation

#
Install the SDK package first:
Code examplebash
1npm install @vanira/sdk-react-native
Native modules are peer dependencies — your app installs them separately (the SDK does not bundle them). npm may show peer warnings until you add the modules you need.

Voice calls (required)

Code examplebash
1npm install react-native-webrtc react-native-incall-manager react-native-permissions2cd ios && pod install
Then add registerGlobals() in index.js — see Native Setup.

Presets (install only what you use)

FeaturePackages
Upload / camerareact-native-image-picker, @react-native-documents/picker
Screenshot / clip regionreact-native-view-shot
Live visionreact-native-vision-camera
Calendar, form, and navigate presets need no extra native packages.
> Full permission and Podfile steps are in Native Setup.

Native Setup

#

1. WebRTC globals (required)

Call registerGlobals() once in index.js before any SDK import:
Code examplejavascript
1import {AppRegistry} from 'react-native';2import {registerGlobals} from 'react-native-webrtc';3 4registerGlobals();5 6import App from './App';7import {name as appName} from './app.json';8 9AppRegistry.registerComponent(appName, () => App);
Without this, WebRTC APIs (RTCPeerConnection, getUserMedia) are undefined and calls fail.

2. iOS permissions

In ios/Podfile:
Code exampleruby
1require_relative '../node_modules/react-native-permissions/scripts/setup'2 3setup_permissions([4  'Camera',5  'Microphone',6  'PhotoLibrary',7])
Code examplebash
1cd ios && pod install
Add usage strings to Info.plist (NSMicrophoneUsageDescription, NSCameraUsageDescription, NSPhotoLibraryUsageDescription).

3. Android permissions

In AndroidManifest.xml:
Code examplehtml
1<uses-permission android:name="android.permission.RECORD_AUDIO" />2<uses-permission android:name="android.permission.CAMERA" />3<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

4. Metro (if resolution fails)

Code examplejavascript
1const path = require('path');2const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');3 4module.exports = mergeConfig(getDefaultConfig(__dirname), {5  resolver: {unstable_enablePackageExports: true},6  watchFolders: [7    path.resolve(__dirname, 'node_modules/@vanira/sdk-react-native'),8  ],9});

Quick Start

#

Step 1 — Wrap the app

PresetHostProvider mounts preset modals (upload, calendar, form, camera, etc.) above your screens.
Code exampletypescript
1import {PresetHostProvider} from '@vanira/sdk-react-native';2 3export default function App() {4  return (5    <PresetHostProvider>6      <YourNavigation />7    </PresetHostProvider>8  );9}

Step 2 — Start a voice call

Code exampletypescript
1import {useRef} from 'react';2import {3  createReactNativeAI,4  usePresetHost,5  type ClientToolCall,6  type VaniraAI,7} from '@vanira/sdk-react-native';8 9function VoiceScreen() {10  const {setAiClient, setActiveToolCall} = usePresetHost();11  const aiRef = useRef<VaniraAI | null>(null);12 13  async function startCall() {14    const ai = createReactNativeAI({15      agentId: 'YOUR_AGENT_ID',16      apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',17      backendUrl: 'https://api.vanira.io',18    });19 20    ai.on('preset', ({toolCall}) => setActiveToolCall(toolCall));21    ai.on('tool_call', (tc: ClientToolCall) => setActiveToolCall(tc));22 23    ai.on('connected', () => console.log('connected'));24    ai.on('disconnected', () => {25      aiRef.current = null;26      setAiClient(null);27    });28    ai.on('error', (msg) => console.error(msg));29 30    aiRef.current = ai;31    setAiClient(ai);   // required — presets call uploadMedia / sendToolResult on this client32    await ai.start();33  }34 35  function stopCall() {36    aiRef.current?.stop();37    aiRef.current = null;38    setAiClient(null);39  }40 41  // your start/stop button UI…42}

Rules

  • Call setAiClient(ai) when the call starts — preset modals need the live client
  • Route both preset and tool_call events to setActiveToolCall()
  • Start calls from a button tap (microphone permission + audio routing)
  • Use ai.stop() on hang-up and clear setAiClient(null)

Preset Handler (RN)

#
On React Native, presets are handled by `PresetHostProvider` — no separate PresetRenderer mount needed.
When the agent triggers a preset tool, route the tool call to the host:
Code exampletypescript
1ai.on('preset', ({toolCall}) => setActiveToolCall(toolCall));2ai.on('tool_call', (tc) => setActiveToolCall(tc));
The SDK automatically renders the matching modal (form, calendar, upload, camera, navigate, etc.) and sends sendToolResult() when the user completes or cancels.
Preset IDUIMode
vanira_formData Collection Formblocking
vanira_calendarDate & Time Pickerblocking
vanira_uploadFile Uploadblocking
vanira_cameraCamera Capturefire_and_forget
vanira_navigateNavigate to Route — requires vanira:navigate listener on SPAsblocking
vanira_highlight_elementHighlight Elementblocking
vanira_click_elementClick Elementblocking
vanira_select_optionSelect Dropdown Optionblocking
vanira_set_dateSet Date Fieldblocking
vanira_type_textDOM Typing Simulationblocking
vanira_erase_textWhiteboard / DOM Eraseblocking
vanira_erase_drawErase Drawing Boardblocking
vanira_drawChalkboard Shape Drawingblocking
vanira_live_visionLive Vision (Streaming Camera)fire_and_forget
vanira_close_live_cameraStop Live Camerablocking
vanira_live_screenLive Screen Sharefire_and_forget
vanira_close_live_screenStop Live Screen Shareblocking
vanira_clip_regionPage Region Clipblocking
vanira_tab_screenshotTab Screenshotblocking
vanira_screen_inkScreen Inkblocking
vanira_screen_cursorScreen Cursorblocking
vanira_screen_clickScreen Clickblocking
vanira_clear_screen_overlayClear Screen Overlayblocking
vanira_page_scanPage Scanblocking
vanira_point_atPoint Atblocking
vanira_outline_targetsOutline Targetsblocking
vanira_clear_guideClear Guideblocking

Native deps by preset

PresetExtra packages
Voice onlyreact-native-webrtc
Uploadreact-native-image-picker, @react-native-documents/picker
Camerareact-native-image-picker
Live visionreact-native-vision-camera
Calendar, form, navigateSDK only

Custom tools

Presets are automatic. For custom client tools (your own UI logic), handle them in the tool_call handler before calling setActiveToolCall:
Code exampletypescript
1ai.on('tool_call', (tc) => {2  if (tc.name === 'my_custom_tool') {3    showMyModal(tc.arguments);4    if (tc.execution_mode === 'blocking') {5      ai.sendToolResult(tc.tool_call_id, {success: true});6    }7    return;8  }9  setActiveToolCall(tc);10});
Dashboard preset tool bodies: see Tools → Preset Tools in this docs sidebar.

RN Events

#
Use .on(event, handler) on VaniraAI (returned by createReactNativeAI):
EventWhen it fires
connectedWebRTC live — show "connected" UI
disconnectedCall ended — clean up client ref
errorConnection or permission failure
transcriptionUser speech-to-text ({ text, isFinal })
presetAgent triggered a built-in preset
tool_callAgent triggered any client tool (preset or custom)

Example

Code exampletypescript
1ai.on('connected', () => setStatus('connected'));2ai.on('disconnected', () => {3  setStatus('idle');4  setAiClient(null);5});6ai.on('error', (message) => Alert.alert('Call failed', message));7ai.on('transcription', ({text, isFinal}) => {8  if (isFinal) setLastUtterance(text);9});10ai.on('preset', ({toolCall}) => setActiveToolCall(toolCall));11ai.on('tool_call', (tc) => setActiveToolCall(tc));

Sending events to the agent

Same API as web VaniraClient:
MethodPurpose
sendToolResult(id, result)Reply to blocking tools
sendToolError(id, message)Report tool failure
uploadMedia(file, reason, message)Send image/PDF during call
sendContextUpdate(data)Silent UI state sync
triggerActionInterrupt()Cut agent speech
Call ai.stop() to end the session.

Session Continuity (RN)

#
Resume a previous voice session after the app restarts by plugging AsyncStorage (or any sync storage) into the runtime.
Code exampletypescript
1import {2  createReactNativeAI,3  createSyncStorageAdapter,4  reactNativeRuntime,5  hasContinueSession,6  loadContinueSession,7} from '@vanira/sdk-react-native';8import AsyncStorage from '@react-native-async-storage/async-storage';9 10const runtime = {11  ...reactNativeRuntime,12  storage: createSyncStorageAdapter(AsyncStorage),13};14 15// Check before showing "Continue" button16const canContinue = hasContinueSession(runtime.storage, agentId);17const stored = loadContinueSession(runtime.storage, agentId);18 19const ai = createReactNativeAI({20  agentId: 'YOUR_AGENT_ID',21  apiKey: 'pk_live_YOUR_PUBLISHABLE_KEY',22  backendUrl: 'https://api.vanira.io',23  sessionBehavior: 'continue',  // or 'new'24  prospectId: stored?.prospectId,25  callId: stored?.callId,26  runtime,27});28 29await ai.start();
sessionBehaviorBehavior
'new' (default)Fresh call every time
'continue'Reuse stored prospect_id + call_id
Storage keys are managed by the SDK (vanira_prospect_id, vanira_latest_call_id) via your storage adapter.

Upload Media (RN)

#
During a live call, upload images or documents with uploadMedia(). The SDK handles the HTTP upload and sends client_media_update to the agent.
The upload preset (vanira_upload) uses this automatically. For manual uploads:
Code exampletypescript
1const response = await ai.uploadMedia(2  {3    uri: fileUri,4    type: 'image/jpeg',5    name: 'photo.jpg',6  },7  'damage_photo',8  'What is wrong with this leaf?',9);

Supported formats

JPEG, JPG, PNG, GIF, WebP, BMP, PDF, TXT, CSV — max 50 MB.

React Native file shape

Pass { uri, type, name, size? } — not File / Blob:
Code exampletypescript
1await ai.uploadMedia(2  {uri: asset.uri, type: 'image/jpeg', name: 'upload.jpg'},3  'general',4  'User uploaded a photo',5);
> Do not call triggerActionInterrupt() after uploadMedia() — the media update already notifies the agent.

RN vs Web SDK

#
Voice entryVaniraCallBox or VaniraClientcreateReactNativeAI()
Preset UIPresetRenderer or automatic in CallBoxPresetHostProvider + setActiveToolCall()
Connectclient.connect() or client.start()await ai.start()
Upload file typeFile / Blob{ uri, type, name }
Session storagelocalStorage / sessionStorageYour AsyncStorage adapter
WebRTC setupBrowser APIsregisterGlobals() + native modules
Same agent, same preset IDs, same data-channel protocol — different platform adapters.

Template Agents

#
Clone a public agent into your Vanira account in one click. Perfect for learning preset tools, voice flows, and industry-specific prompts.

How it works

1. Pick a template below (or browse [/templates](/templates))
2. Sign in → Import to My Account
3. Customize voice, tools, and presets in the dashboard
4. Embed with widget or SDK using your own pk_live_* key

Make your agent shareable

In the dashboard: Agent → Share → Make public. Others can import via:
Code exampletext
1https://vanira.io/import?agentId=YOUR_AGENT_ID

Featured templates

AgentVerticalPlatformImport path
Refund & Returns AgentE-commerceweb/import?agentId=fa1e533d-4970-44ad-b184-beda9868a987&utm_source=docs&utm_medium=template
Kisan Support AgentAgriculturereact-native, web/import?agentId=26aca6ed-0fc9-4342-b2c2-efad87449b32&utm_source=docs&utm_medium=template
Maths Tutor AgentEducationweb/import?agentId=fa1e533d-4970-44ad-b184-beda9868a987&utm_source=docs&utm_medium=template
Citizen Services AgentCitizen accessweb/import?agentId=fa1e533d-4970-44ad-b184-beda9868a987&utm_source=docs&utm_medium=template

Starter Repositories

#
Fork a minimal working app instead of starting from scratch.

vanira-starter-web

Vite + React + VaniraCallBox — voice pill and presets in minutes.
  • GitHub: https://github.com/VaniraAI/vanira-starter-web
  • Deploy: [One-click Vercel deploy](https://vercel.com/new/clone?repository-url=https://github.com/VaniraAI/vanira-starter-web&project-name=vanira-voice-app)

vanira-starter-rn

React Native + PresetHostProvider + createReactNativeAI.
  • GitHub: https://github.com/VaniraAI/vanira-starter-rn
After cloning, add your agentId and pk_live_* from the dashboard.

Developer Referral

#
Invite other developers to Vanira from Dashboard → Settings → Refer a developer.
Your personal link includes a referral code. When someone signs up through it, both accounts can receive bonus credits (when the referral program is active).
Share format:
Code exampletext
1https://vanira.io/signup?ref=YOUR_CLIENT_ID&utm_source=referral
Also share:
  • npm packages: [@vanira/sdk](https://www.npmjs.com/package/@vanira/sdk) · [@vanira/sdk-react-native](https://www.npmjs.com/package/@vanira/sdk-react-native)
  • Docs: [vanira.io/docs](https://vanira.io/docs)
  • Community: [Discord](https://discord.gg/GB3yJMvf)

Built with Vanira

#
Shipped something with Vanira? Submit your project for the Built with Vanira gallery at [/built-with](/built-with).
Featured projects get:
  • Homepage showcase placement
  • Backlink from docs
  • Social promotion
Widget embeds on the free tier display "Powered by Vanira AI" — another discovery path for developers evaluating voice AI stacks.

Preset: Form

#
Collect structured data with a dynamic form modal.
  • *Dashboard:** Client tool → preset vanira_form
  • *client_fields:** title, fields (comma-separated labels), reason
Works on web (PresetRenderer) and React Native (PresetHostProvider) with zero custom UI code.
Preset IDUIMode
vanira_formData Collection Formblocking
vanira_calendarDate & Time Pickerblocking
vanira_uploadFile Uploadblocking
vanira_cameraCamera Capturefire_and_forget
vanira_navigateNavigate to Route — requires vanira:navigate listener on SPAsblocking
vanira_highlight_elementHighlight Elementblocking
vanira_click_elementClick Elementblocking
vanira_select_optionSelect Dropdown Optionblocking
vanira_set_dateSet Date Fieldblocking
vanira_type_textDOM Typing Simulationblocking
vanira_erase_textWhiteboard / DOM Eraseblocking
vanira_erase_drawErase Drawing Boardblocking
vanira_drawChalkboard Shape Drawingblocking
vanira_live_visionLive Vision (Streaming Camera)fire_and_forget
vanira_close_live_cameraStop Live Camerablocking
vanira_live_screenLive Screen Sharefire_and_forget
vanira_close_live_screenStop Live Screen Shareblocking
vanira_clip_regionPage Region Clipblocking
vanira_tab_screenshotTab Screenshotblocking
vanira_screen_inkScreen Inkblocking
vanira_screen_cursorScreen Cursorblocking
vanira_screen_clickScreen Clickblocking
vanira_clear_screen_overlayClear Screen Overlayblocking
vanira_page_scanPage Scanblocking
vanira_point_atPoint Atblocking
vanira_outline_targetsOutline Targetsblocking
vanira_clear_guideClear Guideblocking

Preset: Upload

#
File picker for images, PDF, TXT, CSV during a live call.
  • *Web accept:** image/*,application/pdf,text/plain,text/csv
  • *React Native:** requires react-native-image-picker + @react-native-documents/picker peer deps.

Preset: Navigate

#
SPA or external navigation from voice.
  • *Web:** listen for vanira:navigate or use onNavigate on VaniraCallBox.
  • *React Native:** register registerInternalRouteHandler() for in-app routes.

Preset: Live Vision

#
Stream camera frames to the agent during a call.
  • *React Native:** requires react-native-vision-camera.
Sends client_media_frame (not client_media_update) for continuous vision.

List AI Models

GET
#
GEThttps://api.vanira.io/discovery/models
Returns all active LLM models available on the platform.
Use the provider and model values from this response when creating or updating an agent's model field. Only status: "active" models are returned.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/discovery/models'

Expected Response — 200 OK

json
1{2  "models": [3    {4      "id": "89e40b9c-...",5      "name": "gpt-4.1-mini",6      "ai_provider": "AZURE",7      "status": "active"8    },9    {10      "id": "7d49e047-...",11      "name": "gpt-4o-mini-realtime-preview",12      "ai_provider": "AZURE_REALTIME",13      "status": "active"14    }15  ]16}

Response Schema Details

idREQUIRED
uuid

Internal model UUID (not needed for API calls).

nameREQUIRED
string

Model name to use in agent model.model field. e.g. gpt-4.1-mini

ai_providerREQUIRED
string

Provider string to use in agent model.provider field. e.g. AZURE, AZURE_REALTIME, GROQ

statusREQUIRED
string

active | inactive. Only active models are returned.

HTTP Errors

401
UNAUTHORIZED

No valid API key provided.

List TTS Voices

GET
#
GEThttps://api.vanira.io/discovery/voices
Returns all active TTS voices available on the platform.
Use the tts_provider and name values when setting an agent's voice field.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/discovery/voices'

Expected Response — 200 OK

json
1{2  "voices": [3    {4      "id": "db9faea1-...",5      "name": "Riya Rao",6      "tts_provider": "ELEVENLABS",7      "language": "ENGLISH",8      "gender": "FEMALE",9      "status": "active"10    },11    {12      "id": "c81a39ce-...",13      "name": "Samay Hinglish Super Premium",14      "tts_provider": "ELEVENLABS",15      "language": "HINDI",16      "gender": "MALE",17      "status": "active"18    }19  ]20}

Response Schema Details

idREQUIRED
uuid

Internal voice UUID (not needed for API calls).

nameREQUIRED
string

Voice name to use in agent voice.name field. e.g. Riya Rao

tts_providerREQUIRED
string

Provider to use in agent voice.provider field. e.g. ELEVENLABS, SARVAM

language
string

Primary language of the voice. e.g. ENGLISH, HINDI

gender
string

MALE | FEMALE

statusREQUIRED
string

active | inactive. Only active voices are returned.

HTTP Errors

401
UNAUTHORIZED

No valid API key provided.

List STT Models

GET
#
GEThttps://api.vanira.io/discovery/transcription-models
Returns all active Speech-to-Text models available on the platform.
Use the provider and name values when setting an agent's transcription field.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/discovery/transcription-models'

Expected Response — 200 OK

json
1{2  "models": [3    { "id": "8d398506-...", "name": "nova-2",    "provider": "DEEPGRAM", "status": "active" },4    { "id": "dc641dca-...", "name": "nova-3",    "provider": "DEEPGRAM", "status": "active" },5    { "id": "75bfb690-...", "name": "saaras:v3", "provider": "SARVAM",   "status": "active" },6    { "id": "30fa4dbe-...", "name": "saaras:v2", "provider": "SARVAM",   "status": "active" }7  ]8}

Response Schema Details

idREQUIRED
uuid

Internal model UUID (not needed for API calls).

nameREQUIRED
string

Model name to use in agent transcription.model field. e.g. nova-2, saaras:v3

providerREQUIRED
string

Provider to use in agent transcription.provider field. e.g. DEEPGRAM, SARVAM

statusREQUIRED
string

active | inactive. Only active models are returned.

HTTP Errors

401
UNAUTHORIZED

No valid API key provided.

Fetch ICE Servers

GET
#
GEThttps://api.vanira.io/discovery/ice-servers
Returns active STUN/TURN server configuration for WebRTC peer connection setup.
Pass the returned array to RTCPeerConnection({ iceServers: [...] }) or use the SDK's VaniraClient.fetchIceServers(apiKey) helper which calls this endpoint automatically.
STUN servers help discover your public IP. TURN servers relay media when a direct peer-to-peer connection can't be established (firewalls, symmetric NAT).

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/discovery/ice-servers'

Expected Response — 200 OK

json
1{2  "ice_servers": [3    {4      "urls": ["stun:stun.relay.metered.ca:80"],5      "username": null,6      "credential": null7    },8    {9      "urls": [10        "turn:global.relay.metered.ca:80",11        "turn:global.relay.metered.ca:443",12        "turns:global.relay.metered.ca:443?transport=tcp"13      ],14      "username": "<metered_user_id>",15      "credential": "<metered_credential_secret>"16    }17  ]18}

Response Schema Details

urlsREQUIRED
array

List of STUN/TURN URLs for this server.

username
string

TURN username. null for STUN-only servers.

credential
string

TURN password/credential. null for STUN-only servers.

HTTP Errors

401
UNAUTHORIZED

No valid API key provided.

List Numbers

GET
#
GEThttps://api.vanira.io/phone-numbers
Returns all active phone numbers connected to your account for both inbound and outbound calling.
This includes both bought numbers and numbers imported from external providers.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/phone-numbers'

Expected Response — 200 OK

json
1{2  "numbers": [3    {4      "id": "09d89078-b9cc-452d-ae06-126d04239b73",5      "number": "+918071387205",6      "country_code": "IN",7      "label": "Primary DID",8      "client_id": "91b5f2de-9e01-4520-837f-58f284e40a4c",9      "trunk_id": "0c014935-8e11-4632-8cfe-9028d01b492c",10      "is_active": true,11      "is_vanira_internal": false,12      "agent_id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5"13    }14  ]15}

Response Schema Details

numberREQUIRED
string

The phone number in E.164 format (digits only).

country_codeREQUIRED
string

ISO 2-letter country code.

labelREQUIRED
string

Human-readable label for the number.

agent_id
uuid

ID of the agent currently handling calls for this number.

is_activeREQUIRED
boolean

Whether the number is ready to receive and make calls.

is_vanira_internalREQUIRED
boolean

If true, this number belongs to the Vanira shared pool.

HTTP Errors

401
UNAUTHORIZED

Missing or invalid API key.

400
BAD_REQUEST

Missing client_id.

Import vobiz number

POST
#
POSThttps://api.vanira.io/phone-numbers/import
Import your existing phone number from vobiz and connect it to a Vanira agent. This allows the agent to handle both incoming and outgoing calls on that number automatically.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

phone_numberREQUIRED
string

E.164 phone number (e.g. +918071387205).

agent_idREQUIRED
uuid

ID of the agent who will handle calls.

vobiz_auth_id
string

VoBiz X-Auth-ID. Required for first-time import.

vobiz_auth_token
string

VoBiz X-Auth-Token. Required for first-time import.

use_existing_credentials
boolean

Use previously stored credentials for this client. Default: false.

credential_label
string

Label for newly stored credentials.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/phone-numbers/import' \2  -H "Content-Type: application/json" \3  -d '{4  "phone_number": "+918071387205",5  "agent_id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",6  "vobiz_auth_id": "<vobiz_auth_id>",7  "vobiz_auth_token": "<vobiz_auth_token>",8  "use_existing_credentials": false,9  "credential_label": "<credential_label>"10}'

Expected Response — 200 OK

json
1{2  "phone_number": "+918071387205",3  "agent_id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",4  "trunk_endpoint": "endpoint-1387205",5  "outbound_trunk_id": "8747b89c-a5d4-4307-8e12-ccbdabcc2907",6  "assigned": true,7  "service_reloaded": true8}

HTTP Errors

401
UNAUTHORIZED

Invalid API key.

207
MULTI_STATUS

Upstream OK but secondary sync had non-fatal errors.

400
BAD_REQUEST

No credentials available or missing required fields.

409
CONFLICT

Number already exists in system — delete it first.

422
UNPROCESSABLE_ENTITY

Number not found on provider account or assignment failed.

502
BAD_GATEWAY

Upstream failure (Provider unreachable).

Assign to Agent

PUT
#
PUThttps://api.vanira.io/phone-numbers/link
Connect a phone number to a different agent. Both incoming and outgoing calls will be immediately handled by the new agent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

phone_numberREQUIRED
string

The phone number to update.

agent_idREQUIRED
uuid

ID of the new agent to handle all call traffic.

Implementation Example

Environment
1curl -X PUT 'https://api.vanira.io/phone-numbers/link' \2  -H "Content-Type: application/json" \3  -d '{4  "phone_number": "+918071387205",5  "agent_id": "5396166a-f107-4918-b108-ff97b5987178"6}'

Expected Response — 200 OK

json
1{2  "success": true,3  "phone_number": "+918071387205",4  "agent_id": "5396166a-f107-4918-b108-ff97b5987178"5}

HTTP Errors

404
PHONE_NUMBER_NOT_FOUND

Phone number not found.

404
AGENT_NOT_FOUND

Agent not found.

Delete Number

DELETE
#
DELETEhttps://api.vanira.io/phone-numbers/:number
Remove a phone number from your account. This will stop the agent from making or answering any more calls on this number.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

numberREQUIRED
string

The phone number to remove (E.164 format).

Implementation Example

Environment
1curl -X DELETE 'https://api.vanira.io/phone-numbers/%2B918071387205' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "phone_number": "+918071387205",3  "deleted": true,4  "unassigned": true5}

HTTP Errors

401
UNAUTHORIZED

Invalid API key.

404
PHONE_NUMBER_NOT_FOUND

Phone number not found in system.

502
BAD_GATEWAY

VoBiz unassign failed.

List VoBiz Credentials

GET
#
GEThttps://api.vanira.io/phone-numbers/vobiz/credentials
Fetch stored VoBiz credential metadata for a client. This returns hints and labels, but never the actual secret tokens.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Query Parameters

client_idREQUIRED
uuid

UUID of the owning client.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/phone-numbers/vobiz/credentials?client_id=%3Cclient_id%3E'

Expected Response — 200 OK

json
1{2  "credentials": [3    {4      "id": "436c27d7-f357-4033-8ea0-97de12a989c2",5      "label": "primary",6      "auth_id_hint": "MA_",7      "is_default": false,8      "created_at": "2026-05-08T19:47:47Z",9      "updated_at": "2026-05-08T19:47:47Z"10    }11  ]12}

HTTP Errors

401
UNAUTHORIZED

Missing or invalid API key.

400
BAD_REQUEST

Missing client_id.

List Agents

GET
#
GEThttps://api.vanira.io/assistant
Returns all voice agents owned by the authenticated client.
Each agent includes the three Vapi-style config objects — model, voice, and transcription — instead of raw internal IDs.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/assistant'

Expected Response — 200 OK

json
1{2  "agents": [3    {4      "id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",5      "name": "Sales Rep",6      "active": true,7      "language": "en-US",8      "model":         { "provider": "AZURE",      "model": "gpt-4.1-mini" },9      "voice":         { "provider": "ELEVENLABS",  "name": "Riya Rao" },10      "transcription": { "provider": "DEEPGRAM",    "model": "nova-2" },11      "enable_lid_detection": true,12      "lid_allowed_languages": ["hi", "en"],13      "created_at": "2026-01-10T08:00:00Z",14      "updated_at": "2026-02-01T12:00:00Z",15      "client_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"16    }17  ]18}

Response Schema Details

idREQUIRED
uuid

Agent UUID.

nameREQUIRED
string

Display name.

activeREQUIRED
boolean

Whether the agent is active.

languageREQUIRED
string

Language code e.g. en-US.

model
object

{ provider, model } — LLM config. See GET /discovery/models.

voice
object

{ provider, name } — TTS voice config. See GET /discovery/voices.

transcription
object

{ provider, model } — STT config.

enable_lid_detection
boolean

Whether LID is enabled.

lid_allowed_languages
string[]

Allowed languages for pivoting.

client_idREQUIRED
uuid

Owner client ID.

HTTP Errors

401
UNAUTHORIZED

No valid API key or JWT provided.

500
DATABASE_ERROR

Internal database error.

Get Agent

GET
#
GEThttps://api.vanira.io/assistant/:id
Retrieve full configuration for a specific agent including prompt, data collection settings, and all three config objects.
  • *Ownership enforced** — returns 404 if the agent belongs to a different client.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/assistant/caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5'

Expected Response — 200 OK

json
1{2  "id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",3  "name": "Sales Rep",4  "active": true,5  "language": "en-US",6  "model":         { "provider": "AZURE",      "model": "gpt-4.1-mini" },7  "voice":         { "provider": "ELEVENLABS",  "name": "Riya Rao" },8  "transcription": { "provider": "DEEPGRAM",    "model": "nova-2" },9  "welcome_message": "Hey! How can I help you?",10  "agent_prompt": "You are a helpful sales assistant...",11  "inbound_welcome_message": "Thanks for calling. How can I help?",12  "data_collection": { ... },13  "success_metric": { ... },14  "input_needed_json_format": [ ... ],15  "temperature": 0.7,16  "top_p": 1.0,17  "speed": null,18  "duty": "support",19  "silence_alert_message": "Are you still there?",20  "call_end_duration": 20000,21  "call_user_alert_duration": 7000,22  "initial_disable_mic_duration": 0,23  "enable_lid_detection": true,24  "lid_allowed_languages": ["hi", "en"],25  "created_at": "2026-01-10T08:00:00Z",26  "updated_at": "2026-02-01T12:00:00Z",27  "client_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"28}

Response Schema Details

idREQUIRED
uuid

Agent UUID.

nameREQUIRED
string

Display name.

activeREQUIRED
boolean

Active status.

model
object

{ provider, model } — LLM. Use GET /discovery/models for valid values.

voice
object

{ provider, name } — TTS voice. Use GET /discovery/voices for valid values.

transcription
object

{ provider, model } — STT transcription.

agent_prompt
string

LLM system prompt.

welcome_message
string

First message spoken by the agent.

temperature
number

LLM temperature (0–2).

speed
number

TTS speech speed multiplier.

enable_lid_detection
boolean

Whether LID is enabled.

lid_allowed_languages
string[]

Allowed languages for pivoting.

data_collection
object

Call outcome and scoring configuration.

HTTP Errors

401
UNAUTHORIZED

No valid API key or JWT.

404
AGENT_NOT_FOUND

Agent not found or not owned by the authenticated client.

422
VALIDATION_ERROR

Invalid UUID format for id.

Create Agent

POST
#
POSThttps://api.vanira.io/assistant
Create a new voice agent. Pass model, voice, and transcription as structured objects — no internal UUIDs needed.
Use GET /discovery/models and GET /discovery/voices to discover valid provider + name values.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

nameREQUIRED
string

Display name for the agent.

welcome_messageREQUIRED
string

First message the agent speaks.

agent_promptREQUIRED
string

LLM system prompt that defines the agent personality.

language
string

Language code. e.g. en-US, hi-IN.

model
object

LLM config. If omitted, defaults to AZURE / gpt-4.1-mini. See GET /discovery/models for structure.

voice
object

TTS voice config. If omitted, defaults to ELEVENLABS / Riya Rao. See GET /discovery/voices for structure.

transcription
object

STT transcription config. See GET /discovery/transcription for structure.

data_collection
object

Post-call extraction config.

duty
string

Agent role: support | sales | hr etc.

enable_lid_detection
boolean

Enable LID system.

lid_allowed_languages
array

Allowed ISO 639-1 codes.

active
boolean

Start active.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/assistant' \2  -H "Content-Type: application/json" \3  -d '{4  "name": "Support Bot",5  "welcome_message": "Hey! How can I help you?",6  "agent_prompt": "<agent_prompt>",7  "language": "en-US",8  "model": {9    "provider": "AZURE",10    "model": "gpt-4.1-mini"11  },12  "voice": {13    "provider": "ELEVENLABS",14    "name": "Riya Rao"15  },16  "transcription": {17    "provider": "DEEPGRAM",18    "model": "nova-2"19  },20  "data_collection": {21    "call_cut": [],22    "required_values": {}23  },24  "duty": "support",25  "enable_lid_detection": true,26  "lid_allowed_languages": [27    "hi",28    "en"29  ],30  "active": false31}'

Expected Response — 200 OK

json
1{2  "id": "new-agent-uuid",3  "name": "Support Bot",4  "client_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",5  "created_at": "2026-03-13T09:00:00Z"6}

HTTP Errors

401
UNAUTHORIZED

No valid API key or JWT.

422
VALIDATION_ERROR

model/voice/transcription provider+name not found in active records. Check /discovery/models and /discovery/voices.

500
PERSISTENCE_ERROR

Failed to persist the new agent.

Update Agent

PATCH
#
PATCHhttps://api.vanira.io/assistant/:id
Update any subset of an agent's configuration. All fields are optional — only the ones you send will be updated.
Pass model, voice, or transcription as structured objects to change the LLM, TTS, or STT configuration. Invalid provider/name combinations return 422.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent to update.

Body Parameters

name
string

New display name.

agent_prompt
string

Updated system prompt.

welcome_message
string

Updated opening message.

language
string

Language code.

model
object

Update LLM. { provider, model }. See GET /discovery/models.

voice
object

Update TTS voice. { provider, name }. See GET /discovery/voices.

transcription
object

Update STT config. { provider, model }.

temperature
number

LLM temperature (0–2).

speed
number

TTS speed multiplier (0.25–4).

enable_lid_detection
boolean

Toggle LID system.

lid_allowed_languages
array

Update allowed languages.

active
boolean

Activate or deactivate.

Implementation Example

Environment
1curl -X PATCH 'https://api.vanira.io/assistant/caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5' \2  -H "Content-Type: application/json" \3  -d '{4  "name": "<name>",5  "agent_prompt": "<agent_prompt>",6  "welcome_message": "<welcome_message>",7  "language": "<language>",8  "model": {9    "provider": "AZURE_REALTIME",10    "model": "gpt-4o-mini-realtime-preview"11  },12  "voice": {13    "provider": "ELEVENLABS",14    "name": "Miranda English Voice US"15  },16  "transcription": {17    "provider": "SARVAM",18    "model": "saaras:v3"19  },20  "temperature": null,21  "speed": null,22  "enable_lid_detection": false,23  "lid_allowed_languages": "<lid_allowed_languages>",24  "active": false25}'

Expected Response — 200 OK

json
1{2  "id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",3  "name": "Updated Agent Name",4  "active": true,5  "updated_at": "2026-03-13T09:51:00Z"6}

HTTP Errors

401
UNAUTHORIZED

No valid API key or JWT.

404
AGENT_NOT_FOUND

Agent not found or not owned by the authenticated client.

422
VALIDATION_ERROR

Invalid model/voice/transcription config. Check /discovery/models and /discovery/voices for valid values.

Delete Agent

DELETE
#
DELETEhttps://api.vanira.io/assistant/:id
Permanently delete an agent. Irreversible.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent to delete.

Implementation Example

Environment
1curl -X DELETE 'https://api.vanira.io/assistant/caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",3  "name": "Deleted Agent"4}

HTTP Errors

401
UNAUTHORIZED

No valid API key or JWT.

404
AGENT_NOT_FOUND

Agent not found or not owned by the authenticated client.

422
VALIDATION_ERROR

Invalid UUID format.

Get Agent Widget

GET
#
GEThttps://api.vanira.io/assistant/:id/widget
Fetch the widget embed configuration for an agent. Auto-creates with defaults if none exists.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/assistant/caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5/widget'

Expected Response — 200 OK

json
1{2  "id": "widget-uuid",3  "agent_id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",4  "mode": "voice_only",5  "primary_color": "#6366f1",6  "secondary_color": "#a855f7",7  "created_at": "2026-04-27T12:00:00Z"8}

HTTP Errors

404
AGENT_NOT_FOUND

No agent with this UUID.

Update Agent Widget

PATCH
#
PATCHhttps://api.vanira.io/assistant/widget/:widget_id
Update widget appearance (colors, mode, icon).

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

widget_idREQUIRED
uuid

Widget UUID (from Get Agent Widget response).

Body Parameters

mode
string

voice_only | chat_only | chat_voice | avatar_only | chat_avatar.

primary_color
string

Primary hex color. e.g. #6366f1.

secondary_color
string

Secondary hex color.

icon
string

Widget icon identifier.

Implementation Example

Environment
1curl -X PATCH 'https://api.vanira.io/assistant/widget/a4fbac73-3f8c-4e3e-a742-195e1b68d2c3' \2  -H "Content-Type: application/json" \3  -d '{4  "mode": "<mode>",5  "primary_color": "<primary_color>",6  "secondary_color": "<secondary_color>",7  "icon": "<icon>"8}'

Expected Response — 200 OK

json
1{2  "id": "widget-uuid",3  "mode": "chat_voice",4  "primary_color": "#ff0000",5  "updated_at": "2026-04-27T12:05:00Z"6}

HTTP Errors

404
WIDGET_NOT_FOUND

Widget not found.

422
VALIDATION_ERROR

Invalid field value.

List Data Collections

GET
#
GEThttps://api.vanira.io/assistant/:id/data-collection
Fetch all post-call data extraction parameters for an agent. These define what information the AI should extract from a conversation (e.g., email, sentiment, intent).

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/assistant/caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5/data-collection'

Expected Response — 200 OK

json
1{2  "collections": [3    {4      "id": "766c8b9d-5a4e-4f3d-9c8b-7d6e5f4a3b2c",5      "agent_id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",6      "key": "lead_email",7      "prompt": "Extract the email address mentioned by the user.",8      "data_type": "string",9      "store_to_prospect_data": true,10      "is_active": true11    }12  ]13}

HTTP Errors

404
AGENT_NOT_FOUND

Agent not found.

Create Data Collection

POST
#
POSThttps://api.vanira.io/assistant/:id/data-collection
Add a new post-call data extraction parameter to an agent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent.

Body Parameters

keyREQUIRED
string

Unique key for this field in extraction results.

promptREQUIRED
string

Instructions for the AI to extract this value.

data_type
string

string | boolean | number | enum. Default: string.

enum_values
array

List of valid values if data_type is enum.

store_to_prospect
boolean

Whether to store this value in the main prospect record.

prospect_column_name
string

The specific column name in the prospect table to map to.

store_to_prospect_data
boolean

Whether to store in the custom prospect_data table (key-value storage).

prospect_data_key
string

The key to use when storing in prospect_data.

store_directly_to_prospect
boolean

Flag for direct storage logic.

is_active
boolean

Whether to enable this extraction parameter.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/assistant/<id>/data-collection' \2  -H "Content-Type: application/json" \3  -d '{4  "key": "interested_in_demo",5  "prompt": "Did the user express interest in a demo? Answer yes or no.",6  "data_type": "enum",7  "enum_values": [8    "Interested",9    "Not Interested",10    "Call Back Later"11  ],12  "store_to_prospect": false,13  "prospect_column_name": "<prospect_column_name>",14  "store_to_prospect_data": false,15  "prospect_data_key": "<prospect_data_key>",16  "store_directly_to_prospect": false,17  "is_active": false18}'

Expected Response — 200 OK

json
1{2  "id": "766c8b9d-5a4e-4f3d-9c8b-7d6e5f4a3b2c",3  "key": "interested_in_demo",4  "prompt": "Did the user express interest in a demo? Answer yes or no.",5  "data_type": "boolean",6  "agent_id": "caaa5b2a-5fd9-4974-a59e-1c9c01c4c6f5",7  "created_at": "2026-05-09T12:00:00Z"8}

HTTP Errors

400
BAD_REQUEST

Invalid configuration.

404
AGENT_NOT_FOUND

Agent not found.

Update Data Collection

PATCH
#
PATCHhttps://api.vanira.io/assistant/data-collection/:collection_id
Update an existing data extraction parameter.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

collection_idREQUIRED
uuid

UUID of the collection parameter.

Body Parameters

prompt
string

Updated extraction prompt.

data_type
string

Update the expected data type.

enum_values
array

Update allowed enum values.

store_to_prospect
boolean

Update main record storage setting.

is_active
boolean

Enable/disable this parameter.

Implementation Example

Environment
1curl -X PATCH 'https://api.vanira.io/assistant/data-collection/<collection_id>' \2  -H "Content-Type: application/json" \3  -d '{4  "prompt": "<prompt>",5  "data_type": "<data_type>",6  "enum_values": "<enum_values>",7  "store_to_prospect": false,8  "is_active": false9}'

Expected Response — 200 OK

json
1{2  "id": "766c8b9d-5a4e-4f3d-9c8b-7d6e5f4a3b2c",3  "key": "lead_email",4  "is_active": false,5  "updated_at": "2026-05-09T12:05:00Z"6}

HTTP Errors

404
DATA_COLLECTION_NOT_FOUND

Parameter not found.

Delete Data Collection

DELETE
#
DELETEhttps://api.vanira.io/assistant/data-collection/:collection_id
Remove a data extraction parameter from an agent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

collection_idREQUIRED
uuid

UUID of the collection parameter.

Implementation Example

Environment
1curl -X DELETE 'https://api.vanira.io/assistant/data-collection/<collection_id>' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "success": true,3  "id": "766c8b9d-5a4e-4f3d-9c8b-7d6e5f4a3b2c"4}

HTTP Errors

404
DATA_COLLECTION_NOT_FOUND

Parameter not found.

List Media Handlers

GET
#
GEThttps://api.vanira.io/assistant/:id/media-handlers
Fetch all configured media handlers (multimodal vision/webhooks) for a specific agent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/assistant/<id>/media-handlers'

Expected Response — 200 OK

json
1{2  "handlers": [3    {4      "id": "m1",5      "agent_id": "caaa5b2a-...",6      "reason": "kyc_photo",7      "route": "webhook",8      "webhook_url": "https://api.acme.com/kyc",9      "inject_as": "system",10      "interrupt": true11    }12  ]13}

HTTP Errors

404
AGENT_NOT_FOUND

Agent not found.

Create Media Handler

POST
#
POSThttps://api.vanira.io/assistant/:id/media-handlers
Create a new media handler for an agent to process visual context uploaded via client.uploadMedia().

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the agent.

Body Parameters

reasonREQUIRED
string

The routing category/tag sent by the client SDK (e.g. kyc_photo).

routeREQUIRED
string

"vision" (native LLM vision) or "webhook" (external API).

webhook_url
string

Required if route is webhook.

webhook_headers
object

Custom headers for the webhook (e.g., API keys).

inject_asREQUIRED
string

"system" or "user". How the parsed media result is injected into the prompt context.

interruptREQUIRED
boolean

Whether to interrupt the agent mid-sentence when media is processed.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/assistant/<id>/media-handlers' \2  -H "Content-Type: application/json" \3  -d '{4  "reason": "kyc_photo",5  "route": "webhook",6  "webhook_url": "https://api.acme.com/kyc",7  "webhook_headers": "<webhook_headers>",8  "inject_as": "system",9  "interrupt": true10}'

Expected Response — 200 OK

json
1{2  "id": "new-handler-uuid",3  "reason": "kyc_photo",4  "route": "webhook",5  "inject_as": "system",6  "interrupt": true7}

HTTP Errors

400
BAD_REQUEST

Invalid handler configuration.

404
AGENT_NOT_FOUND

Agent not found.

Update Media Handler

PATCH
#
PATCHhttps://api.vanira.io/assistant/media-handlers/:id
Update an existing media handler configuration.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the media handler.

Body Parameters

reason
string

Updated routing category.

route
string

Updated routing mode (vision/webhook).

webhook_url
string

Updated webhook URL.

inject_as
string

Updated prompt injection mode.

interrupt
boolean

Update interrupt behavior.

Implementation Example

Environment
1curl -X PATCH 'https://api.vanira.io/assistant/media-handlers/<id>' \2  -H "Content-Type: application/json" \3  -d '{4  "reason": "<reason>",5  "route": "<route>",6  "webhook_url": "<webhook_url>",7  "inject_as": "<inject_as>",8  "interrupt": false9}'

Expected Response — 200 OK

json
1{2  "id": "handler-uuid",3  "reason": "updated_kyc_photo",4  "updated_at": "2026-05-09T12:05:00Z"5}

HTTP Errors

404
MEDIA_HANDLER_NOT_FOUND

Handler not found.

Delete Media Handler

DELETE
#
DELETEhttps://api.vanira.io/assistant/media-handlers/:id
Remove a media handler from an agent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the media handler.

Implementation Example

Environment
1curl -X DELETE 'https://api.vanira.io/assistant/media-handlers/<id>' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "success": true3}

HTTP Errors

404
MEDIA_HANDLER_NOT_FOUND

Handler not found.

Create Call (SIP or Web)

POST
#
POSThttps://api.vanira.io/calls/create
Unified endpoint to create an outbound SIP call or a WebRTC web call.
  • *Authentication**
All requests require an X-API-Key header:
  • sk_live_* — secret key (server-side). Can create both web and sip calls.
  • pk_live_* — publishable key (browser/widget). Can only create web calls. Use * to allow all origins, or set domains to restrict usage.
  • *SIP vs Web**
Set type to "sip" for outbound phone calls or "web" for in-browser WebRTC sessions.
For SIP calls, sip_data (phone number + name) is required.
  • Dynamic DID Selection: If sip_data.from_number is provided, it must be a provisioned number owned by the client.
  • Automated Fallback: If sip_data.from_number is omitted, the backend automatically selects a default number from the Vanira managed pool.
  • Strict Validation: All phone numbers are strictly validated against E.164 format (7-15 digits).
For web calls, prospect_id is optional — a new anonymous prospect is created if omitted.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

agent_idREQUIRED
uuid

UUID of the voice agent that will handle the call.

typeREQUIRED
string

"web" for an in-browser WebRTC session. "sip" for an outbound phone call. Note: pk_live_* keys can only create web calls.

sip_data
object

Required when type is "sip". Nested object containing the call destination. See sip_data.to and sip_data.name below.

sip_data.to
string

E.164 formatted destination phone number. Required when type is "sip". Example: +919182517283 (country code + number, no spaces or dashes).

sip_data.name
string

Display name of the person being called. Used for prospect creation and call logging. Defaults to "Unknown" if omitted.

sip_data.from_number
string

Optional. The provisioned phone number (E.164) to dial from. If omitted, Vanira uses its shared pool default.

prospect_id
uuid

Optional. Link the call to an existing prospect record. If omitted for web calls, an anonymous prospect is created automatically.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/calls/create' \2  -H "Content-Type: application/json" \3  -d '{4  "agent_id": "919801d9-f357-4033-8ea0-97de12a989c2",5  "type": "web",6  "sip_data": {7    "to": "+919182517283",8    "name": "John Doe"9  },10  "sip_data.to": "+919182517283",11  "sip_data.name": "John Doe",12  "sip_data.from_number": "+918071387205",13  "prospect_id": "7fdc9111-2b35-4252-a85c-781c37470ac0"14}'

Expected Response — 200 OK

json
1// Web call response2{3  "call_id": "da4ca1e9-e488-4059-b1d2-fdc348d26950",4  "status": "in-progress",5  "worker_url": "https://<worker>.vanira.io/webrtc?agent=919801d9..._da4ca1e9..."6}7 8// SIP call response9{10  "call_id": "6fdc9111-2b35-4252-a85c-781c37470ac0",11  "status": "triggered",12  "worker_url": null13}

Response Schema Details

call_idREQUIRED
uuid

Unique identifier for the created call record.

statusREQUIRED
string

"in-progress" for web calls. "triggered" for SIP calls.

worker_url
string

WebRTC worker URL to connect to. Only returned for type="web". Pass this to the Vanira SDK.

HTTP Errors

401
UNAUTHORIZED

No X-API-Key header provided.

401
INVALID_API_KEY

API key is invalid, revoked, or the secret does not match.

402
INSUFFICIENT_CREDITS

Client has no available call credits.

403
INSUFFICIENT_SCOPE

Publishable key (pk_live_*) attempted to create a SIP call.

404
AGENT_NOT_FOUND

No agent exists with the provided agent_id.

404
PROSPECT_NOT_FOUND

The provided prospect_id does not exist.

422
VALIDATION_ERROR

Invalid E.164 format (7-15 digits) or missing required fields.

502
UPSTREAM_SERVICE_TIMEOUT

SIP gateway is unreachable or returned an error.

500
DATABASE_ERROR

Unexpected server error.

List Calls

GET
#
GEThttps://api.vanira.io/calls
Retrieve a paginated list of calls for the authenticated client.
  • *Authentication**
Requires X-API-Key: sk_live_* or Authorization: Bearer <token>. Publishable keys cannot access call history.
  • *Filtering**
Use query params to filter by agent, status, or paginate. Results are always scoped to the authenticated client — you cannot see other clients' calls.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Query Parameters

agent_id
uuid

Filter calls by a specific agent UUID.

status
string

Filter by call status: triggered | in-progress | completed | failed.

limit
number

Number of results to return. Default 100, max 500.

offset
number

Number of results to skip for pagination.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/calls?agent_id=919801d9-f357-4033-8ea0-97de12a989c2&status=completed&limit=25&offset=0'

Expected Response — 200 OK

json
1{2  "calls": [3    {4      "id": "da4ca1e9-e488-4059-b1d2-fdc348d26950",5      "agent_id": "919801d9-f357-4033-8ea0-97de12a989c2",6      "client_id": "91b5f2de-9e01-4520-837f-58f284e40a4c",7      "phone_to": "+917268030283",8      "phone_from": null,9      "status": "completed",10      "direction": "outbound",11      "type": "sip_call",12      "created_at": "2026-05-01T10:00:00Z",13      "duration": 142,14      "recording_url": null,15      "is_call_successful_according_to_agent_criteria": true,16      "prospect": { "id": "<uuid>", "name": "John Doe", "phone": "+917268030283" },17      "agent": { "id": "919801d9-...", "name": "Support Agent" },18      "call_data": [{ "key": "sentiment", "value": "positive" }]19    }20  ],21  "total": 330822}

Response Schema Details

callsREQUIRED
array

Array of call objects.

totalREQUIRED
number

Total matching calls across all pages (use for pagination UI).

calls[].idREQUIRED
uuid

Call UUID.

calls[].statusREQUIRED
string

triggered | in-progress | completed | failed.

calls[].direction
string

inbound (web) or outbound (SIP).

calls[].type
string

web_call or sip_call.

calls[].duration
number

Call duration in seconds.

calls[].recording_url
string

URL to the call recording if available.

calls[].prospect
object

Linked prospect name and phone.

calls[].agent
object

Agent id and name.

calls[].call_data
array

Structured key/value output from the agent (sentiment, outcome, etc.).

HTTP Errors

401
UNAUTHORIZED

No X-API-Key header provided.

401
INVALID_API_KEY

API key is invalid or revoked.

403
INSUFFICIENT_SCOPE

Publishable key (pk_live_*) cannot access call history.

500
DATABASE_ERROR

Unexpected server error.

Get Call Details

GET
#
GEThttps://api.vanira.io/calls/:id
Retrieve full details for a specific call by its UUID, including the linked prospect (with key/value prospect data) and the agent with its client information.
  • *Authentication**
Requires X-API-Key: sk_live_* or Authorization: Bearer <token>. Publishable keys (pk_live_*) cannot access call details.
The authenticated client must own the call — requests for calls belonging to other clients return 404.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the call to retrieve. Returned by POST /calls/create as call_id.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/calls/6fdc9111-2b35-4252-a85c-781c37470ac0'

Expected Response — 200 OK

json
1{2  "id": "6fdc9111-2b35-4252-a85c-781c37470ac0",3  "agent_id": "919801d9-f357-4033-8ea0-97de12a989c2",4  "client_id": "91b5f2de-9e01-4520-837f-58f284e40a4c",5  "phone_from": "+919182517283",6  "phone_to": "+917268030283",7  "status": "completed",8  "call_triggered_at": "2026-03-13T10:00:00Z",9  "extra_details": { "duration": 142 },10  "provider_call_id": "prov-abc-123",11  "prospect": {12    "id": "<prospect-uuid>",13    "name": "John Doe",14    "phone": "+919182517283",15    "prospect_data": [16      { "key": "company", "value": "Acme Corp" }17    ]18  },19  "agent": {20    "id": "919801d9-f357-4033-8ea0-97de12a989c2",21    "client": {22      "name": "Demo Client",23      "base_prospect_group_id": "<group-uuid>"24    }25  }26}

Response Schema Details

idREQUIRED
uuid

Call UUID.

agent_idREQUIRED
uuid

UUID of the agent that handled the call.

client_idREQUIRED
uuid

UUID of the client who owns this call.

phone_from
string

Caller's phone number.

phone_to
string

Dialled phone number.

status
string

Call status: triggered | in-progress | completed | failed.

call_triggered_at
string

ISO 8601 timestamp when the call was initiated.

extra_details
object

Arbitrary metadata returned by the telephony provider (duration, recording_url, etc.).

provider_call_id
string

Provider-side call identifier.

prospect
object

Linked prospect with name, phone, and prospect_data key/value pairs.

agent
object

Agent info including nested client name and base_prospect_group_id.

HTTP Errors

401
UNAUTHORIZED

No X-API-Key header provided.

401
INVALID_API_KEY

API key is invalid or revoked.

403
INSUFFICIENT_SCOPE

Publishable key (pk_live_*) cannot access call details.

404
CALL_NOT_FOUND

Call not found, or the authenticated client does not own this call.

422
VALIDATION_ERROR

id path parameter is not a valid UUID.

500
DATABASE_ERROR

Unexpected server error.

Upload & Create Campaign

POST
#
POSThttps://api.vanira.io/campaigns
Create a new outbound campaign, bulk-insert prospects, and allocate DIDs. Note: You must either provide from_numbers or set use_vanira_managed to true; otherwise, creation will fail.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

nameREQUIRED
string

The name of the campaign

agent_idREQUIRED
uuid

ID of the voice agent to use

candidatesREQUIRED
array

List of prospects including name and phone number

providerREQUIRED
string

The voice provider to use (e.g., vonage, twilio)

timezoneREQUIRED
string

Timezone for the campaign scheduling

call_hours_startREQUIRED
string

Daily start time for calls (HH:MM:SS)

call_hours_endREQUIRED
string

Daily end time for calls (HH:MM:SS)

call_daysREQUIRED
array

Days of the week to make calls

max_concurrent_callsREQUIRED
number

Maximum number of simultaneous calls

call_timeout_secondsREQUIRED
number

Seconds to wait before considering a call timed out

start_campaignREQUIRED
boolean

Whether to start the campaign immediately after upload

from_numbers
array

Optional list of E.164 phone numbers to use as Caller IDs. System will resolve and allocate them automatically.

use_vanira_managed
boolean

Optional. If true, the campaign will also use Vanira internal managed numbers.

retry_failed_callsREQUIRED
boolean

Retry calls that failed (e.g. error/network issue)

max_retries_failedREQUIRED
number

Maximum number of retries for failed calls

retry_delay_failed_secondsREQUIRED
number

Seconds to wait before retrying a failed call

retry_busy_callsREQUIRED
boolean

Retry calls where the line was busy

max_retries_busyREQUIRED
number

Maximum number of retries for busy calls

retry_delay_busy_secondsREQUIRED
number

Seconds to wait before retrying a busy call

retry_no_answer_callsREQUIRED
boolean

Retry calls where there was no answer

max_retries_no_answerREQUIRED
number

Maximum number of retries for no-answer calls

retry_delay_no_answer_secondsREQUIRED
number

Seconds to wait before retrying a no-answer call

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/campaigns' \2  -H "Content-Type: application/json" \3  -d '{4  "name": "Q1 Feedback Survey",5  "agent_id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",6  "candidates": [7    {8      "name": "John Doe",9      "phone": "+1234567890"10    }11  ],12  "provider": "vonage",13  "timezone": "Asia/Kolkata",14  "call_hours_start": "09:00:00",15  "call_hours_end": "18:00:00",16  "call_days": [17    "Monday",18    "Tuesday",19    "Wednesday",20    "Thursday",21    "Friday"22  ],23  "max_concurrent_calls": 5,24  "call_timeout_seconds": 60,25  "start_campaign": true,26  "from_numbers": [27    "+918071387205",28    "+919876543210"29  ],30  "use_vanira_managed": true,31  "retry_failed_calls": true,32  "max_retries_failed": 3,33  "retry_delay_failed_seconds": 300,34  "retry_busy_calls": true,35  "max_retries_busy": 2,36  "retry_delay_busy_seconds": 180,37  "retry_no_answer_calls": true,38  "max_retries_no_answer": 3,39  "retry_delay_no_answer_seconds": 60040}'

Expected Response — 200 OK

json
1{2  "success": true,3  "campaign_id": "c1234567-89ab-cdef-0123-456789abcdef",4  "total_prospects": 2,5  "message": "Campaign created successfully",6  "started": false7}

Response Schema Details

successREQUIRED
boolean

Always true on success.

campaign_idREQUIRED
uuid

UUID of the created campaign.

total_prospectsREQUIRED
number

Number of prospects added.

messageREQUIRED
string

Human-readable status message.

startedREQUIRED
boolean

True if campaign was auto-started.

HTTP Errors

400
validation_error

More than 50 candidates provided.

400
bad_request

No Caller IDs provided. You must either provide from_numbers or set use_vanira_managed to true.

422
BAD_REQUEST_FORMAT

Missing required fields (agent_id, name, candidates).

404
AGENT_NOT_FOUND

Agent not found or agent has no associated client.

500
INTERNAL_SERVER_ERROR

Failed to create prospect group or insert prospects.

502
UPSTREAM_SERVICE_ERROR

Campaign API or SIP gateway is unreachable.

Start Campaign

POST
#
POSThttps://api.vanira.io/campaigns/:id/start
Transition a campaign from draft or paused to active (running) status. Migrated from n8n to the Python FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the campaign to start.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/campaigns/1a817016-a3f5-41c1-995c-c74a5fb33720/start' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "success": true,3  "campaign_id": "1a817016-a3f5-41c1-995c-c74a5fb33720",4  "status": "active",5  "message": "Campaign started successfully",6  "extra_data": {7    "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",8    "status": "active"9  }10}

Response Schema Details

successREQUIRED
boolean

Always true on success.

campaign_idREQUIRED
uuid

UUID of the campaign.

status
string

New campaign status returned by the Campaign API.

messageREQUIRED
string

Human-readable result.

extra_data
object

Raw upstream Campaign API response.

HTTP Errors

404
CAMPAIGN_NOT_FOUND

Campaign not found or not owned by the authenticated client.

422
BAD_REQUEST_FORMAT

Campaign ID is not a valid UUID.

502
gateway_error

Campaign API unreachable or returned an error.

Pause Campaign

POST
#
POSThttps://api.vanira.io/campaigns/:id/pause
Temporarily stop all outgoing calls for a running campaign. Migrated from n8n to the Python FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the campaign to pause.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/campaigns/1a817016-a3f5-41c1-995c-c74a5fb33720/pause' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "success": true,3  "campaign_id": "1a817016-a3f5-41c1-995c-c74a5fb33720",4  "status": "paused",5  "message": "Campaign paused successfully",6  "extra_data": {7    "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",8    "status": "paused"9  }10}

Response Schema Details

successREQUIRED
boolean

Always true on success.

campaign_idREQUIRED
uuid

UUID of the campaign.

status
string

New status (paused).

messageREQUIRED
string

Human-readable result.

extra_data
object

Raw upstream Campaign API response.

HTTP Errors

404
CAMPAIGN_NOT_FOUND

Campaign not found or not owned by the authenticated client.

422
BAD_REQUEST_FORMAT

Campaign ID is not a valid UUID.

502
gateway_error

Campaign API unreachable or returned an error (e.g. already paused).

Resume Campaign

POST
#
POSThttps://api.vanira.io/campaigns/:id/resume
Restart a paused campaign and resume outgoing calls. Migrated from n8n to the Python FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the campaign to resume.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/campaigns/1a817016-a3f5-41c1-995c-c74a5fb33720/resume' \2  -H "Content-Type: application/json"

Expected Response — 200 OK

json
1{2  "success": true,3  "campaign_id": "1a817016-a3f5-41c1-995c-c74a5fb33720",4  "status": "active",5  "message": "Campaign resumed successfully",6  "extra_data": {7    "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",8    "status": "active"9  }10}

Response Schema Details

successREQUIRED
boolean

Always true on success.

campaign_idREQUIRED
uuid

UUID of the campaign.

status
string

New status (active).

messageREQUIRED
string

Human-readable result.

extra_data
object

Raw upstream Campaign API response.

HTTP Errors

404
CAMPAIGN_NOT_FOUND

Campaign not found or not owned by the authenticated client.

422
BAD_REQUEST_FORMAT

Campaign ID is not a valid UUID.

502
gateway_error

Campaign API unreachable or returned an error (e.g. not paused).

Schedule Campaign Start

POST
#
POSThttps://api.vanira.io/campaigns/:id/schedule-start
Set a future ISO 8601 datetime for the campaign to automatically start. Migrated from n8n to the Python FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the campaign to schedule.

Body Parameters

scheduled_start_timeREQUIRED
string

ISO 8601 datetime for the auto-start (must be in the future).

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/campaigns/1a817016-a3f5-41c1-995c-c74a5fb33720/schedule-start' \2  -H "Content-Type: application/json" \3  -d '{4  "scheduled_start_time": "2026-04-01T09:00:00Z"5}'

Expected Response — 200 OK

json
1{2  "success": true,3  "campaign_id": "1a817016-a3f5-41c1-995c-c74a5fb33720",4  "scheduled_start_time": "2026-04-01T09:00:00Z",5  "status": "scheduled",6  "message": "Campaign start scheduled successfully",7  "extra_data": {8    "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",9    "status": "scheduled"10  }11}

Response Schema Details

successREQUIRED
boolean

Always true on success.

campaign_idREQUIRED
uuid

UUID of the campaign.

scheduled_start_timeREQUIRED
string

Confirmed scheduled start time.

status
string

Campaign status after scheduling.

messageREQUIRED
string

Human-readable result.

extra_data
object

Raw upstream Campaign API response.

HTTP Errors

404
CAMPAIGN_NOT_FOUND

Campaign not found or not owned by the authenticated client.

422
BAD_REQUEST_FORMAT

Campaign ID is not a valid UUID, or scheduled_start_time is blank/missing.

502
gateway_error

Campaign API unreachable or returned an error (e.g. time in the past).

List Campaigns

GET
#
GEThttps://api.vanira.io/campaigns
Fetch a list of all campaigns for a specific client. Migrated to FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/campaigns'

Expected Response — 200 OK

json
1{2  "data": [3    {4      "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",5      "name": "Q1 Outreach",6      "status": "active",7      "agent_id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",8      "client_id": "c2d3e4f5-1111-2222-3333-444455556666",9      "provider": "vobiz",10      "total_prospects": 150,11      "successful_calls": 45,12      "failed_calls": 12,13      "created_at": "2026-03-29T10:00:00Z",14      "updated_at": "2026-03-29T10:00:00Z"15    }16  ]17}

HTTP Errors

422
BAD_REQUEST_FORMAT

Invalid client_id format

Get Campaign Details

GET
#
GEThttps://api.vanira.io/campaigns/:id
Fetch complete details and configuration for a specific campaign. Migrated to FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the campaign to fetch.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/campaigns/<id>'

Expected Response — 200 OK

json
1{2  "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",3  "name": "Q1 Outreach",4  "status": "active",5  "max_concurrent_calls": 3,6  "timezone": "Asia/Kolkata",7  "call_timeout_seconds": 60,8  "allow_reschedule": true,9  "max_reschedules_per_prospect": 3,10  "reschedule_min_delay_hours": 1,11  "total_prospects": 150,12  "active_prospects": 2,13  "pending_prospects": 91,14  "is_hr_campaign": false,15  "created_at": "2026-03-29T10:00:00Z",16  "allocated_dids": [17    {18      "did_id": "09d89078-b9cc-452d-ae06-126d04239b73",19      "number": "918071387205",20      "max_concurrent_calls": 321    }22  ]23}

Response Schema Details

idREQUIRED
uuid

UUID of the campaign.

nameREQUIRED
string

Campaign name.

statusREQUIRED
string

Current status (draft, active, paused, scheduled, completed).

allocated_dids
array

List of phone numbers (Caller IDs) assigned to this campaign.

allocated_dids[].numberREQUIRED
string

The E.164 phone number.

total_prospects
number

Total number of contacts in the campaign.

active_prospects
number

Number of contacts currently being called.

HTTP Errors

404
CAMPAIGN_NOT_FOUND

Campaign not found

Update Campaign

PATCH
#
PATCHhttps://api.vanira.io/campaigns/:id
Modify campaign settings. Migrated to FastAPI backend.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the campaign to update.

Body Parameters

name
string

New name for the campaign

max_concurrent_calls
number

Maximum concurrent calls allowed

allow_reschedule
boolean

Whether to allow rescheduling calls

max_reschedules_per_prospect
number

Maximum reschedules allowed per prospect

Implementation Example

Environment
1curl -X PATCH 'https://api.vanira.io/campaigns/<id>' \2  -H "Content-Type: application/json" \3  -d '{4  "name": "<name>",5  "max_concurrent_calls": null,6  "allow_reschedule": false,7  "max_reschedules_per_prospect": null8}'

Expected Response — 200 OK

json
1{2  "id": "1a817016-a3f5-41c1-995c-c74a5fb33720",3  "name": "Updated Campaign Name",4  "status": "paused",5  "updated_at": "2026-03-29T10:05:00Z"6}

HTTP Errors

404
CAMPAIGN_NOT_FOUND

Campaign not found

400
BAD_REQUEST

No fields provided

422
VALIDATION_ERROR

Invalid fields format

Send WhatsApp Message

POST
#
POSThttps://api.vanira.io/inbox/send
Send a WhatsApp message to a phone number via a connected inbox. Requires an active WhatsApp inbox integration.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

inbox_idREQUIRED
uuid

UUID of the connected WhatsApp inbox.

toREQUIRED
string

Recipient phone number in E.164 format.

messageREQUIRED
string

Message content to send.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/inbox/send' \2  -H "Content-Type: application/json" \3  -d '{4  "inbox_id": "<inbox-uuid>",5  "to": "+919182517283",6  "message": "Hello from API!"7}'

Expected Response — 200 OK

json
1{2  "success": true,3  "message_id": "<message-uuid>",4  "status": "sent"5}

Response Schema Details

successREQUIRED
boolean

true if the message was queued successfully.

message_id
uuid

Unique identifier for the sent message.

status
string

Message status: sent | queued | failed.

HTTP Errors

400
missing_field

inbox_id, to, or message was not provided.

404
inbox_not_found

No WhatsApp inbox exists with the provided inbox_id.

401
inbox_not_authenticated

The inbox has not been authenticated (QR code not scanned).

503
whatsapp_unavailable

WhatsApp service is unavailable or the number is unreachable.

List Leads

GET
#
GEThttps://api.vanira.io/leads
Fetch a list of all leads associated with the authenticated organization/client.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/leads'

Expected Response — 200 OK

json
1{2  "leads": [3    {4      "id": "e30e70ab-7d43-4a11-b75c-3f2d2948cba4",5      "client_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",6      "name": "John Doe",7      "phone_number": "+1234567890",8      "email_id": "john.doe@example.com",9      "alternate_phone_number": null,10      "alternate_email_id": null,11      "lead_source": "Website",12      "status": "New",13      "remarks": "Interested in premium plan",14      "created_at": "2026-04-20T10:30:00Z",15      "updated_at": "2026-04-20T10:30:00Z"16    }17  ]18}

Response Schema Details

idREQUIRED
uuid

Unique identifier for the lead.

client_idREQUIRED
uuid

Owner organization ID.

name
string

Full name of the lead.

phone_number
string

Primary phone number.

email_id
string

Primary email address.

lead_source
string

Source of the lead (e.g., Website, Import).

status
string

Current status of the lead.

HTTP Errors

401
UNAUTHORIZED

Missing or invalid API key.

500
DATABASE_ERROR

Database connectivity issue.

Get Lead

GET
#
GEThttps://api.vanira.io/leads/:id
Retrieve the complete profile and details of a specific lead by its UUID.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the lead to retrieve.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/leads/e30e70ab-7d43-4a11-b75c-3f2d2948cba4'

Expected Response — 200 OK

json
1{2  "id": "e30e70ab-7d43-4a11-b75c-3f2d2948cba4",3  "client_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",4  "name": "John Doe",5  "phone_number": "+1234567890",6  "email_id": "john.doe@example.com",7  "alternate_phone_number": null,8  "alternate_email_id": null,9  "lead_source": "Website",10  "status": "New",11  "remarks": "Interested in premium plan",12  "created_at": "2026-04-20T10:30:00Z",13  "updated_at": "2026-04-20T10:30:00Z"14}

Response Schema Details

idREQUIRED
uuid

Unique identifier for the lead.

client_idREQUIRED
uuid

Owner organization ID.

name
string

Full name of the lead.

phone_number
string

Primary phone number.

email_id
string

Primary email address.

lead_source
string

Source of the lead (e.g., Website, Import).

status
string

Current status of the lead.

HTTP Errors

401
UNAUTHORIZED

Missing or invalid API key.

404
LEAD_NOT_FOUND

No lead exists with the provided UUID.

422
VALIDATION_ERROR

Invalid UUID format.

500
DATABASE_ERROR

Database connectivity issue.

Overview

#
Tools let your AI agent take actions during a conversation — calling an API, showing a UI component, booking an appointment, or triggering a call.
  • *Two tool types**
  • *Server tools** — the AI calls your HTTP webhook with extracted parameters. Your server processes the request and returns a result. The AI uses the result in its next response.
  • *Client tool kinds** (documented separately):
PageWhat it covers
Preset ToolsBuilt-in UI — form, calendar, navigate, DOM actions, screen overlay, …
Custom Client ToolsYour own handler — popups, API calls, custom logic
  • *Server tools — HTTP webhooks; see Create Tool** for POST /tools payload shape.
Use {{param_name}} in request.body or client_fields for AI-extracted values; plain strings for static fields.

Preset Tools

#
  • *Preset tools** are built-in client tools with ready-made UI. The SDK renders them automatically — no onCustomTool handler needed.
Set client_fields.preset_id when creating the tool. With VaniraCallBox or PresetRenderer, preset UI appears on its own.

Add a preset (dashboard)

  • *Agent → Tools → Create tool → Client** — pick a preset tile (Form, Calendar, Navigate, Upload, …). Attach to your agent.

Add a preset (API)

1. POST /tools — copy a body below (set client_fields.preset_id)
2. POST /assistant/{agent_id}/tools — attach with { "tool_id": "<uuid>" }
Code examplebash
1# 1. Create2curl -X POST https://api.vanira.io/tools \3  -H "X-API-Key: sk_live_..." \4  -H "Content-Type: application/json" \5  -d @vanira_form_tool.json6 7# 2. Attach to agent8curl -X POST https://api.vanira.io/assistant/YOUR_AGENT_ID/tools \9  -H "X-API-Key: sk_live_..." \10  -H "Content-Type: application/json" \11  -d '{"tool_id": "TOOL_UUID_FROM_STEP_1"}'

All preset IDs

Preset IDUIMode
vanira_formData Collection Formblocking
vanira_calendarDate & Time Pickerblocking
vanira_uploadFile Uploadblocking
vanira_cameraCamera Capturefire_and_forget
vanira_navigateNavigate to Route — requires vanira:navigate listener on SPAsblocking
vanira_highlight_elementHighlight Elementblocking
vanira_click_elementClick Elementblocking
vanira_select_optionSelect Dropdown Optionblocking
vanira_set_dateSet Date Fieldblocking
vanira_type_textDOM Typing Simulationblocking
vanira_erase_textWhiteboard / DOM Eraseblocking
vanira_erase_drawErase Drawing Boardblocking
vanira_drawChalkboard Shape Drawingblocking
vanira_live_visionLive Vision (Streaming Camera)fire_and_forget
vanira_close_live_cameraStop Live Camerablocking
vanira_live_screenLive Screen Sharefire_and_forget
vanira_close_live_screenStop Live Screen Shareblocking
vanira_clip_regionPage Region Clipblocking
vanira_tab_screenshotTab Screenshotblocking
vanira_screen_inkScreen Inkblocking
vanira_screen_cursorScreen Cursorblocking
vanira_screen_clickScreen Clickblocking
vanira_clear_screen_overlayClear Screen Overlayblocking
vanira_page_scanPage Scanblocking
vanira_point_atPoint Atblocking
vanira_outline_targetsOutline Targetsblocking
vanira_clear_guideClear Guideblocking
  • *Blocking presets wait for `sendToolResult()` (the SDK sends it when the user completes or dismisses the UI). fire_and_forget** presets do not block the agent.

DOM presets — route in client_fields

For vanira_click_element, vanira_select_option, vanira_set_date, vanira_type_text, and vanira_erase_text, set route to the SPA path where the target element lives. The SDK navigates first if needed.

Navigate preset — SPA listener

When the agent calls vanira_navigate, the SDK dispatches a browser event instead of forcing a full page reload:
TargetSDK behavior
Same-origin path (e.g. /pricing, /docs#faq)Fires vanira:navigate with detail.pathyour site must handle it
External URL (different origin)Opens in a new tab automatically — no listener needed
  • *SPA sites (React, Vue, Next.js, etc.) must register a vanira:navigate listener** that routes with your framework and sets event.detail.handled = true. Without it, same-origin navigation fails with status: cancelled and the console shows: No SPA listener handled vanira:navigate.
  • *Blocking tool:** the AI pauses until the SDK sends client_tool_result. Success payload: { status: 'success', navigated_to, target_url }. Server interrupt (clearAudio / client_tool_cancel): { status: 'interrupted', reason, target_url }.
  • *Multi-page sites** can use window.location.assign(event.detail.path) in the listener, or the same pattern as a fallback.

Copy-paste POST /tools bodies

vanira_form — Data Collection Form

Popup form for Name, Email, etc. blocking — AI waits for client_tool_result with submitted fields.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "collect_user_data",3  "ref_code": "collect_user_data",4  "description": "Call this tool to display a form to collect information from the user.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "reason",11      "type": "string",12      "description": "A short message explaining why you need their info (e.g., \"To look up your order\").",13      "required": true14    }15  ],16  "client_fields": {17    "preset_id": "vanira_form",18    "title": "Enter your details",19    "fields": "Name, Email, Phone"20  }21}

vanira_calendar — Date & Time Picker

Calendar + time slots. Optional slots_api_url for live availability. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "display_booking_calendar",3  "ref_code": "display_booking_calendar",4  "description": "Call this tool to display a calendar for the user to select an appointment date and time.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "reason",11      "type": "string",12      "description": "A short message explaining why they need to pick a time (e.g., \"To schedule your consultation\").",13      "required": true14    }15  ],16  "client_fields": {17    "preset_id": "vanira_calendar",18    "title": "Select a Date & Time",19    "timezone": "America/New_York",20    "slots_api_url": "https://api.example.com/slots?date={{date}}&tz={{timezone}}",21    "slots_api_method": "GET",22    "slots_api_headers": "{\"Authorization\": \"Bearer YOUR_TOKEN\"}",23    "slots_api_body": "{}"24  }25}

vanira_upload — File Upload

Drag-and-drop uploader (up to 3 MB). blockingclient_tool_result includes media_id when upload succeeds.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "request_file_upload",3  "ref_code": "request_file_upload",4  "description": "Call this tool to ask the user to upload a file (image, PDF, document, CSV) so the agent can inspect or process it.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "reason",11      "type": "string",12      "description": "A short message explaining why you need the file (e.g., \"To verify your identity\").",13      "required": true14    }15  ],16  "client_fields": {17    "preset_id": "vanira_upload",18    "title": "Upload a File",19    "description": "Drop or select any file — images, PDFs, documents — up to 3 MB",20    "reason": "upload",21    "accept": "application/pdf,image/*"22  }23}

vanira_camera — Camera Capture

Single photo capture mid-call. fire_and_forget.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "open_camera",3  "ref_code": "open_camera",4  "description": "Call this tool to open the user's camera so they can take a photo for you to inspect (e.g. damage, hardware issue, ID verification).",5  "type": "client",6  "execution_mode": "fire_and_forget",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "reason",11      "type": "string",12      "description": "A short message explaining why you need a photo (e.g., \"To inspect the damage on your device\").",13      "required": true14    }15  ],16  "client_fields": {17    "preset_id": "vanira_camera",18    "title": "Take a Photo",19    "description": "Point your camera at the subject, then tap capture to send it to your agent.",20    "reason": "camera_capture",21    "facing_mode": "environment",22    "liveness_check": false23  }24}

vanira_navigate — Navigate to Route

Same-origin paths dispatch vanira:navigateregister a listener on your site (see SPA setup below). External URLs open in a new tab. blocking — AI waits for client_tool_result; server interrupt returns status: interrupted.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "navigate_user",3  "ref_code": "navigate_user",4  "description": "Call this tool to redirect the user to a different route.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_navigate",11    "target_url": "/pricing"12  }13}
When the agent calls vanira_navigate, the SDK dispatches a browser event instead of forcing a full page reload:
TargetSDK behavior
Same-origin path (e.g. /pricing, /docs#faq)Fires vanira:navigate with detail.pathyour site must handle it
External URL (different origin)Opens in a new tab automatically — no listener needed
  • *SPA sites (React, Vue, Next.js, etc.) must register a vanira:navigate listener** that routes with your framework and sets event.detail.handled = true. Without it, same-origin navigation fails with status: cancelled and the console shows: No SPA listener handled vanira:navigate.
  • *Blocking tool:** the AI pauses until the SDK sends client_tool_result. Success payload: { status: 'success', navigated_to, target_url }. Server interrupt (clearAudio / client_tool_cancel): { status: 'interrupted', reason, target_url }.
  • *Multi-page sites** can use window.location.assign(event.detail.path) in the listener, or the same pattern as a fallback.
  • *Listener snippet** (add to your site):
Code examplejavascript
1// Add once on your site (same page as the Vanira widget).2// Required when your agent uses the vanira_navigate preset.3window.addEventListener('vanira:navigate', (event) => {4  const path = event.detail.path; // e.g. "/pricing" or "/docs#section"5 6  // Option A — multi-page site or simple fallback:7  window.location.assign(path);8 9  // Option B — SPA router (pick one that matches your stack):10  // router.push(path);              // React Router: useNavigate()11  // navigate(path);                 // Vue Router12  // router.push(path);              // Next.js App Router13 14  event.detail.handled = true; // required — tells the SDK navigation succeeded15});

vanira_highlight_element — Highlight Element

Glow outline on a CSS selector. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "highlight_ui_element",3  "ref_code": "highlight_ui_element",4  "description": "Call this tool to draw the user's attention to a specific button or element on the page.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_highlight_element",11    "css_selector": "#buy-button",12    "color": "#10B981"13  }14}

vanira_click_element — Click Element

Programmatic click by HTML id (no #). route required — SDK navigates first when the user is on another page. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "click_button",3  "ref_code": "click_button",4  "description": "Call this tool to click a specific button on the user's screen by HTML id.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_click_element",11    "element_id": "buy-button",12    "route": "/checkout"13  }14}

vanira_select_option — Select Dropdown Option

Select native <select> or custom dropdown by HTML id. route required — SDK navigates first. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "select_option",3  "ref_code": "select_option",4  "description": "Call this tool to select a dropdown option on the user's page (e.g. country, cabin class).",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "option_value",11      "type": "string",12      "description": "Option value attribute (e.g. economy, IN).",13      "required": false14    },15    {16      "name": "option_label",17      "type": "string",18      "description": "Visible label to match (e.g. Economy, India).",19      "required": false20    }21  ],22  "client_fields": {23    "preset_id": "vanira_select_option",24    "element_id": "country-select",25    "route": "/flights",26    "allowed_options": ["economy", "business", "first_class"]27  }28}

vanira_set_date — Set Date Field

Set text or native date input by HTML id. Agent passes ISO date; SDK formats per text_format. route required. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "set_date_field",3  "ref_code": "set_date_field",4  "description": "Call this tool to set a departure, check-in, or delivery date on the user's form.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "date",11      "type": "string",12      "description": "Date in ISO YYYY-MM-DD (e.g. 2026-06-15).",13      "required": true14    }15  ],16  "client_fields": {17    "preset_id": "vanira_set_date",18    "element_id": "departure-date",19    "route": "/flights",20    "input_kind": "text",21    "text_format": "DD/MM/YYYY"22  }23}

vanira_type_text — DOM Typing Simulation

Type into an input or chalkboard. typing_mode: append (boards) or replace (search bars). route only when CSS selector / element id is set. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "type_on_whiteboard",3  "ref_code": "type_on_whiteboard",4  "description": "Call when writing something visible to the student — a formula, solution step, definition, or note. Pass text_to_type with the exact text.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "text_to_type",11      "type": "string",12      "description": "Exact text to write — equations (F=ma), solution steps, definitions, or form values from the conversation.",13      "required": true14    }15  ],16  "client_fields": {17    "preset_id": "vanira_type_text",18    "css_selector": "#answer-input",19    "element_id": "",20    "route": "/lesson",21    "typing_mode": "append",22    "delay_ms": 5023  }24}

vanira_erase_text — Whiteboard / DOM Erase

Clear input or erase words on chalkboard. route only when element id is set. blocking — call sendToolResult() when done.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "erase_text",3  "ref_code": "erase_text",4  "description": "Call this tool to clear the whiteboard or erase the last few words.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "mode",11      "type": "string",12      "description": "Whether to erase everything (\"all\") or just the last few words (\"words\").",13      "required": false,14      "enum": ["all", "words"]15    },16    {17      "name": "num_words",18      "type": "number",19      "description": "The number of words to erase (only used if mode is \"words\").",20      "required": false21    }22  ],23  "client_fields": {24    "preset_id": "vanira_erase_text",25    "element_id": "#search-input",26    "route": "/search",27    "delay_ms": 5028  }29}

vanira_erase_draw — Erase Drawing Board

Wipes TOP diagram panel only — notes/formulas in the bottom panel stay. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "erase_drawing_board",3  "ref_code": "erase_drawing_board",4  "description": "Call this tool to clear the diagram/drawing area on the chalkboard. Written notes stay.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_erase_draw"11  }12}

vanira_draw — Chalkboard Shape Drawing

Draw ONE shape per call (flat params). blocking — call multiple times for a full diagram.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "draw_on_board",3  "ref_code": "draw_on_board",4  "description": "Draw one shape on the chalkboard. Call again for each extra shape or label.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "shape_type",11      "type": "enum",12      "description": "line | circle | triangle | rectangle | label",13      "required": false,14      "enum": ["line", "circle", "triangle", "rectangle", "label"]15    },16    {17      "name": "p1_x",18      "type": "number",19      "description": "Triangle apex X (e.g. 400) or line start X",20      "required": false21    },22    {23      "name": "p1_y",24      "type": "number",25      "description": "Triangle apex Y (e.g. 80) or line start Y",26      "required": false27    },28    {29      "name": "p2_x",30      "type": "number",31      "description": "Triangle base corner B X (e.g. 120)",32      "required": false33    },34    {35      "name": "p2_y",36      "type": "number",37      "description": "Triangle base corner B Y (e.g. 420)",38      "required": false39    },40    {41      "name": "p3_x",42      "type": "number",43      "description": "Triangle base corner C X (e.g. 680)",44      "required": false45    },46    {47      "name": "p3_y",48      "type": "number",49      "description": "Triangle base corner C Y (e.g. 420)",50      "required": false51    },52    {53      "name": "center_x",54      "type": "number",55      "description": "Circle center X (e.g. 400)",56      "required": false57    },58    {59      "name": "center_y",60      "type": "number",61      "description": "Circle center Y (e.g. 250)",62      "required": false63    },64    {65      "name": "radius",66      "type": "number",67      "description": "Circle radius (e.g. 90)",68      "required": false69    },70    {71      "name": "label_x",72      "type": "number",73      "description": "Label position X",74      "required": false75    },76    {77      "name": "label_y",78      "type": "number",79      "description": "Label position Y",80      "required": false81    },82    {83      "name": "label_text",84      "type": "string",85      "description": "Label text (e.g. A)",86      "required": false87    },88    {89      "name": "clear_old_diagrams_on_board",90      "type": "boolean",91      "description": "True only when old diagram is not needed — wipes top panel (notes stay). Default false while building.",92      "required": false93    },94    {95      "name": "clear_drawings",96      "type": "boolean",97      "description": "Deprecated — use clear_old_diagrams_on_board",98      "required": false99    }100  ],101  "client_fields": {102    "preset_id": "vanira_draw",103    "shape_duration_ms": 2000,104    "shape_gap_ms": 80105  }106}

vanira_live_vision — Live Vision (Streaming Camera)

Background ~1 FPS camera stream. fire_and_forget.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "open_live_camera",3  "ref_code": "open_live_camera",4  "description": "Call this tool to open the user's camera and start a live video stream so you can continuously see what they're looking at.",5  "type": "client",6  "execution_mode": "fire_and_forget",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "scope",11      "type": "string",12      "description": "How long to stream: until_call_end (default), timed (N seconds), or full_call.",13      "required": false,14      "enum": ["until_call_end", "timed", "full_call"]15    },16    {17      "name": "duration_sec",18      "type": "number",19      "description": "Seconds to stream (only used when scope is \"timed\").",20      "required": false21    },22    {23      "name": "reason",24      "type": "string",25      "description": "Routing key for the media server (e.g. \"damage_inspection\").",26      "required": false27    }28  ],29  "client_fields": {30    "preset_id": "vanira_live_vision",31    "target_fps": 1,32    "max_width": 640,33    "facing_mode": "environment",34    "reason": "camera_capture",35    "show_preview": true36  }37}

vanira_close_live_camera — Stop Live Camera

Stops an active live vision session. blocking. Pair with Live Vision.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "close_live_camera",3  "ref_code": "close_live_camera",4  "description": "Call this tool to stop the live camera stream and close the camera session.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_close_live_camera"11  }12}

vanira_live_screen — Live Screen Share

Background ~1 FPS screen stream. fire_and_forget.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "open_live_screen",3  "ref_code": "open_live_screen",4  "description": "Call this tool to ask the user to share their screen so you can continuously see what they are working on.",5  "type": "client",6  "execution_mode": "fire_and_forget",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "scope",11      "type": "string",12      "description": "How long to stream: until_call_end (default), timed (N seconds), or full_call.",13      "required": false,14      "enum": ["until_call_end", "timed", "full_call"]15    },16    {17      "name": "duration_sec",18      "type": "number",19      "description": "Seconds to stream (only used when scope is \"timed\").",20      "required": false21    },22    {23      "name": "reason",24      "type": "string",25      "description": "Routing key for the media server (e.g. \"support_ticket\").",26      "required": false27    }28  ],29  "client_fields": {30    "preset_id": "vanira_live_screen",31    "target_fps": 1,32    "max_width": 1280,33    "reason": "screen_capture",34    "prefer_current_tab": true,35    "show_preview": true36  }37}

vanira_close_live_screen — Stop Live Screen Share

Stops an active live screen session. blocking. Pair with Live Screen Share.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "close_live_screen",3  "ref_code": "close_live_screen",4  "description": "Call this tool to stop the live screen share and end the screen session.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_close_live_screen"11  }12}

vanira_clip_region — Page Region Clip

Snipping overlay on the host page — user drags a box, only the crop uploads. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "clip_page_region",3  "ref_code": "clip_page_region",4  "description": "Call this tool so the user can clip a region of the page and ask a question about it.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "prompt",11      "type": "string",12      "description": "The question about the selected region.",13      "required": true14    },15    {16      "name": "reason",17      "type": "string",18      "description": "Media routing key (e.g. page_clip).",19      "required": false20    }21  ],22  "client_fields": {23    "preset_id": "vanira_clip_region",24    "hint": "Drag to select an area — release to clip.",25    "reason": "page_clip",26    "min_region_px": 2427  }28}

vanira_tab_screenshot — Tab Screenshot

Captures visible tab JPEG + element layout (positions, labels, css_selector). blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "capture_tab_screenshot",3  "ref_code": "capture_tab_screenshot",4  "description": "Capture the visible tab; returns image + elements with center_x/center_y (0–1) and css_selector for screen_ink.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "prompt",11      "type": "string",12      "description": "Optional context for why the screenshot is needed.",13      "required": false14    },15    {16      "name": "reason",17      "type": "string",18      "description": "Media routing key (e.g. tab_screenshot).",19      "required": false20    },21    {22      "name": "max_width",23      "type": "number",24      "description": "Max JPEG width in pixels (default 1280).",25      "required": false26    },27    {28      "name": "max_elements",29      "type": "number",30      "description": "Max UI elements with positions to return (default 80).",31      "required": false32    }33  ],34  "client_fields": {35    "preset_id": "vanira_tab_screenshot",36    "reason": "tab_screenshot",37    "max_width": 1280,38    "max_elements": 8039  }40}

vanira_screen_ink — Screen Ink

Freeform animated strokes (points or path_d); optional user draw. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "screen_ink",3  "ref_code": "screen_ink",4  "description": "Draw freeform on screen. Prefer css_selector for exact placement, or stroke_points from tab screenshot (0–1 viewport coords).",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "strokes",11      "type": "array",12      "description": "Ordered freeform strokes: [{ points: [[0.4,0.4],[0.4,0.2],[0.7,0.4]], close: true }].",13      "required": false14    },15    {16      "name": "points",17      "type": "array",18      "description": "Single-stroke shorthand [[x,y], ...] (0–1 or px).",19      "required": false20    },21    {22      "name": "path_d",23      "type": "string",24      "description": "Single-stroke SVG path d (viewport px) for curves.",25      "required": false26    },27    {28      "name": "css_selector",29      "type": "string",30      "description": "Target element — live DOM lookup for exact polygon/bbox (best accuracy).",31      "required": false32    },33    {34      "name": "close",35      "type": "boolean",36      "description": "Close point path (triangle, rectangle outline, etc.).",37      "required": false38    },39    {40      "name": "animate",41      "type": "boolean",42      "description": "Stroke animation (default true).",43      "required": false44    },45    {46      "name": "interactive",47      "type": "boolean",48      "description": "Let user freehand draw on screen.",49      "required": false50    },51    {52      "name": "color",53      "type": "string",54      "description": "Stroke color (default #f97316).",55      "required": false56    },57    {58      "name": "clear_before",59      "type": "boolean",60      "description": "Clear existing ink first.",61      "required": false62    }63  ],64  "client_fields": {65    "preset_id": "vanira_screen_ink",66    "color": "#f97316"67  }68}

vanira_screen_cursor — Screen Cursor

Show a pointer at viewport coordinates. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "screen_cursor",3  "ref_code": "screen_cursor",4  "description": "Call this tool to show a cursor at a screen position to guide the user.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "x",11      "type": "number",12      "description": "X position (0–1 normalized or px).",13      "required": false14    },15    {16      "name": "y",17      "type": "number",18      "description": "Y position (0–1 normalized or px).",19      "required": false20    },21    {22      "name": "css_selector",23      "type": "string",24      "description": "Show cursor at center of this element.",25      "required": false26    },27    {28      "name": "label",29      "type": "string",30      "description": "Optional label next to cursor.",31      "required": false32    }33  ],34  "client_fields": {35    "preset_id": "vanira_screen_cursor",36    "color": "#f97316",37    "duration_ms": 250038  }39}

vanira_screen_click — Screen Click

Ripple + programmatic click at coordinates. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "screen_click",3  "ref_code": "screen_click",4  "description": "Call this tool to click at screen coordinates with a visible ripple.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    {10      "name": "x",11      "type": "number",12      "description": "X position (0–1 normalized or px).",13      "required": false14    },15    {16      "name": "y",17      "type": "number",18      "description": "Y position (0–1 normalized or px).",19      "required": false20    },21    {22      "name": "css_selector",23      "type": "string",24      "description": "Click center of this element.",25      "required": false26    },27    {28      "name": "perform_click",29      "type": "boolean",30      "description": "Dispatch click to element at point (default true).",31      "required": false32    }33  ],34  "client_fields": {35    "preset_id": "vanira_screen_click",36    "perform_click": true,37    "show_ripple": true,38    "color": "#f97316"39  }40}

vanira_clear_screen_overlay — Clear Screen Overlay

Removes all screen ink and cursor overlays. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "clear_screen_overlay",3  "ref_code": "clear_screen_overlay",4  "description": "Call this tool to clear all screen annotations when done guiding the user.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_clear_screen_overlay"11  }12}

vanira_page_scan — Page Scan

Fast DOM scan — element ids (e1, e2…) for guide tools. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "page_scan",3  "ref_code": "page_scan",4  "description": "Scan visible page DOM. Returns catalog of element ids. Call before point_at.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    { "name": "prompt", "type": "string", "description": "Optional scan context.", "required": false },10    { "name": "max_elements", "type": "number", "description": "Max elements (default 64).", "required": false }11  ],12  "client_fields": {13    "preset_id": "vanira_page_scan",14    "max_elements": 64,15    "include_image": false16  }17}

vanira_point_at — Point At

Bezier fly cursor to element with live DOM outline. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "point_at",3  "ref_code": "point_at",4  "description": "Fly cursor to element_id from page_scan (e.g. e3) with optional label.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    { "name": "element_id", "type": "string", "description": "Id from page_scan.", "required": false },10    { "name": "label", "type": "string", "description": "Cursor label.", "required": false }11  ],12  "client_fields": {13    "preset_id": "vanira_point_at",14    "fly": true,15    "outline": true,16    "color": "#f97316"17  }18}

vanira_outline_targets — Outline Targets

Animated outlines on live DOM elements. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "outline_targets",3  "ref_code": "outline_targets",4  "description": "Outline elements by targets: [e1, e3] from page_scan.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [9    { "name": "targets", "type": "string", "description": "JSON array of element ids.", "required": false }10  ],11  "client_fields": {12    "preset_id": "vanira_outline_targets",13    "color": "#f97316",14    "animate": true15  }16}

vanira_clear_guide — Clear Guide

Removes guide cursor, ink, and ripples. blocking.
  • *Create tool body** (POST /tools):
Code examplejson
1{2  "name": "clear_guide",3  "ref_code": "clear_guide",4  "description": "Clear all on-page guide annotations when done.",5  "type": "client",6  "execution_mode": "blocking",7  "channels": ["voice_web", "voice_telephony"],8  "parameters": [],9  "client_fields": {10    "preset_id": "vanira_clear_guide"11  }12}

Custom Client Tools

#
Custom client tools are browser actions you implement — popups, modals, client-side API calls, or any UI the SDK presets do not cover.
Create in the dashboard: Agent → Tools → New tool → Client → Custom.

Step 1 — Agent parameters

Define what the AI should extract from the conversation before invoking the tool. These are not sent directly to your handler — they drive the tool schema only.
Example:
  • customer_name (string, required) — "Person's name from the conversation"

Step 2 — Frontend payload

Map the keys your app code expects. Each value is either:
  • {{param_name}} — substituted with the AI-extracted agent parameter
  • a static string — always the same value
This becomes client_fields in the API and resolves to arguments at runtime.
Payload keyValue
name{{customer_name}}
sourcewebsite
At runtime: { "name": "Teja", "source": "website" }

Step 3 — Execution mode

Dashboard labelAPI valueWhen to use
BlockingblockingAI should wait (form submit, user confirmation) — call sendToolResult()
Asyncfire_and_forgetFire-and-forget UI (popup, toast, map pan)

Step 4 — Wire in the SDK

With VaniraCallBox, handle custom tools in onCustomTool (presets are automatic):
Code exampletypescript
1onCustomTool={(call, client) => {2  if (call.name === 'say_hi') {3    showHiPopup();4    if (call.execution_mode !== 'fire_and_forget' && call.tool_call_id) {5      client.sendToolResult(call.tool_call_id, { status: 'success' });6    }7  }8}}
See the SDK Custom Client Tools guide for the full POST /tools payload.

End Call

SDK
#
BUILT-INend_call
The End Call tool is automatically attached to every Vanira agent. You do not need to create it.
### Behavior
The AI will invoke this tool when:
1. It senses the conversation has reached a natural conclusion (e.g., "Goodbye", "Thank you for your help").
2. The user explicitly asks to hang up.
### Payload Structure
In the API response, it appears with the following properties:
Code examplejson
1{2  "name": "end_call",3  "ref_code": "end_call",4  "description": "End the call when the conversation is finished.",5  "type": "client",6  "execution_mode": "fire_and_forget",7  "parameters": []8}

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1const response = await fetch('end_call', {2  method: 'SDK',3  headers: { 'Content-Type': 'application/json' },4  body: JSON.stringify({}),5});6const data = await response.json();

Human Transfer

POST
#
POSThttps://api.vanira.io/tools
The Human Transfer tool escalates the conversation to a live operator.
### Telephony Behavior
In voice calls, calling this tool triggers an immediate SIP Transfer to your configured fallback number or the to_number parameter.

Creation Payload

Code examplejson
1{2  "name": "human_transfer",3  "ref_code": "human_transfer",4  "description": "Transfers the caller to a live human agent.",5  "type": "server",6  "channels": ["voice_telephony"],7  "parameters": [8    {9      "name": "to_number",10      "type": "string",11      "description": "The destination phone number.",12      "required": true13    }14  ],15  "server": {16    "url": "https://api.vanira.io/webhook/human-transfer",17    "method": "POST"18  },19  "request": {20    "body": { "to_number": "919182517283" },21    "headers": {},22    "query": {}23  }24}

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/tools' \2  -H "Content-Type: application/json"

Agent Transfer

POST
#
POSThttps://api.vanira.io/tools
The Agent Transfer tool switches the current conversation context to a different AI agent.
### Use Case
Transferring a user from a "Lead Qualification" agent to a "Support" agent once their identity is verified.

Creation Payload

Code examplejson
1{2  "name": "agent_transfer",3  "ref_code": "agent_transfer",4  "description": "Transfers the call to another AI agent configuration.",5  "type": "server",6  "channels": ["voice_web", "voice_telephony"],7  "parameters": [8    {9      "name": "agent_id",10      "type": "string",11      "description": "UUID of the target agent.",12      "required": true13    }14  ],15  "server": {16    "url": "https://api.vanira.io/webhook/agent-transfer",17    "method": "POST"18  },19  "request": {20    "body": { "agent_id": "dcf2b11c-81c2-4619-8483-580c8e25cb23" },21    "headers": {},22    "query": {}23  }24}

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/tools' \2  -H "Content-Type: application/json"

List Tools

GET
#
GEThttps://api.vanira.io/tools
Returns all tools defined for the authenticated client. Tools are client-level — they can be attached to multiple agents.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/tools'

Expected Response — 200 OK

json
1{2  "tools": [3    {4      "id": "e2705199-...",5      "name": "show_location_map",6      "description": "Show an interactive map for a location the user asks about.",7      "ref_code": "show_location_map",8      "type": "client",9      "execution_mode": "fire_and_forget",10      "channels": ["voice_web"],11      "parameters": [12        { "name": "location_query", "type": "string", "description": "City or landmark", "required": true }13      ],14      "client_fields": { "query": "{{location_query}}" }15    },16    {17      "id": "a1b2c3d4-...",18      "name": "check_order_status",19      "description": "Check the status of a customer order.",20      "ref_code": "check_order_status",21      "type": "server",22      "execution_mode": "fire_and_forget",23      "channels": ["voice_web", "voice_telephony"],24      "parameters": [25        { "name": "order_id", "type": "string", "description": "Order ID", "required": true }26      ],27      "server": { "url": "https://api.acme.com/orders", "method": "POST" },28      "request": {29        "body":    { "order_id": "{{order_id}}", "source": "vanira" },30        "headers": { "X-API-Key": "sk-abc123" },31        "query":   {}32      }33    }34  ],35  "total": 236}

Response Schema Details

idREQUIRED
uuid

Tool UUID.

nameREQUIRED
string

Tool name — used as the function name the AI calls.

descriptionREQUIRED
string

What the tool does — AI uses this to decide when to call it.

typeREQUIRED
string

"server" | "client".

execution_modeREQUIRED
string

"blocking" | "fire_and_forget". For client tools only.

channelsREQUIRED
array

Which channels this tool is active on.

parametersREQUIRED
array

Parameter schema — what the AI extracts from the conversation.

server
object

{ url, method } — present for server tools only.

request
object

{ body, headers, query } with {{param}} notation.

client_fields
object

Fields sent to the client-side action with {{param}} notation.

HTTP Errors

401
UNAUTHORIZED

No valid API key.

Get Tool

GET
#
GEThttps://api.vanira.io/tools/:id
Retrieve the full definition of a single tool by its UUID.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

The unique ID of the tool.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/tools/e2705199-b431-4091-ad7c-ca1110b8e025'

Expected Response — 200 OK

json
1{2  "id": "e2705199-...",3  "name": "check_order_status",4  "description": "Check the status of a customer order.",5  "ref_code": "check_order_status",6  "type": "server",7  "execution_mode": "blocking",8  "channels": ["voice_web", "voice_telephony"],9  "parameters": [10    { "name": "order_id", "type": "string", "description": "Order ID", "required": true }11  ],12  "server": { "url": "https://api.acme.com/orders", "method": "POST" },13  "request": {14    "body": { "order_id": "{{order_id}}", "source": "vanira" },15    "headers": { "X-API-Key": "sk-abc123" }16  }17}

HTTP Errors

401
UNAUTHORIZED

No valid API key.

404
TOOL_NOT_FOUND

Tool not found or not owned by the authenticated client.

Create Tool

POST
#
POSThttps://api.vanira.io/tools
Create a new tool. The tool is created at the client level — attach it to agents separately using POST /assistant/{id}/tools.
  • *Server tools** — describe what the AI extracts (parameters) and map to your webhook (request.body, headers, query). Use {{param_name}} for dynamic values, plain strings for static.
  • *Client tools — custom** — use two layers:
1. parameters — agent parameters (what the AI collects from chat)
  • *Client tools — two kinds:**
  • Preset — see Preset Tools for every preset_id and copy-paste POST /tools body
  • Custom — see Custom Client Tools for agent parameters + frontend payload mapping
If client_fields is omitted for a custom client tool, each parameter auto-maps to the same key in arguments.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Body Parameters

nameREQUIRED
string

Tool name — becomes the function name the AI calls.

descriptionREQUIRED
string

What the tool does. The AI reads this to decide when to call it.

ref_code
string

Optional reference code (slug). If omitted, one is generated from the name.

typeREQUIRED
string

"server" — HTTP webhook. "client" — UI action in the browser.

execution_mode
string

"blocking" = AI waits for result. "fire_and_forget" = AI continues. Default: blocking for server, fire_and_forget for client.

channels
array

voice_web | voice_telephony | chat | whatsapp. Defaults to [voice_web, voice_telephony].

parameters
array

What the AI extracts from the conversation. Each item: { name, type, description, required, enum? }.

server
object

Required when type is "server". { url, method: POST|GET|PUT|DELETE }

request
object

HTTP fields. If omitted, parameters auto-map to body by name. Use {{param}} for dynamic values.

client_fields
object

Frontend payload for client tools. Use {{param}} for agent values or static strings. Presets use preset_id and preset config keys.

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/tools' \2  -H "Content-Type: application/json" \3  -d '{4  "name": "check_order_status",5  "description": "Check the status of a customer order by order ID",6  "ref_code": "check_order_status",7  "type": "server",8  "execution_mode": "blocking",9  "channels": [10    "voice_web",11    "voice_telephony"12  ],13  "parameters": [14    {15      "name": "order_id",16      "type": "string",17      "description": "Order ID to check",18      "required": true19    }20  ],21  "server": {22    "url": "https://api.acme.com/orders",23    "method": "POST"24  },25  "request": {26    "body": {27      "order_id": "{{order_id}}",28      "source": "vanira"29    },30    "headers": {31      "X-API-Key": "sk-abc"32    },33    "query": {}34  },35  "client_fields": {36    "name": "{{customer_name}}",37    "source": "website"38  }39}'

Expected Response — 200 OK

json
1// Server tool example2{3  "name": "check_order_status",4  "description": "Check the status of a customer order",5  "ref_code": "check_order_status",6  "type": "server",7  "execution_mode": "blocking",8  "channels": ["voice_web", "voice_telephony"],9  "server": { "url": "https://api.acme.com/orders", "method": "POST" },10  "parameters": [11    {12      "name": "order_id",13      "type": "string",14      "description": "The order ID the customer mentioned",15      "required": true16    }17  ],18  "request": {19    "body":    { "order_id": "{{order_id}}", "source": "vanira" },20    "headers": { "X-API-Key": "sk-your-key" },21    "query":   {}22  }23}24 25// Client tool example26{27  "name": "show_location_map",28  "description": "Show an interactive map to the user for a location they asked about",29  "ref_code": "show_location_map",30  "type": "client",31  "execution_mode": "fire_and_forget",32  "channels": ["voice_web"],33  "parameters": [34    {35      "name": "location",36      "type": "string",37      "description": "The city or landmark to show on the map",38      "required": true39    }40  ],41  "client_fields": { "query": "{{location}}", "zoom": 12 }42}43 44// Custom client tool — agent params + frontend payload mapping45{46  "name": "say_hi",47  "description": "Show a greeting popup when the user says hello",48  "ref_code": "say_hi",49  "type": "client",50  "execution_mode": "fire_and_forget",51  "channels": ["voice_web"],52  "parameters": [],53  "client_fields": {}54}55 56// Custom client tool with mapped payload57{58  "name": "greet_user",59  "description": "Show a personalized greeting popup",60  "ref_code": "greet_user",61  "type": "client",62  "execution_mode": "blocking",63  "channels": ["voice_web"],64  "parameters": [65    {66      "name": "customer_name",67      "type": "string",68      "description": "The person's name from the conversation",69      "required": true70    }71  ],72  "client_fields": {73    "name": "{{customer_name}}",74    "source": "website"75  }76}

HTTP Errors

401
UNAUTHORIZED

No valid API key.

422
VALIDATION_ERROR

Missing required fields, or server.url not provided for type="server".

Update Tool

PATCH
#
PATCHhttps://api.vanira.io/tools/:id
Update a tool's name, description, URL, request body, headers, or parameters. All fields are optional — only what you send is updated.
When updating request fields, the full body/headers/query object is replaced. Parameters are preserved from the existing tool unless explicitly re-sent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the tool to update.

Body Parameters

name
string

New tool name.

description
string

Updated description.

ref_code
string

Updated reference code (slug).

server
object

Updated server config { url, method }.

request
object

Updated request body/headers/query mapping. {{param}} notation supported.

client_fields
object

Updated client-side fields.

channels
array

Updated channel list.

parameters
array

Updated parameters list. Replaces existing ones.

Implementation Example

Environment
1curl -X PATCH 'https://api.vanira.io/tools/e2705199-b431-4091-ad7c-ca1110b8e025' \2  -H "Content-Type: application/json" \3  -d '{4  "name": "<name>",5  "description": "<description>",6  "ref_code": "<ref_code>",7  "server": "<server>",8  "request": "<request>",9  "client_fields": "<client_fields>",10  "channels": "<channels>",11  "parameters": [12    {13      "name": "order_id",14      "type": "string",15      "description": "Order ID",16      "required": true17    }18  ]19}'

HTTP Errors

401
UNAUTHORIZED

No valid API key.

404
TOOL_NOT_FOUND

Tool not found or not owned by the authenticated client.

Delete Tool

DELETE
#
DELETEhttps://api.vanira.io/tools/:id
Permanently delete a tool and remove it from all agents it is attached to. Irreversible.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

UUID of the tool to delete.

Implementation Example

Environment
1curl -X DELETE 'https://api.vanira.io/tools/e2705199-b431-4091-ad7c-ca1110b8e025' \2  -H "Content-Type: application/json"

HTTP Errors

404
TOOL_NOT_FOUND

Tool not found or not owned by the authenticated client.

List Agent Tools

GET
#
GEThttps://api.vanira.io/assistant/:id/tools
Returns all tools currently attached to a specific agent.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

Agent UUID.

Implementation Example

Environment
1curl -X GET 'https://api.vanira.io/assistant/28c591f1-f17c-4c46-82ac-4054a843007a/tools'

Expected Response — 200 OK

json
1{2  "tools": [3    {4      "id": "7ccfd8ea-...",5      "tool_id": "e2705199-...",6      "is_active": true,7      "name": "show_location_map",8      "ref_code": "show_location_map",9      "type": "client",10      "execution_mode": "fire_and_forget",11      "channels": ["voice_web"],12      "parameters": [13        { "name": "location_query", "type": "string", "required": true }14      ],15      "client_fields": { "query": "{{location_query}}" }16    }17  ],18  "total": 119}

Response Schema Details

idREQUIRED
uuid

agent_actions join record ID — use this to detach the tool.

tool_idREQUIRED
uuid

base_actions ID — use this to reference the tool definition.

is_activeREQUIRED
boolean

Whether the tool is active for this agent.

HTTP Errors

401
UNAUTHORIZED

No valid API key.

404
AGENT_NOT_FOUND

Agent not found or not owned by the authenticated client.

Attach Tool to Agent

POST
#
POSThttps://api.vanira.io/assistant/:id/tools
Attach an existing tool to an agent. The tool must have been created via POST /tools first.
Tools are reusable — the same tool can be attached to multiple agents.

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

Agent UUID.

Body Parameters

tool_idREQUIRED
uuid

UUID of the tool to attach (from GET /tools).

Implementation Example

Environment
1curl -X POST 'https://api.vanira.io/assistant/28c591f1-f17c-4c46-82ac-4054a843007a/tools' \2  -H "Content-Type: application/json" \3  -d '{4  "tool_id": "e2705199-b431-4091-ad7c-ca1110b8e025"5}'

Expected Response — 200 OK

json
1{2  "id": "7ccfd8ea-8c99-4022-82e3-7c68bdb8d02b",3  "is_active": true4}

HTTP Errors

401
UNAUTHORIZED

No valid API key.

404
AGENT_NOT_FOUND

Agent not found or not owned by the authenticated client.

404
TOOL_NOT_FOUND

Tool not found or not owned by the authenticated client.

Detach Tool from Agent

DELETE
#
DELETEhttps://api.vanira.io/assistant/:id/tools/:tool_id
Remove a tool from an agent. The tool definition is not deleted — only the attachment is removed.
Use the id from GET /assistant/{id}/tools (the agent_actions ID, not the tool_id).

Required Headers

X-API-KeyREQUIRED
string

Your Sovereign API key. Securely authorizes all requests.

Content-TypeREQUIRED
string

Must be application/json

Path Parameters

idREQUIRED
uuid

Agent UUID.

tool_idREQUIRED
uuid

The agent_actions.id from GET /assistant/{id}/tools — NOT the base tool ID.

Implementation Example

Environment
1curl -X DELETE 'https://api.vanira.io/assistant/28c591f1-f17c-4c46-82ac-4054a843007a/tools/7ccfd8ea-8c99-4022-82e3-7c68bdb8d02b' \2  -H "Content-Type: application/json"

HTTP Errors

401
UNAUTHORIZED

No valid API key.

404
AGENT_NOT_FOUND

Agent or attachment not found.