zoxaAI
Homepage
API ReferenceExamples

Example agents

Complete, ready-to-copy agent configs for the most common voice-AI use cases.

Each agent below is a complete POST /agents body. Copy, change tts.voice if you want a different voice, and POST.

These are starting points

Tweak systemPrompt, greeting.firstMessages, llm.temperature, and tools to fit your domain. POST /agents/preview-snapshot materializes the resolved config so you can see exactly what the runner gets before saving.


1. Sales qualifier (outbound)

Calls a lead, asks a short qualification script, ends the call once it has the answers.

{
  "name": "Sales qualifier",
  "description": "Qualifies inbound leads on a 3-question script.",
  "systemPrompt": "You qualify B2B SaaS leads. Ask three questions IN ORDER:\n1) What's your role at the company?\n2) How many engineers are on your team?\n3) Are you evaluating tools this quarter?\nKeep replies to one short sentence. Never improvise extra questions. Once you have all three answers, summarize them in one sentence and call the end_call tool.",
  "greeting": {
    "firstMessages": ["Hi, this is Aria from Acme. Do you have a minute for three quick questions about your dev team?"]
  },
  "llm": { "provider": "openai", "model": "gpt-5.4-mini", "temperature": 0.7, "maxTokens": 200 },
  "tts": { "provider": "elevenlabs", "voice": "7qBNUtXRGP0jPi0H4r8k" },
  "stt": { "provider": "soniox", "interruptionMinWords": 2 },
  "tools": [
    {
      "type": "endCall",
      "name": "end_call",
      "description": "End the call after you've summarized the three answers.",
      "config": { "messageType": "custom", "customMessages": ["Thanks for your time! We'll be in touch."] }
    }
  ],
  "maxCallDurationS": 300,
  "userIdleTimeoutS": 5,
  "userIdleMaxRetries": 1
}

Tighten further by adding a query tool for FAQ answers if leads ask "what does Acme do?" — see Tool types — query.


2. Appointment reminder (outbound, campaign-style)

Per-contact context variables drive the script.

{
  "name": "Appointment reminder",
  "description": "Confirms or reschedules tomorrow's appointment.",
  "systemPrompt": "You're calling {{customerName}} to confirm their appointment on {{appointmentDate}} at {{appointmentTime}}. If they confirm, end the call. If they ask to reschedule, take a preferred day, then end. Keep replies short — this is a confirmation, not a sales call.",
  "greeting": {
    "firstMessages": ["Hi {{customerName}}, this is a reminder about your appointment on {{appointmentDate}} at {{appointmentTime}}. Are you still good for that time?"]
  },
  "llm": { "provider": "openai", "model": "gpt-5.4-nano", "temperature": 0.5, "maxTokens": 150 },
  "tts": { "provider": "elevenlabs" },
  "stt": { "provider": "soniox" },
  "tools": [
    { "type": "endCall", "name": "end_call", "config": { "messageType": "custom", "customMessages": ["See you then. Goodbye!"] } }
  ],
  "maxCallDurationS": 120
}

Pair with a campaign — each contact row's customer_name / appointment_date / appointment_time columns become contextVariables at call time.


3. Inbound support receptionist

Triages incoming calls, looks up answers in a knowledge base, transfers to a human if requested.

{
  "name": "Support receptionist",
  "description": "First-line triage for inbound support calls.",
  "systemPrompt": "You are the first-line support agent for Acme. Answer billing, account, and product questions by querying the knowledge base. If the caller explicitly asks for a human, or you've tried twice without a clear answer, transfer them. Be warm, brief, and professional.",
  "greeting": {
    "firstMessages": ["Hi, this is Acme support — what's your question today?"],
    "interruptible": true
  },
  "llm": { "provider": "openai", "model": "gpt-5.4-mini", "temperature": 0.6 },
  "tts": { "provider": "elevenlabs" },
  "stt": { "provider": "soniox", "interruptionMinWords": 2 },
  "tools": [
    {
      "type": "query",
      "name": "search_kb",
      "description": "Search the KB for billing, account, and product questions.",
      "config": {
        "knowledgeBases": [
          { "name": "billing", "description": "Pricing, refunds, plan changes.", "documentIds": ["<billing_kb_doc_uuid>"] },
          { "name": "product", "description": "Features and how-to answers.", "documentIds": ["<product_kb_doc_uuid>"] }
        ],
        "messages": ["One moment — let me check that."]
      }
    },
    {
      "type": "transferCall",
      "name": "transfer_to_support",
      "description": "Transfer the caller to a human support teammate.",
      "config": { "destination": "+14155550199", "customMessage": "Connecting you to a teammate now." }
    },
    { "type": "endCall", "name": "end_call", "config": { "messageType": "custom", "customMessages": ["Thanks for calling. Goodbye!"] } }
  ],
  "maxCallDurationS": 600,
  "userIdleTimeoutS": 10,
  "userIdleMaxRetries": 2
}

Register the binding once via POST /call type=inbound, and every call to your Twilio/Vobiz DID routes through this agent.


4. Browser-embedded voice chat (WebRTC)

Same shape as above — what changes is the call body, not the agent. The agent has no idea it's running over WebRTC.

{
  "name": "In-product voice helper",
  "description": "Voice surface embedded in the customer dashboard.",
  "systemPrompt": "You help users navigate the Acme dashboard. You know the page they're on (passed as {{currentPage}}). Answer questions about features visible on that page. Keep answers under 2 sentences.",
  "greeting": {
    "firstMessages": ["What can I help with?"],
    "agentDelayS": 0.5
  },
  "llm": { "provider": "openai", "model": "gpt-5.4-nano", "temperature": 0.7 },
  "tts": { "provider": "elevenlabs" },
  "stt": { "provider": "soniox", "interruptionMinWords": 0 },
  "maxCallDurationS": 300,
  "userIdleTimeoutS": 10,
  "userIdleMaxRetries": 2
}

Then on the browser side: POST /call transport=webrtc → POST the browser's SDP offer to the returned offerUrl. interruptionMinWords: 0 makes barge-in instant — right for a UI helper the user should be able to cut off freely.


5. Server-side bot reading from a queue (WebSocket)

You control the audio. Pass audio chunks in via the WS and the agent talks back.

{
  "name": "Voicemail-to-text bot",
  "description": "Plays voicemails to an agent that summarizes them.",
  "systemPrompt": "You are reviewing a voicemail. Listen to the caller (no need to reply mid-stream), and at the end produce a one-sentence summary and a callback-priority rating (low/medium/high).",
  "greeting": { "speakFirst": "user", "userTimeoutS": 5.0 },
  "llm": { "provider": "openai", "model": "gpt-5.4-nano", "temperature": 0.3 },
  "tts": { "provider": "elevenlabs" },
  "stt": { "provider": "soniox" },
  "maxCallDurationS": 180
}

Then WebSocket transport — push 16 kHz PCM voicemail audio chunks in, capture the agent's summary from the transcript when the WS closes. greeting.speakFirst: "user" with an empty firstMessages means the agent waits and never speaks an opener.


6. Hinglish receptionist (English + Hindi)

languages order is priority — ["en", "hi"] means English-primary with Hindi code-switching. With Sarvam TTS + exactly this language pair, Hinglish codemix rendering is applied automatically.

{
  "name": "Multilingual receptionist",
  "description": "Handles inbound calls in Hindi + English.",
  "languages": ["en", "hi"],
  "systemPrompt": "आप एक मदद करने वाले voice agent हैं। If the caller speaks English, reply in English. If they speak Hindi, reply in Hindi. Be brief.",
  "greeting": {
    "firstMessages": ["नमस्ते, मैं Acme से बोल रहा हूं — आज मैं आपकी क्या मदद कर सकता हूं?"]
  },
  "llm": { "provider": "openai", "model": "gpt-5.4-mini", "temperature": 0.7 },
  "tts": { "provider": "sarvam", "voice": "ishita" },
  "stt": { "provider": "soniox" },
  "maxCallDurationS": 600
}

Every language in the list must be supported by both the STT and TTS model — the save fails with a clear error otherwise. Support matrices: STT · TTS.


Patterns that recur

PatternWhere it livesWhy
Tight duration cap for sales / remindersmaxCallDurationSCaps cost. A reminder shouldn't go 5 minutes.
Low idle timeout (3–5 s) for transactional flowsuserIdleTimeoutSPicks up quickly if the user trailed off mid-answer.
Hard, numbered script in systemPrompt"Ask three questions IN ORDER"LLMs improvise less when the prompt is unambiguous.
Farewell variants on the endCall toolconfig.customMessagesThe model says the goodbye, you keep tone control — variants keep repeat calls from sounding canned.
contextVariables (per-call substitution){{customerName}} etc.Same agent, personalized to each contact.
greeting.speakFirst: "user" for inbound with an agenda-holding callergreetingLet the caller open. Cuts latency cost from silence.
Instant barge-in for UI helpers, word-gated for phonestt.interruptionMinWords0 in-product; 2 on phone lines to filter coughs and "yeah".

On this page