Trilha — Varejo PDV

Quickstart de integração

Para lojas de varejo — mercados, farmácias, postos, e-commerce. Em ~10 minutos sua primeira venda já credita cashback BMC ao cliente, com a ativação acontecendo automaticamente na primeira compra.

Modelo mental — leia antes dos curls

O varejo opera num modelo diferente da recorrência: o cliente está no balcão na hora da primeira interação— não há um "momento de assinatura" meses antes. Por isso o fluxo é uma única chamada: a primeira venda ativa o cliente e credita o cashback no mesmo passo.

cliente novo(zero state)
pos-cashback + activate
active(BMC creditado)
compras 2..N (sem activate)

Cada venda em fiat gera cashback BMC proporcional ao coin_acceptance_rate configurado para sua loja (percentual de 0 a 100). Por exemplo: rate 10% + venda de R$ 100,00 = R$ 10,00 de BMC creditado na carteira do cliente. O saldo BMC do cliente nunca expira e pode ser usado em qualquer lojista da rede.

Pré-requisitos

  • CNPJ aprovado pela equipe Bumcash (status approved no portal).
  • Termos de Uso aceitos no portal.
  • Pelo menos um local cadastrado com companyType = retail (ou hybrid) e integrationMode = self.
  • Chave Merchant sandbox emitida no portal (bmc_test_mch_…).
  • coin_acceptance_rate configurado pela equipe Bumcash para sua loja (default depende do contrato).

URL base

txt
https://api-v2.bumcash.com.br/v1

Passo 1

Primeira venda (ativa o cliente)

Na primeira vez que o cliente compra na sua loja, envie o bloco activate. Numa única chamada o CPF é validado, o cliente é incluído na rede, e o cashback é creditado na carteira dele.

POST/v1/payments/pos-cashbackperm: payments:create + customers:activate
curlcurl
curl -X POST https://api-v2.bumcash.com.br/v1/payments/pos-cashback \
  -H "Authorization: Bearer bmc_test_mch_xxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "location_id": "loc_abc123",
    "customer_cpf": "22334455667",
    "total_amount": 8000,
    "operator_id": "op_caixa_03",
    "activate": {
      "cpf": "22334455667",
      "phone": "+5511987651234"
    },
    "idempotency_key": "venda_2026-05-02_pdv01_42"
  }'

Resposta — 201 Created

json
{
  "id": "ledg_9f8e7d6c5b4a",
  "type": "POS_CASHBACK",
  "customer_id": "cust_a1b2c3d4e5f6",
  "cashback_amount": 800,
  "total_amount": 8000,
  "coin_acceptance_rate": 10,
  "new_balance": 800,
  "location_id": "loc_abc123",
  "location_name": "Mercadinho do João — Centro",
  "customer_activation": "activated",
  "created_at": "2026-05-02T14:23:00.000Z"
}
  • Valores em centavos. R$ 80,00 = 8000; cashback de R$ 8,00 (10%) = 800.
  • cashback_amount é calculado pela Bumcash a partir de total_amount × coin_acceptance_rate / 100 (com truncamento para baixo). Você não envia o valor do cashback — o servidor é a fonte da verdade.
  • operator_id é opcional e útil quando você tem operadores físicos no PDV (POS terminal). Aparece nas listagens de transações para auditoria.
  • customer_activation retorna "activated" quando esta chamada efetivou a ativação do cliente, ou "already_active" se ele já estava na rede (vindo de outra loja, por exemplo).

Passo 2

Compras subsequentes

Da segunda compra em diante (do mesmo cliente, em qualquer loja), omita o bloco activate. O cliente já está na rede.

POST/v1/payments/pos-cashbackperm: payments:create
curlcurl
curl -X POST https://api-v2.bumcash.com.br/v1/payments/pos-cashback \
  -H "Authorization: Bearer bmc_test_mch_xxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "location_id": "loc_abc123",
    "customer_cpf": "22334455667",
    "total_amount": 5500,
    "operator_id": "op_caixa_03",
    "idempotency_key": "venda_2026-05-15_pdv01_88"
  }'
jsonresposta — 201 Created
{
  "id": "ledg_5b4a3f2e1d0c",
  "type": "POS_CASHBACK",
  "customer_id": "cust_a1b2c3d4e5f6",
  "cashback_amount": 550,
  "total_amount": 5500,
  "coin_acceptance_rate": 10,
  "new_balance": 1350,
  "location_id": "loc_abc123",
  "location_name": "Mercadinho do João — Centro",
  "customer_activation": "already_active",
  "created_at": "2026-05-15T19:11:00.000Z"
}

O que acontece se eu esquecer o bloco activate?

Se o cliente ainda não está na rede e você chama /payments/pos-cashback sem activate, o servidor retorna 404 customer_not_found e nada é creditado. Adicione o bloco activate e retente — não é uma falha permanente, é só o servidor pedindo o cadastro inline.

jsonerro 404
{
  "error": {
    "code": "customer_not_found",
    "message": "Customer not found. Pre-register the CPF via POST /customers/register, or include an `activate` block on this request to perform first-touch activation."
  },
  "request_id": "req_xxx"
}

Em alguns casos seu sistema sabe se o CPF é "novo cliente" só depois de uma consulta. Se preferir uma estratégia simples: sempre envie o bloco activate— se o cliente já estiver na rede, ele é tratado como no-op e a resposta retorna customer_activation: "already_active".

Erros que você vai encontrar

Resumo dos códigos mais comuns desta trilha. Veja todos em referência de erros.

HTTPerror.codeCausaO que fazer
403insufficient_permissionsSua chave não tem payments:create (default não inclui em retail-only).Peça habilitação no portal. O hint na resposta detalha a trilha.
404customer_not_foundCliente novo e o bloco activate não foi enviado.Re-enviar com bloco activate — ativa e credita na mesma chamada.
400customer_blockedCliente está blocked (suspensão administrativa ou inelegível).Não retentar. Notificar internamente.
400invalid_requestLocal não é retail/hybrid, ou coin_acceptance_rate = 0, ou cashback arredonda para 0 (compra muito pequena).Verificar configuração do local em Portal → Lojas, ou ajustar valor mínimo de venda.
409idempotency_conflictMesma idempotency_key com payload diferente.Gerar nova chave para a nova intenção.

Conciliação

  • GET /statements?location_id=… — extratos por período do seu local. Cada extrato traz total devido + contagem de transações.
  • GET /payments?location_id=… — listagem das vendas com cashback que você gerou. Filtros por status e cursor de paginação.
  • GET /earnings — saldo acumulado de "ativador da rede" no período (revenue-share quando outros lojistas vendem para clientes que você ativou).
  • POST /refunds — estornar uma venda específica, revertendo o cashback creditado. Requer refunds:create (não default em retail-only — peça habilitação).

Webhooks recomendados

Subscreva no portal em Webhooks → Endpoints:

customer.activated
Cliente foi incluído na rede a partir da sua chamada (bloco activate aceito na primeira compra).
cashback.granted
Cashback creditado com sucesso. Use para reconciliação em tempo real contra sua base de vendas.
payment.refunded
Estorno processado — cashback debitado da carteira do cliente.

Sandbox — fixtures pré-cadastrados

Para testar sem cadastrar nada, use estes identificadores que já existem no banco sandbox:

RecursoTipoValorTelefone
Local varejoCNPJSolicite ao time o CNPJ sandbox da sua categoria
Local híbridoCNPJ22222222000122
Cliente sandbox 1CPF11111111111+5511900000001
Cliente sandbox 2CPF22222222222+5511900000002
Cliente sandbox 3CPF33333333333+5511900000003

Checklist para produção

  • Verbo payments:create habilitado pelo time Bumcash na sua chave.
  • Sempre enviar bloco activate (no-op em clientes ativos, evita o customer_not_found acidental).
  • idempotency_key derivada de algo estável (ex: venda_<loja>_<data>_<sequencial>), não UUID aleatório.
  • Operador identificado em operator_id quando há POS físico — facilita auditoria.
  • Webhook receptor com verificação HMAC + dedup por id (lançamento contábil).
  • Tratamento de erros 4xx é específico por code (não retentar 4xx exceto idempotency_conflict com chave nova).
  • Validado em sandbox com fixtures, depois trocada a chave para bmc_live_mch_…