Webhooks ou polling
Pourquoi les webhooks l'emportent, quand lire l'API à la place, et ce que cela coûte.
Un paiement Mobile Money n'est pas terminé quand votre requête répond. Le payeur doit encore ouvrir l'invite USSD et saisir son code PIN, ce qui prend de quatre secondes à quatre minutes. Il n'existe donc que trois moyens de savoir comment il s'est terminé.
| Moyen | Mécanisme | Latence | Ce que cela coûte |
|---|---|---|---|
| Webhook | Wajub envoie un POST à votre URL | Moins d'une seconde | Un endpoint HTTPS public |
| Lire un paiement | GET /payments/{id} | Votre intervalle de polling | Du budget de limite de requêtes |
| Lire le journal des événements | GET /events | À chaque exécution | Une requête par page |
Pour livrer la commande, la réponse, ce sont les webhooks. Les deux autres existent pour les cas que les webhooks ne couvrent vraiment pas, et cette page vous aide à les distinguer.
Utilisez chacun pour ce qu'il fait bien
| Situation | À utiliser |
|---|---|
| Livrer la commande, créditer le portefeuille, envoyer le reçu | Webhook, toujours |
| Le payeur vient de revenir sur votre page de retour | Une lecture de GET /payments/{id} |
| Un script, un cron, un outil de back-office sans URL publique | Polling, avec une échéance |
| Votre endpoint a été indisponible une heure et vous devez combler le trou | GET /events, puis rejouer |
| Un tableau de bord qui affiche le statut en direct à une personne | Webhook vers votre propre canal push |
Le polling n'est pas une alternative plus légère aux webhooks. Il est plus lent, il consomme du budget de requêtes, et il ne voit rien de ce qui s'est passé pendant que votre processus ne tournait pas. C'est un complément.
Ce que le polling vous coûte réellement
GET /payments/{id} est relu en base de données à chaque appel, un poll vous donne donc toujours le
statut actuel. Il est aussi compté deux fois : une fois sur le budget global par minute de votre
compte, et une fois sur le compartiment de l'endpoint payments, partagé avec la création de
paiements.
| Plan | Budget du compte, par minute | Compartiment payments, par minute |
|---|---|---|
| Pay as you go | 120 | 60 |
| Growth | 360 | 180 |
| Scale | 720 | 30 |
| Enterprise | Illimité | 30 |
C'est le compartiment de l'endpoint qui vous bloque
Le compartiment payments compte chaque requête dont le chemin contient payments, création
comprise. Une boucle qui interroge un paiement toutes les cinq secondes en consomme 12 par minute,
et dix paiements simultanés en consomment 120, ce qui dépasse déjà le plafond sur tous les plans.
Interrogez une file de paiements avec un seul minuteur, pas un minuteur par paiement. L'ordre
inattendu des deux dernières lignes est expliqué dans Plafonds et quotas.
Au-delà du plafond, vous recevez un 429 avec un en-tête Retry-After en secondes, et la même
valeur dans le corps.
type vous indique quel plafond vous avez atteint : team pour le budget du compte, endpoint
pour le compartiment ci-dessus, api_key pour la limite par clé, et ip.
Faire du polling correctement
Quatre règles font la différence entre un polling utile et un polling qui vous fait atteindre la limite de requêtes.
| Règle | Pourquoi |
|---|---|
| Arrêtez-vous à un statut terminal | succeeded, failed, cancelled et expired sont définitifs. pending, processing et partial ne le sont pas |
| Donnez une échéance à la boucle | Deux minutes suffisent pour le Mobile Money. Au-delà, laissez le webhook terminer le travail et indiquez au client que vous confirmerez par e-mail |
| Appliquez une attente progressive | Commencez à deux secondes et augmentez l'intervalle. Un paiement qui n'a pas bougé en trente secondes ne bougera pas dans les deux suivantes |
| Ne relisez jamais ce qu'on vous a déjà transmis | Une livraison payment.succeeded contient déjà le paiement final. Le relire double votre trafic pour rien |
# One read. The status is in .transaction.status
curl https://api.wajub.com/payments/trx_CSUGajfv9xh0XQ5wu2lx \
-H "Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…"Les quatre SDKs déballent l'enveloppe de la réponse : retrieve vous renvoie directement le
paiement plutôt que le conteneur { code, status, message, transaction } que vous voyez avec cURL.
Rattraper le retard après une panne
Si votre endpoint était injoignable, les événements existent toujours. GET /events liste tout ce
qui a été enregistré pour votre compte dans l'environnement courant, du plus récent au plus ancien,
et POST /events/{id}/resend en renvoie un par le circuit de livraison normal, signé comme
d'habitude.
curl "https://api.wajub.com/events?type=payment.succeeded&per_page=100" \
-H "Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…"
curl -X POST https://api.wajub.com/events/evt_aio5DpN577tNU2vOxdmuZGhT/resend \
-H "Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…"Trois détails déterminent si cela fonctionne.
| Détail | Ce que cela signifie |
|---|---|
Les filtres sont per_page, page et type | Il n'y a pas de plage de dates. Remontez les pages jusqu'à atteindre des horodatages assez anciens |
| La pagination se fait par numéro de page | meta contient current_page, last_page, per_page et total |
| Sandbox et live sont séparés | L'environnement dépend de la clé utilisée, pas d'un paramètre |
Renvoyer un événement n'est pas sans conséquence : l'événement part vers tous les endpoints actifs abonnés à ce type, pas seulement vers celui qui l'a manqué. Sur un compte avec deux endpoints, celui qui fonctionne reçoit un doublon, une raison de plus pour que le handler soit idempotent.
Les événements `transaction.*` ne peuvent pas être renvoyés
Il s'agit de télémétrie interne du checkout, jamais livrée aux marchands. Une demande de renvoi
répond 422 Internal events cannot be resent.
La page de retour n'est pas une confirmation
Quand un payeur revient sur votre URL callback, vous savez seulement qu'un navigateur a chargé une
URL. Le paiement a pu réussir, échouer, ou attendre encore un code PIN. N'importe qui peut aussi
ouvrir cette URL s'il la devine.
Ne livrez jamais sur la redirection
Lisez le paiement côté serveur avant d'afficher une page de succès, et livrez la commande sur le webhook. Une page de retour qui expédie la commande est une page de retour qui expédie des commandes gratuites à quiconque la charge deux fois.
Le schéma qui fonctionne en production repose sur trois couches, et chacune couvre l'angle mort de la précédente.
- 1
Le webhook livre la commande
Il arrive, que le client revienne ou non, et c'est le seul des trois dont l'arrivée est garantie.
- 2
Une lecture côté serveur affiche la page de retour
Un seul
GET /payments/{id}vous indique laquelle des trois pages afficher : réussi, toujours en attente, ou échoué. Pas de boucle. - 3
Une tâche quotidienne fait le rapprochement
Listez les paiements que votre base de données considère encore comme ouverts, lisez chacun d'eux, et comblez l'écart. Cela rattrape l'événement rare qui n'a jamais été livré ni rejoué.
Pages associées
- Recevoir un webhookUn événement signé sur votre ordinateur, sans rien déployer.
- Nouvelles tentatives et ordreCe qui se passe quand c'est votre endpoint qui est en panne.
- Plafonds et quotasTous les plafonds appliqués par l'API, et l'erreur que chacun renvoie.
- MonitoringLes signaux qui méritent une alerte, et d'où vient chacun.