Send ne se limite plus à l'e-mail : c'est la brique de messagerie multi-canal de la plateforme. Un seul service centralise 4 canaux, avec la même traçabilité (PostgreSQL = source de vérité des statuts, les fournisseurs n'assurent que la délivrabilité).
| Canal | Fournisseur | Sert à |
|---|---|---|
| Stalwart (JMAP direct) | transactionnel, marketing — voir Référence API — Send | |
| Push | Expo Push API | notifications des apps mobiles (chat, fidélité…) |
| SMS | Twilio | notifications courtes vers un numéro |
| Twilio | notifications WhatsApp Business |
Trois familles de surfaces¶
Chaque canal est joignable par les mêmes surfaces :
| Surface | Auth | Usage |
|---|---|---|
| Interne (JWT) | JWT + gating send | depuis le Hub / un module côté utilisateur |
| M2M interne | X-Internal-Secret | serveur→serveur (fidélité, RDV, chat…) |
| Publique (clé API) | X-Server-API-Key (psk_live_…) | intégration tierce du tenant |
Module / App ─┐
├─ JWT ───────────────▶ /api/send/{messages, text, push/devices}
Serveur M2M ──┼─ X-Internal-Secret ─▶ /api/send/internal/{push, text}
Intégration ──┴─ X-Server-API-Key ──▶ /api/public/send/{messages, sms, whatsapp}
Twilio ──▶ /api/send/text/webhook/twilio (accusés, signature X-Twilio-Signature)
Push (Expo)¶
Send tient un registre central des appareils : chaque app mobile enregistre son token Expo, et les modules envoient à des utilisateurs (pas à des tokens).
| Méthode | Route | Rôle |
|---|---|---|
| POST | /api/send/push/devices | Enregistrer un appareil (JWT — sujet = l'utilisateur) |
| DELETE | /api/send/push/devices/{app}/{deviceId} | Désenregistrer |
| POST | /api/send/internal/push | Envoyer (M2M) {app, subjectIds[], title, body, data?} |
Send résout les appareils des destinataires, poste sur l'Expo Push API et purge
automatiquement les tokens invalides (DeviceNotRegistered). Les credentials FCM/APNs
vivent dans le build EAS des apps, jamais côté Send.
SMS & WhatsApp (Twilio)¶
Chaque envoi crée un TextMessage tracé : queued → sent → delivered (ou
undelivered / failed), numéro au format E.164 (+336…).
| Méthode | Route | Auth |
|---|---|---|
| POST | /api/send/text/sms · /api/send/text/whatsapp | JWT |
| GET | /api/send/text · /api/send/text/{id} | JWT (historique / statut) |
| POST | /api/send/internal/text | M2M {tenantId, channel, to, body, source?} |
| POST | /api/public/send/sms · /api/public/send/whatsapp | clé API {to, body} |
curl -X POST https://send.puwapi.com/api/public/send/whatsapp \
-H "X-Server-API-Key: psk_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "to": "+33612345678", "body": "Merci pour votre visite 👋" }'
Accusés de livraison : Twilio notifie …/api/send/text/webhook/twilio à chaque
changement de statut ; Send vérifie la signature X-Twilio-Signature puis fait
progresser le statut de façon idempotente (jamais de régression d'un statut terminal).
Bon à savoir¶
- WhatsApp : hors fenêtre de 24 h d'une conversation ouverte par le client, Meta impose des templates approuvés — le corps libre est refusé. En dev, utilisez le WhatsApp Sandbox Twilio.
- Twilio non configuré : le message reste
queued(jamais soumis), sans erreur métier — pratique en dev. - Les changements de statut sont poussés au Hub en temps réel (Convex).
- La liste complète des variables et clés à générer (Expo, Twilio, secrets M2M) est
documentée côté opérateur (
send/CANAUX-NOTIFICATIONS.md).