Sessions Flow
Integrate payments quickly with Plexy's managed checkout experience
Sessions Flow
The Sessions flow is the fastest way to start accepting payments. With a single API call to create a session, Plexy handles payment method rendering, 3D Secure authentication, redirects, and result processing.
How Sessions Work
Your server makes a single API call to /v2/sessions with payment details.
Use the session ID to mount the Plexy checkout component on your page.
The customer enters their payment details in the embedded UI. Plexy handles all payment method logic, 3D Secure challenges, and redirects.
Receive the payment result via webhooks and update your order status.
Server-Side: Create a Session
Create a payment session by calling the /v2/sessions endpoint with the payment amount, currency, and return URL.
import { Plexy } from '@plexy/plexy-web';
const plexy = new Plexy({
apiKey: process.env.PLEXY_API_KEY,
});
async function createCheckoutSession(orderId, amount, currency) {
const session = await plexy.sessions.create({
amount: {
value: amount, // Amount in smallest currency unit
currency: currency // ISO 4217 currency code
},
reference: orderId,
returnUrl: `https://your-site.com/checkout/complete?orderId=${orderId}`,
expiresAt: new Date(Date.now() + 30 * 60 * 1000).toISOString(), // 30 minutes
shopperReference: 'customer_12345',
shopperEmail: 'customer@example.com',
lineItems: [
{
description: 'Premium Subscription',
quantity: 1,
amountIncludingTax: amount,
}
],
metadata: {
orderId: orderId,
source: 'web_checkout'
}
});
return {
sessionId: session.id,
sessionData: session.sessionData
};
}
// Example usage in an Express route
app.post('/api/create-session', async (req, res) => {
try {
const { orderId, amount, currency } = req.body;
const session = await createCheckoutSession(orderId, amount, currency);
res.json(session);
} catch (error) {
console.error('Session creation failed:', error);
res.status(500).json({ error: 'Failed to create checkout session' });
}
});import os
from datetime import datetime, timedelta
from plexy import Plexy
from flask import Flask, request, jsonify
plexy = Plexy(api_key=os.environ['PLEXY_API_KEY'])
def create_checkout_session(order_id: str, amount: int, currency: str) -> dict:
"""Create a Plexy checkout session."""
expires_at = (datetime.utcnow() + timedelta(minutes=30)).isoformat() + 'Z'
session = plexy.sessions.create(
amount={
'value': amount, # Amount in smallest currency unit
'currency': currency # ISO 4217 currency code
},
reference=order_id,
return_url=f'https://your-site.com/checkout/complete?orderId={order_id}',
expires_at=expires_at,
shopper_reference='customer_12345',
shopper_email='customer@example.com',
line_items=[
{
'description': 'Premium Subscription',
'quantity': 1,
'amount_including_tax': amount,
}
],
metadata={
'orderId': order_id,
'source': 'web_checkout'
}
)
return {
'sessionId': session.id,
'sessionData': session.session_data
}
# Example Flask route
app = Flask(__name__)
@app.route('/api/create-session', methods=['POST'])
def create_session():
try:
data = request.json
session = create_checkout_session(
data['orderId'],
data['amount'],
data['currency']
)
return jsonify(session)
except Exception as e:
print(f'Session creation failed: {e}')
return jsonify({'error': 'Failed to create checkout session'}), 500curl -X POST https://api.plexypay.com/v2/sessions \
-H "x-api-key: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": {
"value": 10000,
"currency": "KZT"
},
"reference": "order_12345",
"returnUrl": "https://your-site.com/checkout/complete?orderId=order_12345",
"expiresAt": "2024-12-31T23:59:59Z",
"shopperReference": "customer_12345",
"shopperEmail": "customer@example.com",
"lineItems": [
{
"description": "Premium Subscription",
"quantity": 1,
"amountIncludingTax": 10000
}
],
"metadata": {
"orderId": "order_12345",
"source": "web_checkout"
}
}'Response:
{
"id": "ses_abc123xyz",
"sessionData": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresAt": "2024-12-31T23:59:59Z",
"status": "active",
"amount": {
"value": 10000,
"currency": "KZT"
},
"reference": "order_12345"
}Client-Side: Mount the Checkout
After creating a session, use the session data to initialize the Plexy checkout component on your frontend.
import { PlexyCheckout } from '@plexy/plexy-web/browser';
async function initializeCheckout() {
// Fetch session from your server
const response = await fetch('/api/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderId: 'order_12345',
amount: 10000,
currency: 'KZT'
})
});
const { sessionId, sessionData } = await response.json();
// Initialize checkout
const checkout = new PlexyCheckout({
sessionId: sessionId,
sessionData: sessionData,
environment: 'live', // or 'test' for test mode
onPaymentCompleted: (result) => {
console.log('Payment completed:', result);
// Redirect or show success message
window.location.href = `/order-confirmation?id=${result.reference}`;
},
onPaymentFailed: (error) => {
console.error('Payment failed:', error);
// Show error message to customer
showErrorMessage(error.message);
},
onError: (error) => {
console.error('Checkout error:', error);
// Handle initialization or network errors
}
});
// Mount the checkout component
checkout.mount('#checkout-container');
}
initializeCheckout();import { useEffect, useState } from 'react';
import { PlexyCheckout } from '@plexy/plexy-web/react';
interface CheckoutSession {
sessionId: string;
sessionData: string;
}
export function CheckoutPage({ orderId, amount, currency }: {
orderId: string;
amount: number;
currency: string;
}) {
const [session, setSession] = useState<CheckoutSession | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function createSession() {
try {
const response = await fetch('/api/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ orderId, amount, currency })
});
const data = await response.json();
setSession(data);
} catch (err) {
setError('Failed to initialize checkout');
}
}
createSession();
}, [orderId, amount, currency]);
const handlePaymentCompleted = (result: any) => {
console.log('Payment completed:', result);
window.location.href = `/order-confirmation?id=${result.reference}`;
};
const handlePaymentFailed = (error: any) => {
console.error('Payment failed:', error);
setError(error.message);
};
if (error) {
return <div className="error">{error}</div>;
}
if (!session) {
return <div className="loading">Loading checkout...</div>;
}
return (
<PlexyCheckout
sessionId={session.sessionId}
sessionData={session.sessionData}
environment="live"
onPaymentCompleted={handlePaymentCompleted}
onPaymentFailed={handlePaymentFailed}
/>
);
}<!DOCTYPE html>
<html>
<head>
<title>Checkout</title>
<script src="https://checkout.plexy.money/sdk.js"></script>
</head>
<body>
<div id="checkout-container"></div>
<script>
// Session data passed from your server
const sessionId = '{{ sessionId }}';
const sessionData = '{{ sessionData }}';
const checkout = new PlexyCheckout({
sessionId: sessionId,
sessionData: sessionData,
environment: 'live',
onPaymentCompleted: function(result) {
window.location.href = '/order-confirmation?id=' + result.reference;
},
onPaymentFailed: function(error) {
alert('Payment failed: ' + error.message);
}
});
checkout.mount('#checkout-container');
</script>
</body>
</html>Customizing the Checkout Appearance
You can customize the checkout appearance using style options:
const checkout = new PlexyCheckout({
sessionId: sessionId,
sessionData: sessionData,
environment: 'live',
style: {
theme: 'light', // 'light' or 'dark'
primaryColor: '#6366f1',
borderRadius: '8px',
fontFamily: 'Inter, system-ui, sans-serif',
},
locale: 'en-US', // Checkout language
// ... callbacks
});Webhook Integration
Always verify payment status via webhooks. Do not rely solely on client-side callbacks, as they can be manipulated.
See the Webhooks documentation for full setup, signature verification, and event reference.
Handling the Return URL
When the customer completes the payment, they are redirected to your returnUrl. The URL includes query parameters with the payment result.
// pages/checkout/complete.js (Next.js example)
import { useSearchParams } from 'next/navigation';
export default function CheckoutComplete() {
const searchParams = useSearchParams();
const sessionId = searchParams.get('sessionId');
const resultCode = searchParams.get('resultCode');
const orderId = searchParams.get('orderId');
// Always verify the result with your server
useEffect(() => {
async function verifyPayment() {
const response = await fetch(`/api/verify-payment?orderId=${orderId}`);
const { status } = await response.json();
if (status === 'paid') {
// Show success message
} else {
// Show appropriate message based on status
}
}
verifyPayment();
}, [orderId]);
return (
<div>
{resultCode === 'Authorised' ? (
<h1>Thank you for your order!</h1>
) : (
<h1>Payment was not completed</h1>
)}
</div>
);
}The resultCode in the return URL is for display purposes only. Always verify
the payment status via webhooks or by calling the API from your server.
Session States
| State | Description |
|---|---|
active | Session is valid and ready for payment |
completed | Payment was successfully processed |
expired | Session has passed its expiresAt time |
cancelled | Customer cancelled the payment |
Error Handling
Handle errors gracefully in your checkout implementation:
const checkout = new PlexyCheckout({
// ... configuration
onError: (error) => {
switch (error.code) {
case 'SESSION_EXPIRED':
// Create a new session
window.location.reload();
break;
case 'NETWORK_ERROR':
// Show retry option
showRetryButton();
break;
case 'INVALID_SESSION':
// Redirect to cart
window.location.href = '/cart';
break;
default:
// Show generic error
showErrorMessage('Something went wrong. Please try again.');
}
},
});Testing
Use test card numbers in the test environment:
| Card Number | Result |
|---|---|
4111 1111 1111 1111 | Successful payment |
Set environment: 'test' in your checkout configuration to use test mode.
Next Steps
- Configure checkout settings for your account
- Understand result codes to handle all payment outcomes
- Set up webhooks for production