Para integrar a API de CPF da CPFHub.io em um backend serverless com Firebase, você cria uma Firebase Function que faz uma chamada GET autenticada para https://api.cpfhub.io/cpf/{CPF} e armazena o resultado no Firestore como cache. A latência típica da API é de ~150 ms, por isso o cache no Firestore é indispensável para manter o tempo de resposta aceitável em produção. O deploy na região southamerica-east1 garante a menor latência possível para usuários brasileiros.
Firebase e a plataforma de desenvolvimento de aplicações do Google que oferece um ecossistema completo: autenticação, banco de dados em tempo real, hosting, storage e Cloud Functions. As Firebase Functions (baseadas no Google Cloud Functions) permitem executar código backend em resposta a eventos HTTP, alteracoes no Firestore ou gatilhos de autenticação -- tudo sem gerenciar servidores.
Para aplicações que utilizam Firebase como backend -- apps mobile, SPAs e plataformas web -- as Firebase Functions são a forma natural de integrar a API da CPFHub.io
Configuração do projeto
Inicialize o projeto Firebase com Functions:
# Instalar Firebase CLI
npm install -g firebase-tools
# Login
firebase login
# Inicializar Functions
firebase init functions
# Selecione:
# - TypeScript
# - ESLint: Sim
# - Instalar dependencias: Sim
Estrutura resultante:
functions/
src/
index.ts
package.json
tsconfig.json
Serviço de consulta de CPF
Crie o módulo que encapsula a comunicação com a API:
// functions/src/services/cpfhub.ts
import { defineString } from "firebase-functions/params";
const cpfhubApiKey = defineString("CPFHUB_API_KEY");
const API_URL = "https://api.cpfhub.io/cpf";
const TIMEOUT_MS = 10000;
interface CPFData {
cpf: string;
name: string;
nameUpper: string;
gender: string;
birthDate: string;
day: number;
month: number;
year: number;
}
interface CPFApiResponse {
success: boolean;
data?: CPFData;
}
export interface ConsultaResultado {
sucesso: boolean;
dados?: {
cpf: string;
nome: string;
genero: string;
dataNascimento: string;
dia: number;
mes: number;
ano: number;
};
erro?: string;
}
export async function consultarCPF(cpf: string): Promise<ConsultaResultado> {
const cpfLimpo = cpf.replace(/\D/g, "");
if (cpfLimpo.length !== 11) {
return { sucesso: false, erro: "CPF deve conter 11 digitos" };
}
if (/^(\d)\1+$/.test(cpfLimpo)) {
return { sucesso: false, erro: "CPF invalido" };
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
try {
const response = await fetch(`${API_URL}/${cpfLimpo}`, {
method: "GET",
headers: {
"x-api-key": cpfhubApiKey.value(),
"Accept": "application/json",
},
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
return { sucesso: false, erro: `Erro HTTP ${response.status}` };
}
const resultado: CPFApiResponse = await response.json();
if (!resultado.success || !resultado.data) {
return { sucesso: false, erro: "CPF nao encontrado" };
}
return {
sucesso: true,
dados: {
cpf: resultado.data.cpf,
nome: resultado.data.name,
genero: resultado.data.gender,
dataNascimento: resultado.data.birthDate,
dia: resultado.data.day,
mes: resultado.data.month,
ano: resultado.data.year,
},
};
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.name === "AbortError") {
return { sucesso: false, erro: "Timeout na consulta" };
}
return { sucesso: false, erro: `Erro: ${String(error)}` };
}
}
O defineString do Firebase Functions v2 permite definir parametros de configuração que são solicitados no deploy.
Função HTTP para validação
A função HTTP e o ponto de entrada para consultas via API REST:
// functions/src/index.ts
import { onRequest } from "firebase-functions/v2/https";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { getFirestore, FieldValue } from "firebase-admin/firestore";
import { initializeApp } from "firebase-admin/app";
import { consultarCPF } from "./services/cpfhub";
initializeApp();
const db = getFirestore();
const CACHE_COLLECTION = "cpf_cache";
const CACHE_TTL_HOURS = 24;
export const validarCpf = onRequest(
{
region: "southamerica-east1",
cors: true,
maxInstances: 10,
},
async (req, res) => {
if (req.method !== "GET") {
res.status(405).json({ erro: "Use GET" });
return;
}
const cpf = req.query.cpf as string || req.params[0];
if (!cpf) {
res.status(400).json({ erro: "CPF e obrigatorio" });
return;
}
const cpfLimpo = cpf.replace(/\D/g, "");
// Verificar cache no Firestore
const cacheDoc = await db
.collection(CACHE_COLLECTION)
.doc(cpfLimpo)
.get();
if (cacheDoc.exists) {
const cacheData = cacheDoc.data();
const expiraEm = cacheData?.expiraEm?.toDate();
if (expiraEm && expiraEm > new Date()) {
res.json({
valido: true,
dados: cacheData?.dados,
fonte: "cache",
});
return;
}
}
// Consultar API
const resultado = await consultarCPF(cpfLimpo);
if (!resultado.sucesso) {
const status = resultado.erro?.includes("nao encontrado") ? 404 : 500;
res.status(status).json({ erro: resultado.erro });
return;
}
// Salvar no cache
const expiraEm = new Date();
expiraEm.setHours(expiraEm.getHours() + CACHE_TTL_HOURS);
await db.collection(CACHE_COLLECTION).doc(cpfLimpo).set({
dados: resultado.dados,
expiraEm,
criadoEm: FieldValue.serverTimestamp(),
});
res.json({
valido: true,
dados: resultado.dados,
fonte: "api",
});
}
);
Função acionada por evento do Firestore
Valide CPF automaticamente quando um novo documento e criado no Firestore:
// functions/src/index.ts (continuacao)
export const validarCpfNoCadastro = onDocumentCreated(
{
document: "cadastros/{docId}",
region: "southamerica-east1",
},
async (event) => {
const snapshot = event.data;
if (!snapshot) {
console.log("Documento vazio");
return;
}
const dados = snapshot.data();
const cpf = dados.cpf;
if (!cpf) {
console.log("CPF nao informado no documento");
return;
}
const resultado = await consultarCPF(cpf);
const atualizacao: Record<string, unknown> = {
cpfValidadoEm: FieldValue.serverTimestamp(),
};
if (resultado.sucesso) {
atualizacao.cpfStatus = "validado";
atualizacao.cpfNomeValidado = resultado.dados?.nome;
atualizacao.cpfGenero = resultado.dados?.genero;
atualizacao.cpfDataNascimento = resultado.dados?.dataNascimento;
// Verificar se o nome confere
const nomeInformado = (dados.nome || "").toUpperCase().split(" ")[0];
const nomeAPI = (resultado.dados?.nome || "").toUpperCase().split(" ")[0];
if (nomeInformado && nomeAPI && nomeInformado !== nomeAPI) {
atualizacao.cpfStatus = "divergente";
atualizacao.cpfAlerta = "Nome informado diverge do CPF";
}
} else {
atualizacao.cpfStatus = "invalido";
atualizacao.cpfErro = resultado.erro;
}
await snapshot.ref.update(atualizacao);
console.log(`CPF ${cpf} validado: ${atualizacao.cpfStatus}`);
}
);
Com esse trigger, qualquer documento adicionado a coleção cadastros no Firestore tera o CPF validado automaticamente.
Callable Function para apps Flutter e React Native
Firebase Callable Functions são a forma recomendada de chamar funções a partir de apps mobile:
// functions/src/index.ts (continuacao)
import { onCall, HttpsError } from "firebase-functions/v2/https";
export const consultarCpfCallable = onCall(
{
region: "southamerica-east1",
maxInstances: 10,
},
async (request) => {
// Verificar autenticacao
if (!request.auth) {
throw new HttpsError(
"unauthenticated",
"Usuario nao autenticado"
);
}
const cpf = request.data.cpf;
if (!cpf) {
throw new HttpsError(
"invalid-argument",
"CPF e obrigatorio"
);
}
const resultado = await consultarCPF(cpf);
if (!resultado.sucesso) {
throw new HttpsError(
"not-found",
resultado.erro ?? "CPF nao encontrado"
);
}
return resultado.dados;
}
);
No app mobile (JavaScript/React Native):
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions(app, "southamerica-east1");
const consultarCPF = httpsCallable(functions, "consultarCpfCallable");
async function validar(cpf: string) {
try {
const result = await consultarCPF({ cpf });
console.log("Dados:", result.data);
} catch (error) {
console.error("Erro:", error);
}
}
Configuração de segredos
Configure a chave de API como parametro do Firebase:
# Definir parametro
firebase functions:secrets:set CPFHUB_API_KEY
# Verificar
firebase functions:secrets:access CPFHUB_API_KEY
Deploy e teste
# Deploy de todas as funcoes
firebase deploy --only functions
# Deploy de funcao especifica
firebase deploy --only functions:validarCpf
# Testar localmente
firebase emulators:start --only functions,firestore
Teste local com curl:
curl "http://localhost:5001/meu-projeto/southamerica-east1/validarCpf?cpf=12345678901"
Limpeza de cache com Scheduled Function
Crie uma função agendada para limpar cache expirado:
import { onSchedule } from "firebase-functions/v2/scheduler";
export const limparCacheCPF = onSchedule(
{
schedule: "every 24 hours",
region: "southamerica-east1",
},
async () => {
const agora = new Date();
const snapshot = await db
.collection(CACHE_COLLECTION)
.where("expiraEm", "<", agora)
.limit(500)
.get();
const batch = db.batch();
snapshot.docs.forEach((doc) => batch.delete(doc.ref));
await batch.commit();
console.log(`${snapshot.size} registros de cache removidos`);
}
);
Perguntas frequentes
Por que usar o Firestore como cache para chamadas à API de CPF em Firebase Functions?
A API de CPF tem latência de ~150 ms por consulta. Sem cache, cada validação bloqueia a Function pelo tempo de ida e volta da requisição, aumentando o custo de execução (Firebase Functions cobra por tempo de CPU) e prejudicando a experiência do usuário. O Firestore como cache reduz chamadas repetidas ao mesmo CPF e mantém os dados disponíveis entre cold starts de Function.
O que acontece se o limite do plano gratuito for atingido durante a execução das Functions?
A cota mensal e o limite por minuto não se confundem. No plano Grátis, zerar os 50 créditos pausa as consultas com HTTP 403 ("Limite de créditos excedido"); nos planos pagos, o excedente eventual é faturado depois, no preço da página de preços. Acima do limite por minuto a API responde HTTP 429 e informa o Retry-After. Para ambientes de produção com volume previsível, o plano Pro (R$149/mês, 1.000 consultas) é mais adequado.
Como proteger a chave de API da CPFHub.io em Firebase Functions?
Use firebase functions:secrets:set CPFHUB_API_KEY para armazenar a chave no Secret Manager do Google Cloud, que é o mecanismo nativo do Firebase Functions v2 para segredos. Nunca hardcode a chave no código-fonte nem a coloque em variáveis de ambiente não criptografadas. Consulte a documentação oficial do Firebase para boas práticas de configuração.
Como lidar com timeouts e falhas de rede nas chamadas à API dentro das Functions?
Configure AbortController com timeout de 10 segundos (como no exemplo acima) e implemente retry com backoff exponencial para falhas transitórias. O OWASP recomenda que integrações com APIs externas sempre tenham timeout definido e tratamento explícito de erros de rede para evitar que a Function fique pendurada até o limite máximo de execução.
Conclusão
Firebase Functions oferecem uma integração natural com o ecossistema Firebase para validação de CPF. Funções HTTP para APIs REST, triggers do Firestore para validação automática e Callable Functions para apps mobile criam uma solução completa. O Firestore serve como cache distribuido, e a regiao southamerica-east1 garante a menor latência para usuários brasileiros. A API da CPFHub.io
Cadastre-se em cpfhub.io
CPFHub.io
Pronto para integrar a API?
50 créditos gratuitos para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

