Authentication
There are two directions to secure: requests you send to the PBX (a bearer token), and requests the PBX sends to you — webhooks and programmable-voice callbacks — which are cryptographically signed so you can trust them.
You → PBX: the bearer token
Every REST call carries an Authorization header:
Authorization: Bearer YOUR_TOKEN
The token is configured in the PBX under Settings → Integrations. Two tokens are accepted interchangeably — the reminder-engine token and the CRM integration token — so whichever your workflow already holds will work across the messaging and inbox APIs.
The token is a shared secret — treat it like a password. Prefer the HTTPS endpoint (:8085) so it's
never sent in the clear, keep it out of URLs and logs, and rotate it in Settings if it's ever exposed.
PBX → you: verifying signed callbacks
When the PBX calls your endpoint — a webhook or a programmable-voice callback — it signs the request with your endpoint's shared secret so you can be sure it's genuine and untampered. Verify it before acting:
- Read the
X-Voicer-Timestampheader (call itts) and the raw request body (the exact bytes, before JSON parsing). - Compute
HMAC-SHA256(secret, ts + "." + rawBody), hex-encoded. - Constant-time compare it to the hex after
sha256=in theX-Voicer-Signatureheader. Reject on mismatch — and ideally reject atsmore than a few minutes old (replay defence).
# pseudocode
expected = hmac_sha256(secret, ts + "." + raw_body) # hex
if not constant_time_equals(expected, signature_hex): # from "sha256="
return 401 # forged or altered — drop it
process(body)
Every example app (Python, Swift, Go) factors this into a single
verify() function you can lift verbatim. When the secret is empty the samples skip verification and
print a loud warning — handy for a first run, never for production.
Why the PBX won't call just any URL
The URLs you register (webhook targets, programmable-voice control/action URLs) are validated so the PBX can't be tricked into reaching internal or cloud-metadata addresses. Point them at real, reachable hosts; loopback and link-local addresses are refused.