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"