RustPBX API Integration Guide

June 13, 2026 ยท View on GitHub

RustPBX provides a comprehensive set of HTTP APIs and Webhooks designed to make it a fully programmable Software Defined PBX (SD-PBX). This guide details how to integrate your external business logic (CRM, ERP, AI assistants, billing systems) with RustPBX.


๐Ÿ—๏ธ Architecture Overview

RustPBX interacts with external systems in two ways:

  1. Inbound API (REST): Your system calls RustPBX to manage resources (extensions, trunks) or control active calls.
  2. Outbound Webhooks: RustPBX calls your system to make routing decisions, report events, or authenticate users.
MechanismDirectionTypeUse Case
Console APIInboundRESTCRUD extensions, download recordings, system config
Active Call ControlInboundRESTLive hangup, transfer, mute, force-accept
AMI APIInboundRESTHealth checks, hot-reload, raw dialog inspection
HTTP RouterOutboundWebhookDynamic call routing (per-INVITE decision)
User BackendOutboundWebhookExternal SIP authentication (OAuth/LDAP proxy)
Locator WebhookOutboundWebhookReal-time registration/unregistration events
Call Record PushOutboundWebhookPush CDR JSON + Audio files to external server

๐Ÿ“ก 1. Outbound Webhooks (RustPBX โ†’ Your Server)

1.1 HTTP Router (Dynamic Call Routing)

The most powerful extension point. Instead of static routing rules, RustPBX asks your API "Receive call from A to B, what should I do?".

  • Trigger: Every incoming SIP INVITE.
  • Config:
    [proxy.http_router]
    url = "https://your-api.com/pbx/route"
    fallback_to_static = true       # If your API fails, use internal routes
    timeout_ms = 5000
    [proxy.http_router.headers]
    X-API-Key = "secret-token"
    

Request (POST):

{
  "call_id": "ab39-551-229",
  "from": "<sip:1001@pbx.com>",
  "to": "<sip:200@pbx.com>",
  "source_addr": "1.2.3.4:5060",
  "direction": "inbound",  // inbound | outbound | internal
  "method": "INVITE",
  "uri": "sip:200@pbx.com",
  "headers": {
    "User-Agent": "Yealink T54W",
    "X-Client-ID": "998877"
  },
  "body": "v=0\r\n..." // Full SDP body
}

Response:

{
  "action": "forward",            // Actions: forward | reject | abort | spam | not_handled
  "targets": [
    "sip:1001@192.168.1.50:5060", // Target 1 (Extension)
    "sip:1002@192.168.1.51:5060"  // Target 2 (Mobile App)
  ],
  "strategy": "parallel",         // parallel (Ring All) | sequential (Failover)
  "record": true,                 // Enable recording for this call
  "timeout": 30,                  // Ring timeout in seconds
  "media_proxy": "auto",          // auto | always | none | nat
  "headers": {                    // Inject custom SIP headers into the INVITE sent to B
    "X-Call-Reason": "support-ticket-123"
  }
}

1.2 User Backend (SIP Authentication)

Delegate SIP registration password checking to your external DB or API.

  • Trigger: SIP REGISTER or INVITE with auth.
  • Config:
    [[proxy.user_backends]]
    type = "http"
    url = "https://your-api.com/pbx/auth"
    username_field = "u"
    realm_field = "r"
    

Request (GET): https://your-api.com/pbx/auth?u=1001&r=pbx.com

Response (200 OK):

{
  "id": 1001,
  "username": "1001",
  "password": "hashed_password_or_plaintext", // HA1 hash preferred
  "display_name": "John Doe",
  "email": "john@pbx.com",
  "allow_guest_calls": false
}

Response (403 Forbidden):

{ "reason": "invalid_password", "message": "Account locked" }

1.3 Locator Webhook (Presence Events)

Real-time notification when devices come online or go offline.

  • Config:
    [proxy.locator_webhook]
    url = "https://your-api.com/pbx/events"
    events = ["registered", "unregistered", "offline"]
    

Payload:

{
  "event": "registered",
  "timestamp": 1708201234,
  "location": {
    "aor": "sip:1001@pbx.com",
    "destination": "1.2.3.4:12345",
    "transport": "TLS",
    "user_agent": "MicroSIP/3.21.3",
    "expires": 3600
  }
}

1.4 CDR Event Push and Recording Upload

Push call details immediately after a call ends. Recording media upload is configured separately.

  • Config:
    [recording]
    enabled = true
    auto_start = true
    type = "http"
    path = "./config/recorders"
    url = "https://your-api.com/pbx/recording"
    
    [callrecord]
    type = "http"
    url = "https://your-api.com/pbx/cdr"
    # Maximum concurrent post-call CDR save/upload/hook tasks. Default: 64, minimum: 1.
    max_concurrent = 64
    # Accepted for compatibility, but ignored. Use [recording] for media upload.
    with_media = true
    

CDR format: multipart/form-data

  • Field calllog.json: The full CDR JSON (see next section).

Recording format: multipart/form-data

  • File field recording: The recorded WAV file.
  • Fields call_id and track_id: Recording metadata.

๐Ÿ”Œ 2. Inbound REST API (You โ†’ RustPBX)

Base URL: http://<rustpbx-ip>:8080/console
Authentication: Session cookie (login via /console/login) or API Token (future).

2.1 Active Call Control

Manage calls that are currently in progress.

List Active Calls: GET /console/calls/active

Control a Call: POST /console/calls/active/{call_id}/commands

Payloads:

  1. Hangup:
    { "action": "hangup", "reason": "admin_kick" }
    
  2. Blind Transfer:
    { "action": "transfer", "target": "sip:1002@pbx.com" }
    
  3. Mute/Unmute:
    { "action": "mute", "track_id": "audio-0" } // use 'unmute' to reverse
    
  4. Force Answer (for ringing channels):
    { 
      "action": "accept", 
      "sdp": "v=0..." // Server-generated SDP answer
    }
    

2.2 System Management (CRUD)

ResourceEndpointMethodsDescription
Extensions/console/extensionsGET, POST, PUT, DELETEManage SIP users
Trunks/console/sip-trunkGET, POST, PUT, DELETEManage upstream carriers
Routes/console/routingGET, POST, PUT, DELETEManage dial plan rules
CDRs/console/call-recordsGET, POST (Search)Query history
Recording/console/call-records/{id}/recordingGETStream audio file
SIP Flow/console/call-records/{id}/sip-flowGETGet PCAP-like ladder diagram JSON

2.3 AMI (Admin Interface)

Low-level system operations. Protected by IP whitelist ([ami].allows in config).

Base URL: http://<rustpbx-ip>:8080/ami/v1

  • Health: GET /health - System vital stats (uptime, active calls, load).
  • Reload: POST /reload/trunks, /reload/routes, /reload/acl - Hot reload config without restart.
  • Shutdown: POST /shutdown - Graceful shutdown (stops accepting new calls, waits for active ones).
  • Dialogs: GET /dialogs - Raw dump of internal SIP dialog states (for debugging).
  • SipFlow signaling: GET /sipflow/flow/{call_id} - Query SIP ladder data.
  • SipFlow media: GET /sipflow/media/{call_id} - Export call media as WAV.

SipFlow endpoints support optional time range query parameters:

  • start: range start time
  • end: range end time

Accepted formats:

  • RFC3339 datetime, e.g. 2026-04-16T10:00:00+08:00
  • Unix timestamp (seconds), e.g. 1713232800

Example:

GET /ami/v1/sipflow/flow/abc123?start=2026-04-16T10:00:00%2B08:00&end=2026-04-16T10:30:00%2B08:00
GET /ami/v1/sipflow/media/abc123?start=1713232800&end=1713234600

๐Ÿ› ๏ธ Integration Workflows

Scenario A: CRM Click-to-Dial

  1. User clicks phone number in CRM.
  2. CRM backend sends POST /api/v1/commands (Future feature) OR uses AMI to originate call.
  3. Current workaround: CRM sends SIP REFER to RustPBX or uses a dedicated "Click-to-Dial" SIP extension that the web-app registers as.

Scenario B: AI Voice Assistant

  1. Inbound call hits RustPBX.
  2. HTTP Router sends INVITE details to AI backend.
  3. AI Backend returns {"action": "forward", "targets": ["sip:ai-bot-service@internal"]}.
  4. RustPBX routes audio to the AI bot via SIP/RTP.

Scenario C: Billing System

  1. User Backend authenticates user, checking balance > 0.
  2. Call proceeds.
  3. On hangup, CDR Push sends via HTTP POST to Billing System.
  4. Billing system calculates duration * rate and deducts balance.

Scenario D: Compliance Recording

Two recording backends are available โ€” a traditional local file recorder ([recording]) and sipflow ([sipflow]). When both are configured, sipflow takes precedence for media capture and upload, avoiding duplicate local WAV files.

SipFlow captures raw RTP packets and SIP messages, then generates WAV / JSONL on export. No local WAV file is written.

[recording]
enabled = true
auto_start = true

[sipflow]
type = "local"
root = "./config/sipflow"

[sipflow.upload]
type = "s3"
vendor = "aliyun"
bucket = "my-bucket"
region = "oss-cn-hangzhou"
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
root = "recordings"
media = true
signaling = true

When sipflow backend is present, [recording] enables media anchoring only; media capture and upload are handled by sipflow. The WAV is generated on-demand from stored RTP packets via GET /sipflow/media/{call_id} and uploaded to the sipflow S3/HTTP target. Signaling is uploaded as JSONL to the same target.

Option 2: Local file recorder (legacy)

[recording]
enabled = true
auto_start = true
# No [sipflow] section โ€” falls back to local .wav file

All calls are recorded locally to ./config/recorders/, then asynchronously uploaded via [callrecord] S3 config.