Webhooks
Nas outras páginas, o seu sistema chama a Enjoy.it. Aqui é o contrário: a Enjoy.it chama o seu sistema quando algo acontece na loja.
Nesta API os webhooks também são chamados de IPN — é a razão de os campos se chamarem
consumptionIpn, balanceIpn e openTapIpn. São a mesma coisa.
Webhook só funciona se o seu sistema tiver um endereço público na internet, com HTTPS, ligado 24 horas por dia. Um PDV instalado dentro da loja, sem endereço público, não consegue receber webhooks — nesse caso use consulta na API.
A explicação está em Escolha sua integração.
Eventos disponíveis
| Campo | Direção | Para que serve | Método |
|---|---|---|---|
consumptionIpn | Enjoy.it → você | Avisar que um consumo foi concluído | POST |
balanceIpn | Enjoy.it → você | Perguntar o saldo antes de liberar consumo | GET |
openTapIpn | Enjoy.it → você | Avisar que o estado da torneira mudou | POST |
As URLs podem ser configuradas no cadastro do parceiro ou enviadas no check-in de cada sessão.
Notificação de consumo
O evento principal. A Enjoy.it faz um POST na URL de consumptionIpn depois de cada servida:
{
"createdAt": "2026-08-02T19:43:29.416Z",
"transactionReference": "pedido-987",
"idPlace": "P-EXEMPLO",
"idTap": "T-01",
"idTab": "006",
"rfid": "4623227593",
"sku": "IPA-001",
"consumerReference": "cliente-123",
"product": "IPA da Casa",
"mlServed": 320,
"total": 12.8,
"uid": "5FS6DS0BDERIWG9QL6ojfuLedg23",
"type": "D"
}
O que o seu sistema faz com isso:
| Campo | Uso |
|---|---|
idTab, rfid ou consumerReference | Achar de quem é a conta |
total | O valor a lançar. Já vem calculado |
product e mlServed | A descrição do item para o cliente |
uid + createdAt | A identificação da transação. Use para não lançar duas vezes |
A ordem correta do seu lado:
1. Recebe o POST
2. Verifica se uid + createdAt já foram gravados
- Já gravou? Responda 2xx e pare aqui
3. Lança na conta do cliente
4. Grava o identificador
5. Só agora responde 2xx
A sua resposta de sucesso também dá a baixa da transação (o ack): ela deixa de aparecer na lista de transações não confirmadas. Em integrações por webhook não é preciso chamar o endpoint de confirmação — ele existe para quem importa por consulta.
Responder 2xx antes de gravar dá baixa em um consumo que você ainda não lançou. Se o seu sistema
cair em seguida, o evento não será reenviado e não aparecerá nas pendências: aquele consumo não
será cobrado do cliente.
Reentregas
Quando o seu sistema não responde com sucesso, a Enjoy.it tenta de novo:
| Número de tentativas | Até 5 |
| Intervalo entre tentativas | 15 minutos |
| Quando para | Assim que receber uma resposta de sucesso |
| Depois da 5ª tentativa | O evento não é mais reenviado |
Isso cobre bem uma indisponibilidade curta — um deploy, um reinício —, mas repare no intervalo: a primeira reentrega só acontece 15 minutos depois. Uma falha durante o atendimento pode não se recuperar antes de o cliente ir embora.
Por isso a reentrega não elimina a conferência final nem a rotina de recuperação descritas no fim desta página.
E, como o mesmo consumo pode chegar mais de uma vez, a verificação de uid + createdAt antes de
lançar é obrigatória: é ela que impede a cobrança em dobro quando a sua resposta se perde mas o
lançamento foi feito.
Consulta de saldo
Antes de liberar a torneira em um fluxo com limite, a Enjoy.it faz um GET na URL de balanceIpn
para perguntar quanto o cliente ainda tem. A URL pode conter variáveis, substituídas no momento da
chamada:
https://parceiro.exemplo.com/saldos/{consumerReference}?place={idPlace}&tab={idTab}&rfid={rfid}
Variáveis disponíveis: {idPlace}, {idTab}, {rfid} e {consumerReference}.
Resposta esperada, 200:
{
"balance": 80
}
O valor é em reais e deve representar o saldo disponível naquele instante. Este endereço fica no caminho crítico do atendimento: se demorar a responder, o cliente espera na torneira.
Estado da torneira
A Enjoy.it faz um POST na URL de openTapIpn quando o estado da abertura muda:
{
"idPlace": "P-EXEMPLO",
"idTap": "T-01",
"status": "serving",
"consumerReference": "cliente-123",
"transactionReference": "pedido-987"
}
Responda 2xx para confirmar o recebimento.
Requisitos do seu endereço
- Aceite HTTPS com certificado público válido — certificado autoassinado não serve.
- Responda rápido. Processe tarefas demoradas de forma assíncrona, depois de responder.
- Trate cada evento de forma idempotente, usando
uid+createdAt. - Guarde log com
idPlace,consumerReferenceetransactionReference. - Não dependa da ordem de chegada. Dois consumos seguidos podem chegar fora de ordem.
- Valide a credencial combinada na homologação, quando houver.
Problemas comuns
| Sintoma | Causa provável |
|---|---|
| Nenhum webhook chega | consumptionIpn não foi informado no check-in, ou o endereço não é acessível de fora |
| Chegam alguns e outros não | Seu endereço está lento ou instável e as chamadas expiram |
| Cliente cobrado em dobro | Falta a verificação de uid + createdAt antes de lançar |
| Consumo sumiu | Você respondeu 2xx antes de gravar |
| Só funciona na rede da loja | O endereço é interno; não é alcançável pela internet |
Recuperação: o webhook não basta sozinho
Mesmo com tudo certo, um evento pode se perder — queda de rede, deploy, servidor reiniciando. Por isso, mantenha sempre uma rotina de conferência com transações não confirmadas.
Como a baixa é dada pela sua resposta de sucesso, essa lista contém exatamente os consumos que não chegaram a ser processados — os que falharam e os que esgotaram as 5 tentativas. Não é preciso varrer o extrato inteiro nem comparar com o seu banco: o que está lá é o que falta lançar.
Se você lançar algum consumo a partir dessa lista, dê baixa nele pelo endpoint de confirmação. Fora do webhook a baixa não é automática, e sem ela o mesmo consumo reaparece na próxima verificação.
E, na hora de fechar a conta, faça uma consulta final ao extrato do cliente. É a rede de segurança mais simples que existe.