> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lite.sa/llms.txt
> Use this file to discover all available pages before exploring further.

> How to integrate and manage payments via our web-sdk

# Web sdk

Build a card payment form on your own checkout page with lite elements.

## Overview

The Web SDK lets you collect card details on your own checkout page while keeping card data off your systems.

The SDK renders each card field inside a secure iframe hosted by lite. Your page controls where the fields appear and how the form behaves. Card numbers, expiry dates, and CVV values are entered directly into lite-hosted fields and never pass through your servers. This keeps your integration eligible for the simplest level of PCI DSS validation.

Use the Web SDK when you want full control over your checkout layout. If you prefer a complete payment page hosted by lite, use Checkout or Payment Links instead.

## How it works

1. Your server creates a checkout session with the lite API and receives a session secret.
2. Your page initializes the SDK with the session secret and mounts the card elements.
3. The customer enters their card details into the secure fields.
4. You call `lite.pay()`. The SDK encrypts the card data inside lite-hosted iframes, tokenizes it, and submits the payment. If the issuer requires 3D Secure, the SDK handles the authentication flow automatically.
5. Your server confirms the final payment result.

## Before you begin

You need:

* A lite account with a configured channel. See Channel Configuration.
* Valid API keys.

## Build your payment form

### 1. Load the SDK

Install the SDK from npm:

```bash theme={null}
npm install `@litesa/js-sdk`
```

Then initialize it with the session secret from your server:

```ts theme={null}
import { lite, PaymentOperationStatus } from '@litesa/js-sdk';

const lite = await lite.init({ clientSecret: sessionSecret });
```

`lite.init` fetches the checkout session and resolves when the SDK is ready. The session is available at `lite.session`, including the amount, currency, and enabled payment methods.

### 2. Create the elements

Create an elements group, then create one element for each card field:

```ts theme={null}
const elements = lite.elements();

const cardNumberElement = elements.create('cardNumber');
const expiryElement = elements.create('expiry');
const cvvElement = elements.create('cvv');
const cardholderNameElement = elements.create('cardholderName');
```

`cardholderName` is optional. The SDK collects values only from the fields you mount.

### 3. Mount the elements

Add a container for each field to your page:

```html theme={null}
<div id="cardNumber"></div>
<div id="expiry"></div>
<div id="cvv"></div>
<div id="cardholderName"></div>
```

Then mount each element into its container. `mount` returns a promise and clears any existing content in the container:

```ts theme={null}
await cardNumberElement.mount('#cardNumber');
await expiryElement.mount('#expiry');
await cvvElement.mount('#cvv');
await cardholderNameElement.mount('#cardholderName');
```

### 4. Track field validity

Each card field emits a `change` event whenever the customer's input is re-validated. The payload contains a single `valid` flag:

```ts theme={null}
cardNumberElement.on('change', ({ valid }) => {
  // enable or disable your pay button
});
```

The fields validate as the customer types. The card number must pass a Luhn check, the expiry must be a valid `MM/YY` date that is not in the past, and the CVV must be 3 or 4 digits. Track validity across all mounted fields and enable your pay button only when every field is valid.

### 5. Submit the payment

When the customer clicks your pay button, call `pay` and handle the result:

```ts theme={null}
payButton.addEventListener('click', async () => {
  try {
    const result = await lite.pay({ payment_method: 'card' });

    switch (result.status) {
      case PaymentOperationStatus.SUCCESS:
        // show your success state
        break;
      case PaymentOperationStatus.FAILURE:
        // show result.error and let the customer retry
        break;
      default:
        // payment is still processing; confirm from your server
        break;
    }
  } catch (e) {
    // invalid options or SDK errors surface as thrown errors
  }
});
```

The SDK collects the card details from the mounted fields, encrypts them, tokenizes the card, and submits the payment. Your page never receives the card data.

Calling `pay` while a payment is already in flight returns the same promise, so double clicks do not create duplicate payment attempts.

**3D Secure.** If the payment requires authentication, the SDK opens the 3D Secure challenge in a modal automatically and resumes when the customer completes it. You do not need to handle the redirect yourself. The `pay` promise resolves after authentication finishes.

To save the card for future payments, pass `store_for_future`:

```ts theme={null}
const result = await lite.pay({ payment_method: 'card', store_for_future: true });
```

### 6. Handle the result

`pay` resolves with a result object:

```ts theme={null}
{
  status: PaymentOperationStatus;  // 'success' | 'failure' | 'processing'
  payment?: PaymentResponse;       // present on success
  error?: string;                  // present on failure
}
```

| Status       | Meaning                                                                                |
| ------------ | -------------------------------------------------------------------------------------- |
| `success`    | The payment was authorized or captured. `result.payment.id` contains the payment ID.   |
| `failure`    | The payment failed, was voided, or was rejected. `result.error` describes the failure. |
| `processing` | The payment has not reached a final status yet. Confirm the outcome from your server.  |

### 7. Confirm the payment on your server

A `success` result tells your page that the payment succeeded in the customer's browser. Do not fulfill an order based on this alone. Customers can close the tab before your code runs, and client-side code can fail.

Always confirm the final payment state from your server by retrieving the session before you fulfill the order.

## Pay with a saved card

If the customer has cards stored with lite, retrieve them after initialization:

```ts theme={null}
const instruments = lite.getStoredInstruments('card');
```

Each stored instrument includes an `id` and display details (`scheme`, `last_4`, `expiry_month`, `expiry_year`) you can render in your own UI. To charge a saved card, pass its ID to `pay` instead of a payment method:

```ts theme={null}
const result = await lite.pay({ instrument_id: instrument.id });
```

## Style the fields

Card fields accept styling options when you create them. Choose a variant, then override individual properties:

```ts theme={null}
const cardNumberElement = elements.create('cardNumber', {
  variant: 'stylized',
  style: {
    fontSize: '16px',
    padding: '12px',
    borderRadius: '8px',
    ':focus': { borderColor: '#0570de' },
    '::placeholder': { color: '#a0a0a0' },
  },
});
```

| Variant    | Behavior                                                                                                   |
| ---------- | ---------------------------------------------------------------------------------------------------------- |
| `plain`    | Resets the field styling. You control the appearance through your wrapper DOM and your own `style` values. |
| `stylized` | Starts from the SDK's default appearance and applies your overrides on top.                                |

Omit the options to use the default themed appearance.

Supported base properties: `color`, `backgroundColor`, `fontFamily`, `fontSize`, `fontWeight`, `fontStyle`, `letterSpacing`, `lineHeight`, `textAlign`, `padding`, `borderColor`, `borderWidth`, `borderStyle`, `borderRadius`. Pseudo-state blocks are supported for `:focus`, `:hover`, `:invalid`, and `::placeholder`, each with a subset of these properties. Unsupported values are ignored.

## Clean up

Call `destroy` on an element to remove it from the page, and `lite.destroy()` to tear down the SDK instance, for example when the customer navigates away from your checkout in a single-page app:

```ts theme={null}
cardNumberElement.destroy();
lite.destroy();
```

## Test your integration

Use your test API keys and lite test cards to verify your form end to end. See Testing.
