# Quickstart
Install the Plandalf SDK, open an offer from a button, and handle the completed checkout result.
Source: /docs/quickstart
Last modified: 2026-06-19
This guide adds Plandalf checkout to any page with a script tag and one button.

## Prerequisites

- A Plandalf account with an organization subdomain.
- An offer slug from the Offers editor.
- A live or test payment integration connected before you accept real payments.

## Install the SDK

Add the stub before the SDK script. The stub lets you queue calls before the async SDK file finishes loading.

```html
<script>
  // Queue SDK calls until the async Plandalf bundle is ready.
  window.plandalf = window.plandalf || function () {
    (window.plandalf.q = window.plandalf.q || []).push(arguments);
  };
</script>

<!-- Replace acme with your Plandalf organization subdomain. -->
<script src="https://acme.plandalf.com/js/plandalf-sdk.js" async></script>
```


### Install snippet explained

This script is intentionally small so it can live in page builders, CMS templates, and app layouts.

- `window.plandalf = window.plandalf || function () { ... }` - Creates a temporary function before the real SDK has loaded. Calls made early are not lost.
- `window.plandalf.q.push(arguments)` - Stores queued SDK commands in order. When the SDK initializes, it replays them against the real SDK instance.
- `https://acme.plandalf.com/js/plandalf-sdk.js` - Loads the browser bundle from your Plandalf organization host. Replace acme with your own organization subdomain.

## Open an offer

Replace `pro-plan` with your offer slug.

```html
<button id="buy-pro">Buy Pro</button>

<script>
  document.getElementById("buy-pro").addEventListener("click", async () => {
    // Open the published offer by slug and wait for the final checkout result.
    const result = await plandalf.present("pro-plan");

    // Redirect only after checkout completes successfully.
    if (result.status === "complete") {
      window.location.href = result.redirectUrl ?? "/thank-you";
    }
  });
</script>
```

`plandalf.present()` returns a `FlowHandle`. It behaves like a Promise, so `await` gives you the final checkout result. It also exposes `.events` for live purchase events and `.close()` for dismissing the frame programmatically.


### Checkout snippet explained

- `plandalf.present("pro-plan")` - Opens the published offer with the slug pro-plan. The offer controls the products, prices, layout, payment methods, and completion behavior.
- `await plandalf.present(...)` - Waits until the customer completes or dismisses the checkout. Network errors and invalid offer slugs reject the promise.
- `result.status === "complete"` - Confirms that checkout finished successfully before you redirect, unlock access, or call your backend.
- `result.redirectUrl ?? "/thank-you"` - Uses the offer's configured redirect when present, otherwise falls back to your own local thank-you page.


### What happens when the customer clicks

- Button click - Your page calls `plandalf.present()` with the offer slug.
- Checkout opens - Plandalf creates or resumes a checkout session and renders the published offer.
- Result resolves - Your code receives a completed or dismissed result and can decide what to do next.

## Use declarative HTML

For simple buttons, you can skip custom JavaScript.

```html
<button data-plandalf-present="pro-plan">
  Buy Pro
</button>
```

Add frame and mode options as attributes.

```html
<button
  data-plandalf-present="pro-plan"
  data-plandalf-frame="slideout"
  data-plandalf-mode="test"
  data-plandalf-size="wide"
>
  Test checkout
</button>
```


### The same checkout trigger in different stacks

Use the HTML version in no-code builders, the JavaScript version in static pages, and the React version inside app components.

The SDK listens for data attributes and opens the offer when the customer clicks the button.


```html HTML
<button
  data-plandalf-present="pro-plan"
  data-plandalf-frame="slideout"
  data-plandalf-mode="test"
>
  Buy Pro
</button>
```

Use direct JavaScript when your page needs to handle completion, analytics, or redirects.


```js JavaScript
const button = document.querySelector("[data-buy-pro]");

button.addEventListener("click", async () => {
  // Open the offer and wait for either completion or dismissal.
  const result = await plandalf.present("pro-plan", {
    frame: "slideout",
    mode: "test"
  });

  // Only treat completed checkout as a successful purchase.
  if (result.status === "complete") {
    window.location.href = result.redirectUrl ?? "/thank-you";
  }
});
```

Use the same browser SDK from React when checkout starts from component state or app routing.


```tsx React
export function BuyButton() {
  async function openCheckout() {
    // present() resolves when the Plandalf frame finishes.
    const result = await window.plandalf.present("pro-plan", {
      frame: "modal",
      mode: "test"
    });

    // Keep fulfillment behind a completed checkout result.
    if (result.status === "complete") {
      window.location.assign(result.redirectUrl ?? "/thank-you");
    }
  }

  return <button onClick={openCheckout}>Buy Pro</button>;
}
```


## Expected result

Clicking the button opens the offer in a Plandalf checkout frame. A completed checkout resolves with:

```ts
{
  status: "complete",
  session: {
    uuid: "ck_...",
    total: 2900,
    currency: "usd",
    customer: { email: "jane@example.com" }
  },
  customer: { email: "jane@example.com" },
  redirectUrl: "https://example.com/thanks"
}
```

Customer dismissal is not an exception:

```ts
{ status: "dismissed", reason: "cancel" }
```

Only real errors, such as network failures or an invalid offer slug, reject the Promise.

## Next steps


### [Configure SDK options](/docs/sdk/configure)


    Choose frame, test mode, size, metadata, continuity, and close behavior.


### [Identify customers](/docs/sdk/identity)


    Attach purchases to logged-in users with email or signed JWT identity.


### [Create an offer](/docs/offers/create)


    Build the checkout surface customers will see.


### [Go live](/docs/going-live)


    Check payments, test mode, URLs, invoices, and post-purchase automations.