Aller au contenu

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

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.

  1. 01

    Ouvrez les notifications

    Dans le Business Portal, allez dans Configurations → Clients → Notifications.

  2. 02

    Ajoutez votre URL HTTPS

    Enregistrez l’endpoint HTTPS public de vos serveurs qui recevra les événements.

  3. 03

    Délimitez l’entrée

    Choisissez un pays, ou All, et le compte auquel les notifications se rattachent.

  4. 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
webhook.js
// 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

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.

Branchez votre premier webhook

Configurez un endpoint Stage, déclenchez un encaissement de test et vérifiez la signature de bout en bout.

Comment pouvons-nous vous aider ?

Téléchargez votre exemplaire

Laissez vos coordonnées et recevez l’édition complète immédiatement.