Voice calls (WUTS Voice)
Place and receive WhatsApp voice calls from your WUTS device — start a call over REST, carry live audio over a WSS PCM socket, and use the built-in browser softphone.
WUTS Voice lets your WUTS device place and receive real WhatsApp voice calls. Signaling and call control go over the normal REST API; the live audio is carried over a WebSocket (WSS) as raw PCM, so it works from a browser or any WSS-capable client. WUTS Voice is voice-only, 1:1.
Every REST request below is authenticated with your tenant token (Authorization: Bearer <token>)
and the X-Device-ID header. See Authentication for how to obtain them.
WhatsApp only lets you call a number you already have an open conversation with. Calling a
contact you have never messaged is rejected by WhatsApp's anti-spam layer (the call ends
immediately with reason enc). If in doubt, send a text first, then call.
1. Start a call
POST /calls
curl -X POST https://api.wuts.com.br/calls \
-H "Authorization: Bearer $WUTS_TOKEN" \
-H "X-Device-ID: $DEVICE_ID" \
-H "Content-Type: application/json" \
-d '{"to":"5511999999999"}'{
"success": true,
"call_id": "73EE9BC6A87B1AA5AED857F4DBB73B0E",
"to": "5511999999999@s.whatsapp.net",
"status": "ringing",
"timestamp": "2026-07-16T18:19:47Z"
}The destination is now ringing. Keep the call_id — you need it for audio and to hang up.
2. Carry live audio (WSS)
Audio flows over a dedicated WebSocket. Because a browser cannot set the Authorization header on a
WS handshake — and your bearer must never appear in a URL — you first mint a single-use,
90‑second media token, then open the returned ws_url.
POST /calls/media-token
curl -X POST https://api.wuts.com.br/calls/media-token \
-H "Authorization: Bearer $WUTS_TOKEN" \
-H "X-Device-ID: $DEVICE_ID" \
-H "Content-Type: application/json" \
-d '{"call_id":"73EE9BC6A87B1AA5AED857F4DBB73B0E"}'{
"success": true,
"token": "GqDmOiShYLmydinGTdK83Yb...",
"ws_url": "wss://api.wuts.com.br/calls/media?ct=GqDmOiShYLmydinGTdK83Yb...",
"expires_at": "2026-07-16T18:36:10Z"
}Open ws_url immediately. Over the socket:
- Send binary frames of raw PCM — signed 16‑bit little‑endian, mono, 16 kHz. Frames of ~20 ms (320 samples / 640 bytes) are ideal. This is your microphone.
- Receive binary frames in the same PCM format — the other party's audio.
- Send the text frame
{"type":"hangup"}to end the call.
The server pings every 15 seconds to keep the socket alive across proxies. Audio only flows once the other side answers; anything you send while it is still ringing is discarded.
const ws = new WebSocket(ws_url);
ws.binaryType = "arraybuffer";
ws.onmessage = (e) => {
if (e.data instanceof ArrayBuffer) playPcm16(e.data); // peer audio
};
// ...feed 16 kHz Int16LE mic frames:
ws.send(int16Frame.buffer);3. Hang up
POST /calls/terminate
curl -X POST https://api.wuts.com.br/calls/terminate \
-H "Authorization: Bearer $WUTS_TOKEN" \
-H "X-Device-ID: $DEVICE_ID" \
-H "Content-Type: application/json" \
-d '{"call_id":"73EE9BC6A87B1AA5AED857F4DBB73B0E"}'Sending {"type":"hangup"} on the media socket ends the call too.
4. Inspect calls
GET /calls/active returns calls currently ringing or connected; GET /calls/history returns a
rolling list of recent calls (most recent first), including the termination reason.
curl -H "Authorization: Bearer $WUTS_TOKEN" -H "X-Device-ID: $DEVICE_ID" \
https://api.wuts.com.br/calls/active5. Incoming calls
Inbound calls arrive as call.* webhooks. Accept a ringing call with
POST /calls/accept (pass the call_id from the call.offer event), then open a media socket the
same way as above to carry audio. To decline, use POST /calls/terminate.
The browser softphone
The WUTS manager ships a built‑in softphone. Open an instance page in the WUTS panel and use the WUTS Voice card to dial, mute, and hang up with full two‑way audio straight from your browser — it uses exactly the REST + WSS flow described above, so you never handle tokens by hand.
Limits & notes
- Voice only, 1:1. Video and group calls are not carried (an inbound video/group call is detected and can be declined cleanly).
- Established conversations only — see the warning at the top about the
encrejection. - Media tokens are single‑use and expire in 90 seconds; mint one per call, right before opening the socket.