Skip to main content

Inbound Routing

Callaro uses smart inbound routing to pick the right agent for an incoming call based on the caller’s recent context — not just the dialed number. This page explains how routing works, the layers involved, and how to configure or disable it.

Why smart routing

Hubspot, Salesforce, and similar platforms route by active engagement, not by static DID-to-agent mapping. Callaro applies the same idea so that:
  • A contact returning a missed campaign call lands on the same agent that tried to reach them, with full context.
  • A contact responding to a scheduled retry lands on the agent driving that campaign instead of a generic IVR.
  • A contact replying to a follow-up lands on the agent who created the follow-up.
  • Numbers that have no per-call context still fall back cleanly to the agent assigned to the dialed number.
Smart routing runs in the inbound webhook before the call is bridged. The decision and full layer trace are persisted as an inbound_routing_decision and shown on the call detail page.

How a decision is made

The resolver evaluates layers in this order. The first match wins. Each layer enforces agent eligibility — the agent must be active, not archived, and have a published version. Ineligible agents cause the layer to skip to the next. When multiple campaigns or follow-ups match (multi-campaign tenants), the resolver picks the most recently activated option as the tie-breaker. The resolver is bounded by a per-layer 50ms timeout and a 200ms total budget. Anything slower automatically falls back to DID, and a metric is emitted (inbound_routing.layer_timeout).

Tenant configuration

Tenant admins (and roles above) can change behavior under Tenant settings → Inbound routing.

Routing mode

  • Smart (default) — runs the layers above in order.
  • Legacy DID — disables smart routing and always uses the agent assigned to the dialed number.
Default for all tenants is smart. This is the global flip — both new and existing tenants are migrated automatically. Switch to legacy_did only if your team has a workflow that requires the old behavior.

Layer toggles

You can disable individual layers without leaving smart mode (e.g. turn off last_outbound if you don’t want recent-call attribution to override the DID).

Look-back windows

  • last_outbound_window_days — how far back to look for a recent outbound call. Default 7.
  • retry_window_hours — how soon a retry_pending task is considered “due”. Default 24.

Engagement auto-unenroll

When a contact engages on a call (inbound answered, or outbound that reached a human and ran for ≥10 seconds), Callaro can automatically close other pending follow-ups for that contact. The engagement_unenroll_scope setting controls how broadly: Why campaign is the recommended default:
  • Each campaign has its own intent (sales sequence vs renewal vs survey). A return call for sales does not satisfy the survey objective.
  • Each agent represents a distinct relationship (sales rep vs support rep vs account manager). Multi-agent setups exist precisely so different teams can engage independently.
  • Same-campaign siblings (e.g. a call follow-up + an SMS follow-up scheduled by the same playbook) really were satisfied by the engagement, so they are completed rather than cancelled.
Pick contact only if your business treats the contact as a single thread (one outreach conversation regardless of agent).

Contact memory scope

Independent of routing mode, you can pick how contact memory is shared between agents:
  • exclusive (default) — each agent only reads memory it produced.
  • shared — agents see a union of memory across the tenant, with provenance and concatenated free-text summaries.
  • on_demand — same as exclusive at injection time, but the runtime can call a tool to fetch sibling memory when needed.

Emergency kill switch

The environment variable INBOUND_ROUTING_FORCE_LEGACY forces all tenants into legacy_did mode regardless of their setting. Acceptable truthy values: 1, true, yes, on. Use this only for incident response. Restart the API after toggling.

What appears in the UI

  • Call logs: a Routing reason column shows which layer won.
  • Call detail: the routing reason, agent, and a collapsible Routing decision trace show every layer that was evaluated, the result, and why.
  • Campaign detail: an Inbound returns card shows how many inbound calls were attributed to that campaign, broken down by routing reason, with a link to the filtered call logs.
  • Contact detail: the timeline annotates each inbound voice session with its routing reason badge.

Side effects on tasks and follow-ups

When an inbound call matches a campaign task or follow-up, the resolver closes the matched record at routing time:
  • BulkCallTask is marked contacted_inbound. A bulk_call_task_event is recorded with the inbound call_sid, the matched voice_session_id (backfilled), and inbound_routing_decision_id.
  • FollowUp is marked contacted_inbound. A follow_up_event is recorded with the same cross-links.
  • Sibling follow-ups for the same (contact, agent) are also closed implicitly with reason contacted_inbound_sibling so the contact is not double-pursued.
These records are visible in the call detail debug panel and in the existing task/follow-up event timelines.

Follow-up uniqueness

Follow-ups now dedupe per campaign. The active uniqueness key is: (contact_id, agent_id, follow_up_type, bulk_call_campaign_id) That means a contact in two different campaigns can have one active follow-up per campaign. Ad-hoc follow-ups (no campaign) continue to dedupe per (contact, agent, type).

Troubleshooting