> ## Documentation Index
> Fetch the complete documentation index at: https://developers.uvvipague.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Consulta de Débitos

> Consulte débitos veiculares como multas, IPVA, licenciamento e taxas através da API Uvvipague

## Visão Geral

A API de Consulta de Débitos permite buscar todos os débitos pendentes de um veículo de forma assíncrona. O sistema gera um pedido de consulta que é processado e retorna os resultados via webhook.

<Info>
  **Processamento Assíncrono**: A consulta é processada de forma assíncrona. Os resultados são enviados via webhook quando a consulta for concluída.
</Info>

## Como Funciona

O fluxo de consulta de débitos segue estas etapas:

<Steps>
  <Step title="Enviar Requisição">
    Faça uma requisição POST com os dados do veículo (placa, renavam, CPF/CNPJ)
  </Step>

  <Step title="Receber Confirmação">
    A API retorna imediatamente confirmando que a consulta foi iniciada
  </Step>

  <Step title="Aguardar Processamento">
    O sistema consulta os débitos nos sistemas dos Detrans
  </Step>

  <Step title="Receber Webhook">
    Quando concluída, os resultados são enviados para sua URL de webhook configurada
  </Step>
</Steps>

## Endpoint

```http theme={null}
POST /uvvi/v1/debts
```

## Parâmetros da Requisição

<ParamField body="state" type="string" required>
  Sigla do estado (UF) onde o veículo está registrado. Exemplo: `SP`, `RJ`, `MG`
</ParamField>

<ParamField body="licensePlate" type="string" required>
  Placa do veículo no formato ABC1234 ou ABC1D23 (Mercosul)
</ParamField>

<ParamField body="renavam" type="string" required>
  Número do RENAVAM do veículo (11 dígitos)
</ParamField>

<ParamField body="cpfCnpj" type="string" required>
  CPF ou CNPJ do proprietário do veículo (apenas números)
</ParamField>

<ParamField body="externalId" type="string" optional>
  Identificador único (UUID) para rastreamento da consulta no seu sistema. Este mesmo ID será retornado nos webhooks para correlação.
</ParamField>

<Note>
  **Sobre o externalId**: Este campo é opcional mas **altamente recomendado**. Envie um UUID único gerado pelo seu sistema para rastrear a consulta. A API retornará este mesmo valor no campo `externalId` da resposta e dos webhooks, permitindo que você correlacione facilmente as notificações com as requisições originais.
</Note>

## Exemplo de Requisição

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://api.uvvipague.com.br/uvvi/v1/debts' \
    --header 'x-api-key: SUA_API_KEY_AQUI' \
    --header 'Content-Type: application/json' \
    --data '{
      "state": "DF",
      "licensePlate": "JFI8753",
      "renavam": "56387604559",
      "cpfCnpj": "11111111111",
      "externalId": "550e8400-e29b-41d4-a716-446655440000"
    }'
  ```

  ```javascript JavaScript theme={null}
  const requestBody = {
    state: "DF",
    licensePlate: "JFI8753",
    renavam: "56387604559",
    cpfCnpj: "11111111111",
    externalId: "550e8400-e29b-41d4-a716-446655440000"
  };

  const options = {
    method: 'POST',
    headers: {
      'x-api-key': 'SUA_API_KEY_AQUI',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(requestBody)
  };

  fetch('https://api.uvvipague.com.br/uvvi/v1/debts', options)
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Erro:', error));
  ```

  ```python Python theme={null}
  import requests
  import uuid

  url = "https://api.uvvipague.com.br/uvvi/v1/debts"
  headers = {
      "x-api-key": "SUA_API_KEY_AQUI",
      "Content-Type": "application/json"
  }
  payload = {
      "state": "DF",
      "licensePlate": "JFI8753",
      "renavam": "56387604559",
      "cpfCnpj": "11111111111",
      "externalId": str(uuid.uuid4())
  }

  response = requests.post(url, headers=headers, json=payload)
  data = response.json()
  print(data)
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  $payload = json_encode([
      "state" => "DF",
      "licensePlate" => "JFI8753",
      "renavam" => "56387604559",
      "cpfCnpj" => "11111111111",
      "externalId" => "550e8400-e29b-41d4-a716-446655440000"
  ]);

  curl_setopt_array($curl, [
      CURLOPT_URL => "https://api.uvvipague.com.br/uvvi/v1/debts",
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_POST => true,
      CURLOPT_POSTFIELDS => $payload,
      CURLOPT_HTTPHEADER => [
          "x-api-key: SUA_API_KEY_AQUI",
          "Content-Type: application/json"
      ],
  ]);

  $response = curl_exec($curl);
  curl_close($curl);

  $data = json_decode($response, true);
  print_r($data);
  ?>
  ```
</CodeGroup>

## Resposta Imediata

Ao enviar a requisição, você recebe uma confirmação imediata:

```json theme={null}
{
  "message": "Consulta iniciada com sucesso",
  "transactionId": 817210768,
  "externalId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "PROCESSING"
}
```

## Respostas via Webhook

Os resultados da consulta são enviados via webhook. Existem diferentes tipos de resposta:

### 1. Veículo com Débitos

Quando o veículo possui débitos pendentes:

```json theme={null}
{
  "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",
      "ait": "5E0083715",
      "dueDate": null,
      "expirationDate": null,
      "hasDiscount": false,
      "isExpired": true,
      "type": "ticket",
      "year": null,
      "required": false,
      "dependsOn": [],
      "distinct": []
    },
    {
      "id": "312D6A5F-2B5A-4694-84DA-F640FC01CC74",
      "amount": 1009.36,
      "title": "Licenciamento 2022",
      "description": "Licenciamento 2022",
      "dueDate": null,
      "expirationDate": "2022-12-28T00:00:00Z",
      "hasDiscount": false,
      "isExpired": true,
      "type": "licensing",
      "year": 2022,
      "required": false,
      "dependsOn": [],
      "distinct": []
    }
  ]
}
```

### 2. Veículo sem Débitos

Quando o veículo não possui débitos:

```json theme={null}
{
  "type": "VehicleWithoutDebts",
  "transactionId": 817622466,
  "externalId": "0a384059-eaf0-4240-9dc7-f4125671b4c9",
  "vehicle": {
    "uf": "DF",
    "document": "3138777503",
    "licensePlate": "RCK0E56",
    "renavam": "33864569420"
  }
}
```

### 3. Veículo Não Encontrado

Quando o veículo não é encontrado nos sistemas do Detran:

```json theme={null}
{
  "type": "VehicleNotFound",
  "transactionId": 817211803,
  "externalId": "0a384059-eaf0-4240-9dc7-f4125671b4c9"
}
```

### 4. Erro na Consulta

Quando há erro nos sistemas do Detran:

```json theme={null}
{
  "type": "search-error-event",
  "status": "ERROR",
  "transactionId": 817211803,
  "externalId": "bbf6c1c8-6c60-4806-9454-21a71e1ce1df",
  "error": [
    {
      "errorCode": "900",
      "message": "Serviço indisponível."
    }
  ]
}
```

## Estrutura dos Débitos

Cada débito retornado contém as seguintes informações:

<ResponseField name="id" type="string">
  Identificador único do débito (UUID)
</ResponseField>

<ResponseField name="amount" type="number">
  Valor do débito em reais
</ResponseField>

<ResponseField name="title" type="string">
  Título descritivo do débito
</ResponseField>

<ResponseField name="description" type="string">
  Descrição detalhada do débito
</ResponseField>

<ResponseField name="type" type="string">
  Tipo do débito: `ticket` (multa), `ipva`, `licensing` (licenciamento), `service` (taxa)
</ResponseField>

<ResponseField name="dueDate" type="string">
  Data de vencimento original (formato ISO 8601)
</ResponseField>

<ResponseField name="expirationDate" type="string">
  Data de vencimento com juros/multa (formato ISO 8601)
</ResponseField>

<ResponseField name="hasDiscount" type="boolean">
  Indica se o débito possui desconto disponível
</ResponseField>

<ResponseField name="isExpired" type="boolean">
  Indica se o débito está vencido
</ResponseField>

<ResponseField name="year" type="number">
  Ano de referência do débito (para IPVA e licenciamento)
</ResponseField>

<ResponseField name="required" type="boolean">
  Indica se o débito é obrigatório para licenciamento
</ResponseField>

<ResponseField name="dependsOn" type="array">
  Lista de IDs de débitos que precisam ser pagos junto com este
</ResponseField>

<ResponseField name="distinct" type="array">
  Lista de IDs de débitos que não podem ser pagos junto com este
</ResponseField>

<ResponseField name="ait" type="string">
  Número do Auto de Infração de Trânsito (apenas para multas)
</ResponseField>

## Tipos de Débitos

<CardGroup cols={2}>
  <Card title="Multas (ticket)" icon="triangle-exclamation">
    Infrações de trânsito e multas gerenciadas pelo RENAINF
  </Card>

  <Card title="IPVA (ipva)" icon="car">
    Imposto sobre Propriedade de Veículos Automotores (cota única ou parcelada)
  </Card>

  <Card title="Licenciamento (licensing)" icon="file-certificate">
    Taxa anual de licenciamento do veículo
  </Card>

  <Card title="Taxas (service)" icon="receipt">
    Taxas de serviços diversos, como multa de pátio
  </Card>
</CardGroup>

## Dependências entre Débitos

Alguns débitos possuem dependências que devem ser respeitadas no momento do pagamento:

### dependsOn (Dependências)

Lista de débitos que **devem ser pagos junto** com o débito atual. Por exemplo, uma multa pode depender do pagamento do IPVA.

```json theme={null}
{
  "id": "DEBITO-A",
  "amount": 100.00,
  "title": "Multa de Trânsito",
  "dependsOn": ["DEBITO-B", "DEBITO-C"]
}
```

Neste caso, para pagar o DEBITO-A, você também deve incluir DEBITO-B e DEBITO-C no pagamento.

### distinct (Exclusões)

Lista de débitos que **não podem ser pagos junto** com o débito atual. Por exemplo, IPVA cota única não pode ser pago junto com parcelas.

```json theme={null}
{
  "id": "IPVA-COTA-UNICA",
  "amount": 1500.00,
  "title": "IPVA 2024 - Cota Única",
  "distinct": ["IPVA-PARCELA-1", "IPVA-PARCELA-2", "IPVA-PARCELA-3"]
}
```

## Limitações por Estado

<Warning>
  **Atenção**: Alguns estados possuem limitações específicas nas consultas.
</Warning>

### Estados com IPVA Cota Única Apenas

Os seguintes estados retornam **apenas IPVA em cota única**:

* Goiás (GO)
* Maranhão (MA)
* Mato Grosso do Sul (MS)
* Rio Grande do Sul (RS)

### Manutenção São Paulo

<Note>
  **São Paulo (SP)**: O Detran-SP realiza manutenções diárias entre **00h e 07h**. Durante este período, não é possível realizar consultas para veículos de SP.
</Note>

## Validações

### Validação de RENAVAM

A API valida automaticamente o dígito verificador do RENAVAM antes de processar a consulta:

<AccordionGroup>
  <Accordion title="RENAVAM Válido" icon="circle-check">
    Se o RENAVAM for válido, a consulta prossegue normalmente.
  </Accordion>

  <Accordion title="RENAVAM Inválido" icon="circle-xmark">
    Se o dígito verificador for inválido, a API retorna erro imediatamente:

    ```json theme={null}
    {
      "error": "Bad Request",
      "message": "RENAVAM inválido. Verifique o dígito verificador.",
      "statusCode": 400
    }
    ```

    Esta validação ocorre tanto em **sandbox** quanto em **produção**.
  </Accordion>
</AccordionGroup>

## Códigos de Erro

<ResponseField name="400" type="Bad Request">
  Dados inválidos na requisição (RENAVAM inválido, campos obrigatórios ausentes, etc.)
</ResponseField>

<ResponseField name="401" type="Unauthorized">
  API Key inválida ou ausente
</ResponseField>

<ResponseField name="404" type="Not Found">
  Veículo não encontrado nos sistemas do Detran
</ResponseField>

<ResponseField name="429" type="Too Many Requests">
  Limite de requisições excedido
</ResponseField>

<ResponseField name="500" type="Server Error">
  Erro interno do servidor
</ResponseField>

<ResponseField name="503" type="Service Unavailable">
  Serviço do Detran temporariamente indisponível
</ResponseField>

### Códigos de Erro Específicos

| Código | Descrição                                   |
| ------ | ------------------------------------------- |
| 900    | Serviço indisponível                        |
| 901    | Timeout na consulta ao Detran               |
| 902    | Dados inconsistentes retornados pelo Detran |
| 903    | Manutenção programada do Detran             |

## Boas Práticas

<Steps>
  <Step title="Configure Webhooks">
    Configure corretamente sua URL de webhook para receber os resultados das consultas. Veja [Configuração de Webhooks](/api-reference/endpoint/webhook).
  </Step>

  <Step title="Use externalId">
    Sempre envie um `externalId` único para rastrear a consulta no seu sistema e correlacionar com o webhook recebido.
  </Step>

  <Step title="Valide os Dados">
    Valide placa, RENAVAM e CPF/CNPJ antes de enviar para evitar erros desnecessários.
  </Step>

  <Step title="Trate Dependências">
    Ao processar débitos, respeite os campos `dependsOn` e `distinct` para garantir pagamentos corretos.
  </Step>

  <Step title="Implemente Retry">
    Em caso de erro 503 (serviço indisponível), implemente retry com backoff exponencial.
  </Step>

  <Step title="Cache Inteligente">
    Considere cachear resultados por algumas horas para evitar consultas duplicadas do mesmo veículo.
  </Step>
</Steps>

## Exemplo Completo de Integração

<CodeGroup>
  ```javascript Node.js theme={null}
  const express = require('express');
  const app = express();

  app.use(express.json());

  // Endpoint para iniciar consulta
  app.post('/consultar-debitos', async (req, res) => {
    const { placa, renavam, cpfCnpj, estado } = req.body;
    
    const payload = {
      state: estado,
      licensePlate: placa,
      renavam: renavam,
      cpfCnpj: cpfCnpj,
      externalId: generateUUID()
    };
    
    try {
      const response = await fetch(
        'https://api.uvvipague.com.br/uvvi/v1/debts',
        {
          method: 'POST',
          headers: {
            'x-api-key': process.env.UVVIPAGUE_API_KEY,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(payload)
        }
      );
      
      const data = await response.json();
      
      // Salvar transactionId no banco para correlacionar com webhook
      await salvarConsulta({
        transactionId: data.transactionId,
        externalId: payload.externalId,
        status: 'PROCESSING'
      });
      
      res.json(data);
    } catch (error) {
      res.status(500).json({ error: 'Erro ao consultar débitos' });
    }
  });

  // Webhook para receber resultados
  app.post('/webhook/debts', async (req, res) => {
    const resultado = req.body;
    
    // Processar resultado baseado no tipo
    switch (resultado.type) {
      case 'debts':
        await processarDebitos(resultado);
        break;
      case 'VehicleWithoutDebts':
        await processarSemDebitos(resultado);
        break;
      case 'VehicleNotFound':
        await processarNaoEncontrado(resultado);
        break;
      case 'search-error-event':
        await processarErro(resultado);
        break;
    }
    
    // Sempre retornar 200 para confirmar recebimento
    res.status(200).json({ received: true });
  });

  function generateUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0;
      const v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }
  ```

  ```python Python theme={null}
  from flask import Flask, request, jsonify
  import requests
  import uuid
  import os

  app = Flask(__name__)

  API_KEY = os.getenv('UVVIPAGUE_API_KEY')

  @app.route('/consultar-debitos', methods=['POST'])
  def consultar_debitos():
      data = request.json
      
      payload = {
          'state': data['estado'],
          'licensePlate': data['placa'],
          'renavam': data['renavam'],
          'cpfCnpj': data['cpfCnpj'],
          'externalId': str(uuid.uuid4())
      }
      
      try:
          response = requests.post(
              'https://api.uvvipague.com.br/uvvi/v1/debts',
              headers={
                  'x-api-key': API_KEY,
                  'Content-Type': 'application/json'
              },
              json=payload
          )
          
          resultado = response.json()
          
          # Salvar no banco para correlacionar com webhook
          salvar_consulta({
              'transactionId': resultado['transactionId'],
              'externalId': payload['externalId'],
              'status': 'PROCESSING'
          })
          
          return jsonify(resultado)
      except Exception as e:
          return jsonify({'error': 'Erro ao consultar débitos'}), 500

  @app.route('/webhook/debts', methods=['POST'])
  def webhook_debitos():
      resultado = request.json
      
      # Processar resultado baseado no tipo
      tipo = resultado.get('type')
      
      if tipo == 'debts':
          processar_debitos(resultado)
      elif tipo == 'VehicleWithoutDebts':
          processar_sem_debitos(resultado)
      elif tipo == 'VehicleNotFound':
          processar_nao_encontrado(resultado)
      elif tipo == 'search-error-event':
          processar_erro(resultado)
      
      # Sempre retornar 200
      return jsonify({'received': True}), 200
  ```
</CodeGroup>

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Configurar Webhooks" icon="webhook" href="/api-reference/endpoint/webhook">
    Configure webhooks para receber os resultados das consultas.
  </Card>

  <Card title="Fluxo Completo" icon="diagram-project" href="/fluxo-completo">
    Veja o fluxo completo incluindo pagamento dos débitos.
  </Card>

  <Card title="Enriquecimento de Placa" icon="magnifying-glass-chart" href="/enriquecimento-placa">
    Consulte dados do veículo antes de buscar débitos.
  </Card>

  <Card title="Autenticação" icon="key" href="/autenticacao">
    Entenda como autenticar suas requisições.
  </Card>
</CardGroup>
