Problem (Why)
WhatsApp is a primary messaging channel in many markets, but pushi cannot deliver to it today. Teams wanting WhatsApp notifications must integrate Twilio's WhatsApp API themselves, re-implementing the subscription and routing pushi already provides. A first-class WhatsApp adapter—reusing the Twilio integration introduced for SMS—lets pushi apps reach WhatsApp recipients with the same subscribe/publish model as every other channel.
Description (What)
Introduce a WhatsAppHandler adapter that delivers pushi events to WhatsApp through Twilio's WhatsApp Messages API, with a WhatsApp subscription model, REST controller and API client mirroring the other adapters. Destination WhatsApp numbers are stored per subscription and overridable per published event. It reuses the Twilio credential configuration from the SMS adapter, adding a WhatsApp-specific from-number.
Implementation (How)
- Add
WhatsAppHandler(handler.Handler) in src/pushi/base/whatsapp.py implementing load, add, remove, subscribe, unsubscribe, send(app_id, event, json_d, invalid={}) and a direct send_to_numbers(...); reuse the Twilio backend, formatting recipients/sender as whatsapp:+<number>.
- Send via the Twilio Messages REST API using
netius.clients.HTTPClient with basic auth, honoring per-event number overrides over the stored subscription number.
- Reuse the Twilio config from the SMS work and add a WhatsApp from-number field (
twilio_whatsapp_from) on the App model in src/pushi/app/models/app.py, with an env-var fallback via appier.conf.
- Add the
WhatsApp subscription model in src/pushi/app/models/whatsapp.py with fields (number, event) and handler-sync lifecycle hooks.
- API: add a
WhatsAppController in src/pushi/app/controllers/whatsapp.py exposing GET/POST /whatsapps and DELETE /whatsapps/<number>.
- API client: add
WhatsAppAPI in src/pushi/api/whatsapp.py with create_whatsapp / delete_whatsapp / subscribe_whatsapp / unsubscribe_whatsapp.
- Register the handler in
State.load_handlers() in src/pushi/base/state.py and export new symbols from the four __init__.py files.
- Add tests in
src/pushi/test/whatsapp.py (WhatsApp address formatting, Twilio payload/auth, per-event override, subscription sync).
- Note the dependency/ordering on the SMS/Twilio issue so the shared backend lands first.
- Update
README.md, add an examples/whatsapp/ example, and add a [Unreleased] CHANGELOG entry.
Problem (Why)
WhatsApp is a primary messaging channel in many markets, but pushi cannot deliver to it today. Teams wanting WhatsApp notifications must integrate Twilio's WhatsApp API themselves, re-implementing the subscription and routing pushi already provides. A first-class WhatsApp adapter—reusing the Twilio integration introduced for SMS—lets pushi apps reach WhatsApp recipients with the same subscribe/publish model as every other channel.
Description (What)
Introduce a
WhatsAppHandleradapter that delivers pushi events to WhatsApp through Twilio's WhatsApp Messages API, with aWhatsAppsubscription model, REST controller and API client mirroring the other adapters. Destination WhatsApp numbers are stored per subscription and overridable per published event. It reuses the Twilio credential configuration from the SMS adapter, adding a WhatsApp-specific from-number.Implementation (How)
WhatsAppHandler(handler.Handler)insrc/pushi/base/whatsapp.pyimplementingload,add,remove,subscribe,unsubscribe,send(app_id, event, json_d, invalid={})and a directsend_to_numbers(...); reuse the Twilio backend, formatting recipients/sender aswhatsapp:+<number>.netius.clients.HTTPClientwith basic auth, honoring per-event number overrides over the stored subscription number.twilio_whatsapp_from) on the App model insrc/pushi/app/models/app.py, with an env-var fallback viaappier.conf.WhatsAppsubscription model insrc/pushi/app/models/whatsapp.pywith fields (number,event) and handler-sync lifecycle hooks.WhatsAppControllerinsrc/pushi/app/controllers/whatsapp.pyexposingGET/POST /whatsappsandDELETE /whatsapps/<number>.WhatsAppAPIinsrc/pushi/api/whatsapp.pywithcreate_whatsapp/delete_whatsapp/subscribe_whatsapp/unsubscribe_whatsapp.State.load_handlers()insrc/pushi/base/state.pyand export new symbols from the four__init__.pyfiles.src/pushi/test/whatsapp.py(WhatsApp address formatting, Twilio payload/auth, per-event override, subscription sync).README.md, add anexamples/whatsapp/example, and add a[Unreleased]CHANGELOG entry.