PlexySDK DOCS

Advanced Flow

Build custom payment experiences with full control over the checkout process

Advanced Flow

The Advanced flow gives you complete control over the payment experience. You build your own payment form, collect payment details, and handle the full payment lifecycle through three API calls.

The Advanced flow requires more development effort but provides maximum flexibility. If you're just getting started, consider the Sessions flow first.

How Advanced Flow Works

Call /v2/paymentMethods to get payment methods available for your shopper.

Render payment inputs in your own UI and collect the required payment data.

Submit the payment details to /v2/payments to initiate the payment.

If required, handle 3D Secure or redirects by calling /v2/payments/details.

Step 1: Get Payment Methods

First, request available payment methods for the transaction. The response depends on your account configuration, the shopper's country, and the payment amount.

curl -X POST https://api.plexypay.com/v2/paymentMethods \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "value": 10000,
      "currency": "KZT"
    },
    "countryCode": "KZ",
    "shopperLocale": "en-US",
    "channel": "Web"
  }'

Response:

{
  "paymentMethods": [
    {
      "type": "scheme",
      "name": "Credit Card",
      "brands": ["visa", "mc", "amex"]
    },
    {
      "type": "applepay",
      "name": "Apple Pay",
      "configuration": {
        "merchantId": "merchant.com.plexy.example",
        "merchantName": "Your Store"
      }
    }
  ]
}

Step 2: Collect Payment Details

Build your payment form to collect the required data. For card payments, you must use client-side encryption to protect sensitive card data.

Card Encryption (Client-Side)

Never send raw card numbers to your server. Always encrypt card data client-side using the Plexy encryption library.

import { PlexyEncryption } from '@plexy/plexy-web/browser';

// Initialize with your client encryption key (from Plexy Dashboard)
const encryption = new PlexyEncryption({
  publicKey: 'YOUR_CLIENT_ENCRYPTION_KEY',
});

// Collect card data from your form
const cardData = {
  cardNumber: '4111111111111111',
  expiryMonth: '03',
  expiryYear: '2030',
  securityCode: '737',
  holderName: 'John Smith',
};

// Encrypt the sensitive fields
const encryptedCard = await encryption.encrypt({
  encryptedCardNumber: cardData.cardNumber,
  encryptedExpiryMonth: cardData.expiryMonth,
  encryptedExpiryYear: cardData.expiryYear,
  encryptedSecurityCode: cardData.securityCode,
});

// Send encrypted data to your server
const response = await fetch('/api/pay', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    paymentMethod: {
      type: 'scheme',
      ...encryptedCard,
      holderName: cardData.holderName,
    },
    browserInfo: encryption.getBrowserInfo(),
  }),
});

For easier PCI compliance, use Plexy's secure input fields:

import { PlexySecureFields } from '@plexy/plexy-web/browser';

const secureFields = new PlexySecureFields({
  clientKey: 'YOUR_CLIENT_KEY',
  locale: 'en-US',
});

// Create secure input fields
const cardNumber = secureFields.create('cardNumber', {
  placeholder: 'Card number',
  style: {
    base: { fontSize: '16px', color: '#333' },
    invalid: { color: '#dc3545' },
  },
});

const expiryDate = secureFields.create('expiryDate', {
  placeholder: 'MM/YY',
});

const securityCode = secureFields.create('securityCode', {
  placeholder: 'CVV',
});

// Mount to your form
cardNumber.mount('#card-number');
expiryDate.mount('#expiry-date');
securityCode.mount('#security-code');

// When the form is submitted
async function handleSubmit() {
  const { encryptedData, error } = await secureFields.encrypt();

  if (error) {
    console.error('Encryption error:', error);
    return;
  }

  // Send encrypted data to your server
  const response = await fetch('/api/pay', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      encryptedPaymentMethod: encryptedData,
      browserInfo: secureFields.getBrowserInfo(),
    }),
  });
}

Step 3: Make a Payment

Submit the payment to the /v2/payments endpoint from your server.

curl -X POST https://api.plexypay.com/v2/payments \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "value": 10000,
      "currency": "KZT"
    },
    "reference": "order_12345",
    "paymentMethod": {
      "type": "scheme",
      "encryptedCardNumber": "plexyjs_0_1_25...",
      "encryptedExpiryMonth": "plexyjs_0_1_25...",
      "encryptedExpiryYear": "plexyjs_0_1_25...",
      "encryptedSecurityCode": "plexyjs_0_1_25...",
      "holderName": "John Smith"
    },
    "shopperReference": "customer_12345",
    "shopperEmail": "customer@example.com",
    "shopperIP": "192.168.1.1",
    "browserInfo": {
      "acceptHeader": "text/html",
      "colorDepth": 24,
      "language": "en-US",
      "javaEnabled": false,
      "screenHeight": 1080,
      "screenWidth": 1920,
      "userAgent": "Mozilla/5.0...",
      "timeZoneOffset": -180
    },
    "returnUrl": "https://your-site.com/checkout/complete?orderId=order_12345"
  }'

Response (Successful):

{
  "resultCode": "Authorised",
  "pspReference": "8835511210681324",
  "merchantReference": "order_12345"
}

Response (3D Secure Required):

{
  "resultCode": "IdentifyShopper",
  "action": {
    "type": "threeDS2",
    "subtype": "fingerprint",
    "token": "eyJ0aHJlZURTTWV0aG9kTm90...",
    "paymentMethodType": "scheme"
  }
}

Step 4: Handle Additional Actions

If the payment requires additional action (3D Secure, redirect), handle it client-side and submit the result.

Handling 3D Secure

import { Plexy3DS } from '@plexy/plexy-web/browser';

async function handle3DSAction(action) {
  const threeDS = new Plexy3DS({
    clientKey: 'YOUR_CLIENT_KEY',
    environment: 'live',
  });

  // Create and mount the 3DS component
  const threeDS2Component = threeDS.create('threeDS2', {
    challengeWindowSize: '05', // Full screen
    onComplete: async (result) => {
      // Submit the authentication result to your server
      await submitPaymentDetails(result.data);
    },
    onError: (error) => {
      console.error('3DS error:', error);
      showErrorMessage('Authentication failed');
    },
  });

  // Handle the action from the payment response
  threeDS2Component.handleAction(action);
}

async function submitPaymentDetails(details) {
  const response = await fetch('/api/payments/details', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ details }),
  });

  const result = await response.json();
  handleFinalResult(result);
}

Handling Redirects

For payment methods that require a redirect (e.g., bank transfers):

function handleRedirectAction(action) {
  if (action.type === 'redirect') {
    // Store payment data for when customer returns
    sessionStorage.setItem(
      'pendingPayment',
      JSON.stringify({
        orderId: currentOrderId,
        timestamp: Date.now(),
      }),
    );

    // Redirect to payment provider
    window.location.href = action.url;
  }
}

// On your return URL page
async function handleReturn() {
  const urlParams = new URLSearchParams(window.location.search);
  const redirectResult = urlParams.get('redirectResult');

  if (redirectResult) {
    const response = await fetch('/api/payments/details', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        details: { redirectResult },
      }),
    });

    const result = await response.json();
    handleFinalResult(result);
  }
}

Server-Side: Submit Additional Details

curl -X POST https://api.plexypay.com/v2/payments/details \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "details": {
      "redirectResult": "eyJ0cmFuc1N0YXR1cyI6IlkiL..."
    }
  }'

Response:

{
  "resultCode": "Authorised",
  "pspReference": "8835511210681324",
  "merchantReference": "order_12345"
}

Complete Integration Example

Here's a complete server-side example combining all the steps. Your server proxies each client request to the corresponding Plexy API endpoint:

Step 1 — Get payment methods:

curl -X POST https://api.plexypay.com/v2/paymentMethods \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": { "value": 10000, "currency": "KZT" },
    "countryCode": "KZ",
    "channel": "Web"
  }'

Step 3 — Make a payment:

curl -X POST https://api.plexypay.com/v2/payments \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": { "value": 10000, "currency": "KZT" },
    "reference": "order_12345",
    "paymentMethod": {
      "type": "scheme",
      "encryptedCardNumber": "plexyjs_0_1_25...",
      "encryptedExpiryMonth": "plexyjs_0_1_25...",
      "encryptedExpiryYear": "plexyjs_0_1_25...",
      "encryptedSecurityCode": "plexyjs_0_1_25...",
      "holderName": "John Smith"
    },
    "shopperReference": "customer_12345",
    "shopperEmail": "customer@example.com",
    "shopperIP": "192.168.1.1",
    "browserInfo": {
      "acceptHeader": "text/html",
      "colorDepth": 24,
      "language": "en-US",
      "javaEnabled": false,
      "screenHeight": 1080,
      "screenWidth": 1920,
      "userAgent": "Mozilla/5.0...",
      "timeZoneOffset": -180
    },
    "returnUrl": "https://your-site.com/checkout/complete?orderId=order_12345"
  }'

Step 4 — Submit additional details:

curl -X POST https://api.plexypay.com/v2/payments/details \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "details": {
      "redirectResult": "eyJ0cmFuc1N0YXR1cyI6IlkiL..."
    }
  }'

Alternative Payment Methods

Different payment methods require different data. Here are examples for common methods:

Apple Pay

curl -X POST https://api.plexypay.com/v2/payments \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": { "value": 10000, "currency": "KZT" },
    "reference": "order_12345",
    "paymentMethod": {
      "type": "applepay",
      "applePayToken": "<token from Apple Pay JS API>"
    },
    "returnUrl": "https://your-site.com/checkout/complete"
  }'

Google Pay

curl -X POST https://api.plexypay.com/v2/payments \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": { "value": 10000, "currency": "KZT" },
    "reference": "order_12345",
    "paymentMethod": {
      "type": "googlepay",
      "googlePayToken": "<token from Google Pay API>"
    },
    "returnUrl": "https://your-site.com/checkout/complete"
  }'

Error Handling

Implement robust error handling for production. The Plexy API returns standard HTTP error responses — check the HTTP status code and the errorCode field in the response body:

  • 400 — Invalid request data (missing or malformed fields)
  • 401 — Invalid or missing API key
  • 422 — Request was valid but could not be processed (e.g., amount too low)
  • 500 — Server-side error; retry with exponential back-off

Map these to appropriate messages in your application and always log the full response body for debugging.

Next Steps

On this page