Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Permissions

ScaiDial declares four module permissions. They're requested when an API key is minted and granted by a tenant admin.

Permission Gates
scaidial:trunks:manage Trunks, DIDs, tenant policy (Settings page)
scaidial:extensions:manage Extensions, extension grants, forward rules (admin-tier)
scaidial:dialplan:manage Dialplans and dialplan rules
scaidial:calls:observe Active calls, call history, leg controls (hangup / hold / transfer)

A tenant-admin role typically gets all four. A read-only auditor might get only :calls:observe. A dialplan-editor role (useful for delegating routing changes without giving carrier credentials) gets only :dialplan:manage.

How permissions are evaluated#

The dependency injection layer (require_module_permission) reads the permission set on the authenticated user (JWT path) or the API key (key path). The check is strict: missing the right key returns 403 before the route body runs.

Super-admin bypasses all module permission checks. Cross-tenant access is separately blocked by _require_tenant_scope — even with the right module permission, a tenant admin can't see another tenant's trunks.

End-user portal — no module permission, grant-based#

The /me/* routes don't gate on scaidial:* permissions. They gate on ExtensionGrant rows.

Grant role What it allows on the granted extension
owner Read everything + edit personal config (DND, forwarding, ring timeout, voicemail greeting). Place outbound calls from this extension.
manage Read voicemail + call history. Used for admin-tier reassignment of someone else's line; not for day-to-day "where do my calls go".
answer Receive ringing calls. Read voicemail (a delegated answerer needs to see what they missed).
observe Read-only view of call history. Used for supervisors.

A user with no grants on any extension lands on /my/dial and sees an empty state pointing them at their tenant admin.

The matrix#

Operation Permission needed Or grant role
GET /trunks scaidial:trunks:manage
POST /trunks/{id}/resync scaidial:trunks:manage
GET /dids scaidial:trunks:manage
POST /extensions scaidial:extensions:manage
POST /extensions/{id}/grants scaidial:extensions:manage
GET /dialplans scaidial:dialplan:manage
POST /dialplans/{id}/rules scaidial:dialplan:manage
GET /calls/active scaidial:calls:observe
POST /legs/{id}/hangup scaidial:calls:observe
POST /legs/{id}/transfer scaidial:calls:observe
GET /policy scaidial:trunks:manage
PATCH /policy scaidial:trunks:manage
GET /me/extensions (none) any grant
PATCH /me/extensions/{id} (none) owner
GET /me/voicemail (none) owner or manage (per-row)
GET /me/voicemail/{id}/audio (none) owner or manage
POST /me/click-to-call (none) owner on the source extension
POST /me/extensions/{id}/forward-rules (none) owner

Issuing an API key for ScaiDial#

API keys are minted in ScaiGrid Auth (Identity → API keys). On creation you select the module permissions to attach. For a typical tenant-admin key that should be able to fully manage ScaiDial:

carbon
1
2
3
4
scaidial:trunks:manage
scaidial:extensions:manage
scaidial:dialplan:manage
scaidial:calls:observe

Add scaidial:diarize separately if the tenant has ScaiEcho voicemail-transcript opt-in and you want the key to be able to request diarization on streaming endpoints elsewhere.

Why no per-extension permission scheme#

We considered scaidial:extension:{id}:manage as a separate permission key per extension. It would let you delegate ownership of specific extensions without giving the tenant-wide manage role. We chose grant rows instead because:

  • Grants are a single index on (extension_id, user_id), which scales linearly with users-times-extensions. A permission-per-extension would explode the permission table.
  • Tenant admins already need an admin-tier permission for tenant-wide config; grants cover the per-extension delegation case directly.
  • Grants compose with groups (a group_id instead of a user_id), which permissions don't.

If you need finer-grained admin delegation than the four module permissions allow, file an issue with the use case — we'll add it if there's demand.

Updated 2026-06-23 01:06:32 View source (.md) rev 1