# SDK checkout API
Understand the public checkout endpoints the Plandalf SDK calls for offer loading, session creation, session lookup, mutations, and discounts.
Source: /docs/api/sdk-checkout
Last modified: 2026-06-20
Most projects should use the SDK instead of calling these endpoints directly. This page documents the API shape behind SDK checkout behavior so custom frontends and agents can reason about the same calls.


> **Use the SDK unless you are building a custom checkout surface**
>

  `plandalf.present("pro-plan")` handles identity headers, anonymous visitor IDs, session continuity, frame state, and live checkout events. Call these endpoints directly only when you need to own that behavior.


## Endpoint flow


### Load the published offer


    Fetch the offer, theme, page structure, and first checkout page for the slug you published in Plandalf.


### Create or resume a session


    Create the checkout session that tracks buyer state, selected items, discounts, and payment progress.


### Apply buyer changes


    Send structured mutations when the buyer changes customer details, quantities, bumps, add-ons, or discounts.


### Listen from the SDK


    Use [live events](/docs/sdk/events) or the SDK handle result to unlock UI, redirect, or call your backend after checkout.


## Public checkout endpoints

<ApiEndpoint
  id="initialize-checkout"
  method="GET"
  path="/api/checkout"
  title="Load checkout"
  description="Loads checkout data for a published offer so a custom surface can render the correct theme, pages, and first step."
  operationId="initializeCheckout"
  auth="Public offer route"
>


### Query parameters


- `offer` (string; required):
    Published offer slug, Sqid route key, or UUID. The route also accepts `offer_id` for compatibility.


### Load checkout request


```bash title="GET /api/checkout"
curl "https://api.plandalf.com/api/checkout?offer=pro-plan" \
  -H "Accept: application/json"
```

```js title="initialize-checkout.js"
const response = await fetch(
  "https://api.plandalf.com/api/checkout?offer=pro-plan",
  { headers: { Accept: "application/json" } }
);

const checkout = await response.json();
```


### Checkout initialization response


```json title="200 checkout initialization"
{
  "offer": {
    "id": "off_123",
    "slug": "pro-plan",
    "name": "Pro plan"
  },
  "theme": {
    "primary_color": "#007d96"
  },
  "pages": [],
  "firstPage": null
}
```


</ApiEndpoint>

<ApiEndpoint
  id="create-checkout-session"
  method="POST"
  path="/api/checkout/sessions"
  title="Create checkout session"
  description="Creates a checkout session for a published offer. The SDK uses this before it starts collecting buyer changes."
  operationId="createCheckoutSession"
  auth="Public offer route"
>


### Request body


- `offer` (string; required):
    Published offer slug, Sqid route key, or UUID. The route also accepts `offer_id`.


- `customer` (object):
    Optional customer identity fields or a signed customer token passed by your integration.


- `metadata` (object):
    Optional implementation metadata, such as source page, campaign, or account ID.


### Create session request


```bash title="POST /api/checkout/sessions"
curl -X POST "https://api.plandalf.com/api/checkout/sessions" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "offer": "pro-plan",
    "metadata": {
      "source": "pricing-page"
    }
  }'
```

```js title="create-checkout-session.js"
const response = await fetch("https://api.plandalf.com/api/checkout/sessions", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Accept: "application/json"
  },
  body: JSON.stringify({
    offer: "pro-plan",
    metadata: { source: "pricing-page" }
  })
});

const session = await response.json();
```


### Checkout session response


```json title="201 checkout session"
{
  "id": "cs_123",
  "offer_id": "off_123",
  "status": "open",
  "currency": "USD",
  "subtotal": 4900,
  "discount_total": 0,
  "total": 4900
}
```


</ApiEndpoint>

<ApiEndpoint
  id="retrieve-checkout-session"
  method="GET"
  path="/api/checkout/sessions/{session}"
  title="Retrieve checkout session"
  description="Returns the current checkout session state for a custom checkout surface or recovery flow."
  operationId="retrieveCheckoutSession"
  auth="Public session route"
>


### Path parameters


- `session` (string; required):
    Checkout session route key returned by the create session call.


### Retrieve session request


```bash title="GET /api/checkout/sessions/{session}"
curl "https://api.plandalf.com/api/checkout/sessions/cs_123" \
  -H "Accept: application/json"
```

```js title="retrieve-checkout-session.js"
const response = await fetch("https://api.plandalf.com/api/checkout/sessions/cs_123", {
  headers: { Accept: "application/json" }
});

const session = await response.json();
```


### Checkout session state


```json title="200 checkout session"
{
  "id": "cs_123",
  "status": "open",
  "selected_items": [],
  "customer": null,
  "totals": {
    "subtotal": 4900,
    "discount": 0,
    "total": 4900
  }
}
```


</ApiEndpoint>

<ApiEndpoint
  id="mutate-checkout-session"
  method="POST"
  path="/api/checkout/sessions/{checkoutSession}/mutations"
  title="Mutate checkout session"
  description="Applies a structured checkout change, such as customer details, quantity changes, add-ons, order bumps, or selected options."
  operationId="mutateCheckoutSession"
  auth="Public session route"
>


### Path parameters


- `checkoutSession` (string; required):
    Checkout session route key.


### Request body


- `type` (string; required):
    Mutation type handled by the checkout surface, such as `customer.update`, `line_item.update`, or `component.select`.


- `payload` (object; required):
    Mutation payload. Keep it narrow to the fields changed by this interaction.


### Mutation request


```bash title="POST /api/checkout/sessions/{checkoutSession}/mutations"
curl -X POST "https://api.plandalf.com/api/checkout/sessions/cs_123/mutations" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "type": "customer.update",
    "payload": {
      "email": "buyer@example.com"
    }
  }'
```

```js title="mutate-checkout-session.js"
const response = await fetch(
  "https://api.plandalf.com/api/checkout/sessions/cs_123/mutations",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json"
    },
    body: JSON.stringify({
      type: "customer.update",
      payload: { email: "buyer@example.com" }
    })
  }
);

const session = await response.json();
```


### Mutation response


```json title="200 mutation response"
{
  "id": "cs_123",
  "status": "open",
  "customer": {
    "email": "buyer@example.com"
  },
  "totals": {
    "subtotal": 4900,
    "discount": 0,
    "total": 4900
  }
}
```


</ApiEndpoint>

<ApiEndpoint
  id="apply-discount"
  method="POST"
  path="/api/checkout/sessions/{checkoutSession}/apply-discount"
  title="Apply discount"
  description="Applies a coupon or discount code to an open checkout session and returns recalculated totals."
  operationId="applyCheckoutDiscount"
  auth="Public session route"
>


### Path parameters


- `checkoutSession` (string; required):
    Checkout session route key.


### Request body


- `code` (string; required):
    Coupon or discount code entered by the buyer.


### Apply discount request


```bash title="POST /api/checkout/sessions/{checkoutSession}/apply-discount"
curl -X POST "https://api.plandalf.com/api/checkout/sessions/cs_123/apply-discount" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"code":"LAUNCH20"}'
```

```js title="apply-discount.js"
const response = await fetch(
  "https://api.plandalf.com/api/checkout/sessions/cs_123/apply-discount",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json"
    },
    body: JSON.stringify({ code: "LAUNCH20" })
  }
);

const session = await response.json();
```


### Discounted session response


```json title="200 discounted session"
{
  "id": "cs_123",
  "status": "open",
  "discounts": [
    {
      "code": "LAUNCH20",
      "amount_off": 980
    }
  ],
  "totals": {
    "subtotal": 4900,
    "discount": 980,
    "total": 3920
  }
}
```


</ApiEndpoint>

## SDK-first routes

The newer SDK checkout surface also calls `/api/sdk/checkout/offers/{slug}`, `/api/sdk/checkout/compute`, `/api/sdk/checkout/prepare-payment`, and `/api/sdk/checkout/commit`. Prefer those through the SDK wrapper unless you are implementing a lower-level adapter.

```js title="recommended-sdk-call.js"
await plandalf.present("pro-plan");
```

## Related docs

- [Configure the SDK](/docs/sdk/configure)
- [Session continuity](/docs/sdk/session-continuity)
- [Live events](/docs/sdk/events)