Escopo VIO
vio:decodePermite decodificar documentos VIO.
Integre consultas de transporte e leitura de documentos com exemplos prontos, respostas previsíveis e rastreabilidade por requisição.
Crie uma chave em API Keys, mantenha-a somente no servidor e envie-a no header Authorization. A URL base da API é:
https://rododata.com/v1Use variáveis de ambiente ou um gerenciador de segredos no seu backend. A chave completa é exibida apenas no momento da criação.
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:
{
"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_..."
}Endpoints comerciais exigem uma API Key ativa e com o escopo correto.
Authorization: Bearer rd_live_xxxxxxxxxvio:decodePermite decodificar documentos VIO.
cin:analyzePermite validar o QR/JWT da Carteira de Identidade Nacional.
antt:rntrcPermite 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.
O limite padrão atual é de 120 requisições por minuto por API Key. A API informa o estado do limite nos headers:
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1789398120X-RateLimit-Reset é um timestamp Unix. Ao exceder o limite, a API responde 429 RATE_LIMITED.
/v1/vio/decode1 créditoPDF é 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.
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.
curl -X POST https://rododata.com/v1/vio/decode \
-H "Authorization: Bearer $RODODATA_API_KEY" \
-F "file=@cnh.pdf;type=application/pdf"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);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
$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);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)
}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);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.
{
"image_base64": "data:image/png;base64,iVBORw0KGgoAAA..."
}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.
{
"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_..."
}
}Os endpoints de catálogo são públicos e não consomem créditos.
/v1/vio/documentsLista tipos e campos reconhecidos/v1/vio/documents/{templateID}Detalha um template/v1/cin/analyze1 créditoEnvie 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 -X POST https://rododata.com/v1/cin/analyze \
-H "Authorization: Bearer $RODODATA_API_KEY" \
-F "file=@cin-digital.pdf;type=application/pdf"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.
/v1/antt/rntrc/vehicle5 créditosInforme CPF ou CNPJ do transportador e uma placa brasileira com sete caracteres. Pontuação do documento é removida automaticamente; a placa é normalizada para maiúsculas.
{
"document": "12345678000199",
"plate": "ABC1D23"
}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);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
$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);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)
}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);Toda chamada comercial recebe um identificador próprio. Guarde o request_id ao registrar erros no seu sistema.
X-Request-ID: req_...
X-Credits-Remaining: 95
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1789398120X-Credits-Remaining aparece em consultas comerciais concluídas. O mesmo identificador de requisição também é retornado no JSON.
Erros usam sempre o mesmo envelope:
{
"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.crédito por consulta concluída.
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.
rd_live_... em JavaScript enviado ao navegador, aplicativos distribuídos ou repositórios.429, 502 e 503. Não repita automaticamente erros 400, 401, 402, 403 ou 422.request_id junto do erro. Ele é a principal referência para diagnóstico e suporte.Envie o request_id, horário aproximado e endpoint utilizado. Não envie a sua API Key.