Skip to main content

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

  1. Encrypt only at payment time — Do not store encrypted tokens
  2. Process immediately — Send the token to your API as soon as it is generated
  3. Handle expiration — Implement retry with new encryption if needed
  4. 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

  1. Implement the examples in your development environment
  2. Configure the required environment variables
  3. Test the integration with test data
  4. Integrate with your Payments API
  5. Monitor behavior in production

For more information, see the full Sopague Library documentation.