Envio de Transações
Toda transação processada nas maquininhas é enviada para a BackMoney pela própria adquirente/subadquirente, em tempo real, por webhook. O estabelecimento nunca lança transações manualmente — a fonte da verdade é o fluxo da adquirente. A partir de cada evento, a BackMoney concilia a venda e dispara os benefícios (cashback, vouchers, cupons, multinível).
Visão geral
- Direção: a adquirente envia (push) para a BackMoney — não somos nós que consultamos.
- Em lote: cada requisição leva um array
events(1 ou mais eventos). - Idempotente: cada evento tem um
event_idúnico; reenviar o mesmo id é tratado como duplicado, sem dupla contagem. - Identificação por chave: o parceiro é identificado pela própria API key — o
provideré derivado dela, então não há como forjar a origem de outro. - Resolução do lojista: a loja é resolvida pelo
merchant_cnpjdo evento; um CNPJ ainda desconhecido é cadastrado automaticamente. - Sem perda de dados: um
event_typesem tratamento é armazenado e reconhecido como unhandled (nada é descartado).
Autenticação
A requisição é autenticada com um token Bearer (a API key da adquirente, no formato backmoney-…), que precisa ter a permissão webhooks:ingest. Uma única chave recebe os eventos de todos os estabelecimentos atendidos por aquela adquirente.
Authorization: Bearer backmoney-SUA_CHAVE_AQUIAssinatura da requisição
Além da API key, a BackMoney pode exigir que cada envio seja assinado com a chave privada do certificado do adquirente — dando integridade, proteção contra replay e não-repúdio. Quando a exigência está ligada, requisições sem assinatura válida recebem 401.
Como assinar
- Monte a string canônica:
<t>.<MÉTODO>.<CAMINHO>.<sha256hex(corpo)>— ondeté o timestamp Unix (segundos),MÉTODOéPOST,CAMINHOé/api/webhooks/transactions(sem query string) e o hash é o SHA-256 do corpo exatamente como enviado. - Assine a string canônica com a chave privada (ECDSA P-256, hash SHA-256). A assinatura é ASN.1/DER, codificada em base64.
- Envie no header
X-BackMoney-Signaturecomt,kid(o fingerprint do certificado) esig.
X-BackMoney-Signature: t=1751303525, kid=7125327055e6fd14a1b2…, sig=MEUCIQDk…| Campo | Descrição |
|---|---|
| t | Timestamp Unix (segundos) do momento da assinatura. Aceito dentro de ±5 min do relógio do servidor (anti-replay). |
| kid | Fingerprint do certificado (SHA-256 do DER), exibido na geração, no painel. |
| sig | Assinatura ECDSA-P256-SHA256 (ASN.1/DER) da string canônica, em base64. |
Exemplos de assinatura
import crypto from 'node:crypto'
import fs from 'node:fs'
const privateKey = crypto.createPrivateKey(fs.readFileSync('private-key.pem'))
const ts = Math.floor(Date.now() / 1000)
const bodyHash = crypto.createHash('sha256').update(body).digest('hex')
const canonical = `${ts}.POST./api/webhooks/transactions.${bodyHash}`
// ECDSA P-256 + SHA-256, assinatura ASN.1/DER em base64
const sig = crypto
.sign('sha256', Buffer.from(canonical), { key: privateKey, dsaEncoding: 'der' })
.toString('base64')
const header = `t=${ts}, kid=${fingerprint}, sig=${sig}`Endpoint
| Método | URL | Observação |
|---|---|---|
| POST | /api/webhooks/transactions | Canônico — use este. |
| POST | /api/webhooks/payments | Alias antigo (depreciado). Mesmo comportamento. |
Base de produção: https://api.backmoney.com.br · homologação: https://api-development.backmoney.com.br.
Corpo da requisição
O corpo é um envelope com o lote de eventos:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| events | array | sim (mín. 1) | Lote de eventos a processar. |
Objeto do evento
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| event_id | string | sim | Id único do parceiro para este evento — a chave de idempotência. |
| event_type | string | sim | Discriminador no formato recurso.ação (ex.: pos.sale). |
| occurred_at | string (date-time) | não | Quando ocorreu na origem (ISO 8601). Default = hora da ingestão. |
| data | objeto | sim | Payload tipado conforme o event_type (ver abaixo). |
O objeto data (eventos pos.*)
Para eventos de maquininha (pos.*), o data traz:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| amount.value | inteiro | sim | Valor em centavos (minor units). Ex.: R$100,00 = 10000. |
| amount.currency | string | sim | Moeda ISO-4217 (ex.: BRL). |
| payment_method | string | sim | credit_card, debit_card, pix, … |
| card_brand | string | condicional | Bandeira (visa, master, elo, hiper, amex). Define a taxa de MDR. |
| installments | inteiro | condicional | Parcelas (1 = à vista). Afeta a taxa da maquininha. |
| status | string | sim | Situação da transação (ex.: approved). |
| merchant_cnpj | string | sim | CNPJ do estabelecimento. Resolve a loja; um CNPJ novo é cadastrado automaticamente. |
| transaction_code | string | recomendado | Código/NSU da transação no adquirente (rastreabilidade e conciliação). |
| device_serial | string | não | Serial da maquininha que originou a venda. |
| customer_cpf | string | não | CPF do cliente, quando ele digita na maquininha. Sem CPF, só o lojista é beneficiado. |
| customer_email | string | não | E-mail do cliente (onboarding). |
| customer_phone | string | não | Celular do cliente — usado no cadastro automático na 1ª compra. |
Tipos de evento (event_type)
| event_type | Significado |
|---|---|
| pos.sale | Venda aprovada. |
| pos.refund | Estorno / devolução. |
| pos.reversal | Reversão da transação. |
| pos.cancellation | Cancelamento. |
| pos.chargeback | Chargeback. |
Exemplo — uma venda
curl -X POST https://api.backmoney.com.br/api/webhooks/transactions \
-H "Authorization: Bearer backmoney-SUA_CHAVE_AQUI" \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"event_id": "evt_9f2c7a13b8",
"event_type": "pos.sale",
"occurred_at": "2026-06-30T14:12:05Z",
"data": {
"device_serial": "PAX-A920-00237",
"transaction_code": "NSU-882211",
"amount": { "value": 10000, "currency": "BRL" },
"payment_method": "credit_card",
"card_brand": "visa",
"installments": 1,
"status": "approved",
"merchant_cnpj": "12.345.678/0001-90",
"customer_cpf": "390.533.447-05",
"customer_phone": "+5511987654321"
}
}
]
}'Resposta
A resposta vem no envelope padrão { "data": … }, com o resumo da entrega:
{
"data": {
"provider": "deltapay",
"received": 1,
"ingested": 1,
"duplicates": 0,
"skipped": 0,
"unhandled": 0
}
}| Campo | Descrição |
|---|---|
| provider | O parceiro, derivado da API key. |
| received | Total de eventos na entrega. |
| ingested | Eventos processados por um decoder (novos). |
| duplicates | Eventos já vistos antes (reentrega idempotente). |
| skipped | Descartados (sem event_id/event_type ou payload inválido). |
| unhandled | Armazenados, mas sem decoder para aquele event_type. |
Envio em lote
Você pode agrupar vários eventos numa única entrega — recomendado para reduzir chamadas. Cada evento é processado de forma independente; o resumo da resposta soma os resultados.
{
"events": [
{ "event_id": "evt_001", "event_type": "pos.sale", "data": { /* ... */ } },
{ "event_id": "evt_002", "event_type": "pos.sale", "data": { /* ... */ } },
{ "event_id": "evt_003", "event_type": "pos.refund", "data": { /* ... */ } }
]
}Idempotência, reentrega e erros
- Idempotência: reenviar um
event_idjá processado retorna comoduplicates— não gera nova transação nem benefícios em dobro. - Reentrega: em caso de
5xxou timeout, reenvie o lote inteiro; os eventos já recebidos serão deduplicados. - Parcial: um evento inválido não derruba o lote — ele entra como
skippede os demais seguem.
| HTTP | Quando | Ação |
|---|---|---|
| 200 OK | Entrega aceita (mesmo com itens skipped/unhandled). | Conferir o resumo na resposta. |
| 401 | API key ausente, inválida ou sem webhooks:ingest; ou assinatura ausente/inválida/expirada (quando exigida). | Verificar o token e a assinatura. |
| 422 | Envelope malformado (ex.: events vazio). | Corrigir o corpo e reenviar. |
| 500/503 | Falha temporária na BackMoney. | Reenviar o lote (idempotente) com backoff. |
Boas práticas
- Sempre via HTTPS; envie o
amount.valueem centavos (inteiro). - Use um
event_idestável e único por transação (ex.: o NSU + adquirente). - Inclua
card_brandeinstallments— eles definem a taxa da maquininha (MDR). - Implemente retry com backoff em
5xx/timeout; confie na idempotência. - Acompanhe as entregas em
GET /api/v1/webhooks/events(status por evento).
