Para integrar validação de CPF em lojas Nuvemshop, use o Nexo SDK para criar um aplicativo que roda como iframe no painel administrativo e injeta um script no checkout. O backend do app recebe o CPF, consulta GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key e retorna o resultado ao frontend — tudo em aproximadamente 900ms. A documentação oficial do Nexo SDK detalha os escopos e eventos disponíveis para comunicação com a plataforma.
O que é o Nexo SDK
O Nexo SDK é o framework oficial da Nuvemshop para desenvolvimento de aplicativos. Ele fornece:
- Nimbus Design System: componentes de UI padronizados.
- Nexo: biblioteca para comunicação entre o aplicativo e o admin da Nuvemshop.
- API REST: endpoints para acessar dados da loja.
- Webhooks: notificações de eventos da loja.
O aplicativo é executado como um iframe dentro do painel administrativo da Nuvemshop e pode interagir com o checkout via scripts externos.
Criando o projeto com Nexo
Scaffold do projeto
# Instalar o CLI da Nuvemshop
npm install -g @tiendanube/cli
# Criar o projeto
tiendanube app create cpf-validator
cd cpf-validator
# Instalar dependências
npm install @tiendanube/nexo @nimbus-ds/components axios
Estrutura do projeto
cpf-validator/
src/
pages/
index.tsx
settings.tsx
components/
CpfValidator.tsx
api/
validate-cpf.ts
lib/
nexo.ts
public/
checkout-script.js
package.json
Configurando a comunicação com Nexo
// src/lib/nexo.ts
import nexo from "@tiendanube/nexo";
const instance = nexo.create({
clientId: process.env.NEXT_PUBLIC_NUVEMSHOP_CLIENT_ID!,
log: process.env.NODE_ENV === "development",
});
export default instance;
Criando o endpoint de validação
O backend do aplicativo recebe as requisições do frontend e consulta a API da CPFHub:
// src/api/validate-cpf.ts
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Método não permitido" });
}
const { cpf } = req.body;
const cleanCpf = String(cpf).replace(/\D/g, "");
if (cleanCpf.length !== 11) {
return res.status(400).json({
success: false,
message: "CPF deve conter 11 dígitos.",
});
}
const apiKey = process.env.CPFHUB_API_KEY;
if (!apiKey) {
return res.status(500).json({
success: false,
message: "Chave de API não configurada.",
});
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(
`https://api.cpfhub.io/cpf/${cleanCpf}`,
{
method: "GET",
headers: {
"x-api-key": apiKey,
Accept: "application/json",
},
signal: controller.signal,
}
);
clearTimeout(timeoutId);
const data = await response.json();
return res.status(response.ok ? 200 : response.status).json(data);
} catch (error: any) {
clearTimeout(timeoutId);
if (error.name === "AbortError") {
return res.status(504).json({
success: false,
message: "Tempo de resposta excedido.",
});
}
return res.status(500).json({
success: false,
message: "Erro ao consultar CPF.",
});
}
}
Componente de validação com Nimbus
// src/components/CpfValidator.tsx
import React, { useState, useRef, useCallback } from "react";
import {
Box,
Input,
Text,
Card,
Spinner,
Icon,
Alert,
} from "@nimbus-ds/components";
import { CheckCircleIcon, ExclamationTriangleIcon } from "@nimbus-ds/icons";
interface CpfData {
cpf: string;
name: string;
birthDate: string;
gender: string;
}
const CpfValidator: React.FC = () => {
const [cpf, setCpf] = useState("");
const [loading, setLoading] = useState(false);
const [result, setResult] = useState<CpfData | null>(null);
const [error, setError] = useState("");
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const formatCpf = (value: string): string => {
const digits = value.replace(/\D/g, "").slice(0, 11);
if (digits.length > 9)
return digits.replace(
/(\d{3})(\d{3})(\d{3})(\d{1,2})/,
"$1.$2.$3-$4"
);
if (digits.length > 6)
return digits.replace(/(\d{3})(\d{3})(\d{1,3})/, "$1.$2.$3");
if (digits.length > 3)
return digits.replace(/(\d{3})(\d{1,3})/, "$1.$2");
return digits;
};
const validate = useCallback(async (cleanCpf: string) => {
setLoading(true);
setError("");
setResult(null);
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 12000);
const response = await fetch("/api/validate-cpf", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cpf: cleanCpf }),
signal: controller.signal,
});
clearTimeout(timeoutId);
const data = await response.json();
if (data.success) {
setResult(data.data);
} else {
setError(data.message || "CPF não encontrado.");
}
} catch (err: any) {
setError(
err.name === "AbortError"
? "Tempo excedido."
: "Erro ao validar."
);
} finally {
setLoading(false);
}
}, []);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const formatted = formatCpf(e.target.value);
setCpf(formatted);
const digits = formatted.replace(/\D/g, "");
if (debounceRef.current) clearTimeout(debounceRef.current);
if (digits.length === 11) {
debounceRef.current = setTimeout(() => validate(digits), 500);
} else {
setResult(null);
setError("");
}
};
return (
<Box display="flex" flexDirection="column" gap="4">
<Input
label="CPF"
placeholder="000.000.000-00"
value={cpf}
onChange={handleChange}
append={
loading ? (
<Spinner size="small" />
) : result ? (
<Icon source={<CheckCircleIcon />} color="success-interactive" />
) : null
}
/>
{error && (
<Alert appearance="danger">
<Text>{error}</Text>
</Alert>
)}
{result && (
<Card>
<Card.Body>
<Box display="flex" flexDirection="column" gap="2">
<Text>
<Text as="span" fontWeight="bold">
Nome:
</Text>{" "}
{result.name}
</Text>
<Text>
<Text as="span" fontWeight="bold">
Data de Nascimento:
</Text>{" "}
{result.birthDate}
</Text>
<Text>
<Text as="span" fontWeight="bold">
Genero:
</Text>{" "}
{result.gender}
</Text>
</Box>
</Card.Body>
</Card>
)}
</Box>
);
};
export default CpfValidator;
Página principal do aplicativo
// src/pages/index.tsx
import React, { useEffect } from "react";
import { Page, Layout, Box } from "@nimbus-ds/components";
import nexo from "../lib/nexo";
import CpfValidator from "../components/CpfValidator";
const HomePage: React.FC = () => {
useEffect(() => {
nexo.connect().then(() => {
console.log("Conectado ao Nexo");
});
}, []);
return (
<Page>
<Page.Header title="Validador de CPF" />
<Page.Body>
<Layout>
<Layout.Section>
<Box padding="4">
<CpfValidator />
</Box>
</Layout.Section>
</Layout>
</Page.Body>
</Page>
);
};
export default HomePage;
Script de validação no checkout
Para validar CPF diretamente no checkout da Nuvemshop, crie um script externo que é injetado via configuração do aplicativo:
// public/checkout-script.js
(function () {
"use strict";
var API_URL = "https://seu-app.vercel.app/api/validate-cpf";
var debounceTimer = null;
function init() {
var observer = new MutationObserver(function () {
var cpfField = document.querySelector(
'input[name="cpf"], input[data-checkout-cpf]'
);
if (cpfField && !cpfField.dataset.cpfhubBound) {
cpfField.dataset.cpfhubBound = "true";
bindValidation(cpfField);
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
}
function bindValidation(field) {
var feedback = document.createElement("div");
feedback.style.cssText =
"font-size:12px;margin-top:4px;min-height:16px;";
field.parentNode.appendChild(feedback);
field.addEventListener("input", function () {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(function () {
var cpf = field.value.replace(/\D/g, "");
if (cpf.length === 11) {
validateCpf(cpf, feedback);
}
}, 700);
});
}
function validateCpf(cpf, feedback) {
feedback.textContent = "Validando...";
feedback.style.color = "#666";
var controller = new AbortController();
var timeoutId = setTimeout(function () {
controller.abort();
}, 12000);
fetch(API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cpf: cpf }),
signal: controller.signal,
})
.then(function (r) {
clearTimeout(timeoutId);
return r.json();
})
.then(function (data) {
if (data.success) {
feedback.textContent = "CPF valido";
feedback.style.color = "#059669";
} else {
feedback.textContent = data.message || "CPF invalido";
feedback.style.color = "#dc2626";
}
})
.catch(function () {
clearTimeout(timeoutId);
feedback.textContent = "Erro na validacao";
feedback.style.color = "#dc2626";
});
}
init();
})();
Deploy e publicação
# Deploy no Vercel
npm run build
vercel --prod
# Registrar o aplicativo na Nuvemshop
# Acesse: https://partners.nuvemshop.com.br
# Configure a URL do app e os escopos necessários
Perguntas frequentes
Como o Nexo SDK comunica o aplicativo com o painel da Nuvemshop?
O Nexo SDK usa postMessage para estabelecer um canal seguro entre o iframe do aplicativo e o admin da Nuvemshop. A chamada nexo.connect() inicia o handshake; após a conexão, o app pode disparar ações nativas da plataforma, como navegar para seções do painel ou exibir notificações. Consulte a documentação da API Nuvemshop para ver todos os eventos suportados.
Qual é a latência esperada ao validar CPF via Nexo SDK?
A API CPFHub.io responde em aproximadamente 900ms. Como o frontend faz um POST para o endpoint do próprio app (Next.js), que por sua vez consulta a CPFHub, o ciclo total fica em torno de 1-1,5 segundo em condições normais. O debounce de 500ms no componente evita disparos desnecessários enquanto o usuário ainda está digitando.
O que acontece se o limite de consultas do plano gratuito for atingido?
O plano gratuito cobre 50 consultas por mês. Ao atingir esse limite, a API não bloqueia as requisições: cada consulta adicional é cobrada a R$0,15. Para aplicativos com volume maior, o plano Pro inclui 1.000 consultas mensais por R$149, com o mesmo custo por excedente.
Como garantir conformidade com a LGPD ao usar uma API de CPF em um app Nuvemshop?
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 orienta que dados de identificação devem ser tratados com o princípio da necessidade.
Conclusão
O Nexo SDK da Nuvemshop oferece uma plataforma completa para criar aplicativos que estendem as funcionalidades da loja. Ao combinar o Nexo com a API do CPFHub.io
A API da CPFHub entrega respostas em aproximadamente 900ms, com uptime de 99,9% e conformidade total com a LGPD -- requisitos essenciais para aplicativos no ecossistema Nuvemshop.
Cadastre-se em cpfhub.io
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.



