Skip to Content
Web softphone

Web softphone

The Cloove softphone path separates server authentication from browser media:

  1. Your backend authenticates the user and requests a short-lived Vox client token.
  2. The browser registers with cloove-sip over SIP-over-WSS using that token.
  3. SIP.js establishes WebRTC audio for inbound and outbound calls.
  4. cloove-sip creates and updates the corresponding Vox call through Cloove’s internal voice bridge.

The browser never receives your Cloove API key.

Prerequisites

  • A server-side API key with vox:client_tokens:create.
  • An authenticated user in your application.
  • A supported browser with microphone permission and secure-context WebRTC.
  • SIP.js 0.21 or a compatible RFC 7118 client.

Issue credentials on your backend

// Example application backend route. Authenticate your user before this handler. const response = await fetch('https://api.clooveai.com/v1/vox/client-tokens', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CLOOVE_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ identity: signedInUser.id, channel: 'web', ttl_seconds: 3600, }), }) if (!response.ok) throw new Error('Could not issue voice credentials') const { data } = await response.json() return data

Protect this route with your own session authentication and authorization. A client token permits calls as your business until it expires; do not issue one from an unauthenticated public route.

Register with SIP.js

import { Registerer, UserAgent } from 'sip.js' const credentials = await fetch('/api/my-voice-credentials').then((res) => res.json()) const userAgent = new UserAgent({ uri: UserAgent.makeURI(`sip:${credentials.sipUsername}`), transportOptions: { server: credentials.wssEndpoint }, authorizationUsername: credentials.sipUsername, authorizationPassword: credentials.sipPassword, sessionDescriptionHandlerFactoryOptions: { constraints: { audio: true, video: false }, }, }) await userAgent.start() await new Registerer(userAgent).register()

Use wssEndpoint exactly as returned. Do not construct it from sipDomain; deployments may use a path, non-default port, or regional host.

Place an outbound call

Pass either an E.164 number or a complete SIP URI. Cloove’s SIP edge resolves E.164 destinations to the PSTN and records the call with callChannel: web.

import { Inviter, UserAgent } from 'sip.js' const target = UserAgent.makeURI(`sip:+2348012345678@${credentials.sipDomain}`) const session = new Inviter(userAgent, target, { sessionDescriptionHandlerOptions: { constraints: { audio: true, video: false }, }, }) await session.invite()

The REST POST /v1/vox/calls endpoint is for AI-orchestrated outbound calls. A softphone outbound call is initiated through SIP after registration; do not call both for the same conversation.

Receive calls

Provide an onInvite delegate, show an incoming-call UI, and call accept() only after the user answers.

userAgent.delegate = { onInvite(invitation) { showIncomingCall({ answer: () => invitation.accept(), reject: () => invitation.reject(), }) }, }

Attach the established session’s remote MediaStreamTrack objects to an autoplay audio element. Browsers may require a prior user interaction before audio playback.

Credential lifecycle

  • Keep sipPassword in memory; do not write it to local storage or logs.
  • Refresh several minutes before expiresAt and re-register with the new credential.
  • Let an established call finish before replacing its UserAgent.
  • Unregister and stop the user agent on sign-out or business-context changes.
  • Use one active registration per user/device identity where possible.

Destination and call state

Normalize telephone destinations to E.164 (+ plus country code and subscriber number). Map SIP session state to a compact UI state:

SIP stateSuggested UI state
Incoming INVITEringing
Outgoing INVITE sentcalling
Session establishedactive
Session terminatingending
Session terminatedNo active call

Production checklist

  • Serve the application over HTTPS and request microphone permission from a user gesture.
  • Use the returned WSS URL and configure CSP connect-src to allow its host.
  • Provide STUN/TURN configuration suitable for your users’ networks.
  • Handle WSS disconnect, registration rejection, token expiry, and browser sleep/wake.
  • Support mute by toggling the outgoing audio track’s enabled property.
  • Stop local tracks and detach remote audio when the session ends.
  • Reconcile business call history with GET /v1/vox/calls and Vox webhooks.

Human takeover of an active AI call is currently a Cloove dashboard capability. The public softphone contract covers registered inbound and outbound calling; takeover REST controls are not part of /v1 yet.

Last updated on