Skip to main content

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
string
required
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

Headers Obrigatórios

x-api-key
string
required
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:
1

Tentativa Inicial

Enviamos a primeira requisição imediatamente após o evento ocorrer.
2

1ª Retentativa - 15 minutos

Se não recebermos resposta 200, tentamos novamente após 15 minutos.
3

2ª Retentativa - 60 minutos

Segunda tentativa após 60 minutos da tentativa inicial.
4

3ª Retentativa - 90 minutos

Terceira e última tentativa após 90 minutos da tentativa inicial.
5

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:
{
  "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
    }
  ]
}

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

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.

Exemplo com ngrok

# 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

1

Responda Rapidamente

Retorne HTTP 200 em menos de 5 segundos. Processe o webhook de forma assíncrona.
2

Implemente Idempotência

Use transactionId ou externalId para evitar processar o mesmo webhook múltiplas vezes.
3

Log Tudo

Registre todos os webhooks recebidos para auditoria e debugging.
4

Use Filas

Implemente filas (Redis, RabbitMQ, SQS) para processar webhooks de forma resiliente.
5

Monitore Falhas

Configure alertas para webhooks que falharem após todas as retentativas.
6

Tenha Fallback

Implemente consulta periódica de status como fallback caso os webhooks falhem.

Próximos Passos