Como consumir API de CPF em PrestaShop com módulos customizados

Guia completo para consumir a API de CPF da CPFHub em PrestaShop criando módulos customizados com validação no checkout.

Redação CPFHub.io
Redação CPFHub.io
··8 min de leitura
Como consumir API de CPF em PrestaShop com módulos customizados

Para consumir a API de CPF da CPFHub em PrestaShop, crie um módulo customizado que registra hooks no checkout, faz chamadas cURL para https://api.cpfhub.io/cpf/{CPF} com o header x-api-key e retorna o resultado via AJAX para o JavaScript do storefront. O PrestaShop não oferece validação de CPF nativamente, então essa abordagem por módulo é a maneira mais organizada de adicionar essa funcionalidade sem modificar o core da plataforma. A latência média da API é de ~900ms — exibir um estado de carregamento durante a chamada melhora a experiência do usuário. Consulte a documentação oficial de módulos do PrestaShop para entender o ciclo de vida de hooks e controllers antes de começar.


Estrutura do módulo PrestaShop

Um módulo PrestaShop segue uma estrutura de diretórios bem definida. Crie a seguinte estrutura:

modules/
    cpfhubvalidator/
    cpfhubvalidator.php
    controllers/
    front/
    validation.php
    views/
    templates/
    hook/
    cpf_field.tpl
    js/
    cpfhub-validator.js
    css/
    cpfhub-validator.css

Arquivo principal do módulo

O arquivo principal registra hooks, instala configurações e define o comportamento do módulo:

<?php
// modules/cpfhubvalidator/cpfhubvalidator.php

if (!defined('_PS_VERSION_')) {
    exit;
}

class CpfHubValidator extends Module
{
    public function __construct()
    {
    $this->name = 'cpfhubvalidator';
    $this->tab = 'front_office_features';
    $this->version = '1.0.0';
    $this->author = 'Sua Empresa';
    $this->need_instance = 0;

    parent::__construct();

    $this->displayName = $this->l('CPFHub Validator');
    $this->description = $this->l('Validação de CPF em tempo real via API CPFHub.io');
    }

    public function install()
    {
    return parent::install()
    && $this->registerHook('displayCustomerAccountForm')
    && $this->registerHook('displayHeader')
    && $this->registerHook('actionValidateCustomerAddressForm')
    && Configuration::updateValue('CPFHUB_API_KEY', '')
    && Configuration::updateValue('CPFHUB_ENABLED', 1);
    }

    public function uninstall()
    {
    return parent::uninstall()
    && Configuration::deleteByName('CPFHUB_API_KEY')
    && Configuration::deleteByName('CPFHUB_ENABLED');
    }

    public function getContent()
    {
    $output = '';

    if (Tools::isSubmit('submitCpfHubSettings')) {
    $apiKey = Tools::getValue('CPFHUB_API_KEY');
    $enabled = (int) Tools::getValue('CPFHUB_ENABLED');

    Configuration::updateValue('CPFHUB_API_KEY', $apiKey);
    Configuration::updateValue('CPFHUB_ENABLED', $enabled);

    $output .= $this->displayConfirmation($this->l('Configurações salvas.'));
    }

    return $output . $this->renderForm();
    }

    private function renderForm()
    {
    $fields = [
    'form' => [
    'legend' => [
    'title' => $this->l('Configurações CPFHub'),
    ],
    'input' => [
    [
    'type' => 'text',
    'label' => $this->l('Chave de API'),
    'name' => 'CPFHUB_API_KEY',
    'required' => true,
    'desc' => $this->l('Obtenha em cpfhub.io'),
    ],
    [
    'type' => 'switch',
    'label' => $this->l('Ativar validação'),
    'name' => 'CPFHUB_ENABLED',
    'values' => [
    ['id' => 'active_on', 'value' => 1, 'label' => $this->l('Sim')],
    ['id' => 'active_off', 'value' => 0, 'label' => $this->l('Não')],
    ],
    ],
    ],
    'submit' => [
    'title' => $this->l('Salvar'),
    ],
    ],
    ];

    $helper = new HelperForm();
    $helper->submit_action = 'submitCpfHubSettings';
    $helper->fields_value = [
    'CPFHUB_API_KEY' => Configuration::get('CPFHUB_API_KEY'),
    'CPFHUB_ENABLED' => Configuration::get('CPFHUB_ENABLED'),
    ];

    return $helper->generateForm([$fields]);
    }

    public function hookDisplayHeader()
    {
    if (!Configuration::get('CPFHUB_ENABLED')) {
    return;
    }

    Media::addJsDef([
    'cpfhubValidationUrl' => $this->context->link->getModuleLink(
    'cpfhubvalidator',
    'validation'
    ),
    ]);

    $this->context->controller->addJS(
    $this->_path . 'views/js/cpfhub-validator.js'
    );
    $this->context->controller->addCSS(
    $this->_path . 'views/css/cpfhub-validator.css'
    );
    }

    public function hookDisplayCustomerAccountForm($params)
    {
    if (!Configuration::get('CPFHUB_ENABLED')) {
    return '';
    }

    return $this->display(__FILE__, 'views/templates/hook/cpf_field.tpl');
    }

    public function hookActionValidateCustomerAddressForm($params)
    {
    if (!Configuration::get('CPFHUB_ENABLED')) {
    return;
    }

    $cpf = preg_replace('/\D/', '', Tools::getValue('cpf'));

    if (empty($cpf) || strlen($cpf) !== 11) {
    $params['form']->getField('cpf')->addError(
    $this->l('Por favor, informe um CPF válido.')
    );
    }
    }
}

Controller de validação AJAX

Crie o front controller que recebe as requisições AJAX:

<?php
// modules/cpfhubvalidator/controllers/front/validation.php

class CpfHubValidatorValidationModuleFrontController extends ModuleFrontController
{
    public function initContent()
    {
    parent::initContent();

    if (!$this->isTokenValid()) {
    $this->ajaxResponse(false, 'Token inválido.');
    return;
    }

    $cpf = preg_replace('/\D/', '', Tools::getValue('cpf'));

    if (strlen($cpf) !== 11) {
    $this->ajaxResponse(false, 'CPF deve conter 11 dígitos.');
    return;
    }

    $result = $this->validateCpf($cpf);
    $this->ajaxResponse($result['success'], $result['message'], $result['data'] ?? []);
    }

    private function validateCpf($cpf)
    {
    $apiKey = Configuration::get('CPFHUB_API_KEY');
    $url = "https://api.cpfhub.io/cpf/{$cpf}";

    $ch = curl_init();
    curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
    "x-api-key: {$apiKey}",
    "Accept: application/json",
    ],
    CURLOPT_TIMEOUT => 10,
    CURLOPT_CONNECTTIMEOUT => 5,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);

    if ($error) {
    return [
    'success' => false,
    'message' => 'Erro na comunicação com a API.',
    ];
    }

    $data = json_decode($response, true);

    if ($httpCode === 200 && !empty($data['success'])) {
    return [
    'success' => true,
    'message' => 'CPF válido.',
    'data' => $data['data'],
    ];
    }

    return [
    'success' => false,
    'message' => 'CPF não encontrado na base de dados.',
    ];
    }

    private function ajaxResponse($success, $message, $data = [])
    {
    header('Content-Type: application/json');
    die(json_encode([
    'success' => $success,
    'message' => $message,
    'data' => $data,
    ]));
    }
}

Template Smarty para o campo de CPF

{* modules/cpfhubvalidator/views/templates/hook/cpf_field.tpl *}
<div class="form-group cpfhub-field-wrapper">
    <label for="cpf" class="col-md-3 form-control-label required">
    CPF
    </label>
    <div class="col-md-6">
    <input
    type="text"
    id="cpf"
    name="cpf"
    class="form-control"
    placeholder="000.000.000-00"
    inputmode="numeric"
    maxlength="14"
    required
    />
    <div id="cpfhub-feedback" class="cpfhub-feedback"></div>
    </div>
</div>

JavaScript para validação frontend

// modules/cpfhubvalidator/views/js/cpfhub-validator.js
(function () {
    "use strict";

    var debounceTimer = null;

    document.addEventListener("DOMContentLoaded", function () {
    var cpfField = document.getElementById("cpf");
    if (!cpfField) return;

    var feedback = document.getElementById("cpfhub-feedback");

    cpfField.addEventListener("input", function () {
    formatCpf(cpfField);

    if (debounceTimer) clearTimeout(debounceTimer);
    debounceTimer = setTimeout(function () {
    var cpf = cpfField.value.replace(/\D/g, "");
    if (cpf.length === 11) {
    validateCpf(cpf, feedback);
    } else {
    feedback.textContent = "";
    feedback.className = "cpfhub-feedback";
    }
    }, 600);
    });
    });

    function formatCpf(field) {
    var value = field.value.replace(/\D/g, "").slice(0, 11);
    if (value.length > 9) {
    value = value.replace(/(\d{3})(\d{3})(\d{3})(\d{1,2})/, "$1.$2.$3-$4");
    } else if (value.length > 6) {
    value = value.replace(/(\d{3})(\d{3})(\d{1,3})/, "$1.$2.$3");
    } else if (value.length > 3) {
    value = value.replace(/(\d{3})(\d{1,3})/, "$1.$2");
    }
    field.value = value;
    }

    function validateCpf(cpf, feedback) {
    feedback.textContent = "Validando...";
    feedback.className = "cpfhub-feedback cpfhub-loading";

    var controller = new AbortController();
    var timeoutId = setTimeout(function () {
    controller.abort();
    }, 12000);

    var formData = new FormData();
    formData.append("cpf", cpf);
    formData.append("ajax", "1");
    formData.append("token", prestashop.static_token);

    fetch(cpfhubValidationUrl, {
    method: "POST",
    body: formData,
    signal: controller.signal,
    })
    .then(function (response) {
    clearTimeout(timeoutId);
    return response.json();
    })
    .then(function (result) {
    if (result.success) {
    feedback.textContent = "CPF válido - " + result.data.name;
    feedback.className = "cpfhub-feedback cpfhub-success";
    } else {
    feedback.textContent = result.message;
    feedback.className = "cpfhub-feedback cpfhub-error";
    }
    })
    .catch(function (err) {
    clearTimeout(timeoutId);
    feedback.textContent =
    err.name === "AbortError"
    ? "Tempo excedido. Tente novamente."
    : "Erro na validação.";
    feedback.className = "cpfhub-feedback cpfhub-error";
    });
    }
})();

Estilos CSS do módulo

/* modules/cpfhubvalidator/views/css/cpfhub-validator.css */
.cpfhub-field-wrapper {
    margin-bottom: 1rem;
}

.cpfhub-feedback {
    font-size: 0.85rem;
    margin-top: 4px;
    min-height: 1.2em;
    transition: color 0.2s ease;
}

.cpfhub-loading {
    color: #6b7280;
}

.cpfhub-success {
    color: #059669;
    font-weight: 500;
}

.cpfhub-error {
    color: #dc2626;
}

Testando o módulo

Após instalar o módulo pelo backoffice do PrestaShop em Modules > Module Manager, configure a chave de API e acesse a página de cadastro de clientes. O campo de CPF deve aparecer com validação automática ao digitar.

Para testar via linha de comando, use:

# Verificar se o módulo está instalado
php bin/console prestashop:module list | grep cpfhub

# Limpar cache após alterações
php bin/console cache:clear

Perguntas frequentes

Por que criar um módulo customizado em vez de editar o tema diretamente?

Modificar o tema do PrestaShop diretamente torna o código frágil: qualquer atualização de tema apaga as alterações. Um módulo customizado encapsula toda a lógica de validação, registra os hooks apropriados e pode ser instalado, desinstalado e atualizado de forma independente. Essa separação segue as boas práticas da documentação oficial do PrestaShop para desenvolvimento sustentável.

A API CPFHub.io retorna erro 429 quando o limite de consultas é atingido?

Não. Quando o plano atinge o limite mensal, a API continua respondendo normalmente e cobra R$0,15 por consulta adicional — sem bloquear o serviço nem retornar código de erro 429. O plano gratuito inclui 50 consultas por mês; o plano Pro oferece 1.000 consultas mensais por R$149 com o mesmo modelo de excedente.

Como proteger a chave de API no módulo PrestaShop?

Armazene a chave usando Configuration::updateValue('CPFHUB_API_KEY', $apiKey) e recupere com Configuration::get('CPFHUB_API_KEY') — isso usa a tabela de configuração do banco de dados, nunca exposta ao frontend. A chave é usada apenas no controller PHP server-side; o JavaScript do storefront recebe apenas a URL do endpoint interno do módulo, sem acesso direto à API externa. A ANPD orienta que credenciais de acesso a dados pessoais devem ser tratadas com controles de acesso adequados.

Qual o tempo de resposta esperado e como ajustar os timeouts do cURL?

A latência média da API CPFHub.io é de aproximadamente 900ms. O controller deste módulo define CURLOPT_TIMEOUT => 10 e CURLOPT_CONNECTTIMEOUT => 5, valores adequados para absorver variações de rede sem bloquear o processo PHP por tempo excessivo. No JavaScript, o AbortController com 12 segundos de timeout garante que o usuário receba uma mensagem de erro clara caso a conexão falhe.


Conclusão

Criar um módulo PrestaShop para validação de CPF com a API do CPFHub.io

A API da CPFHub oferece tempo de resposta de aproximadamente 900ms, uptime de 99,9% e conformidade com a LGPD -- características essenciais para operações de e-commerce no Brasil.

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