RustPBX Basics: Three Ways to Extend — HTTP Routing, Webhooks, and the RWI

M
Miuda Team
Building conversational AI tooling

No PBX stays stock. Sooner or later a call needs a CRM lookup, an event needs to reach another system, or a bot needs to hang up on command. RustPBX’s extension surface has three layers — choose by direction: decisions in, events out, and control both ways.

1. Decisions In: HTTP Dynamic Routing

When call routing depends on an external system — CRM data, real-time pricing, fraud scoring — the HTTP router asks your service on every INVITE:

[proxy.http_router]
url = "https://api.example.com/route"
headers = { Authorization = "Bearer token123" }
fallback_to_static = true
timeout_ms = 300

The payload carries caller, callee, source IP, and SIP headers. Your response picks the action: forward to a trunk (with caller override), reject with a status code, or busy. fallback_to_static = true falls back to config/routes/*.toml when your endpoint is down — a routing outage never becomes a call outage. Invalid URIs in the response fail the call loudly rather than routing somewhere unintended.

For deeper logic, Step IVR hands each call step to your API — same idea, per-action granularity.

2. Events Out: RWI Webhooks

The RWI (Real-time WebSocket Interface) event bus mirrors everything — call lifecycle, queue events, DTMF, IVR traces, agent state — and the webhook runtime forwards selected events over HTTP:

[rwi_webhook]
url = "https://your-server.example.com/api/rwi/events"
events = ["call_hangup", "queue_agent_connected", "call_error"]
retries = 3

Delivery runs on dedicated workers (never the SIP hot path), retries 5xx/429 with exponential backoff, keeps the idempotency key identical across attempts, tracks queue latency in metrics, and hot-reloads configuration. Your receiver gets at-least-once delivery it can dedupe safely.

3. Control Both Ways: The RWI WebSocket

For command-and-control — originate, answer, bridge, transfer, hold, queue operations, conference control — connect to the RWI WebSocket. It’s the same protocol the CC desk and voice agents speak, with root call identity on every event and owner-routed operations in clusters (a command issued on node A reaches the call on node B).

Addons console — extension points of the platform

A webhook delivery arrives looking like this (truncated):

{
  "event": "call_ended",
  "call_id": "d3f0-…",
  "session_id": "d3f0-…",
  "direction": "outbound",
  "status": "answered",
  "duration_secs": 187,
  "hangup_reason": "caller",
  "caller": "1001",
  "callee": "+8613800001001"
}

Typical stack: your CTI panel listens for events and issues commands over one socket; your CRM opens popup URLs from the headers (see the screen-pop post); recording and CDR flow back through the call records API.

And the Fourth Way: Addons

When the surface itself must change — new reports, new tables, new console pages — the Addon trait hosts everything from ACME to Contact Center. Commercial addons (wholesale, CC, IVR editor, voicemail) are the proof of concept.

Guides: RWI Events & Webhooks, Step IVR, and JSON-RPC routing.

Get new posts by email

Deep dives on Rust telephony, contact centers and wholesale voice. No spam.

Thanks — you're on the list.

We use cookies for anonymous analytics to improve the site. Nothing is loaded until you accept. Privacy Policy