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.ai via the iframe's allow="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).