Webhook
Sappi quando il denaro si muove
Notifiche in tempo reale per incassi, payout, conti virtuali, abbonamenti, cambio valuta, Wire In e Wire Out, ognuna firmata con HMAC-SHA256 così puoi verificare ogni richiesta prima di agire.
- Firme HMAC-SHA256
- Retry con backoff
- Filtrati per paese e conto
- 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" } } }Configurazione
Configura le notifiche nel Business Portal
Per registrare un endpoint non serve codice. Ogni voce può essere limitata per paese e conto.
- 01
Apri le notifiche
Nel Business Portal vai su Configurations → Clients → Notifications.
- 02
Aggiungi il tuo URL HTTPS
Registra l’endpoint HTTPS pubblico dei tuoi server che riceverà gli eventi.
- 03
Definisci l’ambito
Scegli un paese, o All, e il conto a cui appartengono le notifiche.
- 04
Aggiungi header e testa
Se vuoi, aggiungi header personalizzati per il tuo gateway, poi esegui una transazione di test su Stage.
Payload
Un’unica busta per ogni evento
Tutte le notifiche condividono gli stessi campi radice, quindi un solo handler può instradarle tutte. Il body è JSON, consegnato con Content-Type text/plain.
- transactionType: PayIn, PayOut, VirtualAccount, Subscription, CurrencyExchange, WireIn o WireOut
- transactionFlow: il flusso di elaborazione, utile per il routing
- data: la transazione vera e propria, con externalId, internalId e stato
Eventi
Su cosa ricevi notifiche
Incasso con carta
- transactionType
- PayIn
- Cosa ti dice
- Approvato, completato, rifiutato, rimborsato o soggetto a chargeback
Incasso tramite bonifico o metodo locale
- transactionType
- PayIn
- Cosa ti dice
- Stato finale dopo la conferma del pagatore nella sua app bancaria o wallet
Conto virtuale
- transactionType
- VirtualAccount
- Cosa ti dice
- Conto creato e ogni pagamento ricevuto
Abbonamento
- transactionType
- Subscription
- Cosa ti dice
- Ciclo di vita dell’abbonamento; ogni addebito arriva anche come evento PayIn
Payout
- transactionType
- PayOut
- Cosa ti dice
- Cambi di stato lungo il flusso del payout, fino al completamento
Cambio valuta
- transactionType
- CurrencyExchange
- Cosa ti dice
- Esito di una conversione tra i tuoi saldi
Wire In
- transactionType
- WireIn
- Cosa ti dice
- Fondi accreditati sul tuo conto, in fiat o in USDC/USDT
Wire Out
- transactionType
- WireOut
- Cosa ti dice
- Prelievo inviato; i Wire Out in crypto includono l’hash della transazione on-chain
Schemi completi e codici di stato di ogni evento sono nella reference dei webhook su docs.localpayment.com.
Sicurezza
Verifica ogni firma
Ogni richiesta contiene x-Signature: HMAC-SHA256 seguito dal digest esadecimale del body grezzo, calcolato con il tuo segreto webhook. Ricalcolalo e confrontalo prima di fidarti del payload.
- Leggi il body grezzo: è JSON inviato come Content-Type text/plain
- Rimuovi il prefisso “HMAC-SHA256 ”, poi confronta con una funzione a tempo costante
- Rifiuta le discrepanze con 401 e non loggare mai il payload completo
// Ricevitore Express per i webhook di Localpayment (Node.js 18+).
import crypto from 'node:crypto';
import express from 'express';
import { jobQueue } from './queue.js'; // la tua coda di job asincroni
const app = express();
// Carica il segreto del webhook dal tuo secrets manager all’avvio. Mai scriverlo nel codice.
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;
// Formato dell’header: "x-Signature: HMAC-SHA256 <hex>". Rimuovi prima il prefisso.
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);
}
// Il body è JSON inviato come Content-Type text/plain: conserva il testo grezzo per l’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); // conferma subito, prima di qualsiasi elaborazione pesante
// Elabora in modo asincrono. Deduplica per internalId/externalId + stato
// così un nuovo invio viene applicato una sola volta. Non loggare mai il payload completo.
jobQueue.enqueue(event);
});Elaborazione affidabile
Pensato per i retry e le reti reali
Conferma subito
Rispondi 200 appena la firma è valida e sposta il lavoro pesante in un job in background.
Aspettati i retry
Se non riceviamo un 200, riproviamo con backoff esponenziale. Il tuo handler deve poter girare più volte senza effetti collaterali.
Deduplica
Basa l’elaborazione su internalId o externalId più lo stato, così un nuovo invio viene applicato una sola volta.
Non dare per scontato l’ordine
Confronta lo stato in arrivo con quello salvato prima di applicarlo e non far mai tornare indietro una transazione.
Conferma con l’API
Nel dubbio, interroga GET /api/transactions/{externalId}/status per lo stato attuale di una transazione.
Logga in sicurezza
Logga tipi di evento, ID e stati, mai payload completi, token o dati personali.
Operations
Vedi ogni invio nel Business Portal
I report delle notifiche mostrano cosa è stato inviato ai tuoi endpoint, così supporto e engineering risolvono i problemi senza scavare nei log dei server.
- Log degli invii delle notifiche ai tuoi endpoint
- Ricerca delle transazioni e report di attività dettagliati
- Webhook, allow-list degli IP e utenti gestiti in un unico posto
Panoramica
USD
1.284.560,00
+4,2%
BRL
3.420.118,40
+12,8%
MXN
8.905.332,10
+6,1%
- Incasso · Pixorder_8F2K-1043+ R$ 1.250,00
- Payout · SPEIseller_0921− MX$ 18.400,00
- Cambio · BRL → USDfx_3b7q250.000,00 USD
- Incasso · Bre-Border_9A1C-2210+ COP 890.000
FAQ sui webhook
Come faccio a sapere che un webhook arriva davvero da Localpayment?
Verifica l’header x-Signature: ricalcola l’HMAC-SHA256 del body grezzo con il tuo segreto webhook e confronta i due valori con una funzione a tempo costante. Puoi anche aggiungere header personalizzati a ogni voce di notifica per il tuo gateway.
Ogni quanto vengono ripetuti gli invii falliti?
Gli invii che non ricevono un 200 vengono ripetuti con backoff esponenziale. Progetta il tuo handler per più tentativi e controlla lo storico degli invii nei report delle notifiche del Business Portal.
Perché il Content-Type è text/plain?
Il body è JSON inviato come text/plain. Leggilo come testo grezzo, verifica la firma su quegli esatti byte e solo dopo fai il parsing.
Posso inviare paesi diversi a endpoint diversi?
Sì. Ogni voce di notifica è limitata per paese (o All) e conto, quindi puoi instradare mercati o business unit verso URL separati.
Cosa deve restituire il mio endpoint?
Uno stato 200, il più rapidamente possibile e prima di qualsiasi elaborazione lunga. Senza 200, l’invio è considerato fallito e viene ripetuto.
Correlati
Collega il tuo primo webhook
Configura un endpoint Stage, genera un incasso di test e verifica la firma end-to-end.

Firme HMAC-SHA256