One door for every message
Every WhatsApp message โ inbound from customers, outbound from any agent or staff member โ passes through a single gateway. One door means one place to record, one place to enforce safety, and one place where a mistake can be stopped before it costs money or reaches the wrong person.
flowchart LR
subgraph IN["Inbound"]
META1["Meta / WhatsApp"] --> REC["Recorder
saved BEFORE anything else"]
REC --> BELL["๐ Doorbell
wakes marriageAI"]
end
subgraph OUT["Outbound โ the send door"]
MAI["marriageAI"] --> DOOR
OAI["outreachAI"] --> DOOR
STAFF["Agent Inbox (staff)"] --> DOOR
DOOR["POST /api/v1/send
internal token required"]
DOOR --> DUP{"Duplicate?"}
DUP -->|"yes"| SKIP["skipped โ
idempotent by design"]
DUP --> BAND{"Test-band
number?"}
BAND -->|"registered 8880โฆ"| SIM["๐งช diverted to simulator โ
free, never reaches Meta"]
BAND -->|"unregistered 8880โฆ"| REFUSE["๐ refused outright"]
BAND -->|"real customer"| META2["Meta / WhatsApp"]
end
classDef hi fill:#e7f6f1,stroke:#0e8a72,color:#182420
class REC,DOOR hi
Inbound is recorded before it is acknowledged; outbound is checked before it is spent.
Why "record first" matters
The inbound recorder saves every customer message before acknowledging it to Meta. If anything downstream crashes, the message is already safe โ nothing a customer says can be lost to a bad moment in another service.
Why one send door matters
- Idempotency โ the same message can't be sent twice by a retry; the gateway remembers what it has already delivered.
- A single ledger โ every outbound message is recorded in one place, with who sent it and why.
- Window rules in one place โ WhatsApp's 24-hour free-messaging window is enforced by expiry timestamp, never by cached flags that can go stale.
- Templates must name their language โ a template send without an explicit language is rejected rather than silently defaulting to English against an Urdu template.
The test band that cannot leak
Numbers starting 8880 belong to a reserved international
band that no real customer can own. Registered test numbers are diverted to
the simulator โ the full pipeline runs, nothing reaches Meta, nothing costs
anything. Unregistered band numbers are refused at the door
(this closed a real gap: one unregistered test number had previously slipped
through and been billed). Test traffic is also excluded from the daily
sending quota, so testing never eats production capacity.