Visão Geral
Webhooks permitem que sua aplicação receba notificações automáticas quando eventos importantes ocorrem na API Uvvipague, como mudanças de status de pagamento, liquidação de débitos e conclusão de consultas.
Comunicação Assíncrona : Os webhooks são enviados de forma assíncrona. Configure sua URL para receber as notificações automaticamente.
Correlacionando Requisições e Webhooks : Todos os webhooks incluem o campo externalId que você enviou na requisição original. Use este campo para identificar qual requisição gerou cada webhook. Se você não enviar um externalId, a API gerará um automaticamente, mas é altamente recomendado que você envie seus próprios IDs únicos.
Cadastro de Webhook
Endpoint
POST /uvvi/v1/webhook-register
Parâmetros
URL do endpoint que receberá as notificações webhook. Deve ser uma URL válida e acessível publicamente. Exemplo: https://sua-api.com.br/webhook/uvvipague
Sua API Key para autenticação
Exemplo de Requisição
curl --request POST \
--url 'https://api.uvvipague.com.br/uvvi/v1/webhook-register' \
--header 'x-api-key: SUA_API_KEY_AQUI' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://sua-api.com.br/webhook/uvvipague"
}'
Resposta de Sucesso
{
"request_id" : "req_abc123def456" ,
"status" : "success" ,
"message" : "Webhook cadastrado com sucesso"
}
Política de Retentativas
A Uvvipague implementa uma política robusta de retentativas para garantir que você receba as notificações:
Tentativa Inicial
Enviamos a primeira requisição imediatamente após o evento ocorrer.
1ª Retentativa - 15 minutos
Se não recebermos resposta 200, tentamos novamente após 15 minutos .
2ª Retentativa - 60 minutos
Segunda tentativa após 60 minutos da tentativa inicial.
3ª Retentativa - 90 minutos
Terceira e última tentativa após 90 minutos da tentativa inicial.
Após 3 Retentativas
Após as 3 retentativas sem sucesso, nenhuma nova tentativa será realizada . O cliente precisará consultar o status manualmente usando o transactionId ou o externalId enviado na requisição original.
Importante : Após 3 tentativas falhadas, você deve consultar o status do pedido manualmente através da API de consulta de pagamento.
Timeline de Retentativas
Evento ocorre (t=0)
↓
Tentativa 1 (imediato)
↓ (falha)
Tentativa 2 (t=15min)
↓ (falha)
Tentativa 3 (t=60min)
↓ (falha)
Tentativa 4 (t=90min)
↓ (falha)
Fim das tentativas
Recebendo Webhooks
Estrutura do Payload
Quando um evento ocorre, enviamos uma requisição POST para sua URL cadastrada:
Débitos Encontrados
Veículo Sem Débitos
Veículo Não Encontrado
Erro na Consulta
Pagamento Aprovado
{
"type" : "debts" ,
"transactionId" : 817210768 ,
"externalId" : "c676c954-aa6d-4cb5-a812-c1907a53a442" ,
"vehicle" : {
"uf" : "DF" ,
"document" : "39268450828" ,
"licensePlate" : "DIS9865" ,
"renavam" : "01203988813"
},
"debts" : [
{
"id" : "9547B3A8-05B9-4D1C-8C72-A500BB6D93EF" ,
"amount" : 85.13 ,
"title" : "Infração Vencida - I004242123" ,
"description" : "I004242123 - Infração de Trânsito" ,
"type" : "ticket" ,
"dueDate" : "2024-01-15T00:00:00Z" ,
"isExpired" : true
}
]
}
{
"type" : "VehicleWithoutDebts" ,
"transactionId" : 817622466 ,
"externalId" : "0a384059-eaf0-4240-9dc7-f4125671b4c9" ,
"vehicle" : {
"uf" : "DF" ,
"document" : "3138777503" ,
"licensePlate" : "RCK0E56" ,
"renavam" : "33864569420"
}
}
{
"type" : "VehicleNotFound" ,
"transactionId" : 817211803 ,
"externalId" : "0a384059-eaf0-4240-9dc7-f4125671b4c9"
}
{
"type" : "search-error-event" ,
"status" : "ERROR" ,
"transactionId" : 817211803 ,
"externalId" : "bbf6c1c8-6c60-4806-9454-21a71e1ce1df" ,
"error" : [
{
"errorCode" : "900" ,
"message" : "Serviço indisponível."
}
]
}
{
"type" : "payment-status-update" ,
"paymentId" : "pay_abc123def456" ,
"status" : "paid" ,
"transactionId" : 817210768 ,
"amount" : 1302.86 ,
"paidAt" : "2024-12-15T14:30:00Z" ,
"liquidationStatus" : "settled"
}
Resposta Esperada
Seu endpoint deve retornar HTTP 200 para confirmar o recebimento:
HTTP / 1.1 200 OK
Content-Type : application/json
{
"received" : true
}
Importante : Retorne 200 o mais rápido possível. Processe o webhook de forma assíncrona em sua aplicação para não bloquear a resposta.
Implementação do Endpoint
Exemplo Completo
Node.js + Express
Python + Flask
const express = require ( 'express' );
const app = express ();
app . use ( express . json ());
// Endpoint para receber webhooks
app . post ( '/webhook/uvvipague' , async ( req , res ) => {
try {
// 1. Retorne 200 imediatamente
res . status ( 200 ). json ({ received: true });
// 2. Processe o webhook de forma assíncrona
processWebhookAsync ( req . body );
} catch ( error ) {
console . error ( 'Erro ao receber webhook:' , error );
res . status ( 500 ). json ({ error: 'Internal server error' });
}
});
async function processWebhookAsync ( payload ) {
const { type , transactionId , externalId } = payload ;
console . log ( `Webhook recebido: ${ type } ` );
console . log ( `Transaction ID: ${ transactionId } ` );
console . log ( `External ID: ${ externalId } ` );
// Processar baseado no tipo
switch ( type ) {
case 'debts' :
await handleDebtsFound ( payload );
break ;
case 'VehicleWithoutDebts' :
await handleNoDebts ( payload );
break ;
case 'VehicleNotFound' :
await handleVehicleNotFound ( payload );
break ;
case 'search-error-event' :
await handleSearchError ( payload );
break ;
case 'payment-status-update' :
await handlePaymentUpdate ( payload );
break ;
default :
console . warn ( `Tipo de webhook desconhecido: ${ type } ` );
}
}
async function handleDebtsFound ( payload ) {
const { transactionId , debts } = payload ;
// Salvar débitos no banco de dados
await database . debts . create ({
transactionId ,
debts: debts ,
status: 'found' ,
receivedAt: new Date ()
});
// Notificar cliente
await notifyClient ( transactionId , 'Débitos encontrados' );
}
async function handlePaymentUpdate ( payload ) {
const { paymentId , status , liquidationStatus } = payload ;
// Atualizar status do pagamento
await database . payments . update (
{ paymentId },
{
status ,
liquidationStatus ,
updatedAt: new Date ()
}
);
// Se pago e liquidado, liberar serviço
if ( status === 'paid' && liquidationStatus === 'settled' ) {
await releaseService ( paymentId );
}
}
app . listen ( 3000 , () => {
console . log ( 'Servidor rodando na porta 3000' );
});
Segurança
Validações Recomendadas
Valide que a requisição vem dos servidores da Uvvipague:
Verifique o IP de origem (lista fornecida pelo suporte)
Implemente whitelist de IPs
Valide a estrutura do payload antes de processar: function isValidWebhook ( payload ) {
return payload . type &&
payload . transactionId &&
payload . externalId ;
}
Implemente idempotência usando transactionId ou externalId: async function processWebhook ( payload ) {
const { transactionId , externalId } = payload ;
// Verificar se já foi processado usando externalId
const exists = await database . webhooks . findOne ({ externalId });
if ( exists ) {
console . log ( 'Webhook já processado' );
return ;
}
// Processar e marcar como processado
await processPayload ( payload );
await database . webhooks . create ({
transactionId ,
externalId ,
processedAt: new Date ()
});
}
Configure timeout adequado no seu servidor:
Responda em menos de 5 segundos
Processe de forma assíncrona
Use filas (Redis, RabbitMQ) para processamento
Consulta Manual de Status
Se todas as tentativas de webhook falharem, consulte o status manualmente:
Endpoint de Consulta
POST /uvvi/v1/payment/status
curl --request POST \
--url 'https://api.uvvipague.com.br/uvvi/v1/payment/status' \
--header 'x-api-key: SUA_API_KEY_AQUI' \
--header 'Content-Type: application/json' \
--data '{
"paymentId": "pay_abc123def456"
}'
Testando Webhooks
Ferramentas Úteis
Webhook.site Use webhook.site para testar e visualizar webhooks durante o desenvolvimento.
ngrok Use ngrok para expor seu localhost e receber webhooks em desenvolvimento.
RequestBin Use RequestBin para inspecionar payloads de webhook.
Postman Simule webhooks usando Postman para testar seu endpoint.
# 1. Instale o ngrok
npm install -g ngrok
# 2. Inicie seu servidor local
node server.js # rodando na porta 3000
# 3. Exponha com ngrok
ngrok http 3000
# 4. Use a URL gerada para cadastrar o webhook
# Exemplo: https://abc123.ngrok.io/webhook/uvvipague
Boas Práticas
Responda Rapidamente
Retorne HTTP 200 em menos de 5 segundos. Processe o webhook de forma assíncrona.
Implemente Idempotência
Use transactionId ou externalId para evitar processar o mesmo webhook múltiplas vezes.
Log Tudo
Registre todos os webhooks recebidos para auditoria e debugging.
Use Filas
Implemente filas (Redis, RabbitMQ, SQS) para processar webhooks de forma resiliente.
Monitore Falhas
Configure alertas para webhooks que falharem após todas as retentativas.
Tenha Fallback
Implemente consulta periódica de status como fallback caso os webhooks falhem.
Próximos Passos