WhatsApp for the Owner and for a customer
There is one WhatsApp implementation and both audiences use it. Numbers, credentials, conversations, people, memory and suppressions are per workspace and never shared. The only real differences are commercial — a customer's use is bounded by their plan's allowances, the Owner's is not — and the path a request takes to reach the same code.
One body, two doors#
The Owner's session and a customer's session call different API paths and arrive at the same module. A customer reaches /api/customer/ui/whatsapp/..., the Owner reaches /api/owner/whatsapp/..., and both routers are built by one registration function over the same functions in whatsapp.py — status, connect, verify, disconnect, conversations, send, templates, automation, media, schedule, logs, usage and the QR steps. The only thing that differs is where the workspace id comes from. The webhook is a third door: public, authenticated by Meta's signature rather than by a session, and shared by every workspace.
The Owner router exists because JBRH runs WhatsApp lines for its own products and the screen had only ever been mounted behind the customer prefix — so the Owner console answered as though WhatsApp lived in somebody else's workspace and refused every request it made. Same work underneath; only the session differs. The Assistant's WhatsApp and Owner outreach's WhatsApp go through this same service rather than a second one.
That is a rule about how features are built here, not an accident. A second implementation for the other audience is how two audiences drift apart, and the parity suite exists precisely to stop a capability appearing on one side only. The reasoning is set out in One implementation, two audiences.
What is separate#
| Thing | Shared? | Why |
|---|---|---|
| The code that receives and sends | Shared | One module; two session routers and one public webhook into it |
| The business number and credentials | Separate | Configured per workspace and encrypted at rest |
| The connection mode | Separate | Each workspace is Official API or QR-linked on its own number, with its own hourly cap |
| Conversations and messages | Separate | Every row carries a workspace and is filtered three times |
| People, companies and memory | Separate | The relationship graph belongs to one workspace |
| Suppressions and blocks | Separate | A stop in one workspace is not a stop in another |
| Autonomy rules | Separate | Each workspace decides what Connect may do on its own channel |
| Plan allowances | Customer only | The Owner has no plan and no gates |
Why a test on one audience proves little about the other#
A WhatsApp change that works for the Owner can still fail for a customer, and it usually fails in one of two ways. Either the path the customer's browser asks for is not one tenantAdapt knows, in which case the request becomes a blocked call and answers 403; or the path is not on the customer_safe allowlist, in which case the middleware refuses it. Both look like the feature is broken and neither is a problem with the feature.
The reverse also happens. A customer workspace hits allowance and plan logic the Owner never touches, so a metered send that holds for a tenant goes straight out for the Owner. A test run only as the Owner would never see it.
The practical rule: when somebody reports that WhatsApp behaves oddly on one account, the first question is which audience, and the answer is worth checking on both before anything else is investigated.
What is deliberately Owner-only#
Nothing on the WhatsApp channel. The Owner-only surfaces in Connect are about running the platform rather than using it — verifying customer payments, JBRH's own pricing, and the website enquiry intake. Every messaging capability is available to both audiences over the same implementation.
If you find something on this channel that one audience can reach and the other cannot, that is a gap rather than a design, and it is the kind of thing the parity suite is written to fail on. The Owner router carrying the same twelve operations as the customer one is that rule applied: adding a capability to one and not the other is the failure it prevents.
One caveat applies to both audiences equally. No WhatsApp number is connected in production on either side, so neither the Owner nor a customer has sent a WhatsApp message to Meta from the live build — see What WhatsApp cannot do here.
Questions#
Can the Owner read a customer's WhatsApp conversations?
Not through the application. Conversations are workspace-scoped and filtered by the kernel and by row-level security, and an Owner session is a session in the Owner's own workspace.
Do both audiences see the same screens?
The same screens over the same data services, with the customer surface renaming a few things — a customer's people are the Owner's relationships, for instance. The WhatsApp screen itself is the same screen.
If I test a WhatsApp change on the Owner account, am I done?
No. Check it as a customer too. The two paths differ, and the differences are the usual cause of a change that works on one account and not the other.