Expertise technical

Webhook de statut de livraison SMS qui ne se déclenche pas : guide de debug

Webhook statut livraison sms ne fonctionne pas : causes réelles, méthode de diagnostic et solutions concrètes pour le marché marocain.

sms marocapi smsotp maroc
Webhook de statut de livraison SMS qui ne se déclenche pas : guide de debug

Vous avez développé une application [Laravel](/fr/blog/sms-laravel-maroc/) ou Node.js qui déclenche l'envoi de SMS. L'envoi fonctionne parfaitement, l'API renvoie un succès (HTTP `200`). Vous attendez maintenant le callback (le webhook) de statut de livraison (DLR) pour mettre à jour votre base de données et indiquer à l'utilisateur que le SMS a bien été reçu.

Mais rien n'arrive. Votre endpoint reste silencieux, vos tables ne se mettent pas à jour. C'est un problème de configuration classique dans les architectures événementielles. Voici comment debugger un webhook DLR (Delivery Report) qui ne se déclenche pas.

Comment fonctionne un webhook DLR

Lorsque vous envoyez un [SMS via une API](/fr/api/), l'opération est asynchrone. L'API prend le message, vous donne un `message_id`, puis le transmet aux opérateurs (Maroc Telecom, inwi, Orange). C'est seulement lorsque le téléphone cible confirme la réception que l'opérateur notifie la passerelle, qui à son tour envoie une requête HTTP POST vers l'URL que vous lui avez fournie (votre Webhook). Si vous ne recevez rien, la rupture de communication peut se situer à trois niveaux.

Les 5 erreurs de configuration les plus fréquentes

### 1. Votre URL n'est pas publiquement accessible Si vous développez en local (`http://localhost:8000/api/sms/webhook`), le serveur de la passerelle SMS ne peut pas y accéder. Vous devez utiliser un outil comme Ngrok pour exposer temporairement votre port local sur internet. ### 2. Le Firewall bloque les IPs du fournisseur Si votre application est en production, assurez-vous que le pare-feu de votre serveur (ou Cloudflare) ne bloque pas les requêtes entrantes (POST) provenant des adresses IP du fournisseur SMS. Vérifiez vos logs WAF (Web Application Firewall) pour détecter d'éventuels rejets `403 Forbidden`. ### 3. Protection CSRF activée sur l'endpoint C'est l'erreur numéro 1 avec Laravel. Par défaut, Laravel protège toutes les requêtes POST avec un token CSRF (Cross-Site Request Forgery). Puisque le webhook du fournisseur SMS n'a pas ce token, Laravel rejette la requête avec une erreur `419 Page Expired`. *Solution :* Ajoutez l'URL de votre webhook dans les exceptions du middleware `VerifyCsrfToken` (ou placez l'endpoint dans `routes/api.php` plutôt que `routes/web.php`). ### 4. Timeout trop court ou script bloquant Si votre webhook prend trop de temps à répondre parce qu'il effectue des requêtes complexes en base de données ou appelle d'autres services externes, le fournisseur SMS peut considérer que l'appel a échoué (Timeout) après 3 ou 5 secondes. Votre webhook doit **toujours retourner un code HTTP 200 le plus vite possible**, avant même de traiter l'information. L'idéal est de placer le payload reçu dans une file d'attente (Queue) et de répondre immédiatement. ### 5. L'URL est mal configurée dans la requête Assurez-vous que l'URL du webhook est bien renseignée, soit au niveau global dans le dashboard de votre fournisseur, soit dynamiquement dans le payload de la requête POST d'envoi de SMS (souvent via un paramètre `callback_url` ou `notify_url`).

Tester son endpoint avec ngrok ou webhook.site

Pour isoler le problème, la méthode la plus rapide est d'utiliser [webhook.site](https://webhook.site). 1. Générez une URL temporaire sur webhook.site. 2. Configurez cette URL comme webhook de réception chez votre fournisseur SMS. 3. Envoyez un SMS test. 4. Si vous recevez le payload sur webhook.site, le fournisseur fait bien son travail : le problème vient de votre code, de votre pare-feu ou de votre routage. 5. Si rien n'arrive sur webhook.site, le problème vient de la configuration côté fournisseur (URL non renseignée, webhooks désactivés sur le compte, ou SMS jamais remis à l'opérateur).

Stratégie de retry et de fallback en polling

Même avec une configuration parfaite, un webhook peut échouer (coupure réseau, redémarrage de votre serveur). Vérifiez la *Retry Policy* de votre fournisseur : combien de fois le webhook sera-t-il renvoyé en cas d'erreur `500` ? Pour les applications critiques (banque, OTP transactionnel), ne comptez pas uniquement sur les webhooks. Implémentez un **mécanisme de fallback en polling** (interrogation régulière) : si au bout de 5 minutes vous n'avez toujours pas reçu de statut pour un `message_id` en `Pending`, déclenchez un *Cron Job* (tâche planifiée) qui va interroger manuellement l'API (ex: `GET /v1/messages/{message_id}`) pour récupérer le statut final avec certitude. ```php // Exemple de code fonctionnel et asynchrone (Laravel minimal) Route::post('/api/webhooks/sms', function (Request $request) { // 1. On stocke le statut dans une file d'attente pour traitement asynchrone ProcessSmsDeliveryReport::dispatch($request->all()); // 2. On répond TOUT DE SUITE avec un code 200 pour éviter le timeout return response()->json(['status' => 'received'], 200); }); ```

💡 Pourquoi choisir EnvoiSMS pour votre entreprise ?

Délivrabilité Critique

Moins de 4 secondes pour vos OTP via des canaux directs opérateurs IAM, Inwi et Orange Maroc.

💰

Optimisation du Budget

WhatsApp Business API à 0,13 MAD seulement par session. Le meilleur ROI conversationnel.

🛡️

Données Souveraines (CNDP)

Hébergement conforme aux réglementations de protection des données personnelles locales.