Antes de começar
Este guia descreve o fluxo que um PDV deve implementar para:- consultar benefícios usando o cliente e o carrinho atual;
- validar a identidade do consumidor quando solicitado pela BonifiQ;
- resgatar desconto, cashback, produto ou brinde;
- registrar a venda concluída;
- estornar um resgate abandonado e cancelar um pedido total ou parcialmente.
Raiz da API privada:
https://api.bonifiq.com.br/v1/pvtOs caminhos deste guia são mostrados completos a partir de /v1/pvt. A maioria começa com /POS, mas o resgate de produto ou brinde usa /RewardConfigurations.Fluxo completo
1. Consultar benefícios
ChamePOST /v1/pvt/POS/rewards/available quando:
- o cliente for identificado ou alterado;
- um produto ou quantidade mudar;
- um desconto que não seja da BonifiQ mudar;
- o PDV precisar revalidar a seleção antes do resgate.
Valores do pedido
Exemplo:
A BonifiQ usa
PurchaseValue para regras de valor mínimo, limites e cashback. Ela usa DiscountValue separadamente para avaliar cumulatividade. Não envie o valor líquido em PurchaseValue.
Request
string
required
Identificador do cliente. Pode ser documento ou e-mail. Para CPF/CNPJ, envie apenas números.
decimal
required
Valor bruto atual do carrinho.
decimal
Desconto já aplicado pelo PDV e que não pertence à BonifiQ. Envie
0 ou null quando não houver.array
Carrinho atual. Embora o contrato preserve compatibilidade sem esta lista, envie-a para considerar restrições por produto e benefícios
RewardType = 5.OriginalId: SKU ou identificador estável no PDV;LineId: identificador da linha, útil quando o mesmo SKU aparece com preços diferentes;Title,QuantityeIsActive;ProductPrice: preço unitário regular;ProductDiscountPrice: preço unitário promocional, quando houver;ProductBrandeProductCategory, ambas comOriginalIdeName;ProductCategory.ParentCategorypara hierarquia de categorias.
cURL
Response
Rewards[].CanUse é a fonte autoritativa para habilitar uma opção. Não recalcule elegibilidade usando apenas saldo, preço ou Requirements.Algumas variantes antigas ou respostas internas podem trazer CanUseReward como resumo. A integração POS não deve depender desse campo: use Rewards[].CanUse.Requirements como explicação amigável e CannotUseReason para comportamento estruturado:
Tipos de recompensa
Se
HasRewards=false, prossiga com a venda sem benefício. Se houver recompensas com CanUse=false, elas podem ser exibidas desabilitadas com o motivo retornado.
2. Validar o cliente
Execute o challenge quando:Criar challenge
cURL
- Gere
TransactionIduma vez por tentativa de validação e mantenha-o até concluir ou abandonar o fluxo. - Quando
ShouldValidateCustomerSignup=true, envieDocumenteName, além dos contatos disponíveis. - Se a resposta retornar
ShouldInformPhone=trueouShouldInformEmail=true, repita com o contato solicitado, o mesmoTransactionIde os dados cadastrais originais.
Validar código
cURL
Success=false, não resgate. Permita nova digitação ou solicite outro código. Não hardcode o tempo de validade do PIN; trate a resposta da API.
3. Resgatar o benefício
Antes da primeira chamada:- gere uma
OriginalKeyúnica para a operação; - persista essa chave junto à venda pendente;
- reutilize exatamente a mesma chave em timeout ou retry.
Desconto ou cashback
UsePOST /v1/pvt/POS/rewards/{id}/redeem para os tipos comuns.
cURL
Value com o valor decimal escolhido, maior que zero e limitado por MaxCashbackForCurrentPurchase. Não envie Value para desconto fixo ou percentual.
Result.RewardIdpara um eventual estorno;Result.ExternalCodepara enviar comoCouponno pedido;Result.OriginalKeypara conciliação.
Produto, desconto em SKU ou brinde
QuandoRewardType=5, use:
id da rota é Rewards[].Id. O Product.ExternalProductId deve corresponder ao identificador offline retornado na consulta.
cURL
Para os modos que não são brinde, informe
ProductPrice ou ProductDiscountPrice. Se a linha já possui promoção, envie o preço promocional e HasPromotion=true para que a API aplique as regras de cumulatividade.
ProductDiscountTotal retornado para calcular o preço líquido. Para brinde, o preço final da linha é zero.
4. Registrar o pedido
Envie todos os pedidos concluídos, mesmo quando não houver benefício. Use:OrderTotal é o valor líquido efetivamente pago, sem frete, depois de descontos, cashback, cupons e promoções.
Continuando o exemplo:
cURL
Regras do payload
OriginalIddeve permanecer igual em retries. Não gere um novo ID após timeout.Couponrecebe oExternalCodeescalar retornado pelo resgate.Customeré um DTO de criação. Não copie o objeto da consulta inteiro e não envie campos comoIdouCurrentTier.Products[]usaTitle,ProductPriceeIsActive. O contrato não possuiQuantity,PricenemProductDiscountPrice.ProductPricerepresenta o valor líquido atribuído à linha. Distribua descontos em centavos para a soma dos produtos fechar comOrderTotal.- Prefira
PaymentMethods[]. O campo singularPaymentMethodexiste apenas por compatibilidade. - A soma de
PaymentMethods[].PaidAmountdeve representar o valor efetivamente pago.
Cashback e pontos estimados
A resposta incluiEstimatedBonus:
GenerateBonus=true, o PDV pode informar ao consumidor quanto ganhou. Para cashback, exiba diretamente EstimatedCashbackFormatted; não refaça formatação ou conversão local.
5. Estornos e cancelamentos
Abandono antes do resgate
Se ainda não existeRewardId, não há resgate para estornar. Limpe apenas o estado local.
Resgate realizado, venda ainda não concluída
Antes de permitir edição de cliente, carrinho ou benefício, estorne:cURL
RewardId retornado pelo resgate, não o ID da configuração. Remova a linha resgatada somente depois de confirmar Result.IsCanceled=true.
Também existe cancelamento por OriginalKey em DELETE /v1/pvt/POS/rewards, com a chave no body.
Cancelamento total do pedido
cURL
orderId da rota é o OriginalId enviado no cadastro. O cancelamento remove a bonificação da compra e trata o resgate associado segundo as regras da BonifiQ.
Cancelamento parcial
UsePOST /v1/pvt/POS/{orderId}/partialcancel quando apenas parte do valor pago for devolvida.
cURL
ValueToRefundé o valor líquido devolvido.- A soma de
Products[].ValueToRefunddeve ser exatamente igual aValueToRefundapós arredondamento monetário. - Cada
Products[].OriginalIddeve existir no pedido original. - Omita
ShouldRefundRedeemou envienullpara seguir a configuração do tenant;trueforça efalseimpede o estorno do resgate. - Gere e persista
CancelKeyantes da primeira tentativa. - Em timeout, repita a mesma chave com o mesmo payload.
- Nunca reutilize a chave com valor, produtos ou
ShouldRefundRedeemdiferentes.
400:
HasError=true, Result.IsCanceled=false ou RefundErrorDetails estiver preenchido.
6. Erros, warnings e retries
As respostas envelopadas podem conter:
Não assuma que todo HTTP
200 é sucesso: verifique HasError e Severity. Um warning com HasWarning=true e HasError=false continua sendo um resultado válido.
Os endpoints de challenge têm resposta própria com Success e FriendlyErrorMessage. Não aplique cegamente o envelope genérico a eles.
Implemente timeout explícito, correlação e backoff para falhas transitórias. Em
429 Too Many Requests, respeite Retry-After quando disponível. Não dependa de limites numéricos fixos no cliente.
7. Segurança e operação
- Envie somente campos aceitos pelo contrato. Não reaproveite respostas inteiras como requests.
- Nunca registre o header
Authorization. - Em ambientes reais, aplique política de proteção de PII a documentos, e-mails e telefones.
- Ferramentas de teste podem exibir dados fictícios completos, mas cURLs compartilhados devem manter a credencial como placeholder.
- Persista
OriginalKey,RewardId,ExternalCode,OriginalIddo pedido eCancelKeyde forma durável. - Concilie operações cujo resultado ficou incerto antes de criar novas chaves.
- Envie pedidos sem benefício; eles também geram pontos e cashback conforme a configuração.
Projeto de referência
PDV BonifiQ Integration Example
Projeto educacional com modo mock, fluxo visual e linha do tempo de requests e responses.
- o acesso direto pelo navegador existe apenas para facilitar o aprendizado;
- pedidos e chaves são mantidos em memória;
- o exemplo de produto usa uma unidade e preço simplificado;
- persistência, timeout, recuperação após reinício e proteção de credenciais pertencem ao PDV integrador.
Checklist de implementação
- Credenciais mantidas fora do frontend e dos logs
- JSON enviado em PascalCase
-
PurchaseValuebruto eDiscountValueseparado - Carrinho completo enviado em
Products -
CanUseeCannotUseReasonrespeitados - Challenge executado para qualquer uma das duas flags de validação
-
OriginalKeypersistida e reutilizada - Fluxo específico de
RewardType=5implementado -
ExternalCodeenviado emCoupon -
OrderTotalePaidAmountlíquidos -
EstimatedCashbackFormattedexibido sem recálculo - Estorno obrigatório antes de editar uma venda já resgatada
- Cancelamentos total e parcial testados
-
OriginalIdeCancelKeyestáveis em retries - Timeout, backoff, correlação e recuperação após reinício testados
Perguntas frequentes
OrderTotal deve ser bruto ou líquido?
OrderTotal deve ser bruto ou líquido?
Líquido. Envie o valor efetivamente pago depois de descontos, cashback, cupons e promoções, sem frete.
PurchaseValue e OrderTotal são iguais?
PurchaseValue e OrderTotal são iguais?
Não necessariamente.
PurchaseValue é bruto e serve para consultar elegibilidade; OrderTotal é o total líquido da venda concluída.Posso usar mais de uma recompensa no mesmo pedido?
Posso usar mais de uma recompensa no mesmo pedido?
O fluxo POS vincula um
ExternalCode escalar ao campo Coupon. Apresente as opções e permita que o consumidor escolha uma recompensa.Preciso enviar pedidos sem recompensa?
Preciso enviar pedidos sem recompensa?
Sim. Todos os pedidos concluídos devem ser enviados para que a BonifiQ calcule a bonificação.
Posso gerar outra OriginalKey depois de timeout?
Posso gerar outra OriginalKey depois de timeout?
Não. Reutilize a chave persistida até descobrir o resultado da operação original.