- ›
Agents that log into vendor portals hit SMS 2FA— a shared team inbox leaks one customer's codes to another - ›Naïve provisions a real US number per tenant user via /phone; inbound SMS works immediately after provisioning
- ›
Codes arrive scoped to the number owner— naive.forUser(clientId) ensures Client A's OTP never surfaces to Client B's agent - ›Agents with receive_sms permission read the inbox through the governed API, not a shared Google Voice tab
- ›Pairs with /browser for no-API operators that need to complete login flows end to end
- ›10DLC registration runs at provisioning; inbound is live while outbound campaign approval is pending
A browser agent that can fill login forms still stops at the SMS gate. Banks, airlines, and legacy SaaS portals text a one-time code to a phone number — and if every customer shares one inbox, Customer A's OTP lands where Customer B's agent can read it. Naïve is the autonomous company infrastructure that gives agents real-world capabilities, and /phone is the primitive that gives each tenant agent its own US number for inbound SMS, including 2FA codes, scoped and readable through the governed API. Part of the autonomous company use-case cluster.
This guide shows how to provision per-tenant phone numbers for agents that operate vendor portals: inbound works immediately, messages stay isolated per user, and agents read codes with explicit receive_sms permissions. Pair with /browser for the full no-API login loop.
This tutorial connects to the Multi-Tenant Playbook, no-API operator, and Introducing /phone.
Why 2FA breaks multi-tenant agents
| Phase | Agent-friendly? | Needs a phone? |
|---|---|---|
| Navigate & submit login | Yes — browser automation | No |
| Enter SMS OTP | Fails with shared inbox | Yes — inbound SMS |
| Complete session | Needs scoped credentials | Yes — per-tenant identity |
The failure mode is identity collapse: one number serves every customer, so verification codes are not scoped to the tenant user the agent represents. /phone fixes this by binding each number to one user and surfacing inbound SMS only to that user's workspace.
Architecture
Four pieces work together:
- Users — one tenant user per customer.
- Formation — LLC + EIN for carrier (10DLC) brand registration.
- Phone — provision a US number; inbound SMS immediate.
- Browser — optional, for portal login automation.
Setup
npm install @usenaive-sdk/serverimport { Naive } from "@usenaive-sdk/server";
const naive = new Naive({ apiKey: process.env.NAIVE_API_KEY! });Step 1 — Form the business (one-time prerequisite)
Phone provisioning requires a completed LLC and EIN for carrier brand registration:
naive verification start
naive formation submitSee formation docs for the full chain.
Step 2 — Create a tenant user and provision a number
const customer = await naive.users.create({
external_id: "acme-portal-001",
email: "ops@acme.com",
});
const client = naive.forUser(customer.id);
const { phone, campaign } = await client.phone.provision({
ein: "12-3456789",
area_code: "415",
label: "Acme — vendor 2FA",
});
// phone.e164 is live for inbound SMS immediatelyEach customer gets their own number. Inbound OTPs are stored against that number only.
Step 3 — Assign an agent with receive_sms permission
naive phone assign <phone-id> --agent-id <agent-uuid>An agent without receive_sms is refused when it tries to read the inbox.
Step 4 — Poll for the OTP during login
When the browser agent submits credentials and the portal sends a code:
const messages = await client.phone.messages({ phoneId: phone.id, limit: 5 });
const latest = messages.items[0];
// Parse the OTP from latest.body and submit in the browser sessionSubscribe to the sms.received webhook event for real-time flows instead of polling.
Step 5 — Release or revoke on offboarding
When the customer churns, release the number or revoke the agent session. A released number stops receiving new SMS permanently.
What this enables for portal operators
- Vendor portals without APIs — complete SMS-gated login loops.
- Per-customer isolation — OTPs never cross tenants.
- Audit trail — inbound messages are stored and queryable per number.
- Composes with /browser — the agent fills the form, reads the code, finishes login.
The agent still does the browser work. /phone is what makes the 2FA step real and scoped.
Related reading
- Introducing /phone — primitive overview
- No-API operator — browser + comms stack
- Introducing /browser — governed browser sessions
- Phone documentation — API reference
Can an AI agent receive SMS 2FA codes?+
Why not use a shared Google Voice number for agent 2FA?+
How does multi-tenant 2FA work with agents?+
Does outbound SMS need to work for 2FA receive?+
What is required before provisioning a phone number?+
Building the autonomous company infrastructure.
Provision a real US phone number for any AI Employee — send and receive SMS — with carrier (10DLC) registration handled at provisioning. Inbound works immediately; outbound unlocks automatically on campaign approval.
Build a multi-tenant agent on Naïve for tools with no OAuth or API: the vault holds each customer's secrets, including write-only passwords it can never read.
Browser sessions your agents drive — navigate, act, extract — plus autonomous signup and login that vault credentials, scoped per user and watchable live.
Building multi-tenant AI agents into your SaaS means giving each customer an isolated, governed agent. Here's the full architecture and how to ship it.