Twilio Messaging With Per-Company Keys

Why each company in a multi-tenant app sends text messages with its own Twilio credentials, how webhooks find the right tenant, and how consent is enforced.

By Joshua Hayes October 14, 2026

RE/AMP lets each company send text messages to its own contacts. I built it so every company uses its own Twilio credentials, not a shared account.

Why separate keys

A shared account makes every company’s messages the platform’s responsibility. With separate credentials, responsibility for what a company sends stays with that company, and one company’s messaging is isolated from another’s.

It also keeps the data separate. One company’s numbers, history, and usage never sit under another company’s key.

How webhooks find the right company

Twilio sends events back to the application when a message is delivered, fails, or arrives. The application has to know which company an event belongs to before it can do anything with it.

I pass the company’s ID in the webhook’s query parameters. The handler reads it and attaches the event to the correct tenant, so there is no need to guess from the phone number alone.

Consent

Consent is enforced per phone number for the messages sent to that number, in line with Twilio’s terms. The platform does not rely on each company to remember.

That puts the rule in code. A message to a number without consent does not go out, whatever a user clicks.

What this costs

Per-company credentials mean more setup, because each company has to bring its own account. They also mean more places where a credential can be wrong or expire, so the product needs clear errors.

I accept that cost for the separation. A shared key is easier at first and harder to unwind once many companies depend on it.

A note on trust

An ID in a query string is not proof of anything on its own. The webhook path should still verify that the request really came from Twilio before it trusts the company ID inside it.

Related

This is one of the decisions in the RE/AMP case study. For how company boundaries are enforced in the database, read Multi-Tenant Data Boundaries in PostgreSQL. The API integrations service covers this kind of build.