Exemplo Prático - Integração Sopague
Este guia apresenta exemplos práticos de como integrar a Biblioteca Sopague em diferentes cenários de pagamento.
Exemplo: E-commerce Completo
HTML + JavaScript
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkout - E-commerce</title>
<!-- Para obter a URL do CDN da biblioteca Sopague, entre em contato com o suporte -->
<script src="https://cdn.exemplo.com/sopague/sopague.min.js"></script>
</head>
<body>
<div id="checkout-form">
<h2>Finalizar Compra</h2>
<!-- Dados do Cartão -->
<div class="form-group">
<label>Número do Cartão:</label>
<input type="text" id="cardNumber" placeholder="0000 0000 0000 0000" maxlength="19">
</div>
<div class="form-group">
<label>Nome no Cartão:</label>
<input type="text" id="cardName" placeholder="Nome como no cartão">
</div>
<div class="form-group">
<label>Validade:</label>
<input type="text" id="cardExpiry" placeholder="MM/AA" maxlength="5">
</div>
<div class="form-group">
<label>CVV:</label>
<input type="text" id="cardCvv" placeholder="123" maxlength="4">
</div>
<button id="processPayment" disabled>Processar Pagamento</button>
<div id="status"></div>
</div>
<script>
class PaymentProcessor {
constructor() {
this.publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...
-----END PUBLIC KEY-----`;
this.antiFraudId = this.generateSessionId();
this.initializeSopague();
this.setupEventListeners();
}
generateSessionId() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
initializeSopague() {
try {
// Configurar chave pública
Sopague.setEncryptPublicKey(this.publicKey);
// Inicializar anti-fraude
Sopague.initAntiFraud(this.antiFraudId, {
orgId: 'ecommerce_org',
sessionPrefix: 'ecom_'
});
console.log('Sopague inicializado com sucesso');
this.updateStatus('Sistema de segurança carregado', 'success');
} catch (error) {
console.error('Erro ao inicializar Sopague:', error);
this.updateStatus('Erro ao carregar sistema de segurança', 'error');
}
}
setupEventListeners() {
const cardNumber = document.getElementById('cardNumber');
const processBtn = document.getElementById('processPayment');
// Formatar número do cartão
cardNumber.addEventListener('input', (e) => {
let value = e.target.value.replace(/\s/g, '').replace(/[^0-9]/gi, '');
let formattedValue = value.match(/.{1,4}/g)?.join(' ') || value;
e.target.value = formattedValue;
// Habilitar botão se cartão válido
processBtn.disabled = !this.isValidCard(value);
});
// Processar pagamento
processBtn.addEventListener('click', () => {
this.processPayment();
});
}
isValidCard(cardNumber) {
const cleanNumber = cardNumber.replace(/\s/g, '');
return cleanNumber.length >= 13 && cleanNumber.length <= 19;
}
async processPayment() {
const cardNumber = document.getElementById('cardNumber').value.replace(/\s/g, '');
const cardName = document.getElementById('cardName').value;
const cardExpiry = document.getElementById('cardExpiry').value;
const cardCvv = document.getElementById('cardCvv').value;
if (!this.validateForm(cardNumber, cardName, cardExpiry, cardCvv)) {
return;
}
this.updateStatus('Processando pagamento...', 'info');
try {
// Criptografar dados sensíveis (válido por 5 minutos)
const encryptedCard = await Sopague.encryptCard(cardNumber);
const sessionId = Sopague.getAntiFraudSessionId();
// Simular envio para API
const paymentData = {
encryptedCard: encryptedCard,
cardName: cardName,
cardExpiry: cardExpiry,
cardCvv: cardCvv,
antiFraudSessionId: sessionId,
amount: 100.00,
currency: 'BRL'
};
console.log('Dados do pagamento:', paymentData);
// Aqui você faria a chamada real para sua API
// const response = await fetch('/api/payments', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(paymentData)
// });
this.updateStatus('Pagamento processado com sucesso!', 'success');
} catch (error) {
console.error('Erro no processamento:', error);
this.updateStatus('Erro ao processar pagamento: ' + error.message, 'error');
}
}
validateForm(cardNumber, cardName, cardExpiry, cardCvv) {
if (!cardNumber || !cardName || !cardExpiry || !cardCvv) {
this.updateStatus('Preencha todos os campos', 'error');
return false;
}
if (!this.isValidCard(cardNumber)) {
this.updateStatus('Número do cartão inválido', 'error');
return false;
}
return true;
}
updateStatus(message, type) {
const statusEl = document.getElementById('status');
statusEl.textContent = message;
statusEl.className = `status ${type}`;
}
}
// Inicializar quando a página carregar
document.addEventListener('DOMContentLoaded', () => {
new PaymentProcessor();
});
</script>
<style>
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
#processPayment {
background: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
#processPayment:disabled {
background: #ccc;
cursor: not-allowed;
}
.status {
margin-top: 15px;
padding: 10px;
border-radius: 4px;
}
.status.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.status.info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
</style>
</body>
</html>
Exemplo: React/NextJS
Hook Personalizado
// hooks/useSopague.ts
import { useState, useEffect, useCallback } from 'react';
interface SopagueHook {
Sopague: any;
isLoaded: boolean;
error: string | null;
encryptCard: (cardNumber: string) => Promise<string>;
initAntiFraud: (sessionId: string) => string;
getSessionId: () => string | null;
}
export function useSopague(): SopagueHook {
const [isLoaded, setIsLoaded] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (typeof window !== 'undefined' && window.Sopague) {
setIsLoaded(true);
return;
}
const script = document.createElement('script');
script.src = '/libs/sopague-integration-library-1.0.0.min.js';
script.async = true;
script.onload = () => {
setIsLoaded(true);
// Configurar chave pública automaticamente
if (window.Sopague && process.env.NEXT_PUBLIC_RSA_PUBLIC_KEY) {
window.Sopague.setEncryptPublicKey(process.env.NEXT_PUBLIC_RSA_PUBLIC_KEY);
}
};
script.onerror = () => {
setError('Erro ao carregar Sopague');
};
document.body.appendChild(script);
return () => {
if (document.body.contains(script)) {
document.body.removeChild(script);
}
};
}, []);
const encryptCard = useCallback(async (cardNumber: string): Promise<string> => {
if (!window.Sopague) {
throw new Error('Sopague não carregado');
}
return await window.Sopague.encryptCard(cardNumber);
}, []);
const initAntiFraud = useCallback((sessionId: string): string => {
if (!window.Sopague) {
throw new Error('Sopague não carregado');
}
return window.Sopague.initAntiFraud(sessionId, {
orgId: process.env.NEXT_PUBLIC_ORG_ID || 'default_org',
sessionPrefix: 'nextjs_'
});
}, []);
const getSessionId = useCallback((): string | null => {
if (!window.Sopague) return null;
return window.Sopague.getAntiFraudSessionId();
}, []);
return {
Sopague: typeof window !== 'undefined' ? window.Sopague : null,
isLoaded,
error,
encryptCard,
initAntiFraud,
getSessionId
};
}
Componente de Pagamento
// components/PaymentForm.tsx
import React, { useState, useEffect } from 'react';
import { useSopague } from '../hooks/useSopague';
interface PaymentFormProps {
amount: number;
onSuccess: (paymentData: any) => void;
onError: (error: string) => void;
}
export default function PaymentForm({ amount, onSuccess, onError }: PaymentFormProps) {
const { isLoaded, error, encryptCard, initAntiFraud, getSessionId } = useSopague();
const [formData, setFormData] = useState({
cardNumber: '',
cardName: '',
cardExpiry: '',
cardCvv: ''
});
const [isProcessing, setIsProcessing] = useState(false);
useEffect(() => {
if (isLoaded) {
// Inicializar anti-fraude quando a biblioteca carregar
const sessionId = initAntiFraud(`session_${Date.now()}`);
console.log('Anti-fraude inicializado:', sessionId);
}
}, [isLoaded, initAntiFraud]);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
if (name === 'cardNumber') {
// Formatar número do cartão
const formatted = value.replace(/\s/g, '').replace(/(.{4})/g, '$1 ').trim();
setFormData(prev => ({ ...prev, [name]: formatted }));
} else {
setFormData(prev => ({ ...prev, [name]: value }));
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsProcessing(true);
try {
// Validar formulário
if (!validateForm()) {
return;
}
// Criptografar cartão (válido por 5 minutos)
const cleanCardNumber = formData.cardNumber.replace(/\s/g, '');
const encryptedCard = await encryptCard(cleanCardNumber);
// Obter session ID do anti-fraude
const antiFraudSessionId = getSessionId();
// Preparar dados do pagamento
const paymentData = {
encryptedCard,
cardName: formData.cardName,
cardExpiry: formData.cardExpiry,
cardCvv: formData.cardCvv,
antiFraudSessionId,
amount,
currency: 'BRL'
};
// Simular chamada para API
console.log('Enviando pagamento:', paymentData);
// Aqui você faria a chamada real para sua API
// const response = await fetch('/api/payments', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(paymentData)
// });
onSuccess(paymentData);
} catch (err) {
onError(err instanceof Error ? err.message : 'Erro desconhecido');
} finally {
setIsProcessing(false);
}
};
const validateForm = (): boolean => {
const { cardNumber, cardName, cardExpiry, cardCvv } = formData;
if (!cardNumber || !cardName || !cardExpiry || !cardCvv) {
onError('Preencha todos os campos');
return false;
}
const cleanCardNumber = cardNumber.replace(/\s/g, '');
if (cleanCardNumber.length < 13 || cleanCardNumber.length > 19) {
onError('Número do cartão inválido');
return false;
}
return true;
};
if (error) {
return <div className="error">Erro ao carregar sistema de pagamento: {error}</div>;
}
if (!isLoaded) {
return <div className="loading">Carregando sistema de pagamento...</div>;
}
return (
<form onSubmit={handleSubmit} className="payment-form">
<h3>Dados do Cartão</h3>
<div className="form-group">
<label>Número do Cartão:</label>
<input
type="text"
name="cardNumber"
value={formData.cardNumber}
onChange={handleInputChange}
placeholder="0000 0000 0000 0000"
maxLength={19}
required
/>
</div>
<div className="form-group">
<label>Nome no Cartão:</label>
<input
type="text"
name="cardName"
value={formData.cardName}
onChange={handleInputChange}
placeholder="Nome como no cartão"
required
/>
</div>
<div className="form-row">
<div className="form-group">
<label>Validade:</label>
<input
type="text"
name="cardExpiry"
value={formData.cardExpiry}
onChange={handleInputChange}
placeholder="MM/AA"
maxLength={5}
required
/>
</div>
<div className="form-group">
<label>CVV:</label>
<input
type="text"
name="cardCvv"
value={formData.cardCvv}
onChange={handleInputChange}
placeholder="123"
maxLength={4}
required
/>
</div>
</div>
<div className="amount">
<strong>Valor: R$ {amount.toFixed(2)}</strong>
</div>
<button
type="submit"
disabled={isProcessing}
className="submit-button"
>
{isProcessing ? 'Processando...' : 'Pagar Agora'}
</button>
</form>
);
}
Configuração de Ambiente
Variáveis de Ambiente (NextJS)
# .env.local
NEXT_PUBLIC_RSA_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...\n-----END PUBLIC KEY-----"
NEXT_PUBLIC_ORG_ID="sua_organizacao_id"
NEXT_PUBLIC_SOPAGUE_VERSION="1.0.0"
Configuração do Servidor
// pages/api/payments.js (NextJS)
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
}
const { encryptedCard, antiFraudSessionId, amount, currency } = req.body;
try {
// Validar dados recebidos
if (!encryptedCard || !antiFraudSessionId) {
return res.status(400).json({
message: 'Dados de segurança obrigatórios'
});
}
// Aqui você faria a integração com a API da SoPague
// const paymentResponse = await sopagueAPI.createPayment({
// encryptedCard,
// antiFraudSessionId,
// amount,
// currency
// });
res.status(200).json({
success: true,
message: 'Pagamento processado com sucesso'
});
} catch (error) {
console.error('Erro no processamento:', error);
res.status(500).json({
message: 'Erro interno do servidor'
});
}
}
Boas Práticas de Criptografia
Tempo de Validade
Importante
O token criptografado gerado pela biblioteca Sopague expira em 5 minutos. Após esse período, o token não pode ser usado para processar pagamentos.
Recomendações
- Criptografe apenas no momento do pagamento - Não armazene tokens criptografados
- Processe imediatamente - Envie o token para a API assim que gerado
- Trate expirações - Implemente retry com nova criptografia se necessário
- Valide no servidor - Sempre valide a validade do token no backend
Exemplo de Implementação Segura
async function processPaymentSecurely(cardData) {
try {
// 1. Criptografar apenas quando necessário
const encryptedCard = await Sopague.encryptCard(cardData.number);
// 2. Processar imediatamente
const paymentData = {
encryptedCard,
antiFraudSessionId: Sopague.getAntiFraudSessionId(),
amount: cardData.amount,
// ... outros dados
};
// 3. Enviar para API sem delay
const response = await fetch('/api/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paymentData)
});
return await response.json();
} catch (error) {
// 4. Tratar erros de expiração
if (error.message.includes('expired') || error.message.includes('invalid')) {
console.log('Token expirado, tentando novamente...');
// Retry com nova criptografia
return processPaymentSecurely(cardData);
}
throw error;
}
}
Testes
Teste de Criptografia
// test-encryption.js
async function testEncryption() {
const testCard = '4111111111111111';
try {
Sopague.setEncryptPublicKey(publicKey);
const encrypted = await Sopague.encryptCard(testCard);
console.log('Cartão original:', testCard);
console.log('Cartão criptografado:', encrypted);
console.log('Teste de criptografia: ✅ Sucesso');
} catch (error) {
console.error('Teste de criptografia: ❌ Falha', error);
}
}
// Executar teste
testEncryption();
Teste de Anti-Fraude
// test-antifraud.js
function testAntiFraud() {
try {
const sessionId = Sopague.initAntiFraud('test-session-123');
console.log('Session ID gerado:', sessionId);
const currentSession = Sopague.getAntiFraudSessionId();
console.log('Session ID atual:', currentSession);
console.log('Teste de anti-fraude: ✅ Sucesso');
} catch (error) {
console.error('Teste de anti-fraude: ❌ Falha', error);
}
}
// Executar teste
testAntiFraud();
Próximos Passos
- Implemente os exemplos em seu ambiente de desenvolvimento
- Configure as variáveis de ambiente necessárias
- Teste a integração com dados de teste
- Integre com sua API de pagamentos
- Monitore o funcionamento em produção
Para mais informações, consulte a documentação completa da Biblioteca Sopague.