WABridges
Platforms and multi-tenant

One webhook.
Many tenants. Never crossed.

A single endpoint can serve every bridge in your fleet. The trick is customer_ref: every inbound message arrives tagged with the tenant it belongs to, so you route to the right bot, and guarantee one tenant can never read or reply on another's number.

In a multi-tenant system, the scariest bug isn't downtime: it's a message from one customer's bridge landing in another customer's inbox. Tenant isolation is the property you can't afford to get wrong, and in a shared WhatsApp webhook it comes down to one discipline: trust the customer_ref, and key everything off it.

WABridges tags every inbound event with the customer_ref you set when you provisioned the bridge. That single field is your routing key. One endpoint receives the whole fleet's traffic; you look up the tenant by customer_ref, run only that tenant's logic, and send replies only on that tenant's bridge. Get the lookup and the scoping right and the streams physically cannot cross, even though every message flows through the same handler.

Four steps. One loop.

We keep the number online and hand you every event. You write the part in the middle.

1
Point every bridge at one webhook

When you provision each bridge, set the same webhook_url for all of them. One endpoint serves the entire fleet, there's no per-tenant routing infrastructure to stand up.

2
Read customer_ref as the routing key

Every inbound payload includes the customer_ref you assigned at provisioning time. That's the tenant the message belongs to. Treat it as the first thing you read and the only thing you route on.

3
Scope every query and reply to that tenant

Look up the tenant by customer_ref, then load context, run bot logic, and write data scoped to that tenant id. When you reply, send on that tenant's bridge only: never a bridge id from anywhere but the resolved tenant.

Reject anything you can't resolve

If a customer_ref doesn't map to a known active tenant, drop the message and log it, don't fall back to a default. An unrecognized ref is a signal something's wrong, not an edge case to paper over.

The same three calls. Different jobs.

Every loop below is the one above with your own logic in the middle.

๐Ÿšฆ The routing key
  • customer_ref on every inbound event
  • Set once at provisioning time
  • First field you read, only field you route on
  • Maps 1:1 to a tenant id
๐Ÿงฑ Strict isolation
  • Scope every query by tenant id
  • Reply only on the resolved bridge
  • No shared mutable state across tenants
  • Never a default fallback tenant
๐Ÿ” Fail loud
  • Unknown customer_ref โ†’ drop + log
  • Alert on refs with no tenant
  • Reject inactive or suspended tenants
  • Treat surprises as bugs, not noise
๐Ÿงช Prove it
  • Test cross-tenant leakage explicitly
  • Assert replies go to the right bridge
  • Fuzz with unknown refs
  • One handler, many bridges, zero crossover

Paste into Claude, ChatGPT, or any AI assistant

Copy this prompt, paste it into any AI assistant, get working code in your language.

prompt
I run many WhatsApp bridges on WABridges, all pointed at one shared
webhook. Every inbound event carries a customer_ref that identifies which
tenant the message belongs to. I need bulletproof tenant isolation.

My stack: [Node.js / Express + Postgres, update this to yours]
My setup:
- WA_API_KEY: my WABridges API key
- A "tenants" table keyed by the same id I use as customer_ref
- Each tenant row stores its own bridge id

I need a single POST /webhook handler that:

1. Reads customer_ref from the payload and looks up the tenant. If there's
   no active tenant for that ref, drop the message, log a warning, and
   return 200: never fall back to a default tenant.

2. Runs runBot(tenant, message) scoped entirely to that tenant, every DB
   query filtered by the tenant id, no shared mutable state between
   requests.

3. Sends any reply ONLY on that tenant's bridge id (the one from the
   resolved tenant row), never a bridge id taken from the request.

Please read the WABridges API docs before writing any code:
https://wabridges.com/llms-full.txt

Make isolation the central concern. Add comments where a careless change
could cross tenants, and include a couple of unit tests that prove a
message tagged for tenant A can never trigger a send on tenant B's bridge.

One number, one price, no approval queue.

What you get on the WhatsApp side, whatever you build on yours.

One webhook endpoint serves your entire fleet, no per-tenant routing infra
customer_ref on every inbound event is your single, reliable routing key
Scope queries and replies by tenant id so the streams physically can't cross
Unknown refs fail loud instead of leaking into a default tenant
Testable isolation: assert tenant A can never send on tenant B's bridge
Flat $5/month per bridge, however many tenants share the handler