Como integrar validação de CPF em Nuvemshop com Nexo SDK

Tutorial para integrar validação de CPF em lojas Nuvemshop usando o Nexo SDK para criar aplicativos com a API CPFHub.

Redação CPFHub.io
Redação CPFHub.io
··8 min de leitura
Como integrar validação de CPF em Nuvemshop com Nexo SDK

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.

Redação CPFHub.io

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.

WhatsAppFale conosco via WhatsApp