Authentication
Every REST request is authenticated with HTTP Basic auth; every outbound webhook is signed so you can verify it came from Ruut Voice.
REST API authentication
Send your Account SID as the username and Auth Token as the password with HTTP Basic auth:
Authorization: Basic base64("{AccountSid}:{AuthToken}")
Equivalently, in curl:
curl -u "$RUUT_ACCOUNT_SID:$RUUT_AUTH_TOKEN" \
"https://voice.ruut.chat/2010-04-01/Accounts/$RUUT_ACCOUNT_SID/Calls"
Failed authentication returns 401 Unauthorized.
Scoped API keys
For production, create scoped API keys in the dashboard instead of using your master Auth Token. Keys can be restricted to specific resources (e.g. calls only) and revoked independently — limit blast radius if a key leaks.
credentials flow).
Webhook signature verification
Outbound webhooks are signed with HMAC-SHA1 over the URL and sorted body parameters, keyed by your Auth Token. The signature is sent in the X-Twilio-Signature header.
Verify before trusting any callback:
import { validateWebhookSignature } from "@ruut/voice-sdk";
const valid = await validateWebhookSignature({
url: "https://app.example.com/webhooks/status",
params: req.body,
signature: req.headers["x-twilio-signature"],
authToken: process.env.RUUT_AUTH_TOKEN,
});
if (!valid) return res.status(403).end();
Or use the Express middleware, which verifies and parses in one step:
import { ruutWebhook } from "@ruut/voice-sdk/express";
app.post("/webhooks/status",
ruutWebhook({ authToken: process.env.RUUT_AUTH_TOKEN }),
(req, res) => {
console.log(req.ruutWebhook.CallStatus);
res.sendStatus(200);
}
);
SIP authentication
- Inbound — only source IPs in your trunk's allowlist are accepted.
- Agent softphones — digest authentication against the extension's ephemeral credentials.