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

# JavaScript checkout SDK

> Show the CreptaPay checkout on your website as a popup, inline, or a redirect.

`@creptapay/checkout` opens the CreptaPay checkout from your website. The customer pays with stablecoins without leaving your page (or on the hosted page), and you get a callback when it's paid.

It works in any browser setup: plain HTML, React, Vue, Next.js, and others.

## Install

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npm install @creptapay/checkout
    ```

    ```js theme={null}
    import CreptaPay from "@creptapay/checkout";
    ```
  </Tab>

  <Tab title="Script tag">
    ```html theme={null}
    <script src="https://unpkg.com/@creptapay/checkout@0.2/dist/creptapay.js"></script>
    <script>
      const crepta = new CreptaPay({ publicKey: "pk_test_..." });
    </script>
    ```

    `@0.2` loads the newest 0.2.x release. To pin an exact version, use it in the URL, for example `@creptapay/checkout@0.2.0`.
  </Tab>
</Tabs>

<Warning>
  The SDK only takes your **public** key (`pk_…`). It refuses a secret key, so a secret key never ends up in your website's code.
</Warning>

## Recommended: create on your server, open in the browser

If the browser creates the payment, someone could edit your page and change the price first. Instead, create the payment on your server with your secret key, using the amount from your own order data. Then open it in the browser with `resumePayment`.

<Steps>
  <Step title="Create the payment on your server">
    ```js theme={null}
    // Node 18+, on your server. Never send sk_ keys to the browser.
    const res = await fetch("https://api.creptapay.com/v1/payment", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": process.env.CREPTAPAY_SECRET_KEY, // sk_test_… or sk_live_…
      },
      body: JSON.stringify({
        amount: order.total,          // from your database
        currency: "NGN",              // or "USD", "EUR"
        customer: { email: order.email, first_name: order.firstName, last_name: order.lastName },
        metadata: { order_id: order.id },
        redirect_url: "https://shop.example.com/checkout/complete",
      }),
    });
    const { data } = await res.json();
    // Send data.reference to your page.
    ```
  </Step>

  <Step title="Open it on your page">
    ```js theme={null}
    const crepta = new CreptaPay({ publicKey: "pk_test_..." });

    crepta.resumePayment(reference, {
      mode: "popup", // "popup" | "inline" | "redirect"
      onSuccess: (result) => {
        // A signal for your UI. Fulfil only after your server confirms (see below).
        window.location.href = `/orders/thank-you?reference=${result.reference}`;
      },
    });
    ```

    `resumePayment` checks that the payment belongs to your account and hasn't expired before showing it.
  </Step>

  <Step title="Confirm on your server">
    Wait for the signed `payment.paid` [webhook](/guides/webhooks), then check its `metadata.order_id` and amount match the order.
  </Step>
</Steps>

## Create the payment in the browser

You can also create the payment straight from the browser with your public key. This is quicker to set up, but the price can be changed on the page, so always check the paid amount on your server.

```js theme={null}
const crepta = new CreptaPay({ publicKey: "pk_test_..." });

const payment = await crepta.initialize({
  amount: 25,
  currency: "USD",
  description: "Order #1042",
  customer: { email: "ada@example.com", first_name: "Ada", last_name: "Lovelace" },
  metadata: { order_id: "1042" },
  redirectUrl: "https://shop.example.com/checkout/complete",
});
```

Then show it in one of three ways.

<Tabs>
  <Tab title="Popup">
    A modal over your page.

    ```js theme={null}
    crepta.open(payment, {
      onSuccess: (result) => verifyOnServer(result.reference),
      onClose: () => console.log("checkout closed"),
    });
    ```
  </Tab>

  <Tab title="Inline">
    Inside an element on your page.

    ```html theme={null}
    <div id="pay"></div>
    ```

    ```js theme={null}
    crepta.mount("#pay", payment, { onSuccess: (r) => showThankYou(r.reference) });
    ```
  </Tab>

  <Tab title="Redirect">
    Sends the customer to the hosted checkout page.

    ```js theme={null}
    crepta.redirect(payment);
    ```

    After payment they come back to your `redirectUrl`:
    `https://shop.example.com/checkout/complete?reference=ab12cd34&status=paid`
  </Tab>
</Tabs>

To create and show the payment in one call, use `checkout()`:

```js theme={null}
await crepta.checkout({
  amount: 25,
  customer: { email: "ada@example.com", first_name: "Ada", last_name: "Lovelace" },
  mode: "popup",
  onSuccess: (r) => verifyOnServer(r.reference),
});
```

## Callbacks

| Callback | When it fires |
| - | - |
| `onLoad()` | The checkout has loaded. |
| `onStatusChange(result)` | On every status change: `pending`, `confirming`, `underpaid`, `expired`, `paid`. |
| `onSuccess(result)` | The payment is fully received (`paid` or `overpaid`). Fires once. |
| `onExpired(result)` | The payment window ended before the full amount arrived. |
| `onClose({ reference, status })` | The customer closed the checkout. |
| `onError(error)` | The checkout failed to load. |

If you don't pass `onSuccess` and the payment has a redirect URL, the popup and inline modes redirect after success. Change this with `redirectOnSuccess`. The popup closes itself 2.5 seconds after success; change this with `autoCloseAfterSuccess` (or `false` to keep it open).

## Methods

| Method | Returns |
| - | - |
| `resumePayment(reference, options)` | Opens a payment your server created. Options: `mode`, `container`, `height`, and the callbacks. |
| `initialize(params)` | Creates a payment with your public key. Returns `{ id, reference, checkoutUrl, status, total, currency, … }`. |
| `open(payment, options)` | Shows the popup. Returns `{ reference, close() }`. |
| `mount(container, payment, options)` | Shows the checkout inline. Returns `{ reference, close() }`. |
| `redirect(payment)` | Sends the customer to the hosted page. |
| `checkout(params)` | `initialize` and show in one call. |
| `getPayment(reference)` | The payment's current status, for your UI. Not for deciding to fulfil. |

Errors are thrown as `CreptaPayError`, with `.message` and `.status` (for example `403` for a payment from another account, `410` for an expired one).

## Always confirm on your server

The callbacks and the `?status=paid` on your redirect URL come from the browser, so anyone can fake them. Before you ship an order, confirm on your server that the payment:

* is `paid` or `overpaid`,
* has this order's `metadata.order_id`,
* is for at least the order's amount, in the right currency.

The most reliable way is the [`payment.paid` webhook](/guides/webhooks). You can also fetch the payment with your secret key:

```js theme={null}
const res = await fetch(`https://api.creptapay.com/v1/payment/${paymentId}`, {
  headers: { "x-api-key": process.env.CREPTAPAY_SECRET_KEY },
});
const { data } = await res.json();
if (["paid", "overpaid"].includes(data.status)) fulfil(data.metadata.order_id);
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.