# Validação de CPF para plataformas de venda de passagens aéreas e rodoviárias

> Saiba como integrar validação de CPF via API em plataformas de venda de passagens para cumprir exigências regulatórias e prevenir fraudes.

**Publicado:** 06/09/2025
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/validacao-de-cpf-para-plataformas-de-venda-de-passagens-aereas-e-rodoviarias

---


Plataformas de venda de passagens aéreas e rodoviárias são obrigadas a validar o CPF do passageiro para cumprir exigências da ANAC, ANTT e Receita Federal — sem isso, a emissão do bilhete e da nota fiscal fica comprometida. A CPFHub.io permite essa validação em ~900ms via API REST, retornando nome completo e data de nascimento para conferência automática dos dados, o que reduz erros no embarque e bloqueia fraudes com cartões roubados.

## Introdução

A venda online de passagens aéreas e rodoviárias no Brasil movimenta bilhões de reais por ano. Diferentemente de outros segmentos do e-commerce, esse setor opera sob regulamentações específicas da ANAC e da ANTT que exigem a identificação do passageiro no momento da compra. O CPF é o principal identificador utilizado nesse processo -- e sua validação é obrigatória para garantir conformidade, prevenir fraudes e evitar problemas no embarque.

---

## Exigências regulatórias

### ANAC -- passagens aéreas

A Agência Nacional de Aviação Civil exige que o bilhete aéreo contenha o nome completo do passageiro conforme documento oficial. Embora o CPF não seja tecnicamente obrigatório no bilhete, ele é amplamente utilizado como identificador único para fins fiscais, programas de fidelidade e check-in online. Divergências entre o nome do passageiro e o nome no documento podem impedir o embarque.

### ANTT -- passagens rodoviárias

A Agência Nacional de Transportes Terrestres, por meio da Resolução 4.770, exige que a venda de passagens rodoviárias interestaduais e internacionais inclua a identificação do passageiro. O CPF é o documento mais utilizado para esse fim, especialmente em vendas online onde o passageiro não apresenta documento físico no momento da compra.

### Receita Federal

A emissão de nota fiscal na venda de passagens exige o CPF do comprador. Um CPF inválido ou inexistente impede a emissão fiscal correta, gerando problemas contábeis e regulatórios para a plataforma.

---

## Cenários de fraude no setor

O setor de passagens enfrenta fraudes específicas que a validação de CPF ajuda a combater.

### Compra com cartão roubado

O fraudador compra passagens com cartão de crédito roubado e as revende abaixo do preço de mercado. A validação de CPF permite verificar se o titular do cartão corresponde ao passageiro, adicionando uma camada de verificação.

### Cambistas digitais

Intermediários compram passagens em promoções e as revendem com lucro. Embora nem sempre ilegal, essa prática pode ser controlada limitando o número de compras por CPF em determinado período.

### Reservas fantasma

Bots criam reservas em massa para segurar assentos em voos promocionais, liberando-os apenas quando o prazo de pagamento está prestes a vencer. A exigência de CPF válido no momento da reserva dificulta essa prática.

---

## Implementação em Python

O exemplo a seguir demonstra um sistema de venda de passagens com validação de CPF integrada.

```python
import requests
import re
from datetime import datetime, timedelta
from typing import Optional
import json

CPFHUB_API_URL = "https://api.cpfhub.io/cpf"
CPFHUB_API_KEY = "SUA_CHAVE_DE_API"
REQUEST_TIMEOUT = 10 # segundos

def consultar_cpf(cpf: str) -> Optional[dict]:
 """Consulta CPF na API CPFHub.io."""
 cpf_limpo = re.sub(r"\D", "", cpf)

 try:
 response = requests.get(
 f"{CPFHUB_API_URL}/{cpf_limpo}",
 headers={
 "x-api-key": CPFHUB_API_KEY,
 "Accept": "application/json",
 },
 timeout=REQUEST_TIMEOUT,
 )
 response.raise_for_status()
 dados = response.json()

 if dados.get("success"):
 return dados["data"]
 return None

 except requests.exceptions.Timeout:
 raise Exception("Timeout na consulta de CPF")
 except requests.exceptions.HTTPError as e:
 status = e.response.status_code
 mensagens = {
 401: "Chave de API inválida",
 404: None, # CPF não encontrado
 }
 if status in mensagens:
 if mensagens[status] is None:
 return None
 raise Exception(mensagens[status])
 raise Exception(f"Erro HTTP {status}")
 except requests.exceptions.RequestException:
 raise Exception("Erro de conexão com a API")

def normalizar_nome(nome: str) -> str:
 """Remove acentos e normaliza o nome para comparação."""
 import unicodedata
 nome_normalizado = unicodedata.normalize("NFKD", nome)
 nome_sem_acento = nome_normalizado.encode("ASCII", "ignore").decode("ASCII")
 return nome_sem_acento.upper().strip()

def verificar_correspondencia_nome(
 nome_informado: str, nome_api: str, tolerancia: float = 0.8
) -> dict:
 """Verifica se o nome informado corresponde ao retornado pela API."""
 partes_informado = normalizar_nome(nome_informado).split()
 partes_api = normalizar_nome(nome_api).split()

 # Verifica primeiro e último nome
 primeiro_ok = partes_informado[0] == partes_api[0] if partes_informado and partes_api else False
 ultimo_ok = partes_informado[-1] == partes_api[-1] if partes_informado and partes_api else False

 # Calcula score de similaridade
 partes_em_comum = set(partes_informado) & set(partes_api)
 total_partes = max(len(partes_informado), len(partes_api))
 score = len(partes_em_comum) / total_partes if total_partes > 0 else 0

 return {
 "corresponde": primeiro_ok and ultimo_ok and score >= tolerancia,
 "score": round(score, 2),
 "primeiro_nome_ok": primeiro_ok,
 "ultimo_nome_ok": ultimo_ok,
 "nome_sugerido": nome_api,
 }

def validar_passageiro(
 cpf: str,
 nome_passageiro: str,
 data_viagem: str,
) -> dict:
 """Valida CPF e dados do passageiro para emissão de bilhete."""

 cpf_limpo = re.sub(r"\D", "", cpf)

 # Validação estrutural do CPF
 if len(cpf_limpo) != 11:
 return {"valido": False, "erro": "CPF deve ter 11 dígitos"}

 # Consulta à API
 try:
 dados = consultar_cpf(cpf_limpo)
 except Exception as e:
 return {"valido": False, "erro": str(e)}

 if not dados:
 return {"valido": False, "erro": "CPF não encontrado na base"}

 # Verificação de correspondência de nome
 verificacao_nome = verificar_correspondencia_nome(
 nome_passageiro, dados.get("name", "")
 )

 if not verificacao_nome["corresponde"]:
 return {
 "valido": False,
 "erro": "Nome do passageiro não corresponde ao CPF",
 "nome_no_cpf": dados.get("name"),
 "score_similaridade": verificacao_nome["score"],
 "sugestao": f"Verifique se o nome correto é: {dados.get('name')}",
 }

 # Verificação de idade (menores podem precisar de autorização)
 ano_nascimento = dados.get("year", 0)
 idade = datetime.now().year - ano_nascimento
 menor_de_idade = idade < 18

 return {
 "valido": True,
 "passageiro": {
 "cpf": cpf_limpo,
 "nome": dados.get("name"),
 "nomeUpper": dados.get("nameUpper"),
 "dataNascimento": dados.get("birthDate"),
 "genero": dados.get("gender"),
 "menorDeIdade": menor_de_idade,
 },
 "alertas": (
 ["Passageiro menor de idade -- autorização pode ser necessária"]
 if menor_de_idade
 else []
 ),
 }

def emitir_bilhete(
 cpf: str,
 nome_passageiro: str,
 origem: str,
 destino: str,
 data_viagem: str,
 tipo: str = "aereo",
) -> dict:
 """Emite bilhete após validação completa."""

 # Valida passageiro
 validacao = validar_passageiro(cpf, nome_passageiro, data_viagem)

 if not validacao["valido"]:
 return {"emitido": False, "erro": validacao["erro"]}

 passageiro = validacao["passageiro"]

 # Gera localizador
 import hashlib
 hash_base = f"{cpf}-{origem}-{destino}-{data_viagem}-{datetime.now().isoformat()}"
 localizador = hashlib.md5(hash_base.encode()).hexdigest()[:6].upper()

 bilhete = {
 "emitido": True,
 "localizador": localizador,
 "tipo": tipo,
 "passageiro": passageiro["nomeUpper"],
 "cpf": passageiro["cpf"][:3] + ".***.***-" + passageiro["cpf"][-2:],
 "origem": origem,
 "destino": destino,
 "dataViagem": data_viagem,
 "emitidoEm": datetime.now().strftime("%d/%m/%Y %H:%M"),
 "alertas": validacao.get("alertas", []),
 }

 return bilhete

# Exemplo de uso
if __name__ == "__main__":
 # Emitir passagem aérea
 resultado = emitir_bilhete(
 cpf="123.456.789-09",
 nome_passageiro="João da Silva",
 origem="GRU",
 destino="GIG",
 data_viagem="15/10/2025",
 tipo="aereo",
 )
 print(json.dumps(resultado, indent=2, ensure_ascii=False))

 # Emitir passagem rodoviária
 resultado_rod = emitir_bilhete(
 cpf="987.654.321-00",
 nome_passageiro="Maria Oliveira",
 origem="São Paulo - Tietê",
 destino="Rio de Janeiro - Novo Rio",
 data_viagem="20/10/2025",
 tipo="rodoviario",
 )
 print(json.dumps(resultado_rod, indent=2, ensure_ascii=False))
```

---

## Controle de compras por CPF

Para combater cambistas e reservas fantasma, implemente limites de compra por CPF.

```python
from collections import defaultdict
from datetime import datetime, timedelta

# Registro de compras por CPF
compras_por_cpf = defaultdict(list)

# Limites configuráveis
LIMITE_PASSAGENS_DIA = 5
LIMITE_PASSAGENS_MES = 20
LIMITE_MESMO_TRECHO_DIA = 2

def verificar_limites(cpf: str, origem: str, destino: str) -> dict:
 """Verifica se o CPF atingiu algum limite de compra."""
 cpf_limpo = re.sub(r"\D", "", cpf)
 agora = datetime.now()

 compras = compras_por_cpf.get(cpf_limpo, [])

 # Compras nas últimas 24 horas
 compras_24h = [c for c in compras if agora - c["data"] < timedelta(hours=24)]

 # Compras no mês atual
 compras_mes = [c for c in compras if c["data"].month == agora.month]

 # Mesmo trecho nas últimas 24 horas
 mesmo_trecho_24h = [
 c for c in compras_24h
 if c["origem"] == origem and c["destino"] == destino
 ]

 alertas = []

 if len(compras_24h) >= LIMITE_PASSAGENS_DIA:
 return {
 "permitido": False,
 "erro": f"Limite de {LIMITE_PASSAGENS_DIA} passagens por dia atingido",
 }

 if len(compras_mes) >= LIMITE_PASSAGENS_MES:
 return {
 "permitido": False,
 "erro": f"Limite de {LIMITE_PASSAGENS_MES} passagens por mês atingido",
 }

 if len(mesmo_trecho_24h) >= LIMITE_MESMO_TRECHO_DIA:
 return {
 "permitido": False,
 "erro": f"Limite de {LIMITE_MESMO_TRECHO_DIA} passagens para o mesmo trecho por dia",
 }

 if len(compras_24h) >= LIMITE_PASSAGENS_DIA - 1:
 alertas.append("Próximo do limite diário de compras")

 return {"permitido": True, "alertas": alertas}
```

---

## Integração com companhias

As companhias aéreas e rodoviárias exigem que os dados do passageiro sejam consistentes em todas as etapas -- reserva, emissão, check-in e embarque. A API da [**CPFHub.io**](https://www.cpfhub.io/) retorna exatamente os campos exigidos pelas companhias nos arquivos de manifesto de passageiros, garantindo consistência end-to-end sem retrabalho manual.

Os dados retornados pela API -- nome completo, data de nascimento e gênero -- são precisamente os campos exigidos pelas companhias nos arquivos de manifesto de passageiros.

---

## Considerações de performance

No setor de passagens, a velocidade do checkout é crítica. Promoções de passagens aéreas esgotam em minutos, e qualquer latência adicional pode significar a perda da venda.

A API da [**CPFHub.io**](https://www.cpfhub.io/) opera com latência média de ~900ms, o que é suficiente para validar o passageiro em segundo plano enquanto o usuário preenche os demais campos do formulário, sem impactar a experiência de compra.

---

## Perguntas frequentes

### O que é necessário para implementar validação de CPF neste contexto?
A validação de CPF exige uma chamada à API com o número do documento e a chave de autenticação. A CPFHub.io retorna o status do CPF, nome do titular e data de nascimento em ~900ms, permitindo a verificação em tempo real durante o cadastro ou transação.

### A API CPFHub.io funciona para todos os volumes de consulta?
Sim. O plano gratuito oferece 50 consultas por mês sem cartão de crédito — ideal para testes e projetos pequenos. Para volumes maiores, o plano Pro inclui 1.000 consultas mensais por R$149. Se o limite for ultrapassado, a API não bloqueia: cobra R$0,15 por consulta adicional.

### Como garantir conformidade com a LGPD ao usar uma API de CPF?
Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário (não guarde o CPF cru se um token bastar), implemente controle de acesso aos logs de consulta e documente a base legal para o tratamento. A [ANPD](https://www.gov.br/anpd) orienta que dados de identificação devem ser tratados com o princípio da necessidade.

### Quanto tempo leva para integrar a API CPFHub.io?
A integração básica leva menos de 30 minutos: crie uma conta em cpfhub.io, gere a API key no painel e faça uma chamada GET para `https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`. A documentação inclui exemplos em Python, Node.js, PHP, Java e outras linguagens.

### Leia também

- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)
- [KYC no Brasil: quais setores são obrigados a validar CPF por lei](https://cpfhub.io/blog/kyc-no-brasil-quais-setores-sao-obrigados-a-validar-cpf-por-lei)

---

## Conclusão

A validação de CPF em plataformas de venda de passagens não é apenas uma boa prática -- é uma necessidade regulatória e operacional. Ela garante conformidade com as exigências da ANAC e ANTT, previne fraudes com cartões roubados, combate cambistas digitais e evita problemas no embarque por divergência de dados.

A integração com a [**CPFHub.io**](https://www.cpfhub.io/) leva menos de 30 minutos e já inclui tratamento de erros, comparação de nomes e controle de limites por CPF — tudo o que uma plataforma de passagens precisa para operar com segurança e conformidade. Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e comece hoje mesmo.

