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 — calls one of your registered outbound numbers
- Provider webhook — the provider hits the
{'{/{provider}/answer}'}webhook - Pre-checks — business hours, rate limits, and block rules are evaluated
- Template resolution — the server queries all templates associated with the dialed number
- Routing — single template → direct connect; multiple templates → IVR selection menu
- Voice pipeline — a WebSocket connection is established and the AI agent begins
Template resolution
| Templates Found | Behavior | Customer Experience |
|---|---|---|
| Single template | Direct WebSocket connection | Immediately connected to AI agent |
| Multiple templates | IVR mode activated | Hears a menu, selects an option |
| No templates | Block action triggered | Hears rejection message or gets redirected |
Provider webhooks
| Provider | Webhook | Response Format | IVR Element |
|---|---|---|---|
| Twilio | POST /twilio/answer | TwiML XML | <Gather> |
| Plivo | POST /plivo/answer | Plivo XML | <GetDigits> |
| Exotel | POST /exotel/answer | Applet response | Applet-based IVR |
IVR routing
When multiple templates are mapped to the same number, IVR mode activates:
IVR lifecycle
- The customer dials the inbound number.
- Breeze Buddy resolves every template mapped to that number.
- If only one template matches, the call is routed directly — no IVR menu is played.
- If multiple templates match, an IVR agent is spawned. It concatenates each template’s
ivr_greetinginivr_priorityorder and speaks the resulting menu. - 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.
- The call transfers to the selected template’s voice agent.
IVR configuration fields
Set on the template level.
| Field | Type | Description |
|---|---|---|
ivr_greeting | string | Full TTS text for this template’s menu option. Spoken by the IVR agent. |
ivr_goodbye | string | Message played when the caller provides no input. |
ivr_priority | int (≥1) | Ordering in the IVR menu. Lower numbers are spoken first. |
{
"ivr_greeting": "Press 1 for Sales support",
"ivr_goodbye": "Thank you for calling. Goodbye.",
"ivr_priority": 1
}Example: two templates on one number
[
{
"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:
| Setting | Format |
|---|---|
inbound_call_start_time | HH:MM (e.g., "09:00") |
inbound_call_end_time | HH:MM (e.g., "18:00") |
inbound_call_timezone | IANA timezone (e.g., "Asia/Kolkata") |
Block actions
When a call is blocked (outside hours, no templates, or rate-limited):
| Action | Behavior |
|---|---|
| REJECT | Plays inbound_block_message via TTS, then hangs up |
| REDIRECT | Forwards call to inbound_redirect_number |
{
"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:
| Aspect | Details |
|---|---|
| Scope | Per outbound number |
| Tracking | Redis-based counter with automatic expiry |
| Isolation | Independent from outbound call concurrency |
| Exceeded behavior | Block action is triggered |
Full inbound configuration
{
"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"
}