Phone widget
Embed a Voylo agent softphone on your own pages. Outbound dial, incoming calls, and JS events — six lines of HTML.
What you get
- An agent softphone (registered SIP, WebRTC audio) inside an iframe on your page.
- Auto-login via your backend — agents never see a Voylo login screen.
- A small JS API:
dial,hangup,on,show / hide. - JS events when a call rings, answers, or ends — wire them into your CRM.
Step 1 — Mint a session token (server-side)
Your backend calls Voylo with an API key and the agent's identity. We return a short-lived voywt_… token your frontend can hand to the widget. The API key never touches the browser.
cURL
$ curl https://voylo.ai/v1/agent-widget/session \
-H "Authorization: Bearer vlx_..." \
-H "Content-Type: application/json" \
-d '{"agentEmail":"alice@cust.com","displayName":"Alice"}'
Response:
JSON
{
"token": "voywt_AbCdEf...",
"widgetUrl": "https://widget.voylo.ai/embed?token=...",
"expiresAt": "2026-06-29T22:00:00Z",
"agent": { "id": "...", "username": "alice", "label": "Alice" }
}
If the agent email doesn't exist in your workspace yet, we create the agent for you. SSO-style — your identity drives ours.
Step 2 — Drop the widget on a page (browser)
HTML
<script src="https://widget.voylo.ai/v1/phone.js"></script>
<script>
Voylo.init({
sessionToken: 'voywt_...', // from your backend
mode: 'floating' // or 'inline'
})
</script>
Floating mode shows an Intercom-style button bottom-right; clicking it opens the softphone. Inline mode mounts inside a div you control:
HTML — inline
<div id="voylo-phone"></div>
<script>
Voylo.init({
sessionToken: 'voywt_...',
mode: 'inline',
target: '#voylo-phone'
})
</script>
JS API
JavaScript
// Place a call from any UI on the host page
Voylo.dial('+201234567');
Voylo.hangup();
Voylo.answer();
Voylo.decline();
Voylo.toggleMute();
Voylo.show(); // floating only
Voylo.hide();
Voylo.destroy();
Events
The widget posts events as soon as the SIP layer crosses each transition:
JavaScript
Voylo.on('ready', ({ agent }) => { ... });
Voylo.on('state', ({ state }) => { ... });
Voylo.on('call:ringing', ({ fromUri, displayName }) => {...});
Voylo.on('call:answered', () => {...});
Voylo.on('call:ended', ({ cause, statusCode }) => {...});
Voylo.on('error', ({ message }) => {...});
Theming
Pass a few CSS-variable overrides at init time. Anything you don't set keeps the Voylo default.
JavaScript
Voylo.init({
sessionToken: 'voywt_...',
theme: {
primary: '#5B6CB8', // buttons, accents
bg: '#FFFFFF', // card background
ink: '#0E2A2E', // text
radius: '12' // px
}
})
Revoking a session
Sessions auto-expire after the TTL you set (default 1 hour, max 24). To kick an agent out earlier, DELETE the session by id:
cURL
$ curl -X DELETE https://voylo.ai/v1/agent-widget/session/<id> \
-H "Authorization: Bearer vlx_..."
Security model
- API key stays on your server. Browsers only see the short-lived
voywt_token. - Token is hashed (SHA-256) at rest — a DB leak can't replay a live session.
- Embed runs inside an iframe on
widget.voylo.ai: host-page CSS, JS, and cookies are isolated from us, ours from them. - Microphone permission is granted to
widget.voylo.aivia the iframe'sallow="microphone"attribute — once per browser per origin.
Limits
- TTL: 5 minutes to 24 hours, default 1 hour.
- Token format:
voywt_+ 32 base64url chars. - Only HTTPS pages can embed the widget (the iframe needs secure context for mic access).