How-to

Inbound calls

Handle incoming customer calls with automatic template resolution, IVR routing, business hours enforcement, and rate limiting.

How inbound routing works

When a customer calls one of your registered outbound numbers, the telephony provider sends a webhook to Breeze Buddy. The server resolves which template(s) are mapped to that number and routes accordingly.

Customer Dials Number
Provider Webhook
Business Hours Check
Template Resolution
Single / IVR Routing
WebSocket → Voice Pipeline
  1. Customer dials — calls one of your registered outbound numbers
  2. Provider webhook — the provider hits the {'{/{provider}/answer}'} webhook
  3. Pre-checks — business hours, rate limits, and block rules are evaluated
  4. Template resolution — the server queries all templates associated with the dialed number
  5. Routing — single template → direct connect; multiple templates → IVR selection menu
  6. Voice pipeline — a WebSocket connection is established and the AI agent begins

Template resolution

Templates FoundBehaviorCustomer Experience
Single templateDirect WebSocket connectionImmediately connected to AI agent
Multiple templatesIVR mode activatedHears a menu, selects an option
No templatesBlock action triggeredHears rejection message or gets redirected

Provider webhooks

ProviderWebhookResponse FormatIVR Element
TwilioPOST /twilio/answerTwiML XML<Gather>
PlivoPOST /plivo/answerPlivo XML<GetDigits>
ExotelPOST /exotel/answerApplet responseApplet-based IVR

IVR routing

When multiple templates are mapped to the same number, IVR mode activates:

Multiple Templates Found
Generate TTS Menu
Play IVR Greeting
Customer Selects Option
Route to Selected Template
WebSocket Connection

IVR lifecycle

  1. The customer dials the inbound number.
  2. Breeze Buddy resolves every template mapped to that number.
  3. If only one template matches, the call is routed directly — no IVR menu is played.
  4. If multiple templates match, an IVR agent is spawned. It concatenates each template’s ivr_greeting in ivr_priority order and speaks the resulting menu.
  5. The IVR agent listens for the caller’s response over the same STT pipeline used by regular voice agents. Selection is processed over a WebSocket — the system matches the caller’s speech to the available options.
  6. The call transfers to the selected template’s voice agent.

IVR configuration fields

Set on the template level.

FieldTypeDescription
ivr_greetingstringFull TTS text for this template’s menu option. Spoken by the IVR agent.
ivr_goodbyestringMessage played when the caller provides no input.
ivr_priorityint (≥1)Ordering in the IVR menu. Lower numbers are spoken first.
template-ivr-config.json
json
{
  "ivr_greeting": "Press 1 for Sales support",
  "ivr_goodbye": "Thank you for calling. Goodbye.",
  "ivr_priority": 1
}

Example: two templates on one number

templates-ivr-two.json
json
[
  {
    "name": "sales-agent",
    "ivr_greeting": "Press 1 or say Sales to speak with our sales team.",
    "ivr_goodbye": "We didn't catch your selection. Please try calling again.",
    "ivr_priority": 1
  },
  {
    "name": "support-agent",
    "ivr_greeting": "Press 2 or say Support to reach customer support.",
    "ivr_goodbye": "No selection received. Goodbye.",
    "ivr_priority": 2
  }
]

When a caller dials in, the IVR agent speaks:

Example greeting

“Welcome! Press 1 or say Sales to speak with our sales team. Press 2 or say Support to reach customer support.”

No-input handling

If the caller does not respond within the idle timeout, the IVR agent plays the ivr_goodbye message from the highest-priority template and ends the call.

Agent-side TTS

IVR menu greetings are generated via TTS at runtime — no pre-recorded audio needed. Update the text in the template and changes take effect immediately.

Single-template bypass

When only one template is configured for the inbound number, the IVR menu is skipped entirely and the caller is connected directly to the voice agent.

Business hours

Inbound calls can be restricted to a daily time window:

SettingFormat
inbound_call_start_timeHH:MM (e.g., "09:00")
inbound_call_end_timeHH:MM (e.g., "18:00")
inbound_call_timezoneIANA timezone (e.g., "Asia/Kolkata")

Block actions

When a call is blocked (outside hours, no templates, or rate-limited):

ActionBehavior
REJECTPlays inbound_block_message via TTS, then hangs up
REDIRECTForwards call to inbound_redirect_number
block-action.json
json
{
  "inbound_block_action": "REJECT",
  "inbound_block_message": "We are currently closed. Please call back during business hours.",
  "inbound_redirect_number": "+1234567890"
}

Block Behavior Difference

With REJECT, the customer hears the block message before the call ends. With REDIRECT, the call is forwarded immediately — no message is played.

Rate limiting

Inbound calls are subject to concurrency-based rate limiting per outbound number:

AspectDetails
ScopePer outbound number
TrackingRedis-based counter with automatic expiry
IsolationIndependent from outbound call concurrency
Exceeded behaviorBlock action is triggered

Full inbound configuration

inbound-config-complete.json
json
{
  "ivr_greeting": "Press 1 for Sales, Press 2 for Support",
  "ivr_goodbye": "No input received. Goodbye.",
  "ivr_priority": 1,
  "inbound_call_start_time": "09:00",
  "inbound_call_end_time": "18:00",
  "inbound_call_timezone": "Asia/Kolkata",
  "inbound_block_action": "REJECT",
  "inbound_block_message": "We are currently closed.",
  "inbound_redirect_number": "+1234567890"
}

Next steps

Was this helpful?