Documentation
Webhooks overview
Ruut Voice notifies your application about call and recording lifecycle events by making HTTP requests to URLs you configure. Every webhook can be verified with a signed signature.
What you can receive
| Event | Trigger | Reference |
|---|---|---|
| Call status | Call state changes (ringing, in-progress, completed…) | call status |
| Recording | Recording in-progress / completed / absent | recordings |
| Transcription | Transcription completed / failed (with speaker segments) | transcriptions |
Where to set callback URLs
- Per call —
StatusCallbackon call creation. - Per number —
statusCallback/recordingStatusCallbackon an incoming phone number. - Per TwiML verb —
<Record transcribeCallback>,<Dial recordingStatusCallback>.
Delivery & retries
Webhooks are delivered with POST by default. Failures are retried with exponential backoff. Your endpoint should return a 2xx to acknowledge; anything else triggers a retry.
Signature verification
Every request is signed with HMAC-SHA1 of the URL + sorted parameters, using your account's Auth Token as the key. Verify before trusting the payload:
Examplets
import { parseWebhook, validateWebhookSignature } from "@ruut/voice-sdk";
const valid = await validateWebhookSignature({
url: "https://app.example.com/webhooks/call-status",
params: req.body, // parsed form params
signature: req.headers["x-twilio-signature"],
authToken: process.env.RUUT_AUTH_TOKEN,
});
if (!valid) return res.status(403).end();
const payload = parseWebhook(req.body);
ℹ️
The header is
X-Twilio-Signature (Twilio-compatible). Always validate it — it prevents spoofed callbacks.
Express helper
The SDK ships an Express middleware that validates signatures and parses the payload for you:
Examplets
import { ruutWebhook } from "@ruut/voice-sdk/express";
app.post("/webhooks/call-status",
ruutWebhook({ authToken: process.env.RUUT_AUTH_TOKEN }),
(req, res) => {
const call = req.ruutWebhook;
console.log(call.CallStatus, call.CallSid);
res.sendStatus(200);
}
);