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.
Cada venda em fiat gera cashback BMC proporcional ao pos_cashback_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_…).
- pos_cashback_rate configurado pela equipe Bumcash para sua loja (default depende do contrato).
URL base
https://api-v2.bumcash.com.br/v1Passo 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.
/v1/payments/pos-cashbackperm: payments:create + customers:activatecurl -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 '{
"customer_cpf": "22255588846",
"total_amount": 8000,
"operator_id": "op_caixa_03",
"activate": {
"cpf": "22255588846",
"phone": "+5511987651234"
},
"idempotency_key": "venda_2026-05-02_pdv01_42"
}'Resposta — 201 Created
{
"id": "ledg_9f8e7d6c5b4a",
"type": "POS_CASHBACK",
"customer_id": "cust_a1b2c3d4e5f6",
"cashback_amount": 800,
"total_amount": 8000,
"pos_cashback_rate": 10,
"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 detotal_amount × pos_cashback_rate / 100(com truncamento para baixo). Você não envia o valor do cashback — o servidor é a fonte da verdade.coin_acceptance_ratepermanece na resposta por estabilidade, mas está depreciado para cashback (hoje é igual apos_cashback_rate; use este).operator_idé opcional e útil quando você tem operadores físicos no PDV (POS terminal). Aparece nas listagens de transações para auditoria.customer_activationretorna"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.
/v1/payments/pos-cashbackperm: payments:createcurl -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 '{
"customer_cpf": "22255588846",
"total_amount": 5500,
"operator_id": "op_caixa_03",
"idempotency_key": "venda_2026-05-15_pdv01_88"
}'{
"id": "ledg_5b4a3f2e1d0c",
"type": "POS_CASHBACK",
"customer_id": "cust_a1b2c3d4e5f6",
"cashback_amount": 550,
"pos_cashback_rate": 10,
"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.
{
"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".
Passo 3
Resgate no balcão (cliente paga parte com saldo)
O caminho inverso: o cliente usa o saldo acumulado para abater parte da venda. São duas chamadas porque o PDV precisa saber quanto cobrar antes de cobrar — primeiro autorize, depois debite.
1. Autorize — quanto do saldo pode entrar nesta venda
/v1/payments/coin-quoteperm: payments:createcurl -X POST https://api-v2.bumcash.com.br/v1/payments/coin-quote \
-H "Authorization: Bearer bmc_test_mch_xxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"customer_cpf": "22255588846",
"customer_birth_date": "22071990",
"total_amount": 5000
}'{
"location_id": "loc_abc123",
"location_name": "Mercadinho do João — Centro",
"total_amount": 5000,
"coin_acceptance_rate": 30,
"coin_amount": 1350,
"cash_amount": 3650,
"customer_balance": 1350,
"partial_applied": true,
"requires_activation": false,
"customer_name": null
}- Não debita nada. É só a autorização. Cobre
cash_amount(R$ 36,50) no cartão/dinheiro e siga para o débito. partial_applied: truesignifica que o saldo do cliente — não o teto da loja — foi o limitante. O teto aqui seria R$ 15,00 (30% de R$ 50,00), mas o cliente só tinha R$ 13,50.- A data de nascimento é o fator de confirmação do cliente. Errar retorna
401; após 5 erros em 15 min o CPF entra em bloqueio temporário e passa a retornar429. requires_activation: trueindica cliente ainda fora da rede:coin_amountvem zerado, cobre o valor cheio e ofereça o cadastro.
2. Debite — depois que a venda foi aprovada
/v1/paymentsperm: payments:createcurl -X POST https://api-v2.bumcash.com.br/v1/payments \
-H "Authorization: Bearer bmc_test_mch_xxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"customer_cpf": "22255588846",
"total_amount": 5000,
"coin_amount": 1350,
"idempotency_key": "venda_2026-05-20_pdv01_17"
}'{
"id": "pay_7c6b5a4d3e2f",
"location_id": "loc_abc123",
"total_amount": 5000,
"coin_acceptance_rate": 30,
"coin_amount": 1350,
"cash_amount": 3650,
"status": "completed",
"created_at": "2026-05-20T16:40:00.000Z"
}Reusar a idempotency_key com os mesmos parâmetros devolve o pagamento original — retentar depois de um timeout é seguro. Com parâmetros diferentes você recebe 409 idempotency_conflict, e o erro carrega o payment_id do pagamento que existe, para você reconciliar ou estornar.
3. Estorne — se a venda for cancelada
/v1/payments/{id}/reverseperm: refunds:createcurl -X POST https://api-v2.bumcash.com.br/v1/payments/pay_7c6b5a4d3e2f/reverse \
-H "Authorization: Bearer bmc_test_mch_xxxxxxxxxxxxxxxxxx"Devolve o saldo debitado e marca o pagamento como reversed. Idempotente — estornar duas vezes não credita duas vezes. Sem isso, uma venda cancelada deixaria o cliente sem a compra e sem o saldo.
Erros que você vai encontrar
Resumo dos códigos mais comuns desta trilha. Veja todos em referência de erros.
| HTTP | error.code | Causa | O que fazer |
|---|---|---|---|
| 403 | insufficient_permissions | Sua 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. |
| 404 | customer_not_found | Cliente novo e o bloco activate não foi enviado. | Re-enviar com bloco activate — ativa e credita na mesma chamada. |
| 400 | customer_blocked | Cliente está blocked (suspensão administrativa ou inelegível). | Não retentar. Notificar internamente. |
| 400 | invalid_request | Local não é retail/hybrid, ou pos_cashback_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. |
| 409 | idempotency_conflict | Mesma 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 /payments/pos-cashback/{id}/reverse— estornar uma venda cancelada, retirando o cashback creditado e anulando a cobrança daquela venda. Requerrefunds: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.
- cashback.reversed
- Venda cancelada — cashback retirado da carteira do cliente e a cobrança daquela venda anulada.
- payment.completed
- Cliente usou saldo numa venda (resgate no balcão). Traz coin_amount, cash_amount e o saldo restante.
- payment.refunded
- Pagamento com moeda estornado — o saldo debitado voltou para a carteira do cliente.
Sandbox — fixtures pré-cadastrados
Para testar sem cadastrar nada, use estes identificadores que já existem no banco sandbox:
| Recurso | Tipo | Valor | Telefone |
|---|---|---|---|
| Local varejo | CNPJ | — | Solicite ao time o CNPJ sandbox da sua categoria |
| Local híbrido | CNPJ | 22222222000191 | |
| Cliente sandbox 1 | CPF | 11144477735 | +5511900000001 |
| Cliente sandbox 2 | CPF | 22255588846 | +5511900000002 |
| Cliente sandbox 3 | CPF | 33366699957 | +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_…