> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.recurrente.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.recurrente.com/_mcp/server.

# Embedded Checkouts

> Embed a Recurrente checkout directly on your website

**Recurrente Checkout** is a JavaScript library that lets you **embed a responsive, secure checkout directly on your website**. It renders an iframe with your payment session and handles callbacks for key events like success, failure, or pending payments.

> **Note**
>
> For the most up-to-date version of this guide and sample code, visit the repo: [github.com/recurrente/recurrente-checkout](https://github.com/recurrente/recurrente-checkout)

## Video tutorial

See it in action: [https://youtu.be/OUIYVcrnPr0](https://youtu.be/OUIYVcrnPr0)

## Prerequisites

To use this library, you need to create a checkout in Recurrente. See the [checkout creation docs](/referencia-api/api-reference/checkouts/create-checkout) to get your checkout URL.

### Clave in embedded checkouts

Inside an iframe the browser treats our cookies as third-party, so Clave does not always recognise a customer by their browser. That is why the embedded checkout leads with a **Pay with Clave** button, the way Link's sits beside Apple Pay: it opens the Clave window, a window on our own origin where the browser does hand over the cookie; the customer picks their card and pays, the window closes itself and your page receives `onSuccess` exactly as it does for a payment inside the iframe. Whoever would rather stay in the form keeps the usual path: Clave recognises them by the email or phone they are already typing, sends a one-time code, and confirming it brings their saved methods into the checkout.

Nothing needs configuring for this to work, and your customer never has to change browser permissions. In-app browsers (Instagram, Facebook, WhatsApp) cannot hold a popup, so the button stays out there and the code remains. See [Accept Clave](/guides-english/guides/clave).

### Local development

The checkout's card fields are served by our processor, which only accepts a parent page on an `https://` origin or on `http://localhost` (any port). If you open your site from `http://127.0.0.1`, a LAN address or a host like `myapp.local`, the checkout loads but the card form fails with a `422` on `capture_context` whose body names the rejected origin.

To test locally, open your site at `http://localhost:PORT` or expose it over HTTPS with a tunnel such as ngrok.

## Installation

### NPM (Recommended)

```bash
npm install recurrente-checkout
```

### CDN

```html
<script src="https://cdn.jsdelivr.net/npm/recurrente-checkout@0.0.5/recurrente-checkout.js"></script>
```

Pin the version in the CDN URL, so a new release never changes your checkout without you knowing.

## Usage

```html
<div id="recurrente-checkout-container"></div>
```

```javascript
import RecurrenteCheckout from "recurrente-checkout";

RecurrenteCheckout.load({
  url: "https://app.recurrente.com/checkout-session/ch_abc123",
  onSuccess: (data) => {
    console.log("Payment succeeded", data.checkoutId);
  },
  onFailure: (data) => {
    console.log("Payment failed", data.error);
  },
  onPaymentInProgress: (data) => {
    console.log("Payment in progress", data.checkoutId);
  },
});
```

The checkout mounts in the element with id `recurrente-checkout-container`. If it doesn't exist, the library creates it at the end of the page.

### Parameters

| Parameter             | Type     | Description                                                                |
| --------------------- | -------- | -------------------------------------------------------------------------- |
| `url`                 | string   | The `checkout_url` the API returns when you create a checkout              |
| `onSuccess`           | function | When the payment completes. Receives `checkoutId`                          |
| `onFailure`           | function | When an attempt fails. Receives `error` (and `notice`, with the same text) |
| `onPaymentInProgress` | function | When the payment is pending, such as a bank transfer                       |
| `development`         | boolean  | Accepts events from any origin. For local testing only                     |

## Full flow

1. **Create a checkout** through the Recurrente API (`POST /api/checkouts`)
2. **Pass its `checkout_url`** to `RecurrenteCheckout.load`
3. **Handle the callbacks** for success, failure, or pending payment
4. **Confirm the payment on your server** with the webhook or `GET /api/checkouts/{id}` before fulfilling

```javascript
// 1. Create the checkout from your backend
const response = await fetch("/api/create-checkout", { method: "POST" });
const { checkout_url } = await response.json();

// 2-3. Mount and initialize
RecurrenteCheckout.load({
  url: checkout_url,
  onSuccess: () => window.location.href = "/thank-you",
  onFailure: () => alert("Payment failed. Please try again."),
});
```

Already have your own payment form and only want to add Clave? Use the [Clave button](/guides-english/guides/clave).