Security
Domain allowlist
The widget-id attribute in the embed snippet is public. It contains no credentials and is safe to commit to source control, deploy to a CDN, or serve to any visitor.
Access control is enforced server-side on every request:
- The Powsoo API reads the
Originheader of every/v1/voice-tokensand/v1/embed/*/configrequest. - It validates the origin against the widget’s Allowed origins list, configured in the dashboard.
- A request from an unlisted origin is rejected with
404 widget_unavailablebefore any token is minted or credentials are accessed.
This is the same model Stripe (publishable keys), Segment (write keys), and Behold use. The public identifier is useless without a matching origin.
| Pattern | Example | Matches |
|---|---|---|
| Bare domain | example.com | https://example.com only |
| Wildcard subdomain | *.example.com | Any subdomain |
| Port | localhost:5173 | Exact port match |
localhost and 127.0.0.1 are always allowed without any dashboard configuration.
Credential encryption
When an agency connects their Retell or Vapi API key, Powsoo immediately encrypts it with AES-GCM before writing to Supabase. The encryption key (VOICE_PLATFORM_KEY_SECRET) lives in Cloud Run’s Secret Manager, not in the database.
The plaintext API key:
- Is never written to Powsoo’s database or logs
- Is decrypted in memory only at token-mint time, then discarded
- Uses a per-user AAD (Additional Authenticated Data) so ciphertexts are not portable between tenants
Session tokens
After a voice token is minted, the API issues a sessionToken (sst_*) — a 24-byte random string bound to the callId. This short-lived token authenticates the SSE stream subscription and the result POST for that specific call. It has a ~10-minute TTL and is scoped to one call session.
The session token is never stored in the URL, never sent to Retell, and is cleaned up when the call ends.
No PII by default
Powsoo does not persist card field values (emails, phone numbers, addresses) in its database. Only structural metadata is stored:
- That a card was shown (type, timing)
- Whether the user confirmed, edited, or skipped
- Call duration and session metadata
Raw field values transit Powsoo’s API during the tool-call relay but are not written to any store. Full session replay is available at the Enterprise tier under a separate Data Processing Agreement — it is off by default.
Audio never transits Powsoo
Audio flows direct widget ↔ Retell/Vapi over LiveKit WebRTC. Powsoo’s API is never in the audio path. A Powsoo outage cannot affect in-progress voice audio.
Reporting a vulnerability
Email security@powsoo.com. We aim to respond within 48 hours.