Get started →
Documentation

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:

Exampletext

Authorization: Basic base64("{AccountSid}:{AuthToken}")

Equivalently, in curl:

curlbash

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.

Never expose your Auth Token or a scoped key in client-side code. Always proxy through your server (e.g. use the browser SDK's server-side 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:

Examplets

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:

Examplets

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.

Next