Practical Example — Sopague Integration
This guide provides practical examples of how to integrate the Sopague Library in different payment scenarios.
Example: Full e-commerce
HTML + JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkout - E-commerce</title>
<!-- To get the Sopague Library CDN URL, contact support -->
<script src="https://cdn.exemplo.com/sopague/sopague.min.js"></script>
</head>
<body>
<div id="checkout-form">
<h2>Checkout</h2>
<!-- Card details -->
<div class="form-group">
<label>Card number:</label>
<input type="text" id="cardNumber" placeholder="0000 0000 0000 0000" maxlength="19">
</div>
<div class="form-group">
<label>Name on card:</label>
<input type="text" id="cardName" placeholder="Name as on card">
</div>
<div class="form-group">
<label>Expiry:</label>
<input type="text" id="cardExpiry" placeholder="MM/YY" maxlength="5">
</div>
<div class="form-group">
<label>CVV:</label>
<input type="text" id="cardCvv" placeholder="123" maxlength="4">
</div>
<button id="processPayment" disabled>Process Payment</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 {
// Configure public key
Sopague.setEncryptPublicKey(this.publicKey);
// Initialize anti-fraud
Sopague.initAntiFraud(this.antiFraudId, {
orgId: 'ecommerce_org',
sessionPrefix: 'ecom_'
});
console.log('Sopague initialized successfully');
this.updateStatus('Security system loaded', 'success');
} catch (error) {
console.error('Error initializing Sopague:', error);
this.updateStatus('Error loading security system', 'error');
}
}
setupEventListeners() {
const cardNumber = document.getElementById('cardNumber');
const processBtn = document.getElementById('processPayment');
// Format card number
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;
// Enable button if card number is valid
processBtn.disabled = !this.isValidCard(value);
});
// Process payment
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('Processing payment...', 'info');
try {
// Encrypt sensitive data (valid for 5 minutes)
const encryptedCard = await Sopague.encryptCard(cardNumber);
const sessionId = Sopague.getAntiFraudSessionId();
// Simulate sending to API
const paymentData = {
encryptedCard: encryptedCard,
cardName: cardName,
cardExpiry: cardExpiry,
cardCvv: cardCvv,
antiFraudSessionId: sessionId,
amount: 100.00,
currency: 'BRL'
};
console.log('Payment data:', paymentData);
// Here you would make the real call to your API
// const response = await fetch('/api/payments', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(paymentData)
// });
this.updateStatus('Payment processed successfully!', 'success');
} catch (error) {
console.error('Processing error:', error);
this.updateStatus('Error processing payment: ' + error.message, 'error');
}
}
validateForm(cardNumber, cardName, cardExpiry, cardCvv) {
if (!cardNumber || !cardName || !cardExpiry || !cardCvv) {
this.updateStatus('Please fill in all fields', 'error');
return false;
}
if (!this.isValidCard(cardNumber)) {
this.updateStatus('Invalid card number', 'error');
return false;
}
return true;
}
updateStatus(message, type) {
const statusEl = document.getElementById('status');
statusEl.textContent = message;
statusEl.className = `status ${type}`;
}
}
// Initialize when the page loads
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>
Example: React/NextJS
Custom hook
// 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);
// Automatically configure public key
if (window.Sopague && process.env.NEXT_PUBLIC_RSA_PUBLIC_KEY) {
window.Sopague.setEncryptPublicKey(process.env.NEXT_PUBLIC_RSA_PUBLIC_KEY);
}
};
script.onerror = () => {
setError('Error loading 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 not loaded');
}
return await window.Sopague.encryptCard(cardNumber);
}, []);
const initAntiFraud = useCallback((sessionId: string): string => {
if (!window.Sopague) {
throw new Error('Sopague not loaded');
}
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
};
}
Payment component
// 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) {
// Initialize anti-fraud when the library loads
const sessionId = initAntiFraud(`session_${Date.now()}`);
console.log('Anti-fraud initialized:', sessionId);
}
}, [isLoaded, initAntiFraud]);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
if (name === 'cardNumber') {
// Format card number
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 {
// Validate form
if (!validateForm()) {
return;
}
// Encrypt card (valid for 5 minutes)
const cleanCardNumber = formData.cardNumber.replace(/\s/g, '');
const encryptedCard = await encryptCard(cleanCardNumber);
// Get anti-fraud session ID
const antiFraudSessionId = getSessionId();
// Prepare payment data
const paymentData = {
encryptedCard,
cardName: formData.cardName,
cardExpiry: formData.cardExpiry,
cardCvv: formData.cardCvv,
antiFraudSessionId,
amount,
currency: 'BRL'
};
// Simulate API call
console.log('Sending payment:', paymentData);
// Here you would make the real call to your 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 : 'Unknown error');
} finally {
setIsProcessing(false);
}
};
const validateForm = (): boolean => {
const { cardNumber, cardName, cardExpiry, cardCvv } = formData;
if (!cardNumber || !cardName || !cardExpiry || !cardCvv) {
onError('Please fill in all fields');
return false;
}
const cleanCardNumber = cardNumber.replace(/\s/g, '');
if (cleanCardNumber.length < 13 || cleanCardNumber.length > 19) {
onError('Invalid card number');
return false;
}
return true;
};
if (error) {
return <div className="error">Error loading payment system: {error}</div>;
}
if (!isLoaded) {
return <div className="loading">Loading payment system...</div>;
}
return (
<form onSubmit={handleSubmit} className="payment-form">
<h3>Card details</h3>
<div className="form-group">
<label>Card number:</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>Name on card:</label>
<input
type="text"
name="cardName"
value={formData.cardName}
onChange={handleInputChange}
placeholder="Name as on card"
required
/>
</div>
<div className="form-row">
<div className="form-group">
<label>Expiry:</label>
<input
type="text"
name="cardExpiry"
value={formData.cardExpiry}
onChange={handleInputChange}
placeholder="MM/YY"
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>
);
}
Environment configuration
Environment variables (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"
Server configuration
// 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 {
// Validate received data
if (!encryptedCard || !antiFraudSessionId) {
return res.status(400).json({
message: 'Required security data'
});
}
// Here you would integrate with the SoPague API
// const paymentResponse = await sopagueAPI.createPayment({
// encryptedCard,
// antiFraudSessionId,
// amount,
// currency
// });
res.status(200).json({
success: true,
message: 'Payment processed successfully'
});
} catch (error) {
console.error('Processing error:', error);
res.status(500).json({
message: 'Internal server error'
});
}
}
Encryption best practices
Validity period
Important
The encrypted token generated by the Sopague library expires in 5 minutes. After that, the token cannot be used to process payments.
Recommendations
- Encrypt only at payment time — Do not store encrypted tokens
- Process immediately — Send the token to your API as soon as it is generated
- Handle expiration — Implement retry with new encryption if needed
- Validate server-side — Always validate token validity in your backend
Secure implementation example
async function processPaymentSecurely(cardData) {
try {
// 1. Encrypt only when needed
const encryptedCard = await Sopague.encryptCard(cardData.number);
// 2. Process immediately
const paymentData = {
encryptedCard,
antiFraudSessionId: Sopague.getAntiFraudSessionId(),
amount: cardData.amount,
// ... other fields
};
// 3. Send to the API without 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 with new encryption
return processPaymentSecurely(cardData);
}
throw error;
}
}
Tests
Encryption test
// test-encryption.js
async function testEncryption() {
const testCard = '4111111111111111';
try {
Sopague.setEncryptPublicKey(publicKey);
const encrypted = await Sopague.encryptCard(testCard);
console.log('Original card:', testCard);
console.log('Encrypted card:', encrypted);
console.log('Encryption test: ✅ Success');
} catch (error) {
console.error('Encryption test: ❌ Failed', error);
}
}
// Run test
testEncryption();
Anti-fraud test
// test-antifraud.js
function testAntiFraud() {
try {
const sessionId = Sopague.initAntiFraud('test-session-123');
console.log('Generated session ID:', sessionId);
const currentSession = Sopague.getAntiFraudSessionId();
console.log('Current session ID:', currentSession);
console.log('Anti-fraud test: ✅ Success');
} catch (error) {
console.error('Anti-fraud test: ❌ Failed', error);
}
}
// Run test
testAntiFraud();
Next steps
- Implement the examples in your development environment
- Configure the required environment variables
- Test the integration with test data
- Integrate with your Payments API
- Monitor behavior in production
For more information, see the full Sopague Library documentation.