Módulo Consulta de CNH — API v2
Disponível somente entrando em contato com o suporte.
Valide a habilitação de um condutor em tempo real. Envie o CPF ou o número da CNH e receba, na mesma requisição, os dados da carteira e do condutor — sem filas nem webhooks.
O que dá para fazer
| Ação | Endpoint | Quando usar |
|---|---|---|
| Consultar uma CNH | GET /v2/cnh/consult | Uma consulta por vez, direto no fluxo do usuário |
| Consultar em lote | POST /v2/cnh/consult/batch | Vários documentos numa requisição — onboarding em massa, reconciliação de base |
Use este módulo para:
- Onboarding de motoristas — confirme a CNH antes de liberar o cadastro.
- Checagens de conformidade — verifique bloqueios, exames e validade.
- Validação de habilitação — garanta que o condutor está apto antes de uma operação.
Antes de começar
Pré-requisitos
Antes de usar este módulo, certifique-se de ter:
- Acesso ao módulo — a consulta de CNH precisa estar habilitada para a sua organização. Sem o acesso, a API retorna
403. Solicite no onboarding. - Credenciais HMAC — Access Token e Secret Key fornecidos no onboarding.
Autenticação
Este módulo usa a mesma autenticação HMAC-SHA256 da API v1 — sem novas credenciais. Toda requisição (individual ou em lote) exige dois headers:
| Header | Valor | Descrição |
|---|---|---|
Authorization | Basic {ACCESS_TOKEN} | Access Token fornecido no onboarding. |
Key | {HMAC_SIGNATURE} | Assinatura HMAC-SHA256 da requisição. |
Veja o cálculo da assinatura no Guia de Autenticação HMAC.
Envie o header x-correlation-id: {UUID} para rastrear a requisição nos logs. Se ausente, a API gera um automaticamente.
Tempo de resposta
A consulta é feita em tempo real nos órgãos oficiais, então o tempo de resposta varia com a disponibilidade deles. A maioria das consultas responde em poucos segundos, mas algumas podem levar mais de 30 segundos.
- Cada consulta tem tempo limite de 60 segundos. Passado esse limite, a API retorna
504com o headerRetry-After. - Configure o timeout do seu cliente HTTP com pelo menos 60 segundos, com uma pequena margem (por exemplo, 70 segundos). Um timeout menor encerra do seu lado consultas que ainda seriam concluídas.
Consultar uma CNH
/v2/cnh/consultUma única chamada autenticada por HMAC retorna todos os dados disponíveis para o documento informado — a habilitação e o condutor, na mesma resposta.
Parâmetros de query
| Parâmetro | Obrigatório | Tipo | Descrição |
|---|---|---|---|
documentNumber | Sim | string | Documento do condutor: CPF (11 dígitos) ou o número de registro da CNH. Aceita com ou sem máscara — a API remove a pontuação e completa zeros à esquerda. A distinção entre CPF e CNH é automática. |
Exemplo de requisição
curl -X GET \
'https://api.sandbox.v2.frota162.com.br/v2/cnh/consult?documentNumber=12312312312' \
-H 'Authorization: Basic {ACCESS_TOKEN}' \
-H 'Key: {HMAC_SIGNATURE}'
Resposta (200 OK)
A resposta traz dois blocos: license (dados da habilitação) e driver (dados do condutor). O núcleo de cada bloco vem sempre; os campos estendidos aparecem conforme a UF e o tipo de dado disponível.
Os valores abaixo são ilustrativos do contrato — para CPFs que respondem de verdade, veja Ambiente de testes.
A maioria das datas é ISO 8601 (2033-03-19T03:00:00.000Z), mas quatro campos vêm como string dd/mm/aaaa: exams[].validUntil, courses[].startedAt, courses[].endedAt e courses[].expiresAt.
O caso que mais quebra integração: expiresAt muda de formato conforme o bloco. Em license e em toxicologicalExam é ISO 8601; em courses[] é 31/08/2027. Um parser genérico por nome de campo falha aqui — trate cada bloco pelo formato indicado na coluna Tipo das tabelas abaixo.
Há ainda uma variação dentro do próprio ISO: issuedAt chega com offset local (-03:00) e os demais em UTC (Z). Ambos são ISO 8601 válidos e qualquer parser padrão resolve os dois.
{
"license": {
"number": "1231231231",
"category": "AB",
"renach": "SC123123123",
"registryNumber": "12345678912",
"issuedAt": "2023-03-07T00:00:00-03:00",
"expiresAt": "2033-03-19T03:00:00.000Z",
"firstLicenseAt": "2008-09-13T03:00:00.000Z",
"observation": "Apto para Transporte Remunerado",
"photoUrl": "https://cdn.exemplo.com/cnh/foto.png",
"toxicologicalExam": {
"collectedAt": "2023-06-23T03:00:00.000Z",
"detectionWindowDate": "2023-06-23T03:00:00.000Z",
"status": "APTO",
"expiresAt": "2023-09-21T03:00:00.000Z"
},
"blocks": [
{
"state": "PR",
"date": "2023-11-22T03:00:00.000Z",
"description": "54 PONTOS",
"penaltyDays": 180,
"penaltyStartsAt": "2023-11-22T03:00:00.000Z",
"penaltyEndsAt": "2024-05-20T03:00:00.000Z"
}
],
"exams": [
{
"name": "APTIDÃO FÍSICA E MENTAL",
"date": "2019-04-03T03:00:00.000Z",
"result": "APTO",
"validUntil": "03/04/2024",
"desiredCategory": "E",
"allowedCategory": "E",
"city": "CURITIBA/PR",
"state": "PR"
}
],
"courses": [
{
"name": "ATUALIZAÇÃO - TRANSPORTE PRODUTOS PERIGOSOS",
"startedAt": "30/08/2022",
"endedAt": "31/08/2022",
"workloadHours": 20,
"category": "B",
"modality": "ENSINO A DISTÂNCIA",
"expiresAt": "31/08/2027",
"city": "RECIFE/PE",
"state": "PE"
}
]
},
"driver": {
"name": "TESTE DA SILVA",
"documentNumber": "12312312312",
"birthDate": "1979-04-24T03:00:00.000Z",
"motherName": "MARIA DA SILVA",
"fatherName": "JOSE DA SILVA",
"email": "teste@exemplo.com",
"phone": "47999999991",
"address": "RUA EXEMPLO 000, CENTRO - BLUMENAU/SC",
"rg": {
"number": "89462320",
"state": "PR",
"issuer": "SESP"
}
}
}
Bloco license (habilitação)
| Campo | Tipo | Sempre presente | Descrição |
|---|---|---|---|
number | string | Sim | Número da CNH |
category | string | Sim | Categoria (ex: AB) |
renach | string | Sim | Número RENACH |
registryNumber | string | Sim | Número de registro |
issuedAt | string · ISO 8601 | Sim | Data de emissão |
expiresAt | string · ISO 8601 | Sim | Data de validade |
firstLicenseAt | string · ISO 8601 | Sim | Data da primeira habilitação |
observation | string | Não | Observações da habilitação |
photoUrl | string · URL | Não | URL da foto (quando disponível) |
toxicologicalExam | object | Não | Exame toxicológico — campos |
blocks | object[] | Não | Bloqueios e impedimentos — campos |
exams | object[] | Não | Exames de habilitação — campos |
courses | object[] | Não | Cursos vinculados — campos |
As quatro últimas linhas são os campos estendidos: só aparecem conforme a UF e o dado disponível, e cada uma tem sua tabela logo abaixo.
Bloco driver (condutor)
| Campo | Tipo | Sempre presente | Descrição |
|---|---|---|---|
name | string | Sim | Nome do condutor |
documentNumber | string | Sim | CPF do condutor, só dígitos |
birthDate | string · ISO 8601 | Sim | Data de nascimento |
motherName | string | Sim | Nome da mãe |
fatherName | string | Sim | Nome do pai |
email | string | Não | |
phone | string | Não | Telefone |
address | string | Não | Endereço |
rg | object | Não | Objeto com number, state, issuer |
Campos estendidos de license
Dependendo da UF e do tipo de dado disponível, o bloco license pode incluir os campos abaixo. Quando ausentes, não são retornados.
toxicologicalExam — exame toxicológico
| Campo | Tipo | Descrição |
|---|---|---|
collectedAt | string · ISO 8601 | Data da coleta |
detectionWindowDate | string · ISO 8601 | Data-limite da janela de detecção |
status | string | Situação do exame (ex: APTO) |
expiresAt | string · ISO 8601 | Validade do exame |
blocks[] — bloqueios/impedimentos (ex: suspensão do direito de dirigir)
| Campo | Tipo | Sempre presente | Descrição |
|---|---|---|---|
state | string | Sim | UF |
date | string · ISO 8601 | Sim | Data do bloqueio |
description | string | Não | Descrição |
penaltyDays | number | Não | Dias de penalidade |
penaltyStartsAt | string · ISO 8601 | Não | Início da penalidade |
penaltyEndsAt | string · ISO 8601 | Não | Fim da penalidade |
exams[] — exames de habilitação
| Campo | Tipo | Sempre presente | Descrição |
|---|---|---|---|
name | string | Sim | Nome do exame |
date | string · ISO 8601 | Sim | Data |
result | string | Não | Resultado |
validUntil | string · dd/mm/aaaa | Não | Validade |
desiredCategory | string | Não | Categoria pretendida |
allowedCategory | string | Não | Categoria permitida |
city | string | Não | Cidade |
state | string | Não | UF |
courses[] — cursos vinculados à habilitação
| Campo | Tipo | Sempre presente | Descrição |
|---|---|---|---|
name | string | Sim | Nome do curso |
startedAt | string · dd/mm/aaaa | Sim | Início |
endedAt | string · dd/mm/aaaa | Sim | Término |
workloadHours | number | Não | Carga horária |
category | string | Não | Categoria |
modality | string | Não | Modalidade |
expiresAt | string · dd/mm/aaaa | Não | Validade |
city | string | Não | Cidade |
state | string | Não | UF |
O histórico de pontuação/infrações do condutor não é retornado por este endpoint no momento.
Consultar em lote
/v2/cnh/consult/batchQuando a demanda é por volume, não há motivo para chamar o endpoint individual N vezes. Envie vários documentos numa única requisição e receba um resultado por item.
O lote usa falha parcial: se um documento não for localizado ou a consulta dele falhar, os demais continuam. A resposta é sempre 200 quando o lote é processável — sucesso ou falha é reportado item a item em results[].
Corpo da requisição
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
documentNumbers | Sim | string[] | Lista de documentos: cada item é um CPF (11 dígitos) ou um número de registro da CNH. Aceita com ou sem máscara. Mínimo 1, máximo 50 por requisição. |
{
"documentNumbers": [
"529.982.247-25",
"13987734337",
"70708347487"
]
}
O máximo é 50 documentos por requisição (configurável pelo ambiente). Para bases maiores, divida em lotes e envie sequencialmente. Acima do limite, a API recusa o lote inteiro com 400.
Resposta (200 OK)
A resposta traz results[] (um por documento, na mesma ordem enviada) e summary (contagem consolidada).
{
"results": [
{
"documentNumber": "52998224725",
"status": "found",
"data": {
"license": { "number": "1231231231", "category": "AB" },
"driver": { "name": "TESTE DA SILVA", "documentNumber": "52998224725" }
},
"error": null
},
{
"documentNumber": "13987734337",
"status": "not_found",
"data": null,
"error": null
},
{
"documentNumber": "70708347487",
"status": "error",
"data": null,
"error": {
"code": "CNH_CONSULT_FAILED",
"message": "Falha ao realizar a consulta"
}
}
],
"summary": {
"total": 3,
"found": 1,
"notFound": 1,
"error": 1
}
}
O objeto
datade um itemfoundtem a mesma estrutura (license+driver, com campos estendidos) do endpoint individual documentado acima. Foi resumido no exemplo por brevidade.
Campos de results[]
| Campo | Descrição |
|---|---|
documentNumber | Documento consultado, já normalizado (só dígitos). |
status | found = localizado · not_found = não localizado (resultado válido, não é erro) · error = falha técnica na consulta. |
data | Dados da CNH (license + driver) quando status: found; caso contrário null. |
error | Objeto { code, message } quando status: error; caso contrário null. |
Campos de summary
| Campo | Descrição |
|---|---|
total | Total de itens no lote. |
found | Itens localizados. |
notFound | Itens não localizados. |
error | Itens com falha de consulta. |
Falha do lote vs. falha do item
O lote tem dois níveis de falha — não confunda:
| Nível | Quando | Resultado |
|---|---|---|
| Lote inteiro | Formato inválido: lista vazia, acima do limite, ou qualquer item com CPF/CNH inválido. | 400 — nada é consultado. |
| Item | Documento válido mas não localizado, ou falha temporária na consulta. | 200 — reportado em results[].status (not_found / error). |
Ou seja: a validação de formato é tudo-ou-nada (rejeita o lote); a consulta é resiliente por item.
not_found é um resultado definitivo — não reenvie. Já error indica falha técnica e potencialmente transitória: reprocesse apenas esses itens, com backoff.
Ambiente de testes (sandbox)
No ambiente sandbox, a consulta não acessa dados reais: um catálogo determinístico de CPFs devolve respostas fixas para você exercitar cada cenário da sua integração (inclusive erros e timeout). Mesmo CPF → mesma resposta, sempre. As datas retornadas são relativas à data da consulta (nunca vencem no catálogo).
Envie um destes CPFs em documentNumber (ou monte uma lista com eles no lote):
| CPF | Cenário | Resposta |
|---|---|---|
13460936282 | CNH válida | 200 — categoria AB, sem bloqueios, toxicológico negativo, 1 exame apto, 1 curso |
34048421891 | CNH com suspensão | 200 — igual à válida + 1 bloqueio (suspensão de 180 dias vigente) |
58750246666 | CNH vencida | 200 — expiresAt no passado |
50662186702 | Toxicológico positivo | 200 — toxicologicalExam.status positivo |
13987734337 | Não localizada | 404 |
70708347487 | Erro temporário do serviço | 500 |
92028337532 | Resposta lenta | 200 após ~20s — para testar o timeout do seu cliente |
41837592691 | Serviço de consulta não respondeu a tempo | 504 com header Retry-After |
Regras do catálogo:
- O catálogo resolve apenas por CPF. Uma CNH (número de registro) válida cai no cenário "não localizada" (
404). - Qualquer CPF válido fora da tabela também retorna
404— mesmo comportamento de "não localizada". - CPF inválido é recusado na validação (
400), sem consultar o catálogo.
Monte um documentNumbers com estes CPFs para exercitar found, not_found e error num único request — ex.: 13460936282 (found), 13987734337 (not_found) e 70708347487 (error).
Estes CPFs são fictícios e válidos apenas no ambiente sandbox. Em produção, a consulta usa dados reais.
Referência de erros
A API v2 retorna erros no padrão RFC 7807 Problem Details. Veja o Guia de Tratamento de Erros para a referência completa.
Todos os erros retornam o seguinte formato:
{
"type": "urn:frota162-api-v2:error:{tipo}",
"title": "Título do erro",
"status": 404,
"detail": "Descrição específica do problema",
"instance": "/v2/cnh/consult",
"traceId": "abc123def456"
}
Erros por status
400 — Requisição inválida
Individual: documentNumber não enviado ou fora do formato de CPF/CNH.
Em lote: documentNumbers vazio, com mais de 50 itens, ou contendo um documento fora do formato. A mensagem identifica o documento com problema; o path do erro aponta o índice do item na lista.
{
"type": "urn:frota162-api-v2:error:validation-error",
"title": "Validation Error",
"status": 400,
"detail": "documento inválido \"111\": informe um CPF ou CNH válido",
"instance": "/v2/cnh/consult/batch",
"traceId": "abc123"
}
401 — Autenticação ausente ou inválida
Header Authorization: Basic {ACCESS_TOKEN} ou Key: {HMAC_SIGNATURE} ausente, ou assinatura HMAC inválida.
{
"type": "urn:frota162-api-v2:error:unauthorized",
"title": "Unauthorized Access",
"status": 401,
"detail": "Missing required header: Authorization",
"instance": "/v2/cnh/consult",
"traceId": "abc123"
}
403 — Sem acesso ao módulo
A consulta de CNH não está habilitada para a sua organização. Entre em contato para solicitar acesso.
{
"type": "urn:frota162-api-v2:error:forbidden",
"title": "Forbidden",
"status": 403,
"detail": "You do not have permission to access this resource",
"instance": "/v2/cnh/consult",
"traceId": "abc123"
}
404 — CNH não localizada
Nenhuma CNH localizada para o documento informado. Aplica-se apenas ao endpoint individual — no lote, este cenário vira status: not_found no item.
{
"type": "urn:frota162-api-v2:error:driver-not-found",
"title": "Driver Not Found",
"status": 404,
"detail": "The specified driver was not found in the system",
"instance": "/v2/cnh/consult",
"traceId": "abc123"
}
422 — Documento inválido ou não encontrado
O documento foi recusado na consulta — verifique o CPF/CNH informado. Aplica-se apenas ao endpoint individual.
{
"type": "urn:frota162-api-v2:error:unprocessable-entity",
"title": "Unprocessable Entity",
"status": 422,
"detail": "O documento informado é inválido ou não foi encontrado.",
"instance": "/v2/cnh/consult",
"traceId": "abc123"
}
500 — Erro interno
Falha temporária ao processar a consulta. Retente com backoff; se persistir, contate o suporte informando o traceId. No lote, uma falha de consulta de um item vira status: error — o lote em si continua 200.
{
"type": "urn:frota162-api-v2:error:internal-server-error",
"title": "Internal Server Error",
"status": 500,
"detail": "An unexpected error occurred while processing your request",
"instance": "/v2/cnh/consult",
"traceId": "abc123"
}
504 — Serviço de consulta não respondeu a tempo
A consulta não foi concluída dentro do tempo limite de 60 segundos. É uma falha temporária e a consulta não é cobrada. Aguarde o tempo indicado no header Retry-After (em segundos) e tente novamente, com backoff. No lote, o timeout de um item vira status: error — o lote em si continua 200.
{
"type": "urn:frota162-api-v2:error:gateway-timeout",
"title": "Gateway Timeout",
"status": 504,
"detail": "O serviço de consulta não respondeu a tempo. Tente novamente em instantes.",
"instance": "/v2/cnh/consult",
"traceId": "abc123",
"retryAfter": 5
}
Referência rápida
| Status | type | Aplica-se a | Causa | Ação |
|---|---|---|---|---|
400 | validation-error | Ambos | Documento ausente/inválido; lista vazia ou acima de 50 | Revisar o parâmetro / a lista |
401 | unauthorized / authentication-failed | Ambos | Header ausente ou HMAC inválido | Revisar headers e recalcular HMAC |
403 | forbidden | Ambos | Organização sem acesso ao módulo | Solicitar acesso |
404 | driver-not-found | Individual | CNH não localizada | Verificar o documento |
422 | unprocessable-entity | Individual | Documento inválido/não encontrado | Verificar CPF/CNH |
429 | rate-limit-exceeded | Ambos | Limite de requisições atingido | Aguardar e retentar |
500 | internal-server-error | Ambos | Falha temporária ao processar | Retentar com backoff |
504 | gateway-timeout | Individual | Serviço de consulta não respondeu a tempo | Aguardar o Retry-After e retentar |
status: not_found | — | Item do lote | Documento não localizado | Resultado definitivo — não reenviar |
status: error | — | Item do lote | Falha temporária na consulta | Reprocessar só esse item, com backoff |