Integração da adquirente

Envio de Transações

Como a adquirente ou subadquirente envia cada transação processada para a BackMoney.

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).

Em uma frase
A adquirente faz POST de um lote de eventos para POST /api/webhooks/transactions, autenticando com a API key dela. A BackMoney responde com um resumo da entrega.

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_cnpj do evento; um CNPJ ainda desconhecido é cadastrado automaticamente.
  • Sem perda de dados: um event_type sem 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.

http
Authorization: Bearer backmoney-SUA_CHAVE_AQUI
Guarde a chave com segurança
A API key concede ingestão de transações em nome da sua operação. Trafegue sempre por HTTPS, nunca exponha no front-end e gire a chave em caso de suspeita de vazamento.

Assinatura 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.

Cada adquirente tem o seu certificado
A BackMoney gera um par de chaves ECDSA P-256 por adquirente e entrega a chave privada uma única vez (no painel, ao criar ou rotacionar o certificado). Guarde-a com segurança — a BackMoney retém apenas a parte pública.

Como assinar

  1. Monte a string canônica: <t>.<MÉTODO>.<CAMINHO>.<sha256hex(corpo)> — onde t é 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.
  2. Assine a string canônica com a chave privada (ECDSA P-256, hash SHA-256). A assinatura é ASN.1/DER, codificada em base64.
  3. Envie no header X-BackMoney-Signature com t, kid (o fingerprint do certificado) e sig.
Header
X-BackMoney-Signature: t=1751303525, kid=7125327055e6fd14a1b2…, sig=MEUCIQDk…
CampoDescrição
tTimestamp Unix (segundos) do momento da assinatura. Aceito dentro de ±5 min do relógio do servidor (anti-replay).
kidFingerprint do certificado (SHA-256 do DER), exibido na geração, no painel.
sigAssinatura ECDSA-P256-SHA256 (ASN.1/DER) da string canônica, em base64.

Exemplos de assinatura

sign.mjs
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}`
Assine os bytes exatos do corpo
O hash é calculado sobre o corpo exatamente como transmitido. Não reserialize o JSON depois de assinar — qualquer diferença de bytes (espaços, ordem de campos) invalida a assinatura.

Endpoint

MétodoURLObservação
POST/api/webhooks/transactionsCanônico — use este.
POST/api/webhooks/paymentsAlias 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:

CampoTipoObrigatórioDescrição
eventsarraysim (mín. 1)Lote de eventos a processar.

Objeto do evento

CampoTipoObrigatórioDescrição
event_idstringsimId único do parceiro para este evento — a chave de idempotência.
event_typestringsimDiscriminador no formato recurso.ação (ex.: pos.sale).
occurred_atstring (date-time)nãoQuando ocorreu na origem (ISO 8601). Default = hora da ingestão.
dataobjetosimPayload tipado conforme o event_type (ver abaixo).

O objeto data (eventos pos.*)

Para eventos de maquininha (pos.*), o data traz:

CampoTipoObrigatórioDescrição
amount.valueinteirosimValor em centavos (minor units). Ex.: R$100,00 = 10000.
amount.currencystringsimMoeda ISO-4217 (ex.: BRL).
payment_methodstringsimcredit_card, debit_card, pix, …
card_brandstringcondicionalBandeira (visa, master, elo, hiper, amex). Define a taxa de MDR.
installmentsinteirocondicionalParcelas (1 = à vista). Afeta a taxa da maquininha.
statusstringsimSituação da transação (ex.: approved).
merchant_cnpjstringsimCNPJ do estabelecimento. Resolve a loja; um CNPJ novo é cadastrado automaticamente.
transaction_codestringrecomendadoCódigo/NSU da transação no adquirente (rastreabilidade e conciliação).
device_serialstringnãoSerial da maquininha que originou a venda.
customer_cpfstringnãoCPF do cliente, quando ele digita na maquininha. Sem CPF, só o lojista é beneficiado.
customer_emailstringnãoE-mail do cliente (onboarding).
customer_phonestringnãoCelular do cliente — usado no cadastro automático na 1ª compra.

Tipos de evento (event_type)

event_typeSignificado
pos.saleVenda aprovada.
pos.refundEstorno / devolução.
pos.reversalReversão da transação.
pos.cancellationCancelamento.
pos.chargebackChargeback.

Exemplo — uma venda

POST /api/webhooks/transactions
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:

200 OK
{
  "data": {
    "provider": "deltapay",
    "received": 1,
    "ingested": 1,
    "duplicates": 0,
    "skipped": 0,
    "unhandled": 0
  }
}
CampoDescrição
providerO parceiro, derivado da API key.
receivedTotal de eventos na entrega.
ingestedEventos processados por um decoder (novos).
duplicatesEventos já vistos antes (reentrega idempotente).
skippedDescartados (sem event_id/event_type ou payload inválido).
unhandledArmazenados, 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.

json
{
  "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_id já processado retorna como duplicates — não gera nova transação nem benefícios em dobro.
  • Reentrega: em caso de 5xx ou 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 skipped e os demais seguem.
HTTPQuandoAção
200 OKEntrega aceita (mesmo com itens skipped/unhandled).Conferir o resumo na resposta.
401API key ausente, inválida ou sem webhooks:ingest; ou assinatura ausente/inválida/expirada (quando exigida).Verificar o token e a assinatura.
422Envelope malformado (ex.: events vazio).Corrigir o corpo e reenviar.
500/503Falha temporária na BackMoney.Reenviar o lote (idempotente) com backoff.

Boas práticas

  • Sempre via HTTPS; envie o amount.value em centavos (inteiro).
  • Use um event_id estável e único por transação (ex.: o NSU + adquirente).
  • Inclua card_brand e installments — 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).
Precisa de uma chave de homologação?
Fale com o time de integração da BackMoney para receber a API key de sandbox e o checklist de homologação.