Examples
Real-world examples showing how to integrate Altruon JS in different scenarios.
The Merchant Demo: complete reference integration
The Altruon Merchant Demo is our official, open-source reference integration: a branded SaaS checkout built with React and a minimal Express backend, exercising the full SDK surface. If you only look at one example, make it this one. Every file is heavily commented and meant to be read.
git clone https://github.com/Altruon-io/merchant-demo
cd merchant-demo
npm run setup
cp server/.env.example server/.env # fill in your sandbox credentials
npm run dev # backend :4242, frontend :3030
What it demonstrates:
| Feature | Where to look |
|---|---|
| Server-side session creation (secret key isolation) | server/src/altruonClient.js, server/src/routes.js |
| Full SDK integration walkthrough (init → setSession → render → process) | client/src/pages/CheckoutPage.jsx |
| Live tax & discount estimates with coupon codes | client/src/components/OrderSummary.jsx |
onActionRequired: REDIRECT disclaimer modal before 3-D Secure / bank redirects | client/src/components/RedirectModal.jsx |
onActionRequired: QR_CODE scan-to-pay overlay for Pix / UPI | client/src/components/QrOverlay.jsx |
| Failure handling with retry on a fresh session | client/src/components/FailureModal.jsx |
| Post-payment transaction report with gateway & billing dashboard deep links | client/src/pages/ResultPage.jsx |
| Styling the embedded component to match the host page | buildStyleCustomization() in server/src/routes.js |
The patterns below are shorter, self-contained variations for specific scenarios.
Basic Examples
Simple Subscription Checkout
A minimal implementation for a subscription checkout page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subscribe - Pro Plan</title>
<script src="https://cdn.altruon.io/altruon-sdk.min.js"></script>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
max-width: 500px;
margin: 50px auto;
padding: 20px;
}
.plan-details {
background: #F9FAFB;
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
}
#error-message {
background: #FEE2E2;
color: #DC2626;
padding: 12px;
border-radius: 6px;
margin-bottom: 20px;
display: none;
}
button {
width: 100%;
background: #3B82F6;
color: white;
border: none;
padding: 14px;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
margin-top: 20px;
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>Subscribe to Pro Plan</h1>
<div class="plan-details">
<h2>Pro Plan</h2>
<p>$29/month - Unlimited access to all features</p>
</div>
<div id="error-message"></div>
<div id="payment-container"></div>
<button id="pay-button">Subscribe Now</button>
<script>
// Get session ID from your server (passed via template or API)
const sessionId = '<%= sessionId %>'; // From your backend
// Initialize Altruon with callbacks
altruon
.init("pk_sandbox_your_key_here", "your-domain")
.on("onSuccess", (data) => {
window.location.href = '/welcome';
})
.on("onFailure", (error) => {
const errorDiv = document.getElementById('error-message');
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
});
// Set session
altruon.setSession(sessionId);
// Render payment component
altruon.renderComponent('#payment-container');
</script>
</body>
</html>
Pre-filled Customer Information
Pass existing customer data to streamline the checkout process.
// Initialize Altruon with callbacks
altruon
.init("pk_sandbox_your_key", "your-domain")
.on("onSuccess", (data) => window.location.href = '/success')
.on("onFailure", (error) => alert(error.message));
// Set session (from backend)
altruon.setSession(sessionId);
// Set customer data
altruon.setCustomer({
firstName: "John",
lastName: "Doe",
email: "john.doe@example.com",
phone: "+1234567890",
ip: "127.0.0.1"
});
// Set billing address
altruon.setAddresses({
billing: {
street: "123 Main St",
city: "San Francisco",
state: "CA",
zipCode: "94102",
country: "US"
}
});
// Render component
altruon.renderComponent('#payment-container');
Framework Integration
React Example
import React, { useEffect, useRef, useState } from 'react';
interface AltruonCheckoutProps {
sessionId: string;
customerEmail?: string;
onSuccess: (subscriptionId: string) => void;
onError: (error: any) => void;
}
const AltruonCheckout: React.FC<AltruonCheckoutProps> = ({
sessionId,
customerEmail,
onSuccess,
onError
}) => {
const paymentContainerRef = useRef<HTMLDivElement>(null);
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
// Load Altruon script
const script = document.createElement('script');
script.src = 'https://cdn.altruon.io/altruon-sdk.min.js';
script.async = true;
script.onload = initializeAltruon;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
const initializeAltruon = () => {
const altruon = (window as any).altruon;
// Initialize with callbacks
altruon
.init(process.env.REACT_APP_ALTRUON_PUBLIC_KEY!, "your-domain")
.on("onSuccess", (data: any) => {
onSuccess(data);
setIsProcessing(false);
})
.on("onFailure", (error: any) => {
setError(error.message);
onError(error);
setIsProcessing(false);
});
// Set session
altruon.setSession(sessionId);
// Set customer data if available
if (customerEmail) {
altruon.setCustomer({
email: customerEmail
});
}
// Render component
if (paymentContainerRef.current) {
altruon.renderComponent(paymentContainerRef.current);
setIsLoaded(true);
}
};
const handlePayment = () => {
setIsProcessing(true);
setError(null);
// Manually trigger payment if needed
const iframe = paymentContainerRef.current?.querySelector('iframe');
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({ type: "makePayment" }, "*");
}
};
return (
<div className="altruon-checkout">
{!isLoaded && (
<div className="loading-skeleton">
<div className="skeleton-line"></div>
<div className="skeleton-line"></div>
<div className="skeleton-line"></div>
</div>
)}
{error && (
<div className="error-banner">
{error}
</div>
)}
<div ref={paymentContainerRef} />
{isLoaded && (
<button
onClick={handlePayment}
disabled={isProcessing}
className="pay-button"
>
{isProcessing ? 'Processing...' : 'Pay Now'}
</button>
)}
</div>
);
};
export default AltruonCheckout;
Usage:
function CheckoutPage() {
const navigate = useNavigate();
const [sessionId, setSessionId] = useState<string | null>(null);
useEffect(() => {
// Create session on your backend
fetch('/api/create-checkout-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
billingData: {
lineItems: [
{
type: 'plan',
id: 'price_1SMtJj4hYau76GhIakR22BKu',
quantity: '1'
}
],
billingPlatformId: '3287b8c7-ce43-41fd-9d58-f510e610b8f3'
},
currency: 'USD'
})
})
.then(res => res.json())
.then(data => setSessionId(data.sessionId));
}, []);
const handleSuccess = (subscriptionId: string) => {
navigate(`/success?subscription=${subscriptionId}`);
};
const handleError = (error: any) => {
console.error('Payment error:', error);
// Track error in analytics
};
if (!sessionId) {
return <div>Loading...</div>;
}
return (
<div className="checkout-page">
<h1>Complete Your Subscription</h1>
<AltruonCheckout
sessionId={sessionId}
customerEmail="customer@example.com"
onSuccess={handleSuccess}
onError={handleError}
/>
</div>
);
}
Vue.js Example
<template>
<div class="altruon-checkout">
<div v-if="isLoading" class="loading">
Loading payment form...
</div>
<div v-if="errorMessage" class="error-message">
{{ errorMessage }}
</div>
<div ref="paymentContainer"></div>
<button
v-if="!isLoading"
@click="handlePayment"
:disabled="isProcessing"
class="pay-button"
>
{{ isProcessing ? 'Processing...' : 'Pay Now' }}
</button>
</div>
</template>
<script>
export default {
name: 'AltruonCheckout',
props: {
sessionId: {
type: String,
required: true
}
},
data() {
return {
isLoading: true,
isProcessing: false,
errorMessage: null
};
},
mounted() {
this.loadAltruonScript();
},
methods: {
loadAltruonScript() {
const script = document.createElement('script');
script.src = 'https://cdn.altruon.io/altruon-sdk.min.js';
script.onload = this.initializeAltruon;
document.body.appendChild(script);
},
initializeAltruon() {
const altruon = window.altruon;
// Initialize with callbacks
altruon
.init(process.env.VUE_APP_ALTRUON_PUBLIC_KEY, "your-domain")
.on("onSuccess", (data) => {
this.$emit('payment-success', data);
this.$router.push('/success');
this.isProcessing = false;
})
.on("onFailure", (error) => {
this.errorMessage = error.message;
this.$emit('payment-error', error);
this.isProcessing = false;
});
// Set session
altruon.setSession(this.sessionId);
// Render component
altruon.renderComponent(this.$refs.paymentContainer);
this.isLoading = false;
},
handlePayment() {
this.isProcessing = true;
this.errorMessage = null;
// Manually trigger payment
const iframe = this.$refs.paymentContainer.querySelector('iframe');
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({ type: "makePayment" }, "*");
}
}
}
};
</script>
<style scoped>
.error-message {
background: #FEE2E2;
color: #DC2626;
padding: 12px;
border-radius: 6px;
margin-bottom: 16px;
}
.pay-button {
width: 100%;
background: #10B981;
color: white;
border: none;
padding: 12px;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
margin-top: 16px;
}
.pay-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>
Next.js Example
// components/AltruonCheckout.tsx
'use client';
import { useEffect, useRef, useState } from 'react';
import Script from 'next/script';
interface AltruonCheckoutProps {
sessionId: string;
}
export default function AltruonCheckout({ sessionId }: AltruonCheckoutProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [scriptLoaded, setScriptLoaded] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!scriptLoaded || !containerRef.current) return;
const altruon = (window as any).altruon;
// Initialize with callbacks
altruon
.init(process.env.NEXT_PUBLIC_ALTRUON_PUBLIC_KEY!, "your-domain")
.on("onSuccess", (data: any) => {
window.location.href = '/success';
})
.on("onFailure", (error: any) => {
setError(error.message);
setIsProcessing(false);
});
// Set session
altruon.setSession(sessionId);
// Render component
altruon.renderComponent(containerRef.current);
}, [scriptLoaded, sessionId]);
const handlePayment = () => {
setIsProcessing(true);
setError(null);
// Manually trigger payment
const iframe = containerRef.current?.querySelector('iframe');
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({ type: "makePayment" }, "*");
}
};
return (
<>
<Script
src="https://cdn.altruon.io/altruon-sdk.min.js"
onLoad={() => setScriptLoaded(true)}
/>
{error && (
<div className="bg-red-50 text-red-600 p-4 rounded-lg mb-4">
{error}
</div>
)}
<div ref={containerRef} />
{scriptLoaded && (
<button
onClick={handlePayment}
disabled={isProcessing}
className="w-full bg-blue-600 text-white py-3 px-4 rounded-lg mt-4 disabled:opacity-60"
>
{isProcessing ? 'Processing...' : 'Pay Now'}
</button>
)}
</>
);
}
Advanced Examples
Multi-Step Checkout
let selectedPlan = null;
let sessionId = null;
// Step 1: Plan selection
document.querySelectorAll('.plan-option').forEach(option => {
option.addEventListener('click', async (e) => {
selectedPlan = e.target.dataset.planId;
await showCustomerInfoStep();
});
});
// Step 2: Customer information
async function showCustomerInfoStep() {
document.getElementById('plan-selection').style.display = 'none';
document.getElementById('customer-info-step').style.display = 'block';
document.getElementById('continue-btn').addEventListener('click', async () => {
const email = document.getElementById('email').value;
const firstName = document.getElementById('firstName').value;
const lastName = document.getElementById('lastName').value;
// Create session on backend
const response = await fetch('/api/create-checkout-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
billingData: {
lineItems: [
{
type: 'plan',
id: selectedPlan,
quantity: '1'
}
],
billingPlatformId: '3287b8c7-ce43-41fd-9d58-f510e610b8f3'
},
currency: 'USD'
})
});
const data = await response.json();
sessionId = data.sessionId;
showPaymentStep(email, firstName, lastName);
});
}
// Step 3: Payment
function showPaymentStep(email, firstName, lastName) {
// Initialize Altruon with callbacks
altruon
.init("pk_sandbox_your_key", "your-domain")
.on("onSuccess", (data) => {
showSuccessStep(data);
})
.on("onFailure", (error) => {
showError(error.message);
});
altruon.setSession(sessionId);
altruon.setCustomer({
email: email,
firstName: firstName,
lastName: lastName
});
altruon.renderComponent('#payment-container');
// Show payment step
document.getElementById('customer-info-step').style.display = 'none';
document.getElementById('payment-step').style.display = 'block';
}
// Step 4: Success
function showSuccessStep(subscriptionId) {
document.getElementById('payment-step').style.display = 'none';
document.getElementById('success-step').style.display = 'block';
// Setup account, send welcome email, etc.
setupUserAccount(subscriptionId);
}
Analytics Integration
// Track checkout started
analytics.track('Checkout Started', {
lineItems: [{ type: 'plan', id: 'plan_premium', quantity: 1 }],
planName: 'Premium Monthly',
amount: 29.99
});
// Initialize Altruon with analytics callbacks
altruon
.init("pk_sandbox_your_key", "your-domain")
.on("onSuccess", (data) => {
// Track successful conversion
analytics.track('Payment Success', {
subscriptionId: data.subscriptionId,
amount: data.amount,
currency: data.currency
});
// Google Analytics ecommerce
if (window.gtag) {
gtag('event', 'purchase', {
transaction_id: data.transactionId,
value: data.amount / 100,
currency: data.currency,
items: [{
item_id: 'plan_premium',
item_name: 'Premium Monthly',
price: data.amount / 100
}]
});
}
// Facebook Pixel
if (window.fbq) {
fbq('track', 'Purchase', {
value: data.amount / 100,
currency: data.currency,
content_ids: ['plan_premium']
});
}
// Redirect to success
window.location.href = '/success';
})
.on("onFailure", (error) => {
// Track payment failure
analytics.track('Payment Failed', {
errorCode: error.code,
errorMessage: error.message,
errorType: error.type
});
// Show error to user
showError(error.message);
});
altruon.setSession(sessionId);
// Track component rendered
analytics.track('Payment Form Loaded');
altruon.renderComponent('#payment-container');
Error Recovery: retry with a fresh session
Checkout sessions are single-use: after a failed payment, create a new session before retrying. This pattern is adapted from the Merchant Demo's CheckoutPage.jsx:
// Register the failure handler once, during init.
altruon
.init("pk_sandbox_your_key", "your-domain")
.on("onFailure", (error) => {
// Show the error with a retry option. Do NOT reuse the session.
showFailureModal(error.message, { onRetry: retryCheckout });
});
async function retryCheckout() {
// 1. Ask your backend for a FRESH session (same cart, new session id).
const { sessionId } = await fetch('/api/session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ /* same checkout inputs as before */ })
}).then(r => r.json());
// 2. Re-bind the SDK and re-mount the component. The SDK appends an
// iframe to the container, so clear any previous mount first.
altruon.setSession(sessionId);
document.querySelector('#payment-container').innerHTML = '';
await altruon.renderComponent('#payment-container');
}
Testing Examples
Sandbox Test Cards
Use these test cards in sandbox mode:
// Success
// Card: 4111 1111 1111 1111
// Exp: Any future date
// CVC: Any 3 digits
// Decline
// Card: 4000 0000 0000 0002
// 3D Secure Required
// Card: 4000 0027 6000 3184
// Insufficient Funds
// Card: 4000 0000 0000 9995
Best Practices
- Load Script Asynchronously - Don't block page rendering
- Handle All Events - Especially errors and success
- Provide Feedback - Show loading states and errors clearly
- Track Analytics - Measure conversion funnel
- Test Thoroughly - Test all error scenarios
- Secure Your Keys - Never expose secret keys in client code
Need More Help?
- Clone the Merchant Demo for a complete working integration
- Review Configuration for all options
- Check Callbacks for event handling
- See Style Customization for theming
- Contact support@altruon.com for assistance