Webhooks
Saiba na hora em que o dinheiro se move
Notificações em tempo real de pay-ins, payouts, contas virtuais, assinaturas, câmbio, Wire In e Wire Out, cada uma assinada com HMAC-SHA256 para você verificar cada requisição antes de agir.
- Assinaturas HMAC-SHA256
- Reentregas com backoff
- Por país e por conta
- 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" } } }Configuração
Configure as notificações no Business Portal
Cadastrar um endpoint não exige código. Cada entrada pode ser limitada por país e por conta.
- 01
Abra as notificações
No Business Portal, acesse Configurations → Clients → Notifications.
- 02
Adicione sua URL HTTPS
Cadastre o endpoint HTTPS público dos seus servidores que vai receber os eventos.
- 03
Defina o escopo
Escolha um país, ou All, e a conta à qual as notificações pertencem.
- 04
Adicione cabeçalhos e teste
Se quiser, inclua cabeçalhos personalizados para o seu gateway e depois faça uma transação de teste no Stage.
Payload
Um mesmo envelope para cada evento
Todas as notificações compartilham os mesmos campos raiz, então um único receptor pode roteá-las. O corpo é JSON e chega com Content-Type text/plain.
- transactionType: PayIn, PayOut, VirtualAccount, Subscription, CurrencyExchange, WireIn ou WireOut
- transactionFlow: o fluxo de processamento, útil para rotear
- data: a transação em si, com externalId, internalId e status
Eventos
Sobre o que você será notificado
Pay-in com cartão
- transactionType
- PayIn
- O que indica
- Aprovado, concluído, rejeitado, reembolsado ou com chargeback
Pay-in por transferência ou meio local
- transactionType
- PayIn
- O que indica
- O status final depois que o pagador confirma no banco ou na carteira
Conta virtual
- transactionType
- VirtualAccount
- O que indica
- Conta criada e cada pagamento recebido
Assinatura
- transactionType
- Subscription
- O que indica
- Ciclo de vida da assinatura; cada cobrança também chega como evento PayIn
Payout
- transactionType
- PayOut
- O que indica
- Mudanças de status ao longo do fluxo de payout, até a conclusão
Câmbio
- transactionType
- CurrencyExchange
- O que indica
- Resultado de uma conversão entre seus saldos
Wire In
- transactionType
- WireIn
- O que indica
- Fundos creditados na sua conta, em moeda fiduciária ou USDC/USDT
Wire Out
- transactionType
- WireOut
- O que indica
- Saque enviado; os Wire Out em cripto incluem o hash da transação na blockchain
Os esquemas completos e os códigos de status de cada evento estão na referência de webhooks em docs.localpayment.com.
Segurança
Verifique cada assinatura
Cada requisição traz x-Signature: HMAC-SHA256 seguido do HMAC em hexadecimal do corpo bruto, calculado com o seu segredo de webhook. Recalcule e compare antes de confiar no payload.
- Leia o corpo bruto: é JSON enviado como Content-Type text/plain
- Remova o prefixo “HMAC-SHA256 ” e compare com uma função de tempo constante
- Rejeite assinaturas divergentes com 401 e nunca registre o payload completo
// Receptor Express para webhooks da Localpayment (Node.js 18+).
import crypto from 'node:crypto';
import express from 'express';
import { jobQueue } from './queue.js'; // sua própria fila de jobs assíncronos
const app = express();
// Carregue o segredo do webhook do seu gerenciador de segredos na inicialização. Nunca o deixe no código.
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 do header: "x-Signature: HMAC-SHA256 <hex>". Remova o prefixo antes.
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);
}
// O corpo é JSON enviado como Content-Type text/plain: mantenha o texto bruto para o 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); // responda rápido, antes de qualquer processamento pesado
// Processe de forma assíncrona. Deduplique por internalId/externalId + status
// para aplicar cada reentrega uma única vez. Nunca registre o payload completo.
jobQueue.enqueue(event);
});Processamento confiável
Feito para reentregas e redes do mundo real
Responda rápido
Retorne 200 assim que a assinatura for validada e faça o processamento pesado em uma tarefa em segundo plano.
Espere reentregas
Se não recebermos um 200, reenviamos com backoff exponencial. Seu receptor precisa poder rodar mais de uma vez sem efeitos duplicados.
Deduplique
Processe por internalId ou externalId mais o status, para aplicar cada reentrega uma única vez.
Não presuma a ordem
Compare o status recebido com o que você tem salvo antes de aplicá-lo e nunca faça uma transação retroceder.
Confirme pela API
Na dúvida, consulte GET /api/transactions/{externalId}/status para saber o status atual de uma transação.
Registre com cuidado
Guarde tipos de evento, IDs e status, nunca payloads completos, tokens ou dados pessoais.
Operações
Acompanhe cada entrega no Business Portal
Os relatórios de notificações mostram o que foi enviado aos seus endpoints, para que suporte e engenharia resolvam problemas sem vasculhar logs de servidor.
- Registro das notificações enviadas aos seus endpoints
- Busca de transações e relatórios de atividade detalhados
- Webhooks, lista de IPs permitidos e usuários em um só lugar
Visão geral
USD
1.284.560,00
+4,2%
BRL
3.420.118,40
+12,8%
MXN
8.905.332,10
+6,1%
- Pay-in · Pixorder_8F2K-1043+ R$ 1.250,00
- Payout · SPEIseller_0921− MX$ 18.400,00
- Câmbio · BRL → USDfx_3b7q250.000,00 USD
- Pay-in · Bre-Border_9A1C-2210+ COP 890.000
Perguntas frequentes sobre webhooks
Como sei que um webhook veio mesmo da Localpayment?
Verifique o cabeçalho x-Signature: recalcule o HMAC-SHA256 do corpo bruto com o seu segredo de webhook e compare com uma função de tempo constante. Você também pode adicionar cabeçalhos personalizados a cada entrada para o seu gateway.
Com que frequência as entregas com falha são reenviadas?
Entregas que não recebem um 200 são reenviadas com backoff exponencial. Projete seu receptor para várias tentativas e consulte os relatórios de notificações do Business Portal para ver o histórico de entregas.
Por que o Content-Type é text/plain?
O corpo é JSON enviado como text/plain. Leia-o como texto bruto, verifique a assinatura sobre esses bytes exatos e só então interprete o JSON.
Posso enviar países diferentes para endpoints diferentes?
Sim. Cada entrada de notificação é limitada por país (ou All) e por conta, então você pode direcionar mercados ou unidades de negócio para URLs separadas.
O que meu endpoint deve retornar?
Um status 200, o mais rápido possível e antes de qualquer processamento longo. Sem um 200, a entrega é considerada com falha e reenviada.
Relacionados
Guia rápido
Receba e verifique seu primeiro webhook no passo 5.
Guia rápido —Ambiente Stage
Dispare webhooks VirtualAccount quando quiser com o simulador.
Ambiente Stage —Relatórios e conciliação
Relatórios do portal com exportação em XLS e APIs de saldo, atividade e conciliação.
Relatórios e conciliação —
Conecte seu primeiro webhook
Configure um endpoint no Stage, dispare um pay-in de teste e verifique a assinatura de ponta a ponta.

Assinaturas HMAC-SHA256