Phone Number Assignment
Overview
Phone number assignments control which organizations and customers can use which numbers and in which direction. The system enforces a strict hierarchy with cascading rules.
PhoneNumberAssignment Model
{
assignmentUID: string, // Unique identifier
phoneUID: string, // Reference to PhoneNumber
number: string, // Denormalized phone number (for quick lookups)
orgUID: string, // Organization the number is assigned to
customerUID: string, // Customer within the org (optional for org-level)
direction: "outbound" | "inbound" | "both",
status: "active" | "inactive",
inboundConfig: { // Present only when direction includes inbound
dispatchRuleId: string, // LiveKit dispatch rule ID
defaultAgentId: string, // Agent linked for inbound calls
isActive: boolean // Whether inbound is currently active
}
}Assignment Hierarchy
Superadmin (owns phone numbers)
└── Org (assigned by superadmin)
└── Customer (assigned by org admin)Assignments flow downward. An org must have access before a customer within that org can be assigned.
One Doc Per Combination
There is ONE assignment document per unique combination of phoneUID + orgUID + customerUID. Duplicates are never created.
Merge Behavior
When assigning a direction that already has a partial assignment:
- Phone assigned as
"outbound"to Org A - Later assigned as
"inbound"to Org A - Result: existing doc upgraded to
"both"(not a new doc)
This merge ensures the one-doc-per-combination invariant is maintained.
Direction Enforcement
Direction enforcement is hierarchical each level cannot exceed the level above:
PhoneNumber.direction >= Org Assignment.direction >= Customer Assignment.direction| Scenario | Result |
|---|---|
| Phone is "outbound" only, try to assign inbound to org | ❌ Rejected |
| Phone is "both", org assigned "outbound", customer wants "inbound" | ❌ Rejected (org doesn't have inbound) |
| Phone is "both", org assigned "both", customer wants "inbound" | ✅ Allowed |
Inbound Exclusivity
Only one customer per phone number globally can have inbound access.
- If Customer A in Org X has inbound for number +1555..., no other customer in any org can get inbound for that number
- Outbound has no such exclusivity constraint multiple customers can share outbound access to the same number
Cascading Behavior
Revoking Org Access
When an org's assignment is revoked or downgraded, all customer assignments under that org are affected:
Full revocation (delete org assignment):
- All customer assignments for that org + phone are deleted
Direction downgrade on org (e.g., "both" → "outbound"):
- Customer assignments that only had the removed direction → deleted
- Customer assignments that had "both" → downgraded to match
Downgrade Behavior for "both"
When a "both" assignment is downgraded:
| Revoked Direction | Result |
|---|---|
| Revoking inbound | Assignment becomes "outbound" |
| Revoking outbound | Assignment becomes "inbound" |
| Revoking both | Assignment is deleted |
Cascade Examples
Before: Org has "both", Customer has "both"
Action: Revoke inbound from Org
After: Org has "outbound", Customer has "outbound"
Before: Org has "both", Customer has "inbound"
Action: Revoke inbound from Org
After: Org has "outbound", Customer assignment DELETED (can't keep inbound)
Before: Org has "both", Customer has "outbound"
Action: Revoke inbound from Org
After: Org has "outbound", Customer still "outbound" (unaffected)