VoiceaiAgentstable

AI receptionist

Hands the caller to an AI voice receptionist — a natural, speech-to-speech agent that greets the caller, answers questions from its knowledge base, runs t…

What it does

Hands the live caller to an AI voice receptionist — a natural, speech-to-speech agent that greets the caller, answers questions from its knowledge base, runs tools (look up a contact, take a message, check business hours, send an SMS, transfer, escalate), and decides how the call should end.

Under the hood the node emits the Protocol-v1 llm verb and breaks out of the flow for the entire conversation (just like dial waits for a bridge). When the session ends, the node resumes and routes on how the conversation ended — the receptionist's terminal outcome, stamped onto vars.agentOutcome by the tool the model called (or derived from the session-end reason when no tool stamped one).

You build the receptionist once — persona, tools, knowledge base, business hours, and the voice + model — in the dedicated AI receptionist builder, then point this node at it with agentId. The node is the in-flow handoff; the builder is where the brain is configured. The same receptionist can also be bound directly to a phone number ("point this number at the receptionist") without a flow at all; use this node when the receptionist is one step inside a larger call flow (e.g. after an IVR menu, or as the after-hours branch).

agentId is the node's only setting. The greeting, instructions, voice and model all come from the receptionist, so a flow that needs a different greeting (an after-hours line, say) points at a second receptionist rather than overriding one inline.

When to use it

  • Replace a phone-tree IVR with a conversational front door: callers say what they want instead of pressing 1-2-3.
  • After-hours / overflow: route to the receptionist when no agent is available, let it take a structured message (emailed to the owner) and end on voicemail.
  • A self-serve tier in front of a queue: the receptionist answers FAQs from the knowledge base and only transfers / escalates the calls a human needs.
  • A specific sub-flow: drop it after a gatherDigits menu so one menu option ("press 4 to talk to our assistant") reaches the AI while the others route normally.

Configuration

Hands the caller to an AI voice receptionist — a natural, speech-to-speech agent that greets the caller, answers questions from its knowledge base, runs tools (look up a contact, take a message, check hours, send an SMS), and decides how the call should end. Build the receptionist (persona, tools, knowledge base, business hours, voice + model) under AI receptionist, then point this node at it. The node waits for the whole conversation, then branches on how it ended: Transfer, Agent handoff, Call flow, Voicemail, Completed, or Error. An escalation to a queue or an on-call rotation arrives on Transfer, with the kind in {{vars.agentTransferKind}}. Wire the Agent-handoff outcome into a second AI receptionist node for a warm AI→AI transfer on the same call (the summary is carried automatically). Greeting, instructions, voice and model all come from the receptionist.

FieldLabelTypeRequiredDefaultNotes
agentIdReceptionisttextRequired""The published AI receptionist to run, by id. Manage receptionists under AI receptionist. Accepts a template, so a node on the Agent-handoff outcome can run whichever receptionist the previous one chose ({{vars.agentTransferTarget}}). Required.

Outgoing events: outcome-transfer, transfer, outcome-agent, agent, outcome-voicemail, voicemail, outcome-flow, flow, outcome-completed, completed, outcome-error, error, default

Outcomes

Routing is only the six terminal outcomes — there is no plain "next" edge. Each outcome is a canonical case on vars.agentOutcome, so you can also branch on {{vars.agentOutcome}} in a downstream node. Wire every outcome you care about; an unwired outcome simply ends the flow.

OutcomeFires whenTypical wiring
Transfer (transfer)The receptionist chose to hand off to a human — an extension, a number, a call queue, or the on-call rotation. The chosen target is in vars.agentTransferTarget and what it IS in vars.agentTransferKind. An escalation arrives here: escalate_to_human ends the session as a transfer, so there is no separate Escalate outcome. Branch on {{vars.agentTransferKind}} when a queue needs different handling from one person.A Transfer node whose destination templates {{vars.agentTransferKind}} / {{vars.agentTransferTarget}} — it covers every kind (extension, queue, number, on-call rotation) with no branch needed.
Agent handoff (agent)The receptionist called transfer_to_agent — a WARM handoff to another AI receptionist on the same call leg (no new carrier call). The target receptionist id is in vars.agentTransferTarget; the model-authored summary carries over automatically.A short say bridge line ("Connecting you now.") → the target AI receptionist node. With multiple allow-listed targets, branch on {{vars.agentTransferTarget}} first.
Call flow (flow)The receptionist called run_flow — it handed the caller into one of your own published call flows on the same leg (a self-service menu, an automated line). The flow id it picked, resolved out of the tool’s pinned allow-list, is in vars.agentTransferTarget; vars.agentTransferKind is flow. The caller does not come back.A runFlow node whose Flow field is {{vars.agentTransferTarget}}. Never system-transfer — that would try to ring the flow id as an extension.
Voicemail (voicemail)The receptionist took (or routed to) a message. With the default structured take_message, the owner is emailed; route to a goodbye + hangup.A goodbye say → hangup, or a record node for a spoken voicemail.
Completed (completed)The conversation finished normally — caller satisfied, end_call, or caller hangup.hangup, or a wrap-up side-chain.
Error (error)The session failed — provider error, missing key, an unrecoverable tool failure, or the agent-handoff loop cap (3 per call) was breached.A safety net: a human-transfer or a "sorry, please hold" + enqueue.

vars.agentTranscript holds the running conversation transcript for logging or post-processing downstream.

Warm agent→agent handoff (the agent outcome)

Enable the Transfer to another assistant tool on receptionist A and pin its allow-list of target receptionists (the model picks a target by LABEL, never a free-form id). When it fires, the runtime carries three things into receptionist B's session on the same leg:

  • the model-authored summary (who's calling, what they need, what was collected) — injected at session start so B acknowledges the transfer instead of re-greeting from zero and never re-asks captured facts;
  • the caller's verification state (the ANI/KBA/OTP ladder level carries — same caller, same call; each tool's own gate still applies);
  • a handoff row in the call's AI-conversation log (the CDR card shows the baton pass inline).

Handoffs are capped at 3 per call — a ping-pong loop routes the error outcome instead. An agent outcome with no wired handle is a misconfiguration: the runtime error-logs it and ends the call gracefully (it never silently dials). Directly-bound receptionists (no custom flow) cannot complete the handoff in v1 — the target node must be authored on a flow.

Examples

Self-serve receptionist, then transfer or take a message

The receptionist answers from its knowledge base. If the caller asks for a person it transfers; if it takes a message it ends on voicemail; otherwise it wraps up.

{
  "id": "reception-ai",
  "type": "aiAgent",
  "config": {
    "agentId": "{{config.agentId}}"
  },
  "on": {
    "outcome-transfer": "transfer-target",
    "outcome-voicemail": "goodbye",
    "outcome-completed": "goodbye",
    "outcome-error": "human-fallback"
  }
}

The matching Transfer node reads the target and kind the receptionist picked — destination covers every kind so there's no branch needed. An outside number that fails to answer falls back to a goodbye instead of leaving the caller stranded:

{
  "id": "transfer-target",
  "type": "transfer",
  "config": {
    "destination": {
      "kind": "{{vars.agentTransferKind}}",
      "id": "{{vars.agentTransferTarget}}",
      "number": "{{vars.agentTransferTarget}}"
    }
  },
  "on": { "failed": "goodbye", "call.hangup": "goodbye" }
}

Warm handoff to a second receptionist (support → sales)

The support receptionist's transfer_to_agent allow-list names the sales receptionist; the flow wires the Agent-handoff outcome through a bridge line into a second aiAgent node — one call, one leg, summary carried over:

[
  {
    "id": "support-ai",
    "type": "aiAgent",
    "config": {
      "agentId": "<support-agent-id>",
      "cases": [
        { "path": "vars.agentOutcome", "op": "==", "value": "agent", "nodeId": "bridge" }
      ]
    },
    "on": { "outcome-completed": "end" }
  },
  {
    "id": "bridge",
    "type": "say",
    "config": { "prompt": { "kind": "text", "text": "Connecting you now." } },
    "on": { "__next": "sales-ai" }
  },
  {
    "id": "sales-ai",
    "type": "aiAgent",
    "config": { "agentId": "<sales-agent-id>" },
    "on": { "outcome-completed": "end" }
  }
]

Gotchas

  • It auto-answers if needed. The realtime session needs media, so the node answers the caller leg first when the call isn't already answered — the same thing gather/record do. You don't need a separate Answer node before it.
  • No "next" edge — wire the outcomes. Unlike say/gather, this node never takes a plain forward transition. Route at least completed (and ideally error) so the call doesn't dead-end when the conversation finishes.
  • All configuration lives on the receptionist. Persona, greeting, tools, knowledge base, business hours, voice and model are set in the receptionist builder (agentId). The node has no per-flow overrides; retired keys like greeting, voice or maxSessionSecs on a stored node are stripped on save.
  • The voice is OpenAI GPT-Live. Receptionists speak through GPT-Live only (openai_live, model gpt-live-1); the older OpenAI Realtime and Gemini Live voices were removed on 2026-10-27.
  • Transfer target comes from the tool, not the node. The receptionist decides where to transfer at conversation time; the destination lands in vars.agentTransferTarget. Reference that in the downstream Dial/Transfer — don't hard-code a number on the node and expect the AI to use it.
  • The AI disclosure always plays before the session opens. Every caller hears "Thanks for calling business. You're speaking with business's automated AI assistant, and this call is recorded and transcribed." before the AI hears a word — at the head of the call when the routed flow contains this node, otherwise right before this node's session (and before its recording starts). It is a platform line: the greeting, the prompt and the org's disclosure wrapper (Settings → Consent) cannot remove it, and the agent is told never to contradict it. Don't repeat it in your greeting.

See also