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

# Embed the checkout

> The fastest, safest way to take payments: drop the Kwugwo overlay onto your site with @kwugwo/checkout.

<Tip>
  **This is the recommended way to integrate Kwugwo.** Unless you
  have a strong reason to build your own checkout UI, embed ours;
  you'll ship faster, stay out of PCI scope, and pick up every new
  payment medium we add the day it goes live, with no client-side
  changes.
</Tip>

`@kwugwo/checkout` is the official browser SDK for embedding the
Kwugwo checkout. It opens a hosted overlay on your page, listens for
the result via `postMessage`, and fires your callbacks. No React, no
framework, **\~5 KB gzipped**.

The merchant's backend creates an [ugwo](/ugwo/create) and returns
its `uid` to the frontend. The SDK takes it from there; card and
bank-transfer data never touch your origin, so you stay out of PCI
scope.

## Why use the embed

* **5 lines of code.** Init, open, done.
* **PCI scope stays at zero.** Sensitive data never enters your page.
* **All mediums, no extra work.** New payment methods we add show up
  in your checkout automatically; you don't have to ship anything.
* **Mobile-friendly out of the box.** Desktop modal, full-screen on
  mobile, backdrop + Escape to close, body-scroll lock while open.
* **Tiny.** \~5 KB gzipped, no framework, no peer deps.

## Install

<CodeGroup>
  ```bash npm theme={null}
  npm install @kwugwo/checkout
  ```

  ```html Script tag theme={null}
  <script src="https://cdn.jsdelivr.net/npm/@kwugwo/checkout"></script>
  ```
</CodeGroup>

<Note>
  **Framework SDKs are coming soon**: first-party packages for
  **React**, **Vue**, and **Angular** are on the roadmap. Until they
  ship, use `@kwugwo/checkout` directly from inside your
  component: call `KwugwoCheckout.init(...)` once on mount and
  `instance.open(...)` from your event handler. The vanilla SDK
  works the same in every framework.
</Note>

## Usage

<CodeGroup>
  ```js ES modules theme={null}
  import { KwugwoCheckout } from '@kwugwo/checkout';

  const checkout = KwugwoCheckout.init({
      publicKey: 'pk.VCvr.iemkSYEKZlpPqUEoeHLqEmvbHPln4JnyNBehFnATM3GzpcMILEUjNPJSpyMuYc13JiByfYohiCPPlwnu'
  });

  document.getElementById('pay').addEventListener('click', async () => {
      // 1. Your backend creates the ugwo and returns its uid
      const { ugwoUid } = await fetch('/checkout/create', { method: 'POST' }).then(r => r.json());

      // 2. Open the checkout overlay
      const result = await checkout.open({
          ugwoUid,
          returnUrl: 'https://merchant.com/thanks',
          onSuccess: ({ activityUid }) => console.log('Paid', activityUid),
          onClose:   () => console.log('User closed the modal'),
          onError:   (e) => console.error(e.code, e.message),
      });

      // result is { type: 'success' | 'closed' | 'error', ... }
  });
  ```

  ```html Script tag theme={null}
  <script src="https://cdn.jsdelivr.net/npm/@kwugwo/checkout"></script>
  <script>
      var checkout = KwugwoCheckout.init({
          publicKey: 'pk.VCvr.iemkSYEKZlpPqUEoeHLqEmvbHPln4JnyNBehFnATM3GzpcMILEUjNPJSpyMuYc13JiByfYohiCPPlwnu'
      });

      document.getElementById('pay').onclick = function () {
          checkout.open({
              ugwoUid: 'ugw.VCvr.qnbBJaElzSTHOcaTzxbuDlIs',
              onSuccess: function (r) { console.log('paid', r); }
          });
      };
  </script>
  ```
</CodeGroup>

## API reference

### `KwugwoCheckout.init(options)`

Returns a `KwugwoCheckoutInstance`.

<ParamField body="publicKey" type="string" required>
  Merchant public key (the one prefixed `pk.`). The matching secret
  key stays on your backend; the public key only lets the SDK fetch
  the ugwo from `/checkout/v1`.
</ParamField>

<ParamField body="baseUrl" type="string" default="https://checkout.kwugwo.africa">
  Override the hosted-checkout origin. Useful for staging.
</ParamField>

### `instance.open(options)` → `Promise<CheckoutResult>`

<ParamField body="ugwoUid" type="string" required>
  Ugwo ID (`ugw.XXXX.YYYY...`) returned from your backend after a
  [Create an ugwo](/ugwo/create) call.
</ParamField>

<ParamField body="returnUrl" type="string">
  If set, the parent window navigates here after a successful
  payment. Promise still resolves first so `onSuccess` can run any
  cleanup.
</ParamField>

<ParamField body="onSuccess" type="(result) => void | Promise<void>">
  Fires on successful payment. The promise is awaited before
  redirecting to `returnUrl`.
</ParamField>

<ParamField body="onClose" type="() => void">
  Fires when the user dismisses the modal without completing payment.
</ParamField>

<ParamField body="onError" type="(err) => void">
  Fires when the checkout cannot complete (invalid session, expired,
  network, etc).
</ParamField>

The returned promise **always resolves** (never rejects) with one of:

```ts theme={null}
type CheckoutResult =
  | { type: 'success'; ugwoUid: string; activityUid?: string }
  | { type: 'closed';  ugwoUid: string }
  | { type: 'error';   ugwoUid?: string; code: string; message: string };
```

### `instance.close()`

Programmatically dismiss the overlay (fires `onClose`).

## Browser support

ES2020 targets: Chrome 80+, Edge 80+, Firefox 74+, Safari 13.1+.
No polyfills needed for modern browsers; if you support older
targets, bundle through your existing toolchain.

## End-to-end flow

<Steps>
  <Step title="Create the ugwo on your backend">
    Call [`POST /v1/ugwo`](/ugwo/create) with your secret key. Return
    the resulting `uid` to your frontend.
  </Step>

  <Step title="Open the overlay">
    Pass that `uid` to `checkout.open({ ugwoUid })`. The SDK
    authenticates the iframe with your **public** key.
  </Step>

  <Step title="Listen for the result">
    `onSuccess` fires with the `activityUid`. Trust your webhook
    (not the browser callback) as the source of truth for fulfilment.
    See [Webhook deliveries](/webhook-deliveries) for details.
  </Step>

  <Step title="Reconcile on your backend">
    Either poll [`GET /v1/ugwo/{uid}`](/ugwo/get) or wait for the
    `ugwo.activity.updated` webhook. Mark the order paid once the
    ugwo is `ugwo_successful`.
  </Step>
</Steps>
