Documentação

API RodoData v1

Integre consultas de transporte e leitura de documentos com exemplos prontos, respostas previsíveis e rastreabilidade por requisição.

Comece aqui

Primeira chamada em poucos minutos

Crie uma chave em API Keys, mantenha-a somente no servidor e envie-a no header Authorization. A URL base da API é:

Base URL
https://rododata.com/v1
Não coloque a API Key no navegador.

Use variáveis de ambiente ou um gerenciador de segredos no seu backend. A chave completa é exibida apenas no momento da criação.

Exemplo rápido — ANTT / RNTRC

cURL
curl -X POST https://rododata.com/v1/antt/rntrc/vehicle \
  -H "Authorization: Bearer $RODODATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"document":"12345678000199","plate":"ABC1D23"}'

Uma resposta bem-sucedida segue este envelope:

HTTP 200
{
  "success": true,
  "data": {
    "dt_cadastro": "2025-01-15T00:00:00Z",
    "apto_transporte_remunerado": true,
    "endereco_municipio": "CURITIBA",
    "endereco_uf": "PR",
    "mensagem": "",
    "rntrc": "01234567",
    "situacao": "ATIVO",
    "transportador": "EMPRESA EXEMPLO LTDA",
    "documento_transportador": "12345678000199",
    "veiculo_tipo": "TRATOR",
    "placa": "ABC1D23"
  },
  "processing_time_ms": 842,
  "credits_used": 5,
  "credits_remaining": 95,
  "request_id": "req_..."
}
Segurança

Autenticação Bearer

Endpoints comerciais exigem uma API Key ativa e com o escopo correto.

Header
Authorization: Bearer rd_live_xxxxxxxxx

Escopo VIO

vio:decode

Permite decodificar documentos VIO.

Escopo CIN [Beta]

cin:analyze

Permite validar o QR/JWT da Carteira de Identidade Nacional.

Escopo ANTT

antt:rntrc

Permite consultar RNTRC por documento e placa.

Uma chave sem o escopo necessário recebe 403 FORBIDDEN. Uma chave ausente, inválida ou revogada recebe 401 UNAUTHORIZED.

Proteção

Rate limit

O limite padrão atual é de 120 requisições por minuto por API Key. A API informa o estado do limite nos headers:

Headers
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1789398120

X-RateLimit-Reset é um timestamp Unix. Ao exceder o limite, a API responde 429 RATE_LIMITED.

Documentos

VIO API

POST/v1/vio/decode1 crédito

PDF é o formato recomendado. Envie o arquivo original da CNH, CRLV ou outro documento VIO no campo file. Além de localizar e validar o QR Code, a RodoData analisa metadados, assinatura digital do PDF, cobertura da revisão assinada, certificado do signatário e alterações posteriores. PNG, JPEG e GIF continuam disponíveis como alternativa.

PDF original libera a camada profunda.

O processamento considera até as 20 primeiras páginas do PDF e interrompe assim que encontra um QR Code compatível. Em CNH Digital, a resposta também pode trazer a foto visual extraída do PDF para comparação com a foto embarcada no QR VIO.

PDF — formato recomendado

cURL
curl -X POST https://rododata.com/v1/vio/decode \
  -H "Authorization: Bearer $RODODATA_API_KEY" \
  -F "file=@cnh.pdf;type=application/pdf"
Node.js
Node.js
import fs from "node:fs";

const form = new FormData();
form.append(
  "file",
  new Blob([fs.readFileSync("cnh.pdf")], { type: "application/pdf" }),
  "cnh.pdf"
);

const response = await fetch("https://rododata.com/v1/vio/decode", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.RODODATA_API_KEY
  },
  body: form
});

const data = await response.json();
if (!response.ok) throw new Error(data.error?.message || "Erro na API RodoData");
console.log(data);
Python
Python
import os
import requests

with open("cnh.pdf", "rb") as document:
    response = requests.post(
        "https://rododata.com/v1/vio/decode",
        headers={"Authorization": f"Bearer {os.environ['RODODATA_API_KEY']}"},
        files={"file": ("cnh.pdf", document, "application/pdf")},
        timeout=30,
    )

response.raise_for_status()
print(response.json())
PHP
PHP
<?php

$ch = curl_init('https://rododata.com/v1/vio/decode');
$file = new CURLFile('cnh.pdf', 'application/pdf', 'cnh.pdf');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('RODODATA_API_KEY'),
    ],
    CURLOPT_POSTFIELDS => ['file' => $file],
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException($data['error']['message'] ?? 'Erro na API RodoData');
}
print_r($data);
Go
Go
package main

import (
    "bytes"
    "encoding/json"
    "io"
    "mime/multipart"
    "net/http"
    "os"
    "path/filepath"
)

func main() {
    var body bytes.Buffer
    writer := multipart.NewWriter(&body)
    file, _ := os.Open("cnh.pdf")
    defer file.Close()

    part, _ := writer.CreateFormFile("file", filepath.Base(file.Name()))
    _, _ = io.Copy(part, file)
    _ = writer.Close()

    req, _ := http.NewRequest(http.MethodPost,
        "https://rododata.com/v1/vio/decode", &body)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("RODODATA_API_KEY"))
    req.Header.Set("Content-Type", writer.FormDataContentType())

    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()

    var result any
    _ = json.NewDecoder(resp.Body).Decode(&result)
}
C#
C#
using System.Net.Http.Headers;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("RODODATA_API_KEY"));

await using var stream = File.OpenRead("cnh.pdf");
using var content = new MultipartFormDataContent();
using var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(file, "file", "cnh.pdf");

var response = await client.PostAsync("https://rododata.com/v1/vio/decode", content);
var body = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
Console.WriteLine(body);

Imagem ou Base64

Se o documento já estiver em imagem, envie PNG, JPEG ou GIF no mesmo campo file. Para integrações que já trabalham com imagem Base64, o JSON abaixo continua aceito.

JSON
{
  "image_base64": "data:image/png;base64,iVBORw0KGgoAAA..."
}

Resposta normalizada

O envelope é estável entre os documentos reconhecidos. Os campos específicos ficam em data. Quando a entrada é PDF, pdf.source_integrity distingue PDF assinado íntegro, dados externos anexados, alteração posterior e PDF sem assinatura; pdf.consistency cruza inclusive alegações textuais de assinatura com a assinatura real do arquivo; pdf.images registra dimensões, formato, objeto PDF, hashes e fingerprint do perfil JPEG das imagens internas; media.qr_photo e media.pdf_photo permitem apresentação comparativa quando disponíveis.

HTTP 200
{
  "success": true,
  "document": {
    "type": "cnh",
    "name": "CNH",
    "template_id": 83,
    "issuer": "SENATRAN",
    "recognized": true
  },
  "validation": {
    "signature_checked": true,
    "signature_valid": true,
    "signature_algorithm": "ECDSA",
    "certificate_id": "...",
    "qr_created_at": "2026-09-14T12:00:00Z"
  },
  "authenticity": {
    "status": "verified",
    "warnings": []
  },
  "pdf": {
    "metadata": {
      "title": "CNH Digital",
      "creator": "CDT",
      "producer": "CDT"
    },
    "digital_signature": {
      "present": true,
      "cryptographically_valid": true,
      "signer": "DETRAN PR",
      "icp_brasil_detected": true,
      "signing_time_within_certificate_validity": true
    },
    "integrity": {
      "signed_revision_covers_file": true,
      "signed_pdf_revision_complete": true,
      "unsigned_bytes_after_signature": false,
      "trailing_unsigned_bytes": 0,
      "active_pdf_changes_after_signature": false
    },
    "source_integrity": {
      "status": "signed_pdf_intact"
    },
    "consistency": {
      "text_evidence_checked": true,
      "visible_digital_signature_claim": true,
      "serpro_validation_reference": true,
      "signature_claim_matches_pdf": true
    },
    "images": {
      "count": 5,
      "profile_version": "pdfimages-v1",
      "structural_sha256": "...",
      "object_graph_sha256": "...",
      "front_candidate_detected": true,
      "images": [
        {
          "index": 0,
          "width": 963,
          "height": 680,
          "color_space": "rgb",
          "bits_per_component": 8,
          "encoding": "jpeg",
          "object_id": 20,
          "x_ppi": 287,
          "y_ppi": 275,
          "content_sha256": "...",
          "jpeg": {
            "jfif": true,
            "exif_present": false,
            "xmp_present": false,
            "icc_profile_present": false,
            "photoshop_app13_present": false,
            "adobe_app14_present": false,
            "quantization_sha256": "...",
            "huffman_sha256": "...",
            "marker_profile_sha256": "..."
          }
        }
      ]
    }
  },
  "media": {
    "qr_photo": {
      "source": "vio_qr",
      "mime": "image/png",
      "base64": "..."
    },
    "pdf_photo": {
      "source": "pdf_visual",
      "mime": "image/png",
      "base64": "...",
      "extraction": "pdfimages_cnh_front_crop_v1",
      "width": 183,
      "height": 272,
      "sha256": "..."
    }
  },
  "data": {
    "nome": "NOME EXEMPLO",
    "categoria": "B"
  },
  "meta": {
    "qr_version": 6,
    "input_encoding": "api-pdf",
    "credits_used": 1,
    "credits_remaining": 99,
    "request_id": "req_..."
  }
}

Catálogo de documentos

Os endpoints de catálogo são públicos e não consomem créditos.

GET/v1/vio/documentsLista tipos e campos reconhecidos
GET/v1/vio/documents/{templateID}Detalha um template
Identidade

CIN API [Beta]

POST/v1/cin/analyze1 crédito

Envie exclusivamente o PDF original da CIN Digital compartilhado pelo aplicativo GOV.BR. Fotos, prints e imagens não são aceitos. A RodoData valida a assinatura digital do PDF, a integridade do arquivo, o assinante GOV.BR/SERPRO, o QR/JWT e a assinatura ES512. Também extrai as imagens incorporadas (frente, verso e dados complementares), MRZ, OCR bruto e campos visuais estruturados, mantendo esses dados separados dos campos criptograficamente assinados no QR. A resposta comercial expõe as imagens assinadas em media para inspeção e integração.

cURL
curl -X POST https://rododata.com/v1/cin/analyze \
  -H "Authorization: Bearer $RODODATA_API_KEY" \
  -F "file=@cin-digital.pdf;type=application/pdf"
PDF digital obrigatório.

O endpoint de análise rejeita fotos e capturas de tela. A situação cadastral atual da CIN continua fora da validação offline e exige o fluxo autenticado oficial do GOV.BR.

Transporte

ANTT / RNTRC por veículo

POST/v1/antt/rntrc/vehicle5 créditos

Informe CPF ou CNPJ do transportador e uma placa brasileira com sete caracteres. Pontuação do documento é removida automaticamente; a placa é normalizada para maiúsculas.

Body JSON
{
  "document": "12345678000199",
  "plate": "ABC1D23"
}

Exemplos por linguagem

Node.js
Node.js
const response = await fetch("https://rododata.com/v1/antt/rntrc/vehicle", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.RODODATA_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    document: "12345678000199",
    plate: "ABC1D23"
  })
});

const data = await response.json();
if (!response.ok) throw new Error(data.error?.message || "Erro na API RodoData");
console.log(data);
Python
Python
import os
import requests

response = requests.post(
    "https://rododata.com/v1/antt/rntrc/vehicle",
    headers={
        "Authorization": f"Bearer {os.environ['RODODATA_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={"document": "12345678000199", "plate": "ABC1D23"},
    timeout=30,
)

response.raise_for_status()
print(response.json())
PHP
PHP
<?php

$ch = curl_init('https://rododata.com/v1/antt/rntrc/vehicle');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('RODODATA_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'document' => '12345678000199',
        'plate' => 'ABC1D23',
    ]),
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException($data['error']['message'] ?? 'Erro na API RodoData');
}
print_r($data);
Go
Go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

func main() {
    payload, _ := json.Marshal(map[string]string{
        "document": "12345678000199",
        "plate": "ABC1D23",
    })

    req, _ := http.NewRequest(http.MethodPost,
        "https://rododata.com/v1/antt/rntrc/vehicle",
        bytes.NewReader(payload),
    )
    req.Header.Set("Authorization", "Bearer "+os.Getenv("RODODATA_API_KEY"))
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()

    var result any
    _ = json.NewDecoder(resp.Body).Decode(&result)
    fmt.Printf("status=%d result=%#v\n", resp.StatusCode, result)
}
C#
C#
using System.Net.Http.Headers;
using System.Net.Http.Json;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("RODODATA_API_KEY"));

var response = await client.PostAsJsonAsync(
    "https://rododata.com/v1/antt/rntrc/vehicle",
    new { document = "12345678000199", plate = "ABC1D23" }
);

var body = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
Console.WriteLine(body);
Contrato

Headers e rastreabilidade

Toda chamada comercial recebe um identificador próprio. Guarde o request_id ao registrar erros no seu sistema.

Headers úteis
X-Request-ID: req_...
X-Credits-Remaining: 95
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1789398120

X-Credits-Remaining aparece em consultas comerciais concluídas. O mesmo identificador de requisição também é retornado no JSON.

Falhas

Erros previsíveis

Erros usam sempre o mesmo envelope:

Exemplo
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "informe CPF/CNPJ e placa válidos"
  },
  "request_id": "req_..."
}
400INVALID_REQUESTJSON, PDF, imagem ou parâmetros inválidos.
401UNAUTHORIZEDAPI Key ausente, inválida ou revogada.
402INSUFFICIENT_CREDITSSaldo insuficiente para reservar a consulta.
403FORBIDDENA chave não possui o escopo solicitado.
404DOCUMENT_NOT_FOUNDTemplate VIO não encontrado.
422DOCUMENT_NOT_PROCESSEDQR Code não pôde ser processado.
429RATE_LIMITEDLimite temporário excedido.
500INTERNAL_ERRORFalha interna da RodoData.
502UPSTREAM_ERRORFonte externa não concluiu a consulta.
503SERVICE_UNAVAILABLEServiço temporariamente indisponível, inclusive o processamento de PDF quando o renderizador não estiver disponível.
Cobrança

Como os créditos são consumidos

VIO

1

crédito por consulta concluída.

ANTT / RNTRC

5

créditos por consulta concluída.

O saldo é reservado antes do processamento. Se a consulta falhar durante o processamento interno ou na fonte externa, a RodoData estorna os créditos da requisição. Erros de validação, autenticação, escopo e rate limit acontecem antes da cobrança.

Boas práticas

Integração em produção

Segredo no backendNunca exponha rd_live_... em JavaScript enviado ao navegador, aplicativos distribuídos ou repositórios.
Timeout explícitoConfigure timeout HTTP no cliente. Consultas que dependem de fontes externas ou renderização de PDF podem demorar mais que chamadas puramente locais.
Retry seletivoConsidere retry com backoff para falhas de rede, 429, 502 e 503. Não repita automaticamente erros 400, 401, 402, 403 ou 422.
Request IDRegistre o request_id junto do erro. Ele é a principal referência para diagnóstico e suporte.
Não registre dados sensíveisEvite armazenar API Keys, PDFs, imagens, QR Codes, documentos completos ou respostas pessoais desnecessariamente.
Precisa de suporte?

Envie o request_id, horário aproximado e endpoint utilizado. Não envie a sua API Key.