CallwiseDocs

Security model

The rules Postgres enforces, whatever the app or an API client sends.

The app hides what you can't use, but hiding is not the protection. Every rule below is enforced by the database with row level security, column permissions, triggers or checked functions, and each one has a test that tries to break it (pnpm test:rls, see Tests).

Product tables start with cw_ and every row belongs to one workspace. Access is decided by one function, cw_can_access(workspace, module, level), used by every policy.

The rules

#RuleHow Postgres enforces it
1Only billing can change a workspace's plan, status, period or pool allowance.Signed-in users can read cw_subscriptions but have no write permission on it.
2Nobody unlocks a module without paying. New modules start locked; switching on a locked module fails.access_state can't be written by users; owners may only update enabled, and a trigger refuses it for locked modules.
3Publishing a script needs publish on Receptionist.Versions are only created by cw_publish_agent(), which checks the level. Direct writes to versions or the published pointer are refused.
4Call records can't be rewritten from the app. Only the review mark and flag change, and the reviewer is always you.Column permission on review fields only; a trigger sets the reviewer and time from the signed-in user.
5Users can't create calls or transcript lines.No insert permission. Only the voice service, through the signed webhook, writes them.
6A module set to none, or switched off, returns no rows.cw_can_access in every read policy.
7One workspace never sees another's data.cw_can_access checks membership first.
8People can't raise their own access level.Only owners and admins edit access; admins can't touch the owner's rows.
9Audit entries are written only as yourself.Insert policy requires actor_type = 'user' and your own user id; no updates or deletes.
10A read-only workspace can't be changed.cw_can_access caps every level at view for read-only modules.
11Erasing a caller, and routing a phone number, need publish.cw_erase_caller() checks the level; the update policy on phone numbers requires publish.
12Notes belong to their author.Inserts must use your own user id; you can only edit or delete your own notes.

Other protections

  • Service role. The key that bypasses these rules is used in one server file only (apps/web/lib/callwise/service-role.ts), for billing and the voice webhook.
  • Voice webhook. HMAC-signed, timestamp checked within 5 minutes, idempotent on event id.
  • Recordings. Private bucket; a file is readable only with view on Receptionist in its workspace; no uploads from the app.
  • Outgoing webhooks. Destination URLs pass a server-side guard before anything is sent.
  • Demo mode can't run in production without an explicit ALLOW_DEMO_IN_PROD=true, and never makes an outside request.

What is not covered yet

No external security audit or penetration test has been done, and Callwise holds no compliance certification. See Data and privacy.

On this page