Web softphone
The Cloove softphone path separates server authentication from browser media:
- Your backend authenticates the user and requests a short-lived Vox client token.
- The browser registers with
cloove-sipover SIP-over-WSS using that token. - SIP.js establishes WebRTC audio for inbound and outbound calls.
cloove-sipcreates 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.21or 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 dataProtect 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
sipPasswordin memory; do not write it to local storage or logs. - Refresh several minutes before
expiresAtand 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:
Production checklist
- Serve the application over HTTPS and request microphone permission from a user gesture.
- Use the returned WSS URL and configure CSP
connect-srcto 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
enabledproperty. - Stop local tracks and detach remote audio when the session ends.
- Reconcile business call history with
GET /v1/vox/callsand 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.