Security
What WhatsApp Sales and Payment Automation can read and write, what it stores, and what leaves your instance.
Webhook signatures
Every delivery carries X-Hub-Signature-256: HMAC-SHA256 over the request body with your App Secret.
It is verified over the raw request bytes. Hashing a re-serialised copy of the parsed JSON would produce a different digest and reject every genuine delivery, which is the bug this note exists to say we did not write.
The signature and the verify token are both compared in constant time.
Require signed webhooks is on by default and should stay on. An unsigned endpoint is a public endpoint anybody can post fabricated customer messages to — including messages that trigger an opt-in, a lead, or a handover.
Credentials are separated from configuration
The access token, App Secret and verify token are on fields restricted to a WhatsApp Administrator, enforced by field-level groups rather than by hiding a menu.
Configuring rules and holding the credential are different jobs. A manager who writes the auto-replies does not need the token that can send as your business.
No credential is ever logged, placed in a URL, or stored in an error message.
The three groups
| Group | Can |
|---|---|
| WhatsApp Agent | Read and reply to conversations, take one over |
| WhatsApp Manager | The above, plus rules, templates and office hours |
| WhatsApp Administrator | Credentials and webhook configuration |
Five rules enforced in code, not settings
A setting that can turn a safety rule off is a setting somebody turns off. These are not settings.
An action that reads records will not run for an unknown number. Order status, invoices, payment links and statements all need to know whose records to show. A number matching no contact would mean guessing, and the wrong guess shows one customer another customer's business. Only reply, menu, lead, handover, opt-out, opt-in and do-nothing run for a stranger.
A statement request never attaches the statement. A phone-number match is not authentication, and a statement shows a customer's entire position with you. The rule raises a task; a person confirms identity.
A conversation a human owns is never answered automatically.
An opt-out is permanent. The check lives in the single function that queues a message, so no rule, button, action or agent can route around it. Opting back in must come from the customer.
A quotation is a draft with no lines. Pricing a sentence automatically would be guessing on the customer's behalf.
Nothing is sent from inside the webhook
Every outbound message is a record first and a request second. The webhook stores and acknowledges; a scheduled action sends.
Meta retries an unacknowledged webhook for 36 hours, so sending inline would replay every reply on every retry — a customer receiving the same message a dozen times, and a number reported for spam.
Inbound is idempotent
Messages are deduplicated on Meta's own wamid, so a retried delivery is stored once and answered once.
It never starts a conversation
WhatsApp is the customer's channel. An unsolicited first message from a business is what gets a number blocked, and there is no feature here that could send one.
Media is stored, not interpreted
An image or document is recorded verbatim with its type and handed to a person. Nothing parses it, renders it, or acts on its contents.
Multi-company
Record rules on every model: accounts, conversations, messages, rules and templates.
Model namespace
This module declares its models under wa.sales., separate from technovision_whatsapp_core's whatsapp..
That separation exists because of a real defect: an earlier version declared whatsapp.account, whatsapp.message and whatsapp.template independently, which Odoo silently merged — the newer definition won and Core's fields vanished with no error. A customer who owned Core and then bought this would have had the first module quietly stop working. There is now a check that fails the build if it recurs.
What has not been verified
No call has ever been made to Meta from this module. There is no app, phone number id, system-user token or app secret on the development account.
Verified over real HTTP against Meta's documented payload shapes: the verification handshake, signature validation, wamid idempotency, status transitions, the store-then-acknowledge split, every send refusal. Verified in shape only: the outbound request body. Unverified: acceptance by Meta, and template synchronisation in both endpoint and response shape.
Reporting a vulnerability
info@technovision.dev. We acknowledge within two business days.