Home / Blog / Product
Product · 6 min read · Published 2026-10-22 · OTP Route Engineering

Virtual Numbers for Team 2FA and Support Lines (US and Canada)

Use dedicated US and Canada virtual numbers for team 2FA and support lines, with inbound SMS webhooks, browser calling, renewal hygiene and clean release.

TL;DR — Dedicated US and Canada virtual numbers give teams a persistent line for shared 2FA and support, with inbound SMS in the dashboard and via webhook, outbound SMS, browser calling, term renewal and release at any time.

A dedicated virtual number is the right tool when a team needs one stable phone number that several people can use: a shared account protected by SMS 2FA, a support line customers can text or call, or an operational identity that must survive staff changes. OTP Route's dedicated lines are US and Canada numbers with inbound SMS delivered to the dashboard and to your webhook, outbound SMS, browser calling, term-based renewal, and release at any time.

This guide covers how to set up numbers for team 2FA and support, how to route inbound messages into your own systems, and the renewal and release hygiene that keeps the inventory clean.

Why teams outgrow personal phones

Many organisations start by attaching a shared account's 2FA to one employee's mobile number. It works until it doesn't:

  • The person is unavailable. Codes arrive on a phone that is on holiday, switched off or in another time zone.
  • The person leaves. Their number goes with them, and recovering the account becomes a support ticket with the vendor.
  • There is no audit trail. Nobody else can see which codes were requested, or when.
  • Support lines get personal. A customer-facing number that rings a personal handset blurs work and private life and is hard to hand over.

A dedicated virtual number moves that identity from a person to the organisation. The number lives in your OTP Route account, codes are visible to authorised team members, and the line can be handed over without porting a SIM.

What a dedicated line includes

Capability How it works Typical use
Inbound SMS Shown in the dashboard and sent as a number.sms_received webhook 2FA codes, customer texts
Outbound SMS Sent from the dashboard Replying to customers, confirmations
Browser calling Place and receive calls in the browser Support calls without a handset
Term renewal Renew the line for another term from your USD wallet Keep long-lived identities
Release Give the number up whenever you choose Decommission projects cleanly
Coverage United States and Canada North American presence

Lines are paid from the same wallet as temporary activations, topped up by card through Stripe or with USDT and USDC. See /virtual-numbers for the product overview and /pricing for current term prices.

If you only need to capture a single code once, a temporary verification number is usually a better fit; the trade-offs are laid out in temporary vs dedicated numbers.

Pattern 1 — Shared team 2FA

Setup

  1. Provision a dedicated US or Canada number from the dashboard.
  2. On the vendor platform (your registrar, cloud console, analytics tool, ad account, and so on), add that number as the SMS second factor for the shared account.
  3. Configure a webhook endpoint in the developer console so number.sms_received events reach your systems, and use the console's test-send to confirm delivery.
  4. Document the mapping — which number protects which account — in your internal runbook or password manager entry.

Routing codes to the right people

Rather than asking everyone to watch the dashboard, forward codes to where the team already works. A minimal receiver that verifies the signature and posts to an internal chat channel:

import hmac, hashlib, time, json, os
from flask import Flask, request, abort
import requests

app = Flask(__name__)
SECRET = os.environ["OTPROUTE_WEBHOOK_SECRET"]
CHAT_WEBHOOK = os.environ["INTERNAL_CHAT_WEBHOOK"]

# Map your dedicated numbers to the accounts they protect
NUMBER_LABELS = {
    "+15550100001": "Cloud console (shared ops account)",
    "+15550100002": "Domain registrar",
}

def verified(raw: bytes, header: str) -> bool:
    try:
        parts = dict(p.split("=", 1) for p in header.split(","))
        ts = int(parts["t"])
    except (KeyError, ValueError):
        return False
    if abs(time.time() - ts) > 300:
        return False
    mac = hmac.new(SECRET.encode(), f"{parts['t']}.".encode() + raw, hashlib.sha256)
    return hmac.compare_digest(mac.hexdigest(), parts.get("v1", ""))

@app.post("/hooks/otproute")
def hook():
    raw = request.get_data()
    if not verified(raw, request.headers.get("X-OTPRoute-Signature", "")):
        abort(400)
    event = json.loads(raw)
    if event.get("type") == "number.sms_received":
        data = event["data"]  # payload fields illustrative; see /docs
        label = NUMBER_LABELS.get(data.get("to"), data.get("to"))
        requests.post(CHAT_WEBHOOK, json={"text": f"New SMS for {label}"}, timeout=10)
    return "", 200

Notice the message posted to chat says that a code arrived, not the code itself. For sensitive accounts, keep the code in the access-controlled dashboard and use chat only as a notification. For low-risk internal tools, teams sometimes forward the code directly; decide deliberately, per account. Signature verification is explained in detail in securing OTP webhooks with HMAC.

Access control

  • Give dashboard access only to the people who should see codes.
  • Use separate API keys per integration so you can revoke one without affecting others; the developer console supports multiple keys and shows usage logs.
  • Where the vendor supports it, prefer an authenticator app or hardware key for human admins, and reserve the shared SMS number for accounts that genuinely require SMS.

Pattern 2 — A support line customers can text and call

A dedicated number can serve as a lightweight support line: customers text it, agents reply from the dashboard, and anyone on the team can take a call in the browser.

Inbound routing into your helpdesk

Use the same number.sms_received webhook to create or update tickets:

import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.OTPROUTE_WEBHOOK_SECRET;

function verify(raw, header) {
  const p = Object.fromEntries((header || "").split(",").map((x) => x.split("=", 2)));
  if (!p.t || !p.v1 || Math.abs(Date.now() / 1000 - Number(p.t)) > 300) return false;
  const exp = crypto.createHmac("sha256", SECRET).update(`${p.t}.`).update(raw).digest("hex");
  return exp.length === p.v1.length && crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(p.v1));
}

app.post("/hooks/otproute", express.raw({ type: "application/json" }), async (req, res) => {
  if (!verify(req.body, req.get("X-OTPRoute-Signature"))) return res.sendStatus(400);
  const event = JSON.parse(req.body.toString("utf8"));
  if (event.type === "number.sms_received") {
    await helpdesk.upsertConversation({
      channel: "sms",
      customer: event.data.from,   // illustrative field names; see /docs
      line: event.data.to,
      body: event.data.text,
    });
  }
  res.sendStatus(200);
});

Key design choices for support use:

  • Thread by customer number. Group messages from the same sender into one conversation so agents see context.
  • Respond quickly to the webhook. Acknowledge with 200 and push slow work, such as helpdesk API calls, to a queue if volume grows.
  • Deduplicate. Treat each event idempotently so a redelivered webhook does not create a duplicate ticket.
  • Set expectations. Publish support hours alongside the number, since browser calling depends on someone being signed in.

Browser calling

Browser calling lets agents handle voice without a desk phone or a personal mobile. Practical tips:

  • Use a headset and a stable connection; browser audio quality depends on the agent's device and network.
  • Agree on who is "on call" for the line at any given time.
  • Keep a short call-handling checklist in your runbook — greeting, identity checks, escalation path.

Inventory, renewal and release hygiene

Dedicated numbers are billed per term, so unmanaged lines quietly accumulate cost. Treat them like any other infrastructure resource.

Keep an inventory

List your lines programmatically and reconcile them against your runbook:

curl -s https://otproute.com/api/v1/numbers \
  -H "Authorization: Bearer or_live_xxxxxxxxxxxxxxxx"

A simple scheduled job can compare the API response with a YAML file of expected numbers and owners, and flag anything unknown.

Renewal checklist

Before each term renews, confirm:

Check Question
Owner Is there a named owner for this number?
Purpose Which accounts or customers depend on it?
Activity Has it received or sent messages recently?
Wallet Is the wallet balance sufficient for upcoming renewals? (GET /v1/balance)
Replacement If the line lapses, how would dependent accounts be recovered?

The last row matters most for 2FA. Never let a number that protects an account lapse before you have moved that account's second factor elsewhere. A released number can no longer receive that account's codes.

Releasing a number safely

When a project ends or a support line is retired:

  1. Remove the number as a 2FA factor from every account that uses it, replacing it with another method first.
  2. Update public pages and email signatures that list the number.
  3. Remove it from your webhook routing tables and runbook.
  4. Release it from the dashboard.

Release is available at any time, so there is no reason to keep paying for a line you no longer need — but the dependency check above should always come first.

Responsible use

Dedicated numbers are intended for legitimate operational use: team access, customer support, and app verification flows. Respect the terms of each platform where you register a number, follow applicable messaging rules when sending outbound SMS, and do not use lines for spam, fraud or abuse.

For implementation details, see the API docs and the developer hub.

Frequently asked questions

Can several team members receive 2FA codes from one virtual number?

Yes. Inbound SMS to a dedicated number appears in the OTP Route dashboard for authorised users and can also be delivered to your systems through the number.sms_received webhook, so a team can share access without passing around a phone.

Which countries are dedicated virtual numbers available in?

Dedicated virtual numbers are available in the United States and Canada. Each line supports inbound SMS, outbound SMS from the dashboard and browser calling.

Can I make and receive calls on a dedicated number?

Yes. Dedicated lines support browser calling, so team members can place and take calls from the dashboard without a physical handset.

What happens if I stop renewing a number used for 2FA?

Once the line is no longer yours, it cannot receive codes for the accounts tied to it, which can lock you out. Move each account's second factor to another method before releasing a number or letting it lapse.

Should I use a dedicated number or a temporary number for one-off verifications?

For a single code you will never need again, a temporary verification number billed per activation, with automatic refunds when no SMS arrives, is usually more economical. Use a dedicated line when the same number must keep receiving messages.

Route your first OTP in minutes

Pay as you go · no monthly fee · automatic refunds on unused activations.

Topics: virtual number for 2FA · team 2FA phone number · virtual support line · US virtual number · Canada virtual number · inbound SMS webhook · browser calling