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

# Web SDK

> Integrate the Payaza Checkout SDK into any website to accept card, bank transfer, and mobile money payments with a prebuilt, hosted payment modal.

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install payaza-web-sdk
  ```

  ```bash yarn theme={null}
  yarn add payaza-web-sdk
  ```
</CodeGroup>

Alternatively, load the SDK directly via CDN — no build step required.

***

## Integration

### Option 1 — CDN (HTML)

Include the Payaza bundle script and call `PayazaCheckout.setup()` when the customer initiates checkout.

```html theme={null}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Checkout</title>
    <script
      defer
      src="https://checkout-v2.payaza.africa/js/v1/bundle.js"
    ></script>
    <script defer>
      function handleCheckout() {
        const payazaCheckout = PayazaCheckout.setup({
          merchant_key: "PZ78-PKTEST-B0F603C4-7787-432D-B105-C7FEEDF472E1",
          connection_mode: "Test", // "Live" or "Test"
          checkout_amount: Number(5000),
          currency_code: "NGN",
          email_address: "johndoe@example.com",
          first_name: "John",
          last_name: "Doe",
          phone_number: "+2347012345678", // international format: +[country code][number]
          transaction_reference: "TXN-" + Date.now(),

          // Optional: set bank transfer expiry window (15–480 mins)
          virtual_account_configuration: {
            expires_in_minutes: 30,
          },

          // Optional: Add Your subscription Plan ID here
          subscription: {
            plan_id: "PLN_D1D8BFF",
          },

          // Optional: attach custom metadata
          additional_details: {
            order_id: "ORD-001",
            user_id: "USR-1273",
          },

          // Optional: attach split account
          split_accounts: [
            {
              code: "SSA_C0900E891783950401871",
            },
          ],
        });

        payazaCheckout.setCallback(function (response) {
          console.log("Payment result:", response);
        });

        payazaCheckout.setOnClose(function () {
          console.log("Checkout closed by user");
        });

        payazaCheckout.showPopup();
      }
    </script>
  </head>
  <body>
    <button onclick="handleCheckout()">Pay Now</button>
  </body>
</html>
```

***

### Option 2 — npm / yarn (JavaScript)

```javascript theme={null}
import PayazaCheckout from "payaza-web-sdk";

const payazaCheckout = new PayazaCheckout({
  merchant_key: "<your-public-api-key>",
  connection_mode: "Live", // "Live" or "Test"
  checkout_amount: 5000,
  currency_code: "NGN",
  email_address: "johndoe@example.com",
  first_name: "John",
  last_name: "Doe",
  phone_number: "+2347012345678", // international format: +[country code][number]
  transaction_reference: "TXN-" + Date.now(),

  virtual_account_configuration: {
    expires_in_minutes: 30,
  },

  // Optional: Add Your subscription Plan ID here
  subscription: {
    plan_id: "PLN_D1D8BFF",
  },

  // Optional: attach split account
  split_accounts: [
    {
      code: "SSA_C0900E891783950401871",
    },
  ],

  additional_details: {
    order_id: "ORD-001",
    user_id: "USR-1273",
  },

  callback: function (response) {
    console.log("Payment result:", response);
  },

  onClose: function () {
    console.log("Checkout closed by user");
  },
});

payazaCheckout.showPopup();
```

***

### Option 3 — npm / yarn (TypeScript)

```typescript theme={null}
import PayazaCheckout from "payaza-web-sdk";
import { PayazaCheckoutOptionsInterface } from "payaza-web-sdk/lib/PayazaCheckoutDataInterface";

const config: PayazaCheckoutOptionsInterface = {
  merchant_key: "<your-public-api-key>",
  connection_mode: "Live",
  checkout_amount: 5000,
  currency_code: "NGN",
  email_address: "johndoe@example.com",
  first_name: "John",
  last_name: "Doe",
  phone_number: "+2347012345678", // international format: +[country code][number]
  transaction_reference: "TXN-" + Date.now(),

  virtual_account_configuration: {
    expires_in_minutes: 30,
  },

  // Optional: Add Your subscription Plan ID here
  subscription: {
    plan_id: "PLN_D1D8BFF",
  },

  additional_details: {
    order_id: "ORD-001",
    user_id: "USR-1273",
  },

  // Optional: attach split account
  "split_accounts": [
    {
      "code": "SSA_C0900E891783950401871”,
      “ratio”: 1
    },
    {
      "code": "SSA_39B5E6E91783951863120",
      “ratio”: 9
    }
  ],

  callback: function (response) {
    console.log("Payment result:", response);
  },

  onClose: function () {
    console.log("Checkout closed by user");
  },
};

const checkout = new PayazaCheckout(config);
checkout.showPopup();
```

<Note>
  If `setup` conflicts with a function name in your codebase, import it under an alias: `import { setup as PayazaSetup } from "payaza-web-sdk";`
</Note>

***

## Phone number format

The `phone_number` field must be in **international format** — country code followed by the subscriber number, with no spaces, dashes, or `+` prefix.

| Country            | Local format  | International format |
| ------------------ | ------------- | -------------------- |
| Nigeria 🇳🇬       | `07012345678` | `+2347012345678`     |
| Ghana 🇬🇭         | `0241234567`  | `+233241234567`      |
| Kenya 🇰🇪         | `0712345678`  | `+254712345678`      |
| South Africa 🇿🇦  | `0821234567`  | `+27821234567`       |
| Côte d'Ivoire 🇨🇮 | `0701234567`  | `+2250701234567`     |

<Tip>
  Strip the leading `0` from the local number and prepend the country code. For
  Nigeria: `07012345678` → `+2347012345678`.
</Tip>

***

## Callback response

The `callback` function fires when the payment flow completes. It receives a single response object:

```json theme={null}
{
  "type": "success",
  "status": 201,
  "data": {
    "message": "Transaction Successful",
    "payaza_reference": "P-C-20231018-1TLB7K68",
    "transaction_reference": "TXN-1697635200000",
    "transaction_fee": 100,
    "transaction_total_amount": 5100,
    "currency": {
      "name": "Naira",
      "code": "NGN",
      "unicode": "₦",
      "html_value": "&#8358;"
    },
    "customer": {
      "customer_id": "HCC4ZX96W",
      "email_address": "johndoe@example.com",
      "first_name": "John",
      "last_name": "Doe",
      "mobile_number": "+2347012345678"
    }
  }
}
```

<Warning>
  Always verify the payment server-side using the `transaction_reference` before
  fulfilling an order. The callback fires on the client and can be intercepted.
  Use the [Transaction Status Query API](/api-reference/introduction) or listen
  for a [webhook](/guides/webhooks) to confirm the final state.
</Warning>

***

## Errors

Ensure all required parameters are present and correctly formatted before calling `showPopup()`.

### Invalid merchant key

```json theme={null}
{
  "type": "error",
  "status": 401,
  "data": {
    "message": "Sorry merchant key is not valid"
  }
}
```

### Validation error

```json theme={null}
{
  "type": "error",
  "status": 400,
  "data": {
    "message": "Error during validation",
    "errors": [
      {
        "field": "merchant_key",
        "errors": ["'merchant_key' is required"]
      },
      {
        "field": "checkout_amount",
        "errors": ["'checkout_amount' must be numeric"]
      },
      {
        "field": "first_name",
        "errors": ["'first_name' cannot be blank"]
      },
      {
        "field": "email_address",
        "errors": [
          "'email_address' cannot be blank",
          "'email_address' must be a valid email address"
        ]
      }
    ]
  }
}
```

### Environment mismatch

```json theme={null}
{
  "type": "error",
  "status": 401,
  "data": {
    "message": "Business Profile Credentials does not match connection mode selected"
  }
}
```

***

## Parameters

### Required

<ParamField body="merchant_key" type="string" required>
  Your public API key from the Payaza dashboard. Do **not** Base64-encode this —
  pass the raw key directly.
</ParamField>

<ParamField body="connection_mode" type="string" required>
  Environment for the transaction. Accepts `"Live"` or `"Test"`. Must match the
  environment of your `merchant_key`.
</ParamField>

<ParamField body="checkout_amount" type="number" required>
  Amount to charge the customer. Pass as a number — e.g. `5000`. Do not pass as
  a string.
</ParamField>

<ParamField body="currency_code" type="string" required>
  ISO currency code — e.g. `"NGN"`, `"GHS"`, `"USD"`.
</ParamField>

<ParamField body="email_address" type="string" required>
  The customer's email address. Used for payment receipts and customer
  identification.
</ParamField>

<ParamField body="first_name" type="string" required>
  The customer's first name.
</ParamField>

<ParamField body="last_name" type="string" required>
  The customer's last name.
</ParamField>

<ParamField body="phone_number" type="string" required>
  The customer's phone number in **international format** — country code
  followed by the number, no spaces or dashes. Example: `"+2347012345678"` for
  Nigeria. See the [phone number format table](#phone-number-format) above.
</ParamField>

<ParamField body="transaction_reference" type="string" required>
  A unique identifier you generate for each transaction. Must be unique per
  payment attempt — reusing a reference will cause an error.
</ParamField>

***

### Optional

<ParamField body="country_code" type="string">
  Required only for **CIV and BEN collections**. Pass the ISO country code —
  e.g. `"CIV"` or `"BEN"`. Not needed for NGN, GHS, or other standard
  currencies.
</ParamField>

<ParamField body="biller_name" type="string">
  Overrides the business name shown on the checkout page. Defaults to your
  registered Payaza business name if omitted.
</ParamField>

<ParamField body="virtual_account_configuration" type="object">
  Controls the bank transfer option in the checkout modal. Set `expires_in_minutes` to define how long the virtual account stays active. Min: `15`, max: `480`. Defaults to `30` if omitted.

  ```json theme={null}
  {
    "expires_in_minutes": 30
  }
  ```
</ParamField>

<ParamField body="subscription" type="object">
  Set `plan_id` to the value that was created using the Create Subscription Plan API or from your Payaza Dashboard which acts as a unique identifier for your subscription plan.

  ```json theme={null}
  {
    "plan_id": PLN_D1D8BFF
  }
  ```
</ParamField>

<ParamField body="split_accounts" type="array">
  An array containing the split account values and corresponding ratios.

  ### Field Parameters

  * **`code`** (string): Set this to the unique split account identifier value that was generated using the **Create Split Account API**.
  * **`ratio`** (integer): Defines the relative weighted portion used to calculate how the transaction remainder is divided between the split accounts.

  ### Ratio Rules

  The calculation matches integers directly to decimal percentage scales where `1` represents 10%, `2` represents 20%, `3` represents 30%, and `4` represents 40% allocations.

  > **Critical Rule:** When assigning multiple split account elements inside this configuration array, the cumulative sum of all `ratio` values **must equal exactly 10 in total** (representing 100%).
</ParamField>

```json Example Payload theme={null}
"split_accounts": [
  {
    "code": "SSA_C0900E891783950401871",
    "ratio": 1
  },
  {
    "code": "SSA_39B5E6E91783951863120",
    "ratio": 9
  }
]
```

<ParamField body="additional_details" type="object">
  Custom metadata attached to the transaction — e.g. order ID, user ID, ticket reference. Returned in the callback response. Must be a valid JSON object.

  ```json theme={null}
  {
    "order_id": "ORD-001",
    "user_id": "USR-1273"
  }
  ```
</ParamField>

<ParamField body="callback" type="function">
  Called when the payment flow completes (success or failure). Receives the
  transaction outcome object. See [Callback response](#callback-response) above.
</ParamField>

<ParamField body="onClose" type="function">
  Called when the user closes the checkout modal before completing payment.
</ParamField>
