Designing a Scalable Phone Number Masking System for Hyperlocal Apps
In hyperlocal delivery and ride-hailing platforms such as Gojek, Uber, and Swiggy, customers and delivery partners must frequently coordinate in real time. However, a user’s phone number is Personally Identifiable Information (PII). Exposing real phone numbers creates substantial risks: spam, harassment, targeted social engineering, and unauthorized account takeovers.
To mitigate these risks without hindering seamless communication, platforms employ Phone Number Masking using temporary, virtual phone numbers provided via CPaaS (Communications Platform as a Service) providers and telecom operators. This guide explores the architectural blueprints, data flows, and design trade-offs behind implementing phone number masking at scale.
1. The Core Problem Statement
Consider an active delivery order with two entities:
- Customer A with real phone number
123.
- Delivery Partner D with real phone number
456.
[Customer A: 123] <--- Must communicate bidirectionally ---> [Driver D: 456]
WITHOUT revealing 123 or 456
The functional requirements are straightforward:
- Customer A must be able to call Driver D without knowing D‘s real number.
- Driver D must be able to call Customer A without knowing A‘s real number.
- Neither party should be able to contact the other once the transaction completes.
2. Why Static Virtual Numbers Do Not Work
A naive approach is assigning a dedicated, permanent virtual number to every registered user.
Challenges with Static Mappings:
- Cost and Number Exhaustion: Phone numbers are limited and cost recurring rental fees. A platform with 50 million registered accounts would require 50 million rented numbers, even if only 100,000 users are active concurrently.
- Loss of Anonymity Over Time: If Customer A always appears to drivers as virtual number
AAA, bad actors can correlate trips, map behavioral patterns, and execute targeted harassment or social engineering.
System Constraints:
- On-Demand Allocation: Virtual numbers must be leased dynamically when a transaction begins.
- Ephemeral Scope: The number mapping must be bound strictly to the lifetime of an active transaction/order.
- Resource Pooling: After an order is marked delivered or cancelled, numbers are deallocated and returned to an available pool.
3. High-Level Architecture
The architecture divides responsibilities among the Order Service, Event Bus (Kafka), an internal Virtual Number Service (VNS), and Telecom Partners (such as Twilio, Exotel, Airtel, or Jio).
sequenceDiagram
autonumber
actor Customer
participant OrderService as Order Service
participant Kafka as Event Bus (Kafka)
participant VNS as Virtual Number Service (VNS)
participant VN_DB as VNS Inventory DB
participant Telecom as Telecom Operator / CPaaS
actor Driver
OrderService->>Kafka: Emit OrderStateChanged(DRIVER_ASSIGNED)
Kafka->>VNS: Consume DriverAssigned Event
VNS->>VN_DB: Lease 2 Virtual Numbers (AAA, DDD)
VNS->>OrderService: Store Virtual Mappings for Order
OrderService-->>Customer: Display Driver Virtual Number (DDD)
OrderService-->>Driver: Display Customer Virtual Number (AAA)
Customer->>Telecom: Calls DDD from 123
Telecom->>VNS: Webhook: Validate Call (From: 123, To: DDD)
VNS-->>Telecom: Forward to 456, Mask Source as AAA
Telecom->>Driver: Connects Call (Displays AAA, Rings 456)
Component Breakdown:
-
Virtual Number Pool (VNS Inventory):
- Rather than purchasing numbers synchronously on every order (which introduces latency and vendor rate-limiting risks), the VNS pre-provisions and manages a pool of rented numbers from CPaaS providers.
-
Virtual Number Service (VNS):
- Manages stateful leases for active transactions.
- Validates call bridging requests sent by telecom webhooks.
-
Order Service & Event Pipeline:
- Tracks order lifecycles.
- Emits events (
DRIVER_ASSIGNED, ORDER_COMPLETED, ORDER_CANCELLED) over Apache Kafka.
4. End-to-End Execution Flow
Step 1: Ephemeral Number Assignment
When Customer A places an order and Driver D is assigned:
- The
Order Service changes state and publishes a DriverAssignedEvent to Kafka.
- A VNS consumer picks up the event.
- VNS queries its inventory database for two available virtual numbers:
AAA (assigned to represent Customer A).
DDD (assigned to represent Driver D).
- VNS creates an active lease entry in its database:
Order_ID: ORD-9871
Party_A: Real = 123, Virtual = AAA
Party_D: Real = 456, Virtual = DDD
Status: ACTIVE
- The masked numbers are written back to the order record so client applications can render them:
- Customer A‘s UI displays the “Call Driver” button dialing
DDD.
- Driver D‘s UI displays the “Call Customer” button dialing
AAA.
Step 2: Inbound Call Interception and Bridging
When Customer A taps “Call Driver” in their application:
- Customer A‘s phone dials
DDD using real caller ID 123.
- The carrier routes this call to the CPaaS/Telecom provider that owns the virtual number
DDD.
- The CPaaS provider receives the incoming call on
DDD from 123. However, the telecom platform has no internal context on which driver should receive this call.
- The Webhook Query: The CPaaS provider makes a synchronous HTTP/gRPC request to Gojek’s VNS:
POST /api/v1/telecom/incoming-call
{
"caller_number": "+123",
"dialed_virtual_number": "+DDD"
}
Step 3: Authorization and Dynamic Bridging
VNS evaluates the request through a strict validation layer:
Step 4: Connecting the Call
- The telecom provider bridges the audio stream to
456.
- The telecom provider overrides the caller ID display using
display_caller_id = AAA.
- Driver D receives an incoming call from
AAA.
- Result: Both parties communicate in real time, but neither party’s true PII is exposed.
5. Critical Edge Cases and Design Nuances
1. Multi-Order Batching (Concurrent Deliveries)
A single delivery partner may handle multiple active deliveries simultaneously (e.g., delivering food for Customer A and groceries for Customer B).
[Customer A] ---> Calls DDD_1 ---
\---> Both ring [Driver D (456)]
[Customer B] ---> Calls DDD_2 ---/
- If Driver D were assigned the same virtual number across both orders, incoming calls from drivers back to customers could lead to collision ambiguity.
- Solution: Driver D is assigned a distinct virtual number per active transaction. When D calls Customer A, they dial Customer A‘s unique virtual number
AAA, allowing VNS to route accurately.
2. Guarding the Validation Step
The telecom webhook verification is a critical security barrier:
- Without strict caller validation (
caller == 123 AND dialed == DDD), any arbitrary caller who dials DDD could connect to the delivery partner or customer.
- Strict lookup ensures that ephemeral pairing is restricted entirely to the authorized parties for the duration of the ride/delivery.
3. Grace Periods and Teardown
- When the order transitions to
DELIVERED, deallocating numbers immediately can be disruptive (e.g., the customer may need to call the driver back because an item was left behind).
- Grace Period (Cool-off window): Systems typically keep the mapping active for a small time buffer (e.g., 5 to 10 minutes post-delivery) before running garbage collection and returning numbers back to the free pool.
6. Summary of Architectural Trade-Offs
| Strategy | Pros | Cons |
|---|
| Static 1:1 Number Allocation | Simple to implement; no dynamic routing engine needed. | Prohibitively expensive; leads to number pool exhaustion; identity tracking risks. |
| Ephemeral Transaction-Scoped Pooling | Highly cost-effective; maximizes pool reuse; strong PII isolation. | Requires stateful lease management, CPaaS webhook latency, and concurrency handling. |
| On-Demand Vendor API Purchasing | Zero idle inventory cost. | High latency on order placement; vulnerable to external vendor downtime and rate limits. |
| Pre-Provisioned Local Pool (Chosen Pattern) | Sub-millisecond local allocation; decoupled from vendor checkout latency. | Requires holding an idle baseline inventory of virtual numbers. |
By combining pre-provisioned virtual number pools with event-driven lease lifecycles and real-time telecom routing hooks, hyperlocal platforms achieve strict customer privacy at multi-million transaction scale.