Guides

Build an IVR

Create programmable IVR menus with TTS audio generation and DID assignment.

Build interactive voice response menus that qualify callers before routing them to an AI agent. Define the menu tree, generate audio with TTS, assign to a DID, and start taking calls.

Define your menu tree

An IVR is a tree of nodes. Each node either gathers a keypress (and routes to the next node) or performs a terminal action.

{
  "name": "Plumber Qualifier",
  "nodes": {
    "welcome": {
      "audio": "welcome.wav",
      "gather": { "1": "has_license", "9": "dnc" },
      "timeout_node": "welcome"
    },
    "has_license": {
      "audio": "license_check.wav",
      "gather": { "1": "service_area", "2": "unqualified" }
    },
    "service_area": {
      "audio": "area_check.wav",
      "gather": { "1": "transfer_ai", "2": "out_of_area" }
    },
    "transfer_ai": { "action": "transfer" },
    "unqualified": { "action": "hangup", "audio": "not_qualified.wav" },
    "out_of_area": { "action": "hangup", "audio": "wrong_area.wav" },
    "dnc": { "action": "suppress" }
  }
}

Node types:

TypeFieldsBehavior
Gatheraudio, gather, timeout_nodePlay audio, collect keypress, route to next node
Transferaction: "transfer"Hand off to AI agent
Hangupaction: "hangup", optional audioPlay goodbye audio and disconnect
Suppressaction: "suppress"Add caller to DNC list and hang up

Create the IVR

curl -X POST https://api.trunx.io/ivr \
  -H "Authorization: Bearer $TRUNX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Plumber Qualifier",
    "nodes": {
      "welcome": {
        "audio": "welcome.wav",
        "gather": { "1": "has_license", "9": "dnc" },
        "timeout_node": "welcome"
      },
      "has_license": {
        "audio": "license_check.wav",
        "gather": { "1": "service_area", "2": "unqualified" }
      },
      "service_area": {
        "audio": "area_check.wav",
        "gather": { "1": "transfer_ai", "2": "out_of_area" }
      },
      "transfer_ai": { "action": "transfer" },
      "unqualified": { "action": "hangup", "audio": "not_qualified.wav" },
      "out_of_area": { "action": "hangup", "audio": "wrong_area.wav" },
      "dnc": { "action": "suppress" }
    }
  }'

Response:

{
  "id": "ivr_abc123",
  "name": "Plumber Qualifier",
  "status": "draft",
  "created_at": "2026-03-09T12:00:00.000Z"
}

Generate audio for each node

Use TTS to generate audio for every node that has an audio field. Repeat for each node.

curl -X POST https://api.trunx.io/ivr/ivr_abc123/audio \
  -H "Authorization: Bearer $TRUNX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "node": "welcome",
    "text": "Thanks for calling. Press 1 if you are a licensed plumber, or press 9 to be removed from our list.",
    "voice": "rachel"
  }'
curl -X POST https://api.trunx.io/ivr/ivr_abc123/audio \
  -H "Authorization: Bearer $TRUNX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "node": "has_license",
    "text": "Great. Press 1 if you serve the Phoenix metro area, or press 2 if you do not.",
    "voice": "rachel"
  }'

Audio is generated via TTS and stored as WAV files. Each generation costs $0.01/second of audio.

Assign to a DID

Bind the IVR to a phone number so inbound calls trigger the menu.

curl -X POST https://api.trunx.io/ivr/ivr_abc123/assign \
  -H "Authorization: Bearer $TRUNX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "did": "+14155559876"
  }'

The IVR is now live. Calls to +14155559876 will hear the welcome prompt.

Test by calling the DID

Call the assigned number from your phone. Walk through the menu tree and verify:

  • Audio plays clearly at each node
  • Keypresses route to the correct next node
  • Transfer hands off to the AI agent
  • Pressing 9 adds you to the DNC list
  • Timeout replays the current node

IVR definitions are cached on write. The call handler reads from cache at call time — your IVR works even if the hub is mid-deploy.

Use IVRs as cheap pre-qualifiers before routing to AI agents. An IVR minute costs $0.008 vs. $0.10 for AI voice. Deflect unqualified callers before incurring per-minute AI costs.

Updating an IVR

To modify nodes or regenerate audio, update the IVR definition and re-generate audio for changed nodes.

curl -X PATCH https://api.trunx.io/ivr/ivr_abc123 \
  -H "Authorization: Bearer $TRUNX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "nodes": {
      "welcome": {
        "audio": "welcome.wav",
        "gather": { "1": "has_license", "2": "hours", "9": "dnc" },
        "timeout_node": "welcome"
      }
    }
  }'

The Redis cache updates immediately. The next inbound call uses the new definition.

On this page