PlexySDK DOCS

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'}), 500
curl -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

StateDescription
activeSession is valid and ready for payment
completedPayment was successfully processed
expiredSession has passed its expiresAt time
cancelledCustomer 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 NumberResult
4111 1111 1111 1111Successful payment

Set environment: 'test' in your checkout configuration to use test mode.

Next Steps

Осы бетте