Webhooks
Sachez à quel moment l’argent bouge
Des notifications en temps réel pour les encaissements, décaissements, comptes virtuels, abonnements, opérations de change, Wire In et Wire Out, chacune signée en HMAC-SHA256 pour que vous puissiez vérifier chaque requête avant d’agir.
- Signatures HMAC-SHA256
- Relances avec backoff
- Filtrés par pays et par compte
- 09:41:02.11409:41:02PayIn100 INPROGRESS20084 ms
- 09:41:05.90209:41:05PayIn200 COMPLETED20091 ms
- 09:42:18.33009:42:18PayOut100 INPROGRESS20077 ms
- 09:42:40.01809:42:40PayOut200 COMPLETED20088 ms
- 09:43:00.55109:43:00VirtualAccount200 COMPLETED20080 ms
POST https://example-merchant.com/webhooks/localpayment
x-Signature: HMAC-SHA256 3f9a1c0e…b47e2b
{ "transactionType": "PayIn", "transactionFlow": "DIRECT",
"data": { "externalId": "order_8F2K-1043",
"status": { "code": "200", "description": "COMPLETED" } } }Configuration
Configurez les notifications dans le Business Portal
Aucun code n’est nécessaire pour enregistrer un endpoint. Chaque entrée peut être limitée à un pays et à un compte.
- 01
Ouvrez les notifications
Dans le Business Portal, allez dans Configurations → Clients → Notifications.
- 02
Ajoutez votre URL HTTPS
Enregistrez l’endpoint HTTPS public de vos serveurs qui recevra les événements.
- 03
Délimitez l’entrée
Choisissez un pays, ou All, et le compte auquel les notifications se rattachent.
- 04
Ajoutez des en-têtes et testez
Ajoutez si besoin des en-têtes personnalisés pour votre passerelle, puis lancez une transaction de test sur Stage.
Payload
Une seule enveloppe pour tous les événements
Toutes les notifications partagent les mêmes champs racine : un seul handler peut donc toutes les router. Le corps est du JSON, livré avec Content-Type text/plain.
- transactionType : PayIn, PayOut, VirtualAccount, Subscription, CurrencyExchange, WireIn ou WireOut
- transactionFlow : le flux de traitement, utile pour le routage
- data : la transaction elle-même, avec externalId, internalId et statut
Événements
Ce qui vous est notifié
Encaissement par carte
- transactionType
- PayIn
- Ce qu’il vous indique
- Approuvé, finalisé, rejeté, remboursé ou rétrofacturé
Encaissement par virement ou moyen local
- transactionType
- PayIn
- Ce qu’il vous indique
- Statut final une fois que le payeur a confirmé dans son application bancaire ou son wallet
Compte virtuel
- transactionType
- VirtualAccount
- Ce qu’il vous indique
- Compte créé, puis chaque paiement reçu
Abonnement
- transactionType
- Subscription
- Ce qu’il vous indique
- Cycle de vie de l’abonnement ; chaque prélèvement arrive aussi sous forme d’événement PayIn
Décaissement
- transactionType
- PayOut
- Ce qu’il vous indique
- Changements de statut tout au long du flux de décaissement, jusqu’à la finalisation
Change
- transactionType
- CurrencyExchange
- Ce qu’il vous indique
- Résultat d’une conversion entre vos soldes
Wire In
- transactionType
- WireIn
- Ce qu’il vous indique
- Fonds crédités sur votre compte, en fiat ou en USDC/USDT
Wire Out
- transactionType
- WireOut
- Ce qu’il vous indique
- Retrait envoyé ; les Wire Out crypto incluent le hash de la transaction sur la blockchain
Les schémas complets et les codes de statut de chaque événement figurent dans la référence des webhooks sur docs.localpayment.com.
Sécurité
Vérifiez chaque signature
Chaque requête porte x-Signature: HMAC-SHA256 suivi d’un condensé hexadécimal du corps brut, calculé avec votre secret de webhook. Recalculez-le et comparez avant de vous fier au contenu du payload.
- Lisez le corps brut : c’est du JSON envoyé en Content-Type text/plain
- Retirez le préfixe « HMAC-SHA256 », puis comparez avec une fonction à temps constant
- Rejetez les écarts avec un 401 et ne journalisez jamais le payload complet
// Récepteur Express pour les webhooks Localpayment (Node.js 18+).
import crypto from 'node:crypto';
import express from 'express';
import { jobQueue } from './queue.js'; // votre propre file de tâches asynchrones
const app = express();
// Chargez le secret du webhook depuis votre gestionnaire de secrets au démarrage. Jamais en dur dans le code.
const WEBHOOK_SECRET = process.env.LP_WEBHOOK_SECRET;
if (!WEBHOOK_SECRET) throw new Error('LP_WEBHOOK_SECRET is not configured');
function hasValidSignature(rawBody, header) {
if (typeof rawBody !== 'string') return false;
// Format de l’en-tête : "x-Signature: HMAC-SHA256 <hex>". Retirez d’abord le préfixe.
const received = String(header ?? '').replace(/^HMAC-SHA256\s+/i, '').trim();
if (!/^[0-9a-f]{64}$/i.test(received)) return false;
const expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(rawBody, 'utf8').digest();
return crypto.timingSafeEqual(Buffer.from(received, 'hex'), expected);
}
// Le corps est du JSON envoyé en Content-Type text/plain : conservez le texte brut pour le HMAC.
app.post('/webhooks/localpayment', express.text({ type: '*/*', limit: '1mb' }), (req, res) => {
if (!hasValidSignature(req.body, req.get('x-signature'))) return res.sendStatus(401);
let event;
try {
event = JSON.parse(req.body);
} catch {
return res.sendStatus(400);
}
res.sendStatus(200); // accusez réception vite, avant tout traitement lourd
// Traitez de façon asynchrone. Dédupliquez sur internalId/externalId + statut
// pour qu’une livraison renvoyée ne s’applique qu’une fois. Ne journalisez jamais le payload complet.
jobQueue.enqueue(event);
});Traitement fiable
Conçu pour les relances et les réseaux réels
Accusez réception vite
Répondez 200 dès que la signature est validée, et confiez le traitement lourd à une tâche en arrière-plan.
Prévoyez les relances
Sans réponse 200, nous relançons avec un backoff exponentiel. Votre handler doit pouvoir s’exécuter plusieurs fois sans effet de bord.
Dédupliquez
Indexez le traitement sur internalId ou externalId plus le statut, pour qu’une livraison renvoyée ne s’applique qu’une fois.
Ne présumez pas de l’ordre
Comparez le statut reçu à celui que vous avez stocké avant de l’appliquer, et ne faites jamais reculer une transaction.
Confirmez avec l’API
En cas de doute, interrogez GET /api/transactions/{externalId}/status pour connaître l’état actuel d’une transaction.
Journalisez en sécurité
Journalisez types d’événement, identifiants et statuts, jamais les payloads complets, les jetons ou les données personnelles.
Opérations
Suivez chaque livraison dans le Business Portal
Les rapports de notifications montrent ce qui a été envoyé à vos endpoints : support et équipes techniques résolvent les incidents sans fouiller les logs serveur.
- Journal de livraison des notifications envoyées à vos endpoints
- Recherche de transactions et rapports d’activité détaillés
- Webhooks, liste blanche d’IP et utilisateurs gérés au même endroit
Aperçu
USD
1 284 560,00
+4,2 %
BRL
3 420 118,40
+12,8 %
MXN
8 905 332,10
+6,1 %
- Encaissement · Pixorder_8F2K-1043+ R$ 1 250,00
- Décaissement · SPEIseller_0921− MX$ 18 400,00
- Change · BRL → USDfx_3b7q250 000,00 USD
- Encaissement · Bre-Border_9A1C-2210+ COP 890 000
FAQ webhooks
Comment savoir qu’un webhook provient vraiment de Localpayment ?
Vérifiez l’en-tête x-Signature : recalculez le HMAC-SHA256 du corps brut avec votre secret de webhook et comparez les deux avec une fonction à temps constant. Vous pouvez aussi ajouter des en-têtes personnalisés à chaque entrée de notification pour votre passerelle.
À quelle fréquence les livraisons en échec sont-elles relancées ?
Les livraisons qui ne reçoivent pas de 200 sont relancées avec un backoff exponentiel. Concevez votre handler pour plusieurs tentatives et consultez l’historique de livraison dans les rapports de notifications du Business Portal.
Pourquoi le Content-Type est-il text/plain ?
Le corps est du JSON envoyé en text/plain. Lisez-le comme texte brut, vérifiez la signature sur ces octets exacts, puis parsez-le.
Puis-je envoyer différents pays vers différents endpoints ?
Oui. Chaque entrée de notification est délimitée par pays (ou All) et par compte : vous pouvez router des marchés ou des business units vers des URL distinctes.
Que doit renvoyer mon endpoint ?
Un statut 200, le plus vite possible et avant tout traitement long. Sans 200, la livraison est considérée comme échouée et relancée.
À voir aussi
Quickstart
Recevez et vérifiez votre premier webhook à l’étape 5.
Quickstart —Sandbox
Déclenchez des webhooks VirtualAccount à la demande avec le simulateur.
Sandbox —Reporting et rapprochement
Rapports du portail avec export XLS, plus des API de soldes, d’activité et de rapprochement.
Reporting et rapprochement —
Branchez votre premier webhook
Configurez un endpoint Stage, déclenchez un encaissement de test et vérifiez la signature de bout en bout.

Signatures HMAC-SHA256