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} renvoie 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 | 30 |
| Growth | 360 | 90 |
| Scale | 720 | 180 |
| Enterprise | Illimité | Illimité |
C'est le compartiment de l'endpoint qui vous bloque
Chaque appel à un endpoint de paiements compte dans le compartiment 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 Pay as you go et
Growth. Interrogez une file de paiements avec un seul minuteur, pas un minuteur par paiement.
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é, qui a la même valeur que le budget
du compte, et ip pour un appel fait sans clé.
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.xxxxxxxxxxxxxxxx…"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.xxxxxxxxxxxxxxxx…"
curl -X POST https://api.wajub.com/events/evt_aio5DpN577tNU2vOxdmuZGhT/resend \
-H "Authorization: sk.xxxxxxxxxxxxxxxx…"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 |
Le renvoi part vers chaque endpoint actif abonné à ce type qui n'a pas encore accepté l'événement,
chacun recevant sa tentative suivante. Un endpoint qui l'a déjà accepté ne le reçoit pas une
seconde fois : sur un compte avec deux endpoints, celui qui fonctionne ne reçoit pas de doublon.
Quand tous l'ont accepté, l'appel répond quand même 202 et n'envoie rien.
Le journal ne contient que ce que reçoit un endpoint
Les entrées de la chronologie du checkout enregistrées à côté des événements (transaction.*,
payment.attempt_refused, payment.checkout_page_opened, payment.redirected_to_callback) ne
sont jamais livrées : GET /events ne les liste donc pas et répond 404 pour l'une d'elles
demandée par son id, en lecture comme en renvoi. Elles restent visibles dans
Événements dans Konsole.
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. Cette étape est obligatoire. Un événement peut vous parvenir jusqu'à une heure en retard pendant que Wajub le reconstruit, et aucun n'est envoyé tant que Wajub restreint vos webhooks (Nouvelles tentatives) : sans cette tâche, un tel paiement reste ouvert chez vous pour de bon.
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.