Validação de CPF em Ruby on Rails: guia completo de integração
Como validar e consultar CPF em Rails usando a API SmartCPF v2 com autenticação X-API-KEY, tratamento de erros e exemplos práticos.

Validar CPF é um requisito recorrente em sistemas brasileiros — cadastros, onboarding, compliance, antifraude. Implementar a validação apenas no frontend ou com algoritmos locais resolve o formato, mas não garante que o CPF exista, esteja regular na Receita Federal ou pertença à pessoa informada. A API SmartCPF resolve essa lacuna consultando bases oficiais em tempo real, retornando nome, data de nascimento, situação cadastral, e-mails, telefones e endereços vinculados, tudo via uma única chamada HTTPS com autenticação por header X-API-KEY.
Este artigo mostra como integrar a SmartCPF v2 em uma aplicação Ruby on Rails de forma robusta: configurando o cliente HTTP, tratando códigos de erro, parseando a resposta e expondo um service object reutilizável. O foco é código de produção — logs, timeouts, retentativas e fallback para não travar o fluxo principal.
Como a SmartCPF valida CPF na prática
A SmartCPF não roda apenas o algoritmo de dígito verificador. Ao receber um CPF no endpoint GET /v2/individuals/{cpf}?package=X, a API consulta fontes oficiais (Receita Federal, bureaus de crédito, bases de telefonia) e monta um dossiê consolidado. O parâmetro package define o nível de detalhe: basic (apenas situação cadastral), standard (dados pessoais + contatos) ou complete (inclui endereços e score). A resposta chega em JSON padronizado com metadados de auditoria (consultId, executionTimeMs, balance de créditos) e o objeto result com os dados da pessoa.
A autenticação é obrigatória via header X-API-KEY — não use Authorization: Bearer, query string nem cookies. Cada requisição consome créditos do plano contratado; o campo balance no retorno mostra o saldo restante em tempo real, permitindo monitoramento proativo sem painel administrativo.
Vantagens de usar a SmartCPF em Rails
1. Validação real, não apenas sintática
O algoritmo de dígito verificador aceita CPFs inexistentes. A SmartCPF confirma existência na base da Receita e situação cadastral (Regular, Suspenso, Cancelado, Nulo).
2. Dados enriquecidos em uma chamada
Nome completo, data de nascimento, idade, nome da mãe, sexo, e-mails, telefones com operadora/tipo/WhatsApp e endereços — tudo no mesmo result, sem necessidade de múltiplos provedores.
3. Auditoria nativa via consultId
Cada consulta gera UUID único rastreável nos logs da SmartCPF. Em caso de disputa ou auditoria LGPD, basta informar o consultId para obter o log completo da requisição.
4. Controle de custo transparente
O campo balance retorna o saldo de créditos após cada chamada. Integre alertas (ex.: saldo < 100) no seu monitoramento para evitar interrupção silenciosa.
5. Latência previsívelexecutionTimeMs médio de 50–120 ms na região Brasil. Com timeout de 5 s no cliente HTTP, a integração não degrada a experiência do usuário mesmo em picos.
6. Modelo de créditos sem assinatura mínima
Paga-se por consulta realizada. Ideal para projetos com volume variável — desenvolvimento, staging e produção compartilham o mesmo pool de créditos.
Desafios e o que considerar antes de integrar
1. Dependência de rede externa
Se a SmartCPF estiver indisponível, sua validação falha. Implemente circuit breaker e fallback (ex.: validação apenas de formato + fila para reprocessamento assíncrono).
2. Rate limiting por API Key
Planos têm limite de requisições por segundo/minuto. Exceder retorna 429. Configure Retry-After no cliente e exponha métrica de rate_limit_remaining nos logs.
3. LGPD e consentimento
A consulta retorna dados pessoais sensíveis. Garanta base legal (legítimo interesse, consentimento ou obrigação legal) antes de chamar a API e não logue o result completo em produção.
4. CPFs inválidos ou não encontrados
A API retorna success: false com errors descrevendo o motivo (formato inválido, não encontrado, CPF nulo). Trate cada caso: UX amigável para o usuário, alerta para fraude tentada.
5. Variação de pacotes (package)
Escolher basic economiza créditos mas não traz contatos. Defina o pacote por caso de uso (cadastro simples vs. KYC completo) e documente a decisão no código.
Como implementar com a SmartCPF
O exemplo abaixo encapsula a chamada em um CpfValidationService com Faraday, timeouts configuráveis, retentativa exponencial em erros 5xx/429 e parsing seguro da resposta. Ajuste PACKAGE e BASE_URL via variáveis de ambiente.
# frozen_string_literal: true
# Service object para validar e consultar CPF via SmartCPF v2.
# Uso:
# result = CpfValidationService.call(cpf: "111.111.111-11", package: "standard")
# result.success? # => true/false
# result.data # => Hash com :cpf, :name, :birth_date, :status, :emails, :phones, :addresses
# result.meta # => Hash com :consult_id, :balance, :execution_time_ms
# result.errors # => Array de strings (vazio se success?)
class CpfValidationService
include ActiveModel::Model
include ActiveModel::Attributes
attribute :cpf, :string
attribute :package, :string, default: -> { ENV.fetch("SMARTCPF_DEFAULT_PACKAGE", "standard") }
validates :cpf, presence: true
validates :package, inclusion: { in: %w[basic standard complete] }
BASE_URL = ENV.fetch("SMARTCPF_BASE_URL", "https://api.smartcpf.com.br/v2")
API_KEY = ENV.fetch("SMARTCPF_API_KEY") { raise "SMARTCPF_API_KEY não configurado" }
TIMEOUT = ENV.fetch("SMARTCPF_TIMEOUT", 5).to_i
RETRIES = ENV.fetch("SMARTCPF_MAX_RETRIES", 2).to_i
# Estrutura de retorno padronizada
Result = Struct.new(:success?, :data, :meta, :errors, keyword_init: true)
def self.call(cpf:, package: nil)
new(cpf: cpf, package: package).call
end
def call
return failure(errors: ["CPF inválido"]) unless valid?
normalized_cpf = normalize_cpf(cpf)
response = http_get("/individuals/#{normalized_cpf}", params: { package: package })
case response.status
when 200
parse_success(response.body)
when 400, 404, 422
parse_client_error(response.body)
when 401, 403
failure(errors: ["Credenciais inválidas ou sem permissão"], meta: { status: response.status })
when 429
failure(errors: ["Rate limit excedido"], meta: { retry_after: response.headers["Retry-After"] })
when 500..599
failure(errors: ["Erro interno da SmartCPF"], meta: { status: response.status })
else
failure(errors: ["Resposta inesperada: #{response.status}"])
end
rescue Faraday::TimeoutError
failure(errors: ["Timeout ao consultar SmartCPF (#{TIMEOUT}s)"])
rescue Faraday::ConnectionFailed => e
failure(errors: ["Falha de conexão: #{e.message}"])
rescue JSON::ParserError => e
failure(errors: ["Resposta inválida da API: #{e.message}"])
end
private
def http_get(path, params: {})
connection.get(path, params) do |req|
req.options.timeout = TIMEOUT
req.options.open_timeout = 2
end
end
def connection
@connection ||= Faraday.new(url: BASE_URL) do |f|
f.request :retry,
max: RETRIES,
interval: 0.5,
interval_randomness: 0.5,
backoff_factor: 2,
exceptions: [Faraday::TimeoutError, Faraday::ConnectionFailed],
retry_statuses: [429, 500, 502, 503, 504]
f.headers["X-API-KEY"] = API_KEY
f.headers["Accept"] = "application/json"
f.headers["User-Agent"] = "SmartCPF-Ruby/#{Smartcpf::VERSION rescue '1.0'}"
f.response :raise_error # lança em 4xx/5xx para o rescue externo
f.adapter Faraday.default_adapter
end
end
def normalize_cpf(raw)
raw.gsub(/\D/, "")
end
def parse_success(body)
json = JSON.parse(body, symbolize_names: true)
# A API retorna success: true no envelope E no result
unless json[:success] && json.dig(:result, :cpf)
return failure(errors: ["Resposta de sucesso sem dados válidos"], meta: { raw: json })
end
result = json[:result]
meta = json[:meta] || {}
data = {
cpf: result[:cpf],
name: result[:name],
birth_date: result[:birthDate],
age: result[:age],
mother_name: result[:motherName],
gender: result[:gender],
status: result[:status],
emails: result[:emails] || [],
phones: result[:phones] || [],
addresses: result[:addresses] || []
}
meta_data = {
consult_id: meta[:consultId],
balance: meta[:balance],
execution_time_ms: meta[:executionTimeMs],
search_type: meta[:searchType],
api_version: meta[:apiVersion],
date: meta[:date]
}
Result.new(success?: true, data: data, meta: meta_data, errors: [])
end
def parse_client_error(body)
json = JSON.parse(body, symbolize_names: true)
errors = Array(json[:errors] || json[:message] || "Erro desconhecido")
failure(errors: errors, meta: { raw: json })
rescue JSON::ParserError
failure(errors: ["Erro de validação (resposta não-JSON)"])
end
def failure(errors:, meta: {})
Result.new(success?: false, data: nil, meta: meta, errors: Array(errors))
end
end
Resposta da API
{
"meta": {
"searchType": "CPF G",
"consultId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"user": "Fulano de Tal",
"message": "CPF encontrado com sucesso",
"ip": "127.0.0.1",
"success": true,
"apiVersion": "v2",
"date": "2025-08-17T14:32:10.123Z",
"executionTimeMs": 74.1,
"balance": 9.77
},
"result": {
"cpf": "111.111.111-11",
"name": "João da Silva",
"birthDate": "10/09/1992",
"age": 33,
"motherName": "Maria da Silva",
"gender": "M",
"status": "Regular",
"emails": ["[email protected]"],
"phones": [
{
"number": "(55) 99999-9999",
"blockedTelemarketing": false,
"operator": "VIVO",
"type": "CELULAR",
"whatsapp": false
}
],
"addresses": []
},
"success": true,
"errors": []
}
O fluxo acima resolve na prática:
- Identificação única —
consultIdpermite rastrear a consulta nos logs da SmartCPF e no seu próprio sistema para auditoria LGPD. - Controle de custo em tempo real —
balance: 9.77mostra o saldo restante; integre alerta quando < 50 para evitar interrupção. - Validação de situação cadastral —
status: "Regular"confirma que o CPF está ativo na Receita Federal (outros valores:Suspenso,Cancelado,Nulo,Falecido). - Dados de contato prontos para uso —
emails,phones(comoperator,type,whatsapp) eaddresseseliminam necessidade de bases separadas. - Performance observável —
executionTimeMs: 74.1permite SLA interno e alerta se latência subir acima do esperado.
Por que usar a SmartCPF no seu Rails
- Integração em minutos — Apenas
Faraday+ headerX-API-KEY; sem SDK pesado, sem geração de token, sem OAuth. - Latência baixa e previsível — Infraestrutura no Brasil, tempo médio < 100 ms, timeout configurável no cliente.
- Modelo pay-per-use — Créditos não expiram, compartilhados entre ambientes, sem taxa mínima mensal.
- Dados completos e atualizados — Fontes oficiais + bureaus + telefonia em uma resposta, com versionamento de API (
apiVersion: "v2"). - Escalabilidade nativa — Rate limits generosos por plano;
Retry-Afterno header 429 facilita backoff automático.
Conclusão
Validar CPF apenas pelo dígito verificador expõe seu sistema a fraudes, cadastros fantasmas e problemas de compliance. A SmartCPF v2 entrega a validação real — existência, regularidade e dados enriquecidos — com uma integração HTTP simples, autenticação por header X-API-KEY e resposta JSON padronizada. O service object mostrado aqui isola a complexidade de rede, retries, parsing e tratamento de erro, devolvendo um objeto Result tipado que o resto da aplicação consome sem conhecer detalhes da API. Crie sua conta na SmartCPF e faça sua primeira consulta em minutos.
Sobre a redação
Redação Smart CPF
Autor do blog
Mais artigos

SmartCPF vs Consulta Manual na Receita Federal: Tempo e Confiabilidade
Comparativo técnico entre consulta automatizada via API SmartCPF e processo manual no e-CAC: latência, disponibilidade e integração

Validação de CPF em Rust com Axum: exemplo prático com SmartCPF
Aprenda a validar CPF em Rust usando Axum e a API SmartCPF v2. Código completo com autenticação X-API-KEY, tratamento de erros e parsing da resposta.

Validação de CPF em plugin WordPress: passo a passo com a API SmartCPF
Tutorial completo de como validar CPF em plugins WordPress usando a API SmartCPF v2, com exemplos PHP práticos e tratamento de erros.

Validação de CPF com Deno: consumo nativo da API SmartCPF via fetch
Como validar CPFs em Deno usando fetch nativo para consumir a API SmartCPF v2 com autenticação X-API-KEY.
Pronto para validar CPFs em segundos?
Consultas gratuitas para testar agora. Acesso imediato à documentação.