#Browser softphone (@voice/softphone)
A small wrapper around SIP.js for WebRTC calling in your CRM. Use it from your frontend; it never sees your API key — it gets short-lived credentials from your backend.
import { Softphone } from '@voice/softphone';
const phone = new Softphone({
// Your backend calls POST /v1/agents/{agent_ref}/softphone-config and returns the JSON.
getConfig: () => fetch('/crm/softphone-config').then((r) => r.json()),
autoAnswer: false,
});
phone.on('registered', () => setStatus('online'));
phone.on('incoming', (call) => {
// Click-to-call: the agent leg carries the platform call id (X-Call-Id).
if (call.platformCallId === pendingClickToCallId) void phone.answer(call.id);
else showIncomingUi(call); // from: call.remote
});
phone.on('call', (call) => render(call)); // state: ringing | connecting | active | held | ended
phone.on('error', (e) => console.error(e));
await phone.start(); // connects over WSS and registers; renews credentials before they expire
| Method | Does |
|---|---|
start() / stop() |
Register / unregister and disconnect |
call(target, { headers }) |
Call an agent (agent_ref) or a number (+31…). Choose the caller ID with header X-Caller-Id: +31… (must be one of your numbers; otherwise the workspace default is used) |
answer(id?), hangup(id?) |
Answer / end |
hold(id?), unhold(id?) |
SIP hold |
mute(id?), unmute(id?) |
Microphone |
sendDtmf('123#', id?) |
RFC 4733 DTMF |
transfer(target, id?) |
Blind transfer (SIP REFER) |
attendedTransfer(id, consultId) |
Connect two calls |
calls |
Current calls |
Requirements: HTTPS page (microphone permission), the browser must reach the SIP WSS URL
(TCP 7443) and the TURN server (UDP/TCP 3478). A plain <script> build is published as
dist/softphone.global.js (global VoiceSoftphone); /demo/softphone on the API is a working example.