Validar CPF no servidor com Next.js API Routes garante que somente documentos algoritmicamente corretos e presentes na base da Receita Federal sejam aceitos pelo sistema. A validação no servidor — e não apenas no cliente — protege contra manipulação de requisições e evita chamadas desnecessárias à API externa. O fluxo combina validação local de dígitos verificadores com consulta ao endpoint GET https://api.cpfhub.io/cpf/{CPF} usando o header x-api-key.
Introdução
Validar CPF exclusivamente no cliente é insuficiente para garantir a integridade dos dados. A validação no servidor protege contra manipulação de requisições e garante que somente CPFs verificados sejam aceitos pelo sistema. Com o Next.js App Router, é possível criar Route Handlers que validam o CPF algoritmicamente e consultam a API do CPFHub.io para confirmação dos dados cadastrais.
Criando o módulo de validação
Implemente a validação algorítmica do CPF em um módulo reutilizável:
// lib/cpf-validator.js
export function validarDigitosCpf(cpf) {
const cpfLimpo = cpf.replace(/\D/g, '');
if (cpfLimpo.length !== 11) {
return { valido: false, erro: 'CPF deve conter 11 dígitos' };
}
if (/^(\d)\1{10}$/.test(cpfLimpo)) {
return { valido: false, erro: 'CPF com todos os dígitos iguais' };
}
const digitos = cpfLimpo.split('').map(Number);
let soma = 0;
for (let i = 0; i < 9; i++) {
soma += digitos[i] * (10 - i);
}
const d1 = soma % 11 < 2 ? 0 : 11 - (soma % 11);
soma = 0;
for (let i = 0; i < 10; i++) {
soma += digitos[i] * (11 - i);
}
const d2 = soma % 11 < 2 ? 0 : 11 - (soma % 11);
if (digitos[9] !== d1 || digitos[10] !== d2) {
return { valido: false, erro: 'Dígitos verificadores inválidos' };
}
return { valido: true, cpfLimpo };
}
export function formatarCpf(cpf) {
const limpo = cpf.replace(/\D/g, '');
return limpo.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
}
Route Handler de validação
Crie o Route Handler que combina validação local com consulta à API:
// app/api/validar-cpf/route.js
import { validarDigitosCpf } from '@/lib/cpf-validator';
export async function POST(request) {
const body = await request.json();
const { cpf } = body;
if (!cpf) {
return Response.json(
{ success: false, message: 'CPF é obrigatório' },
{ status: 400 }
);
}
const validacaoLocal = validarDigitosCpf(cpf);
if (!validacaoLocal.valido) {
return Response.json({
success: false,
validacaoLocal: false,
message: validacaoLocal.erro,
}, { status: 400 });
}
try {
const apiResponse = await fetch(
`${process.env.CPFHUB_BASE_URL}/cpf/${validacaoLocal.cpfLimpo}`,
{
headers: {
'x-api-key': process.env.CPFHUB_API_KEY,
},
}
);
if (!apiResponse.ok) {
return Response.json({
success: true,
validacaoLocal: true,
encontradoNaBase: false,
message: 'CPF válido, porém não encontrado na base',
});
}
const dados = await apiResponse.json();
return Response.json({
success: true,
validacaoLocal: true,
encontradoNaBase: dados.success,
data: dados.success ? dados.data : null,
message: dados.success
? 'CPF válido e encontrado'
: 'CPF válido, mas sem dados',
});
} catch (error) {
return Response.json({
success: false,
validacaoLocal: true,
message: 'Erro ao consultar API externa',
}, { status: 502 });
}
}
Route Handler para validação em lote
Crie um endpoint que aceita múltiplos CPFs para validação simultânea:
// app/api/validar-cpf/lote/route.js
import { validarDigitosCpf } from '@/lib/cpf-validator';
export async function POST(request) {
const { cpfs } = await request.json();
if (!Array.isArray(cpfs) || cpfs.length === 0) {
return Response.json(
{ success: false, message: 'Envie um array de CPFs' },
{ status: 400 }
);
}
if (cpfs.length > 50) {
return Response.json(
{ success: false, message: 'Máximo de 50 CPFs por requisição' },
{ status: 400 }
);
}
const resultados = await Promise.allSettled(
cpfs.map(async (cpf) => {
const validacao = validarDigitosCpf(cpf);
if (!validacao.valido) {
return { cpf, valido: false, erro: validacao.erro };
}
const response = await fetch(
`${process.env.CPFHUB_BASE_URL}/cpf/${validacao.cpfLimpo}`,
{
headers: { 'x-api-key': process.env.CPFHUB_API_KEY },
}
);
if (!response.ok) {
return { cpf, valido: true, encontrado: false };
}
const dados = await response.json();
return {
cpf,
valido: true,
encontrado: dados.success,
nome: dados.success ? dados.data.name : null,
};
})
);
const processados = resultados.map((r) =>
r.status === 'fulfilled' ? r.value : { erro: 'Falha no processamento' }
);
return Response.json({ success: true, resultados: processados });
}
| Endpoint | Método | Corpo | Descrição |
|---|---|---|---|
/api/validar-cpf | POST | { "cpf": "123..." } | Validação individual |
/api/validar-cpf/lote | POST | { "cpfs": [...] } | Validação em lote (max 50) |
Middleware de rate limiting
Proteja os endpoints contra abuso implementando rate limiting:
// middleware.js
import { NextResponse } from 'next/server';
const rateLimit = new Map();
const WINDOW_MS = 60 * 1000;
const MAX_REQUESTS = 30;
export function middleware(request) {
if (!request.nextUrl.pathname.startsWith('/api/validar-cpf')) {
return NextResponse.next();
}
const ip = request.headers.get('x-forwarded-for') ||
request.headers.get('x-real-ip') || 'unknown';
const now = Date.now();
const windowStart = now - WINDOW_MS;
if (!rateLimit.has(ip)) {
rateLimit.set(ip, []);
}
const requests = rateLimit.get(ip).filter((t) => t > windowStart);
requests.push(now);
rateLimit.set(ip, requests);
if (requests.length > MAX_REQUESTS) {
return Response.json(
{ success: false, message: 'Limite de requisições excedido' },
{ status: 429, headers: { 'Retry-After': '60' } }
);
}
return NextResponse.next();
}
export const config = {
matcher: '/api/validar-cpf/:path*',
};
Consumindo a API do lado do cliente
Crie um hook personalizado para facilitar o uso nos componentes React:
// hooks/useCpfValidation.js
'use client';
import { useState, useCallback } from 'react';
export function useCpfValidation() {
const [loading, setLoading] = useState(false);
const [resultado, setResultado] = useState(null);
const [erro, setErro] = useState(null);
const validar = useCallback(async (cpf) => {
setLoading(true);
setErro(null);
setResultado(null);
try {
const response = await fetch('/api/validar-cpf', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cpf }),
});
const data = await response.json();
if (response.ok && data.success) {
setResultado(data);
} else {
setErro(data.message || 'Erro na validação');
}
} catch {
setErro('Erro de conexão');
} finally {
setLoading(false);
}
}, []);
return { validar, loading, resultado, erro };
}
Perguntas frequentes
Por que validar o CPF no servidor e não apenas no cliente em Next.js?
A validação no cliente pode ser burlada por qualquer pessoa com acesso às ferramentas de desenvolvedor do navegador: basta interceptar a requisição e enviar um CPF diferente do que foi validado. A validação no Route Handler — no servidor — garante que todo CPF processado pela sua lógica de negócio passou pela verificação, independente do que o cliente enviou.
Qual a diferença entre a validação algorítmica e a consulta à API de CPF?
A validação algorítmica verifica se os dígitos verificadores são matematicamente corretos — ela detecta CPFs mal formatados ou fabricados, mas não confirma se o CPF pertence a uma pessoa real. A consulta à API da CPFHub.io acessa a base da Receita Federal e retorna nome, gênero e data de nascimento do titular, confirmando que o CPF existe e está ativo.
Como o rate limiting no middleware protege o endpoint de validação?
O middleware limita cada IP a 30 requisições por minuto. Isso previne ataques de força bruta que tentam descobrir CPFs válidos enviando sequências numéricas em massa. O rate limiting acontece antes de qualquer lógica de negócio, reduzindo carga no servidor e nas chamadas à API externa. Para mais detalhes sobre middleware no Next.js, consulte a documentação oficial do Next.js.
A API da CPFHub.io retorna erro 429 quando o limite do plano é atingido?
Não. A API da CPFHub.io nunca retorna HTTP 429 nem bloqueia requisições por limite de plano. Ao ultrapassar o limite mensal (50 consultas no plano gratuito ou 1.000 no Pro), as consultas adicionais são cobradas automaticamente a R$0,15 cada — o fluxo de validação continua sem interrupções.
Conclusão
Validar CPF no servidor com Next.js API Routes garante segurança e integridade dos dados. A chave de API fica protegida em variáveis de ambiente, a validação algorítmica evita chamadas desnecessárias à API externa e o rate limiting previne abuso. A combinação dos dois níveis de validação — local e via API — cobre tanto CPFs matematicamente inválidos quanto documentos que não existem na base da Receita Federal.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e implemente validação de CPF no servidor do seu projeto Next.js hoje mesmo.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



