Aller au contenu

Recevoir des webhooks en local

Des événements live transmis à localhost, signés par Wajub et sans tunnel.

wajub listen transmet les événements de votre compte à l'URL locale de votre choix, signés comme des livraisons de production, sans déployer votre handler ni ouvrir de tunnel.

Toute la configuration
wajub listen --forward-to localhost:3000/webhooks/wajub

Aucun de vos services n'est exposé : ni URL publique, ni port entrant.

Ce que vous voyez

wajub listen
$ wajub listen --forward-to localhost:3000/webhooks/wajub

Ready! Streaming sandbox events for your account.
Your webhook signing secret is whsec_test_xxxxxxxxxxxxxxxx… (^C to quit)
It stays the same between runs: set WAJUB_WEBHOOK_SECRET=whsec_test_xxxxxxxxxxxxxxxx… in your app's .env once.
Forwarding to http://localhost:3000/webhooks/wajub
subscribed — waiting for events…

6:37:35 AM  customer.created    evt_test_Example00000000000000001  → 200 http://localhost:3000/webhooks/wajub
6:37:35 AM  payment.created     evt_test_Example00000000000000002  → 200 http://localhost:3000/webhooks/wajub
6:37:36 AM  payment.processing  evt_test_Example00000000000000003  → 200 http://localhost:3000/webhooks/wajub
6:37:39 AM  payment.succeeded   evt_test_Example00000000000000004  → 200 http://localhost:3000/webhooks/wajub
6:37:39 AM  balance.updated     evt_test_Example00000000000000005  → 200 http://localhost:3000/webhooks/wajub
6:37:39 AM  fee.charged         evt_test_Example00000000000000006  → 200 http://localhost:3000/webhooks/wajub

Le nombre à droite est la réponse de votre propre endpoint. Un 500 indique donc l'échec de votre handler, pas celui de la CLI. L'exécution ci-dessus correspond à un seul wajub trigger payment.succeeded. Une commande a produit six événements, comme un véritable paiement.

C'est le moyen le plus rapide de découvrir le nombre de types silencieusement ignorés par votre handler.

La requête transmise est un véritable webhook

Chaque livraison locale est signée comme une livraison de production, avec le même corps et les mêmes en-têtes.

En-têteValeur
X-Wajub-Signaturev1= suivi du HMAC
X-Wajub-TimestampSecondes Unix, incluses dans la chaîne signée
X-Wajub-EventLe type d'événement
X-Wajub-Delivery-Idwhd_ suivi d'un UUID, identique pour chaque livraison d'un événement à cette écoute

Votre code de vérification s'exécute donc réellement en local, au lieu d'être ignoré derrière un if (process.env.NODE_ENV === 'development') qui masque un défaut jusqu'à la production.

Contenu reçu par votre endpoint
{
"id": "evt_test_Example00000000000000002",
"event": "payment.created",
"data": {
"id": "trx_test_Example0000000000001",
"amount": 5000,
"status": "pending",
"currency": "XAF",
"sandbox": true,
"amount_paid": 0,
"description": "Payment",
"customer": {
"id": "cus_test_Example00000000000000001",
"name": "CLI Trigger",
"email": "cli-trigger@example.com"
},
"created_at": "2026-09-14T04:37:34+00:00",
"updated_at": "2026-09-14T04:37:34+00:00"
},
"livemode": false,
"pending_webhooks": 0,
"api_version": "2026-10-11",
"request": {
"id": null,
"idempotency_key": "idem_Example0000000000000000000000001"
},
"created": "2026-09-14T04:37:34+00:00"
}

Comme le corps est celui de la production, un handler qui vérifie la signature sur le corps brut réussit en local exactement quand il réussira une fois déployé.

Le secret de signature reste le même à chaque wajub listen pour ce compte et cet environnement : un pour la sandbox, un pour le live. Placez-le une seule fois dans votre .env et votre handler effectue la vérification sans autre modification. Ce n'est pas le secret d'un endpoint enregistré : chaque endpoint garde le sien.

Configurer votre application avec le secret d'écoute
export WAJUB_WEBHOOK_SECRET=$(wajub listen --print-secret)
npm run dev

--print-secret affiche le secret seul puis s'arrête, ce qui le rend utilisable dans un script. Avec une clé live, ajoutez --live (wajub listen --live --print-secret) : sans lui la commande échoue, et $(…) récupère alors un secret vide.

Si votre application répond sur une adresse https:// avec un certificat auto-signé ou émis par une autorité locale, comme un site local avec un certificat auto-signé, ajoutez --insecure-tls. La vérification du certificat est ignorée uniquement pour la transmission à votre handler ; les appels de la CLI à l'API Wajub restent vérifiés. Faire pointer NODE_EXTRA_CA_CERTS vers votre autorité locale fonctionne aussi.

Options

OptionEffet
--forward-toDestination du POST. http:// est utilisé lorsque le schéma est absent
--eventsTypes séparés par des virgules, jokers acceptés (payment.*), à la place de tous les événements
--liveObligatoire avec une clé live : les événements de vrais clients arrivent sur cette machine
--print-secretAffiche le secret de signature puis s'arrête
--unsignedTransmet sans signature. Consultez l'avertissement ci-dessus
--insecure-tlsAccepte un certificat auto-signé ou d'une autorité locale sur une URL https:// de transmission
--profileCompte et environnement dont le flux est utilisé
Limiter le flux
# Only what your handler currently implements
wajub listen \
  --forward-to localhost:3000/webhooks/wajub \
  --events "payment.*,refund.succeeded"

# Watch without forwarding anywhere
wajub listen

Sans --forward-to, la commande affiche les événements sans les envoyer. Utilisez-la pour vérifier si un événement est émis avant d'accuser votre handler. Une valeur --events mal formée arrête la commande avant tout démarrage, et Wajub n'envoie que les types demandés.

À connaître

L'environnement provient de votre profil. Une clé de sandbox diffuse les événements de la sandbox. Une clé live diffuse les événements live, et seulement avec --live : les données de vrais clients arrivent alors sur votre machine. wajub doctor indique le profil utilisé. --profile le remplace pour une exécution.

Il faut une clé secrète, ou une clé restreinte avec event.read. La clé créée par wajub login a un accès complet, sauf si vous la restreignez. Une clé publique ne peut pas écouter, et une clé révoquée par wajub logout arrête un flux en cours.

Aucun endpoint enregistré n'est nécessaire. Le flux est indépendant de POST /webhooks. Même un compte sans endpoint transmet tous ses événements à wajub listen.

Il ne remplace pas vos endpoints enregistrés. Un endpoint live abonné aux mêmes événements continue de les recevoir. L'écoute ne détourne rien.

Vos écoutes apparaissent dans le Dashboard. Konsole › Webhooks liste chaque wajub listen en cours pour l'environnement actuel, avec la réponse de votre handler aux derniers événements.

Il survit à la mise en veille. Il se reconnecte tout seul, rien à faire.

Vingt à la fois. Un compte peut avoir 20 sessions wajub listen ouvertes par environnement ; la vingt et unième est refusée avec 429. Arrêter une commande avec ^C libère sa place aussitôt.

Un 503 signifie que le flux n'a pas pu être ouvert. La commande s'arrête avant de commencer. Réessayez dans un instant ; si cela persiste, transmettez au support l'identifiant de requête affiché par la CLI. Toutes les autres commandes continuent de fonctionner.

Aucune donnée n'est mise en mémoire tampon. Les événements produits lorsque la commande est arrêtée ne sont pas rejoués à son démarrage. Pour les récupérer, consultez wajub events list et renvoyez ceux qui vous intéressent.

La boucle

Deux terminaux suffisent, sans toucher à un téléphone.

Terminal 1, puis terminal 2
# 1: forward everything to your handler
wajub listen --forward-to localhost:3000/webhooks/wajub

# 2: make something happen
wajub trigger payment.succeeded
wajub trigger payment.failed --amount 2500

Écrivez le handler, enregistrez, puis déclenchez de nouveau l'événement. La boucle dure quelques secondes, ce qui est précisément son intérêt.

Que pensez-vous de ce contenu ?