# 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.

:::info[Info]
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

<Steps>
  <Step title="Get Available Payment Methods">
    Call `/v2/paymentMethods` to get payment methods available for your shopper.
  </Step>
  <Step title="Collect Payment Details">
    Render payment inputs in your own UI and collect the required payment data.
  </Step>
  <Step title="Make a Payment">
    Submit the payment details to `/v2/payments` to initiate the payment.
  </Step>
  <Step title="Handle Additional Actions">
    If required, handle 3D Secure or redirects by calling
    `/v2/payments/details`.
  </Step>
</Steps>

### 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.

```bash
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": "ru-KZ",
    "channel": "Web"
  }'
```

:::warning[Shopper locale]
`shopperLocale` / `locale` is the checkout interface language and regional formatting, for example `ru-KZ`, `en-US`, or `kk-KZ`. Do not use it as a currency field. Currency belongs only in `amount.currency`, for example `KZT`.
:::

**Response:**

```json
{
  "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)

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

```javascript
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(),
  }),
});
```

#### Secure Input Fields (Recommended)

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

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

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

// 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.

```bash
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):**

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

**Response (3D Secure Required):**

```json
{
  "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

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

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

  // 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):

```javascript
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

```bash
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:**

```json
{
  "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:**

```bash
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:**

```bash
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:**

```bash
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

```bash
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

```bash
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

- Understand result codes to handle all payment outcomes
- Implement 3D Secure for card authentication
- Set up webhooks for asynchronous notifications
- Configure checkout settings in the Dashboard

