Proxy session (number masking) model
A proxy session lets two people reach each other — by SMS or voice — without either one learning the other’s real phone number. You create a session between two participant numbers, Orbit allocates one shared pool number to the session, and for the session’s lifetime every message or call routed through that pool number is forwarded to the other participant. When the session ends, the pool number goes back into the shared pool and the link dies. This page is the conceptual model: what a session is, how its lifecycle runs, how forwarding resolves the counterparty, how the shared pool stays fair, and how masking differs from short-links and inbound routing. For the full request flow and error handling, see the number masking guide; for request and response schemas, the proxy API reference; for how masking sits next to OTP and other privacy primitives, Choosing a privacy primitive.1. What a proxy session is
A session is four things:- Two participants.
participant_aandparticipant_b, both E.164 numbers, and they must be different numbers. One is not special — the session is symmetric, and forwarding uses whichever participant sent the inbound traffic. - One shared pool number. Orbit claims a number from the platform’s shared proxy pool and binds it to the session for its lifetime. Both participants address the same number; it is the only number either side ever sees.
- A TTL.
ttl_minutesbounds how long the binding lives — 1 to 1440 minutes (24 hours), defaulting to 60 when you omit it. The TTL is the session’s disposal plan: pick the window in which the two parties legitimately need each other. - An id and an expiry. The create response returns
session_id, the allocatedproxy_number, andexpires_at, the moment the session stops forwarding.
POST /api/v1/proxy/sessions — body { participant_a, participant_b, ttl_minutes? }. List sessions with an optional status filter on GET /api/v1/proxy/sessions, fetch one with GET /api/v1/proxy/sessions/:id, and end it with DELETE /api/v1/proxy/sessions/:id.
A session belongs to your tenant. Your tenant’s sessions, participants, and audit entries are yours alone; the only thing shared across the platform is the pool the numbers come from.
2. Session lifecycle
active, closed, or expired.
- active → closed when you call
DELETE /api/v1/proxy/sessions/:id. This is the explicit ending. - active → expired when the TTL lapses. A platform sweeper runs every five minutes, marks lapsed sessions
expired, and releases their numbers. Because the sweep is periodic, an expired number can linger up to one sweep interval pastexpires_atbefore recycling. - Forwarding also stops at the wall-clock expiry: inbound traffic that arrives past
expires_atis not forwarded even before the sweeper gets to the row.
3. How forwarding works
Inbound SMS and calls to proxy numbers arrive on the platform’s internal inbound webhook (POST /api/v1/proxy/inbound), an authenticated server-to-server path that is not callable by either participant. For each inbound message, the platform:
- Resolves the session that owns the destination pool number.
- Checks the session has not expired.
- Matches the sender to one of the two participants — a sender that matches neither participant is never forwarded.
- Sends the message to the other participant with the pool number as the sender.
rider → proxy → driver):
4. Pool fairness
Sessions draw from a shared platform pool, and there is no per-organization concurrency cap on active sessions. A marketplace, delivery, or ride-share tenant can hold as many sessions as its transaction volume needs; one organization’s load never blocks another’s claim. Fairness instead comes from recycling:- On close or expiry the number is released and becomes claimable again by any organization. Numbers churn through the platform rather than accumulating in one tenant.
- A released number is re-issued only after release completes, so a stale binding can never route traffic to the wrong session — closed-session inbound traffic short-circuits on the session lookup.
- Releases are ownership-scoped: only the organization that claimed a number can release it, so a late or duplicated close cannot free a number that has since been re-claimed by another session.
5. Validation and error shapes
The session endpoints fail in a small, deliberate set of ways:
Two of these encode races, not bugs. A 409 on close means the sweeper or an earlier close got there first — the desired end state holds either way, so log it and move on; retrying or alerting on it creates noise about a correct outcome.
6. What masking is — and is not
Masking is easy to confuse with two neighboring features. The distinction matters because they solve different problems:- Against short-links and landing pages. A short-link intentionally exposes intent: the recipient clicks, and the click is the signal — tracked, attributed, led back to a landing page. Masking does the opposite with identity: it hides who is on each side while contact happens. Links reveal a call to action; a proxy session hides the parties.
- Against inbound message routing. Routing rules are tenant-level and durable: they decide, for every inbound message on your numbers, which destination handles it — webhook, inbox, queue, auto-reply. Masking is none of that. It is a per-session overlay for exactly one pair of participants, with no match rules and no routing targets; it lives for its TTL and then disappears. Routing answers “where do my inbound messages go”; a proxy session answers “let these two specific people talk, privately, for a while.”