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

# JavaScript SDK

> Accept payments on any website with a few lines of code

Drop a single script tag into your website and start accepting payments with Quickei. No backend required — the SDK handles the entire checkout flow in a secure inline modal or popup window.

## Installation

Add the Quickei SDK to your page:

```html theme={null}
<script src="https://quickei.io/sdk/quickei.js"></script>
```

<Tip>
  Load the script before your payment code runs. Place it in the `<head>` or just before your closing `</body>` tag.
</Tip>

## Quick Start

```html theme={null}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Store</title>
  <script src="https://quickei.io/sdk/quickei.js"></script>
</head>
<body>
  <button id="pay-btn">Pay 25.00 EUR</button>

  <script>
    const quickei = new Quickei({
      publicKey: 'qi_live_abc123def456'
    });

    document.getElementById('pay-btn').addEventListener('click', () => {
      quickei.pay({
        amount: 25.00,
        currency: 'EUR',
        reference: 'INV-2026-001',
        description: 'Premium subscription',
        customer: {
          email: 'john@example.com',
          name: 'John Doe'
        },
        callbackUrl: 'https://mystore.com/webhook',
        onSuccess: (response) => {
          console.log('Payment successful:', response.trx_id);
          window.location.href = '/thank-you?ref=' + response.reference;
        },
        onCancel: () => {
          console.log('Payment cancelled by user');
        },
        onError: (error) => {
          console.error('Payment error:', error);
        }
      });
    });
  </script>
</body>
</html>
```

## API Reference

### Constructor

```javascript theme={null}
const quickei = new Quickei({ publicKey });
```

| Parameter   | Type     | Required | Description                                                              |
| ----------- | -------- | -------- | ------------------------------------------------------------------------ |
| `publicKey` | `string` | Yes      | Your public key (`client_id`) from the Merchant Dashboard → API Settings |

### `quickei.pay(options)`

Opens an inline iframe modal overlay on the current page. The customer completes payment without leaving your site.

```javascript theme={null}
quickei.pay({
  amount: 25.00,
  currency: 'EUR',
  reference: 'INV-2026-001',
  description: 'Premium subscription',
  customer: { email: 'john@example.com', name: 'John Doe' },
  callbackUrl: 'https://mystore.com/webhook',
  onSuccess: (response) => { /* ... */ },
  onCancel: () => { /* ... */ },
  onError: (error) => { /* ... */ }
});
```

### `quickei.popup(options)`

Opens payment in a new popup window. Takes the same parameters as `pay()`. Use this when your site has strict CSP rules or you prefer a separate window.

```javascript theme={null}
quickei.popup({
  amount: 50.00,
  currency: 'USD',
  reference: 'ORD-789',
  onSuccess: (response) => {
    console.log('Paid:', response.trx_id);
  }
});
```

### `quickei.close()`

Programmatically close the payment modal or popup. Useful for timeout scenarios or navigation changes.

```javascript theme={null}
// Close after 5 minutes of inactivity
setTimeout(() => quickei.close(), 5 * 60 * 1000);
```

## Parameters

All parameters for `pay()` and `popup()`:

| Parameter        | Type       | Required | Description                                       |
| ---------------- | ---------- | -------- | ------------------------------------------------- |
| `amount`         | `number`   | Yes      | Payment amount (e.g. `25.00`)                     |
| `currency`       | `string`   | Yes      | ISO 4217 currency code (e.g. `EUR`, `USD`, `XOF`) |
| `reference`      | `string`   | Yes      | Your unique order/invoice reference               |
| `description`    | `string`   | No       | Human-readable description shown to the customer  |
| `customer`       | `object`   | No       | Customer details (see below)                      |
| `customer.email` | `string`   | No       | Customer email address                            |
| `customer.name`  | `string`   | No       | Customer full name                                |
| `callbackUrl`    | `string`   | No       | Server-side webhook URL for payment notifications |
| `onSuccess`      | `function` | No       | Called when payment completes successfully        |
| `onCancel`       | `function` | No       | Called when customer closes the payment modal     |
| `onError`        | `function` | No       | Called on payment failure or network error        |

## Callback Response

The `onSuccess` callback receives a response object:

```javascript theme={null}
{
  "reference": "INV-2026-001",
  "trx_id": "TRX-A1B2C3D4",
  "amount": 25.00,
  "currency": "EUR",
  "status": "success"
}
```

| Field       | Type     | Description                   |
| ----------- | -------- | ----------------------------- |
| `reference` | `string` | Your original order reference |
| `trx_id`    | `string` | Quickei transaction ID        |
| `amount`    | `number` | Amount paid                   |
| `currency`  | `string` | Currency of the payment       |
| `status`    | `string` | Payment status (`success`)    |

<Warning>
  Always verify the payment on your server using the `callbackUrl` webhook or the [Check Payment Status](/api-reference/03-check-payment-status) endpoint. Client-side callbacks can be spoofed.
</Warning>

## Sandbox vs Production

Use key prefixes to switch between environments:

| Environment    | Key Prefix | Base URL                         |
| -------------- | ---------- | -------------------------------- |
| **Sandbox**    | `qi_test_` | `https://quickei.io/pay/sandbox` |
| **Production** | `qi_live_` | `https://quickei.io/pay`         |

The SDK automatically detects the environment based on your key prefix. No code changes needed — just swap the key.

```javascript theme={null}
// Sandbox — test payments, no real charges
const quickei = new Quickei({
  publicKey: 'qi_test_abc123def456'
});

// Production — real payments
const quickei = new Quickei({
  publicKey: 'qi_live_abc123def456'
});
```

## Examples

### Complete Checkout Page

A full checkout page with order summary and payment button:

```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 — My Store</title>
  <script src="https://quickei.io/sdk/quickei.js"></script>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f5f5f5; }
    .checkout { max-width: 480px; margin: 40px auto; background: #fff; border-radius: 12px; padding: 32px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
    .checkout h2 { margin-bottom: 24px; }
    .line-item { display: flex; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #eee; }
    .total { display: flex; justify-content: space-between; padding: 16px 0; font-weight: 700; font-size: 1.2em; }
    .pay-btn { width: 100%; padding: 16px; background: #095367; color: #fff; border: none; border-radius: 8px; font-size: 16px; font-weight: 600; cursor: pointer; margin-top: 16px; }
    .pay-btn:hover { background: #0a6a82; }
    .pay-btn:disabled { opacity: 0.6; cursor: not-allowed; }
    .status { text-align: center; margin-top: 16px; padding: 12px; border-radius: 8px; display: none; }
    .status.success { display: block; background: #ecfdf5; color: #065f46; }
    .status.error { display: block; background: #fef2f2; color: #991b1b; }
  </style>
</head>
<body>
  <div class="checkout">
    <h2>Order Summary</h2>
    <div class="line-item"><span>Premium Plan (1 year)</span><span>99.00 EUR</span></div>
    <div class="line-item"><span>Setup fee</span><span>10.00 EUR</span></div>
    <div class="total"><span>Total</span><span>109.00 EUR</span></div>

    <button class="pay-btn" id="pay-btn">Pay 109.00 EUR</button>
    <div class="status" id="status"></div>
  </div>

  <script>
    const quickei = new Quickei({
      publicKey: 'qi_live_abc123def456'
    });

    const btn = document.getElementById('pay-btn');
    const status = document.getElementById('status');

    btn.addEventListener('click', () => {
      btn.disabled = true;
      btn.textContent = 'Processing...';

      quickei.pay({
        amount: 109.00,
        currency: 'EUR',
        reference: 'ORD-' + Date.now(),
        description: 'Premium Plan (1 year) + Setup fee',
        customer: {
          email: 'customer@example.com',
          name: 'Jane Doe'
        },
        callbackUrl: 'https://mystore.com/api/quickei-webhook',
        onSuccess: (res) => {
          status.className = 'status success';
          status.textContent = 'Payment successful! Transaction: ' + res.trx_id;
          btn.textContent = 'Paid';
        },
        onCancel: () => {
          btn.disabled = false;
          btn.textContent = 'Pay 109.00 EUR';
        },
        onError: (err) => {
          status.className = 'status error';
          status.textContent = 'Payment failed. Please try again.';
          btn.disabled = false;
          btn.textContent = 'Pay 109.00 EUR';
        }
      });
    });
  </script>
</body>
</html>
```

### Custom Button Styling

You can trigger the payment from any element. Style it however you want:

```html theme={null}
<style>
  .quickei-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 24px;
    background: linear-gradient(135deg, #095367, #0891b2);
    color: #fff;
    border: none;
    border-radius: 8px;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s;
  }
  .quickei-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(9, 83, 103, 0.3);
  }
  .quickei-btn svg {
    width: 18px;
    height: 18px;
  }
</style>

<button class="quickei-btn" onclick="handlePayment()">
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
    <rect x="1" y="4" width="22" height="16" rx="2" ry="2"/>
    <line x1="1" y1="10" x2="23" y2="10"/>
  </svg>
  Pay with Quickei
</button>

<script>
  const quickei = new Quickei({ publicKey: 'qi_live_abc123def456' });

  function handlePayment() {
    quickei.pay({
      amount: 29.99,
      currency: 'EUR',
      reference: 'ITEM-' + Date.now(),
      description: 'Widget Pro',
      onSuccess: (res) => alert('Thanks! Ref: ' + res.reference)
    });
  }
</script>
```

## Security

<CardGroup cols={2}>
  <Card title="Public key only" icon="key">
    The SDK uses your **public key** (`client_id`). Never include your `client_secret` in client-side code — it would allow anyone to make API calls on your behalf.
  </Card>

  <Card title="Server-side verification" icon="shield-check">
    Always confirm payments server-side using webhooks or the payment status API. Client-side callbacks are for UX only — they can be tampered with.
  </Card>

  <Card title="HTTPS required" icon="lock">
    The SDK only loads on pages served over HTTPS. Callback URLs must also use HTTPS.
  </Card>

  <Card title="CSP compatible" icon="browser">
    If you use Content Security Policy headers, allow `https://quickei.io` in `frame-src` and `script-src` directives.
  </Card>
</CardGroup>

## Browser Support

The SDK works in all modern browsers:

| Browser       | Minimum Version |
| ------------- | --------------- |
| Chrome        | 60+             |
| Firefox       | 55+             |
| Safari        | 12+             |
| Edge          | 79+ (Chromium)  |
| Opera         | 47+             |
| Mobile Chrome | 60+             |
| Mobile Safari | 12+             |

<Note>
  Internet Explorer is not supported. The SDK uses modern JavaScript features (Promises, `fetch`, arrow functions) that require a modern browser.
</Note>
