Back to Blog
Developer ResourcesFebruary 25, 20269 min read

Add Phone Numbers to Your SaaS: A Multi-Tenant Guide

How to add per-tenant phone numbers to your SaaS product using AgentCall's agent-scoped API. CRMs, helpdesks, and marketing tools — give every customer their own number.

Your Customers Want Phone Features

If you build a CRM, helpdesk, marketing platform, or any SaaS that touches customer communication, your users will eventually ask: “Can I text customers from the app?” or “Can I get a dedicated phone number for my business?”

Adding phone features to a multi-tenant SaaS is hard. You need to provision numbers per-tenant, route incoming messages to the right tenant, track usage separately, and handle billing. Building this on raw Twilio or Telnyx means months of engineering. AgentCall's per-agent architecture maps directly to multi-tenant SaaS — each tenant becomes an agent.

The Multi-Tenant Phone Problem

When you integrate phone features into a SaaS product, you face several challenges that don't exist in single-tenant applications:

  • Number isolation: Tenant A's customers should never see Tenant B's messages. Each tenant needs their own phone numbers with isolated inboxes.
  • Webhook routing: When an SMS arrives, you need to know which tenant it belongs to and route it to the correct handler.
  • Usage tracking: Each tenant's SMS and voice usage must be tracked independently for billing and quota enforcement.
  • Provisioning at scale: New tenants should get phone numbers automatically during onboarding, not through manual setup.

Agent = Tenant

AgentCall's core abstraction is the agent. Everything — numbers, webhooks, usage, API keys — is scoped to an agent. In a multi-tenant SaaS, each agent maps to one of your tenants.

This means you don't need to build tenant isolation yourself. AgentCall enforces it at every layer: API requests are scoped by API key, webhooks are delivered per-agent, and usage is tracked per-agent. Your application just needs to map tenant IDs to agent API keys.

Provision on Tenant Signup

import AgentCall from 'agentcall';

// Each tenant gets their own AgentCall agent (API key)
// Store the API key alongside the tenant in your database

async function onboardTenant(tenantId: string, agentApiKey: string) {
  const client = new AgentCall({ apiKey: agentApiKey });

  // Provision a local number for the tenant
  const number = await client.numbers.provision({
    country: 'US',
    type: 'local',
    label: `tenant-${tenantId}`,
  });

  // Set up webhooks to route events to your app
  await client.webhooks.create({
    url: `https://my-saas.com/api/tenants/${tenantId}/phone-events`,
    events: ['sms.received', 'sms.sent', 'call.completed'],
  });

  // Save the number to your tenant record
  await db.tenant.update({
    where: { id: tenantId },
    data: { phoneNumber: number.number, phoneNumberId: number.id },
  });

  return number;
}

Send SMS on Behalf of a Tenant

async function sendTenantSMS(
  tenantId: string,
  to: string,
  message: string
) {
  const tenant = await db.tenant.findUnique({
    where: { id: tenantId },
  });

  const client = new AgentCall({ apiKey: tenant.agentApiKey });

  const sms = await client.sms.send({
    from: tenant.phoneNumberId,
    to,
    body: message,
  });

  return sms;
}

Handle Inbound Messages per Tenant

// POST https://my-saas.com/api/tenants/:tenantId/phone-events
app.post('/api/tenants/:tenantId/phone-events', async (req, res) => {
  const { tenantId } = req.params;
  const { event, data } = req.body;

  if (event === 'sms.received') {
    // Route to the correct tenant's inbox
    await db.message.create({
      data: {
        tenantId,
        from: data.from,
        body: data.body,
        direction: 'inbound',
      },
    });

    // Notify the tenant's users in real-time
    await pusher.trigger(`tenant-${tenantId}`, 'new-message', data);
  }

  res.json({ received: true });
});

Per-Tenant Usage and Billing

AgentCall tracks usage per-agent automatically. Each agent has its own usage dashboard showing SMS count, voice minutes, and costs. If you need to bill your tenants for phone usage, you can query per-agent usage via the API:

// Get this month's usage for a specific tenant
const usage = await client.usage.get({ period: '2026-02' });

// usage = {
//   sms: { sent: 142, received: 89, cost: 3.47 },
//   voice: { minutes: 23, cost: 0.81 },
//   total: 4.28
// }
//
// Bill this to the tenant via your own billing system

How This Compares to Building on Twilio Directly

Many SaaS products integrate Twilio directly. It works, but you end up building a significant amount of infrastructure:

  • Twilio: One account for your entire SaaS. You manage a number-to-tenant mapping table, build webhook routing logic, track per-tenant usage manually, and handle number lifecycle yourself. Expect 2-4 weeks of engineering.
  • AgentCall: One agent per tenant. Isolation, routing, and usage tracking are built in. Provision a number and set a webhook — done. Expect 1-2 days of integration.

Use Cases

CRM with SMS

Give each sales team their own phone number. Reps send texts from the CRM, replies come back to the team's inbox. Each team's messages are isolated and tracked.

Helpdesk with Phone Support

Each customer support team gets a dedicated number. Customers call or text for help. Calls are recorded for quality assurance. Usage is tracked per-team for internal billing.

Marketing Platform with SMS Campaigns

Each business using your marketing platform gets their own number for SMS campaigns. Replies route back to the business. Opt-outs are handled per-number. Usage is metered for billing.


FAQ

How many tenants can I support?

There's no limit on the number of agents (tenants) on the Pro plan. Each agent can have multiple phone numbers. Scale from 10 to 10,000 tenants without architectural changes.

Can tenants have multiple phone numbers?

Yes. Each agent (tenant) can provision as many numbers as needed. A tenant might want a local number for each region, a toll-free number for general inquiries, and a SIM number for verification.

How do I handle tenant offboarding?

When a tenant leaves your platform, release their phone numbers via the API. The numbers are deprovisioned and stop incurring charges immediately. Webhook endpoints for that agent stop receiving events.

Ready to get started?

Give your AI agents their own phone numbers in minutes.

Start Building