---
title: "Checkout Sessions"
description: "6 operations, with parameters and examples."
url: https://docs.fluveo.com/api/checkout_sessions/
---

> Index of every page: https://docs.fluveo.com/llms.txt. Integrating Fluveo? Read https://docs.fluveo.com/agents/integrate.md first.

> Too long? This page with code in one language only: https://docs.fluveo.com/api/checkout_sessions.curl.md (cURL), https://docs.fluveo.com/api/checkout_sessions.node.md (Node.js), https://docs.fluveo.com/api/checkout_sessions.python.md (Python), https://docs.fluveo.com/api/checkout_sessions.php.md (PHP).

# Checkout Sessions

6 operations, with parameters and examples.

A Checkout Session is a hosted payment page for one payment. Create a session with its line items, send the buyer to its url, and read the session or wait for checkout.session.completed. Each session pays through a PaymentIntent, made when the buyer first presses Pay: until then the session's payment_intent is null.

Send every request to `https://api.fluveo.com/v1` with your secret key as a Bearer token. This page lists only what Fluveo serves; [the OpenAPI file](https://docs.fluveo.com/openapi.json) holds the same operations.

An operation or a parameter marked **Preview** works, but it is not locked yet and may change: [what Preview means](https://docs.fluveo.com/api.md#preview).

> **For AI agents:**
>
> Use plain HTTP; install no payments SDK. Send `Authorization: Bearer sk_test_...` and a fresh `Idempotency-Key` on every POST; reuse the same key only when you retry that same POST. Send only the documented parameters. An operation or a parameter marked Preview may change: prefer the ones without the mark.

## Creates a Checkout Session. Its PaymentIntent is made when the buyer pays; a setup session makes its SetupIntent at once

`POST /v1/checkout/sessions`

Permission: [`rak_checkout_session_write`](https://docs.fluveo.com/permissions.md#checkout_session).

**Headers**

- `Idempotency-Key` (string, optional): Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

**Body parameters**

- `billing_address_collection` (enum, optional, preview): auto (the country and, where it applies, the postal code) or required (the whole address). The paid session shows it in customer_details.address. On a Pix or Boleto session the payer form asks the whole address when required.

  One of: `auto`, `required`.
- `cancel_url` (string, optional, preview): Where the buyer goes if they leave the payment page. A card number in it is stored with each digit written X.
- `client_reference_id` (string, optional, preview): Your own reference for this session, such as an order id, up to 200 characters.
- `currency` (string, optional): Three-letter ISO code. In setup mode it is required unless payment_method_types is sent; in payment mode it must be the line items' currency.
- `custom_fields` (array of object, optional, preview): Up to three fields the page asks the buyer to fill before paying: key, label[type]=custom with label[custom], type text, numeric or dropdown (dropdown[options][] with label and value), and optional. A text or numeric field takes minimum_length, maximum_length and default_value. The paid session shows each answer as its value; the page refuses an answer that reads as a card number. A card number in a key, label, option, default_value or custom_text is stored with each digit written X.
  - `dropdown` (object, optional)
    - `default_value` (string, optional)
    - `options` (array of object, optional)
      - `label` (string, optional)
      - `value` (string, optional)
  - `key` (string, optional)
  - `label` (object, optional)
    - `custom` (string, optional)
    - `type` (enum, optional): One of: `custom`.
  - `numeric` (object, optional)
    - `default_value` (string, optional)
    - `maximum_length` (integer, optional)
    - `minimum_length` (integer, optional)
  - `optional` (boolean, optional)
  - `text` (object, optional)
    - `default_value` (string, optional)
    - `maximum_length` (integer, optional)
    - `minimum_length` (integer, optional)
  - `type` (enum, optional): One of: `dropdown`, `numeric`, `text`.
- `customer` (string, optional): An existing customer id to attach to the session. In setup mode the card is saved to this customer.
- `customer_creation` (enum, optional, preview): if_required (the default) or always. With always, paying the session makes a Customer from its email and the cardholder name, and the session, its PaymentIntent and its charge name it. Not with customer.

  One of: `always`, `if_required`.
- `customer_email` (string, optional): The buyer's email, filled in on the payment page.
- `expires_at` (integer, optional): When the session stops taking payment, a Unix timestamp. Default 24 hours after creation.
- `line_items` (array of object, optional): What the buyer pays for, at most 100 lines. Each line takes quantity and either price, the id of one of the store's active one-time Prices, or price_data: currency, unit_amount or unit_amount_decimal, an optional tax_behavior, and product, the id of one of the store's Products, or product_data (name, with optional description, images, metadata, tax_code and unit_label). Fluveo makes an inactive Price and Product of a price_data line, read as POST /v1/prices reads them, so a refusal names the field under line_items[n][price_data]; a product_data that says the same as the first Product of its name takes that Product again. Required in payment mode; refused in setup mode.
  - `adjustable_quantity` (object, optional): Lets the buyer change this line's quantity on the payment page until they pay: enabled (required; false keeps the quantity fixed and takes no bound), an optional minimum from 0 (default 0) and maximum from 1 to 999999 (default 99), the minimum below the maximum and the line's quantity within them. The line item shows the bounds the session keeps. Fluveo computes the amount on the server, the unit amount times the quantity the buyer picked, and refuses a quantity outside the bounds; the session's amount_total, its line items, its PaymentIntent and its events show the quantity and amount chosen. A minimum of 0 lets the buyer go down to 1, not remove the line.
    - `enabled` (boolean, optional)
    - `maximum` (integer, optional)
    - `minimum` (integer, optional)
  - `price` (string, optional): The id of one of the store's active one-time Prices (price_...), in the store's currency. Send it or price_data, never both.
  - `price_data` (object, required): The price of one unit.
    - `currency` (string, required): The currency, the store's own (usd or brl).
    - `product` (string, optional)
    - `product_data` (object, required): The product.
      - `description` (string, optional): The product's description, kept on the line's Product.
      - `images` (array of string, optional): Up to 8 image URLs, kept on the line's Product.
      - `metadata` (object, optional): Key-value pairs kept on the line's Product.
      - `name` (string, required): The product name shown to the buyer.
      - `tax_code` (string, optional): A tax code (txcd_...), kept on the line's Product.
      - `unit_label` (string, optional): A label for one unit, at most 12 characters, kept on the line's Product.
    - `tax_behavior` (enum, optional): inclusive, exclusive or unspecified, kept on the line's Price. Fluveo computes no tax, so the amount is the same.

      One of: `exclusive`, `inclusive`, `unspecified`.
    - `unit_amount` (integer, required): The price of one unit in the smallest unit of the currency.
    - `unit_amount_decimal` (string, optional): The price of one unit in the smallest unit of the currency, as a decimal string, instead of unit_amount. It must be a whole number of minor units (2000 or 2000.00); a fraction of one, such as 2000.5, is refused on line_items[n], never rounded.
  - `quantity` (integer, optional): How many units.
- `locale` (enum, optional, preview): The language of the hosted page: one of the Checkout locales listed here, written as listed (pt-BR, en-GB, zh-TW), or auto for the buyer's browser language. The session shows it as locale. A language the page has no text for shows English.

  One of: `auto`, `bg`, `cs`, `da`, `de`, `el`, `en`, `en-GB`, `es`, `es-419`, `et`, `fi`, `fil`, `fr`, `fr-CA`, `hr`, `hu`, `id`, `it`, `ja`, `ko`, `lt`, `lv`, `ms`, `mt`, `nb`, `nl`, `pl`, `pt`, `pt-BR`, `ro`, `ru`, `sk`, `sl`, `sv`, `th`, `tr`, `vi`, `zh`, `zh-HK`, `zh-TW`.
- `metadata` (object, optional): Up to 50 key-value pairs of your own, sent as metadata[key]=value: keys of 1 to 40 characters, values up to 500. Keys starting with fluveo_ are reserved. On an update, an empty value removes a key.
- `mode` (enum, required): payment, or setup: a setup session saves the buyer's card with a SetupIntent and charges nothing (no line_items, amount_total null, payment_status no_payment_required).

  One of: `payment`, `setup`.
- `payment_intent_data` (object, optional, preview): Settings for the PaymentIntent the session makes when the buyer pays: description, metadata, capture_method, setup_future_usage, receipt_email, shipping, statement_descriptor and statement_descriptor_suffix, each as POST /v1/payment_intents takes it.
  - `capture_method` (enum, optional): automatic or manual capture for the payment. manual holds a card payment only: beside pix or boleto it is refused, and payment_method_options[card][capture_method]=manual holds only the card payment there.

    One of: `automatic`, `automatic_async`, `manual`.
  - `description` (string, optional): Description of the PaymentIntent, up to 1000 characters.
  - `metadata` (object, optional): Key-value pairs copied to the PaymentIntent.
  - `receipt_email` (string, optional): The email the payment's receipt goes to.
  - `setup_future_usage` (enum, optional): on_session or off_session: the payment saves the buyer's card to the session's Customer (customer, or the one customer_creation=always makes), for later payments; off_session for charges without the buyer. Card only.

    One of: `on_session`, `off_session`.
  - `shipping` (object, optional): Where the order ships: name and address (line1 required), with phone, carrier and tracking_number.
    - `address` (object, optional)
      - `city` (string, optional)
      - `country` (string, optional)
      - `line1` (string, optional)
      - `line2` (string, optional)
      - `postal_code` (string, optional)
      - `state` (string, optional)
    - `carrier` (string, optional)
    - `name` (string, optional)
    - `phone` (string, optional)
    - `tracking_number` (string, optional)
  - `statement_descriptor` (string, optional): The statement descriptor of a Pix or Boleto payment, up to 22 characters. A card payment refuses it: send statement_descriptor_suffix.
  - `statement_descriptor_suffix` (string, optional): Text Fluveo adds after the store's statement descriptor on a card payment, up to 22 characters.
- `payment_method_configuration` (string, optional, preview): The id of the store's payment method configuration (the one GET /v1/payment_method_configurations lists); not together with payment_method_types.
- `payment_method_data` (object, optional, preview): allow_redisplay: always, limited or unspecified, set on the card the session saves to the Customer (a setup session, or a payment session with payment_intent_data[setup_future_usage] or payment_method_options[card][setup_future_usage]) as that PaymentMethod's allow_redisplay. Without it, a setup session's card gets always. always is refused on a payment session without payment_intent_data[setup_future_usage], even when the card option saves the card. The session object does not show it.
  - `allow_redisplay` (enum, optional): One of: `always`, `limited`, `unspecified`.
- `payment_method_options` (object, optional): Options for one payment method type of the page, keyed by the type: card, pix or boleto. Any other option answers parameter_unknown with the option as param.
  - `boleto` (object, optional): Boleto options.
    - `expires_after_days` (integer, optional): How many days the Boleto stays payable, 0 to 60. Without it, 3.
  - `card` (object, optional): Card options.
    - `capture_method` (enum, optional): manual: the card payment is only authorized, and you capture it later. Beside pix or boleto only a card payment waits for the capture; a Pix or a Boleto is captured when it is paid.

      One of: `manual`.
    - `request_three_d_secure` (enum, optional): Ask for 3D Secure: automatic (when the bank asks), any (whenever possible) or challenge.

      One of: `any`, `automatic`, `challenge`.
    - `setup_future_usage` (enum, optional): on_session or off_session: the card the buyer pays with is saved for later payments. The session's PaymentIntent gets it as its card option, which wins over payment_intent_data[setup_future_usage] for card. A setup session refuses it.

      One of: `off_session`, `on_session`.
  - `pix` (object, optional): Pix options.
    - `expires_after_seconds` (integer, optional): How long the Pix code stays payable, 60 to 86400 seconds.
- `payment_method_types` (array of enum, optional): Payment method types the page offers: card, and pix or boleto on a store that takes them. Without it, a payment session offers every method the store takes that its payment method configuration has on (pix and boleto only when the PaymentIntent is not captured by hand as a whole and does not set setup_future_usage), less any excluded_payment_method_types; a setup session offers card.

  One of: `card`, `pix`, `boleto`.
- `phone_number_collection` (object, optional): enabled=true makes the page ask a phone number, shown in E.164 as the paid session's customer_details.phone, on card and on Pix and Boleto sessions alike.
  - `enabled` (boolean, optional)
- `redirect_on_completion` (enum, optional, preview): Only with ui_mode=embedded_page. always (the default): the paid page sends the buyer to return_url. if_required and never: the buyer stays on the embedded page, since no payment method here needs a redirect to finish.

  One of: `always`, `if_required`, `never`.
- `return_url` (string, optional, preview): Only with ui_mode=embedded_page: where the buyer's browser goes once the session is paid, with {CHECKOUT_SESSION_ID} replaced by the session id. Required unless redirect_on_completion=never. A URL with no host is refused. A card number in it is stored with each digit written X.
- `setup_intent_data` (object, optional, preview): Setup mode only: the SetupIntent the session makes takes this description and metadata.
  - `description` (string, optional): Description of the SetupIntent, up to 1000 characters.
  - `metadata` (object, optional): Key-value pairs copied to the SetupIntent.
- `shipping_address_collection` (object, optional): allowed_countries[]: the two-letter countries the page takes a shipping address in. The page asks a name and address; the PaymentIntent, its charge and the paid session's collected_information.shipping_details carry them, on card and on Pix and Boleto sessions alike.
  - `allowed_countries` (array of string, optional)
- `success_url` (string, optional): Where the buyer goes after paying. An http or https URL. A card number in it is stored with each digit written X.
- `ui_mode` (enum, optional, preview): hosted_page (or hosted, the default): the payment page at the session's url. embedded_page: the same page shown inside your own page; the session has no url, and its client_secret starts with the session id, so you mount the page at <checkout base>/c/<session id> in an iframe. Its client_secret is null once the session is no longer open.

  One of: `hosted`, `hosted_page`, `embedded_page`.

Use only the documented body parameters. Send a new `Idempotency-Key` with each new request, and the same key again only to retry that request.

Returns a [`checkout.session`](https://docs.fluveo.com/api/checkout_sessions.md#object-checkout_session) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/checkout/sessions \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-urlencode "line_items[0][price_data][currency]=usd" \
  --data-urlencode "line_items[0][price_data][product_data][name]=T-shirt" \
  --data-urlencode "line_items[0][price_data][unit_amount]=2000" \
  --data-urlencode "line_items[0][quantity]=1" \
  --data-urlencode "mode=payment" \
  --data-urlencode "success_url=https://example.com/thanks"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/checkout/sessions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_test_...",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: new URLSearchParams([["line_items[0][price_data][currency]","usd"],["line_items[0][price_data][product_data][name]","T-shirt"],["line_items[0][price_data][unit_amount]","2000"],["line_items[0][quantity]","1"],["mode","payment"],["success_url","https://example.com/thanks"]]),
});
console.log(await response.json());
```

Python:

```python
import uuid

import requests

response = requests.post(
    "https://api.fluveo.com/v1/checkout/sessions",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
    data=[("line_items[0][price_data][currency]", "usd"), ("line_items[0][price_data][product_data][name]", "T-shirt"), ("line_items[0][price_data][unit_amount]", "2000"), ("line_items[0][quantity]", "1"), ("mode", "payment"), ("success_url", "https://example.com/thanks")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/checkout/sessions");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
        "Idempotency-Key: " . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => "line_items%5B0%5D%5Bprice_data%5D%5Bcurrency%5D=usd&line_items%5B0%5D%5Bprice_data%5D%5Bproduct_data%5D%5Bname%5D=T-shirt&line_items%5B0%5D%5Bprice_data%5D%5Bunit_amount%5D=2000&line_items%5B0%5D%5Bquantity%5D=1&mode=payment&success_url=https%3A%2F%2Fexample.com%2Fthanks",
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "amount_subtotal": 2000,
  "amount_total": 2000,
  "created": 1767225600,
  "currency": "usd",
  "expires_at": 1767312000,
  "id": "cs_test_123",
  "livemode": false,
  "metadata": {},
  "mode": "payment",
  "object": "checkout.session",
  "payment_intent": "pi_123",
  "payment_method_types": [
    "card"
  ],
  "payment_status": "unpaid",
  "status": "open",
  "success_url": "https://example.com/thanks",
  "ui_mode": "hosted_page",
  "url": "https://checkout.example.com/c/cs_test_123"
}
```

## Lists the store's Checkout Sessions

`GET /v1/checkout/sessions`

Permission: [`rak_checkout_session_read`](https://docs.fluveo.com/permissions.md#checkout_session).

**Query parameters**

- `created` (object, optional, preview): Filter on the creation time, a Unix timestamp: created=<t> for an exact match, or created[gt], created[gte], created[lt], created[lte].
- `customer` (string, optional): Only the sessions of this customer.
- `customer_details` (object, optional): customer_details[email]: only the sessions whose buyer gave this email. An address that is not a valid email is refused with email_invalid.
  - `email` (string, optional)
- `ending_before` (string, optional): Cursor: the id of the first object of the current page, to get the previous page. Do not send it with starting_after.
- `limit` (integer, optional): How many objects to return, from 1 to 100. Default 10.
- `payment_intent` (string, optional, preview): Only the session that created this PaymentIntent.
- `payment_link` (string, optional): Only the sessions opened from this payment link's page. A link that is not the store's is refused with resource_missing.
- `starting_after` (string, optional): Cursor: the id of the last object of the previous page, to get the next page. Do not send it with ending_before.
- `status` (enum, optional): Only sessions in this status.

  One of: `open`, `complete`, `expired`.

**Headers**

- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

Returns a list of [`checkout.session`](https://docs.fluveo.com/api/checkout_sessions.md#object-checkout_session) objects.

**Request**

cURL:

```bash
curl -G https://api.fluveo.com/v1/checkout/sessions \
  -H "Authorization: Bearer sk_test_..." \
  --data-urlencode "status=complete"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/checkout/sessions" + "?" + new URLSearchParams([["status","complete"]]), {
  method: "GET",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/checkout/sessions",
    headers={"Authorization": "Bearer sk_test_..."},
    params=[("status", "complete")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/checkout/sessions?status=complete");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
    ],
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "data": [
    {
      "amount_subtotal": 2000,
      "amount_total": 2000,
      "created": 1767225600,
      "currency": "usd",
      "expires_at": 1767312000,
      "id": "cs_test_123",
      "livemode": false,
      "metadata": {},
      "mode": "payment",
      "object": "checkout.session",
      "payment_intent": "pi_123",
      "payment_method_types": [
        "card"
      ],
      "payment_status": "unpaid",
      "status": "open",
      "success_url": "https://example.com/thanks",
      "ui_mode": "hosted_page",
      "url": "https://checkout.example.com/c/cs_test_123"
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/checkout/sessions"
}
```

## Updates a Checkout Session's metadata, in any state; no other field can change

`POST /v1/checkout/sessions/{session}`

Permission: [`rak_checkout_session_write`](https://docs.fluveo.com/permissions.md#checkout_session).

**Path parameters**

- `session` (string, required): The Checkout Session's id (cs_test_... in test mode).

**Headers**

- `Idempotency-Key` (string, optional): Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

**Body parameters**

- `metadata` (object, optional): Up to 50 key-value pairs of your own, sent as metadata[key]=value: keys of 1 to 40 characters, values up to 500. Keys starting with fluveo_ are reserved. On an update, an empty value removes a key.

Use only the documented body parameters. Send a new `Idempotency-Key` with each new request, and the same key again only to retry that request.

Returns a [`checkout.session`](https://docs.fluveo.com/api/checkout_sessions.md#object-checkout_session) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/checkout/sessions/cs_123 \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-urlencode "metadata[order_id]=1042"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/checkout/sessions/cs_123", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_test_...",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: new URLSearchParams([["metadata[order_id]","1042"]]),
});
console.log(await response.json());
```

Python:

```python
import uuid

import requests

response = requests.post(
    "https://api.fluveo.com/v1/checkout/sessions/cs_123",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
    data=[("metadata[order_id]", "1042")],
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/checkout/sessions/cs_123");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
        "Idempotency-Key: " . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => "metadata%5Border_id%5D=1042",
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "amount_subtotal": 2000,
  "amount_total": 2000,
  "created": 1767225600,
  "currency": "usd",
  "expires_at": 1767312000,
  "id": "cs_test_123",
  "livemode": false,
  "metadata": {},
  "mode": "payment",
  "object": "checkout.session",
  "payment_intent": "pi_123",
  "payment_method_types": [
    "card"
  ],
  "payment_status": "unpaid",
  "status": "open",
  "success_url": "https://example.com/thanks",
  "ui_mode": "hosted_page",
  "url": "https://checkout.example.com/c/cs_test_123"
}
```

## Retrieves a Checkout Session

`GET /v1/checkout/sessions/{session}`

Permission: [`rak_checkout_session_read`](https://docs.fluveo.com/permissions.md#checkout_session).

**Path parameters**

- `session` (string, required): The Checkout Session's id (cs_test_... in test mode).

**Headers**

- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

Returns a [`checkout.session`](https://docs.fluveo.com/api/checkout_sessions.md#object-checkout_session) object.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/checkout/sessions/cs_123 \
  -H "Authorization: Bearer sk_test_..."
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/checkout/sessions/cs_123", {
  method: "GET",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/checkout/sessions/cs_123",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/checkout/sessions/cs_123");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
    ],
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "amount_subtotal": 2000,
  "amount_total": 2000,
  "created": 1767225600,
  "currency": "usd",
  "expires_at": 1767312000,
  "id": "cs_test_123",
  "livemode": false,
  "metadata": {},
  "mode": "payment",
  "object": "checkout.session",
  "payment_intent": "pi_123",
  "payment_method_types": [
    "card"
  ],
  "payment_status": "unpaid",
  "status": "open",
  "success_url": "https://example.com/thanks",
  "ui_mode": "hosted_page",
  "url": "https://checkout.example.com/c/cs_test_123"
}
```

## Expires an open Checkout Session, so the buyer can no longer pay through it

`POST /v1/checkout/sessions/{session}/expire`

Permission: [`rak_checkout_session_write`](https://docs.fluveo.com/permissions.md#checkout_session).

**Path parameters**

- `session` (string, required): The Checkout Session's id (cs_test_... in test mode).

**Headers**

- `Idempotency-Key` (string, optional): Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

Use only the documented body parameters. Send a new `Idempotency-Key` with each new request, and the same key again only to retry that request.

Returns a [`checkout.session`](https://docs.fluveo.com/api/checkout_sessions.md#object-checkout_session) object.

**Request**

cURL:

```bash
curl -X POST https://api.fluveo.com/v1/checkout/sessions/cs_123/expire \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: $(uuidgen)"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/checkout/sessions/cs_123/expire", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_test_...",
    "Idempotency-Key": crypto.randomUUID(),
  },
});
console.log(await response.json());
```

Python:

```python
import uuid

import requests

response = requests.post(
    "https://api.fluveo.com/v1/checkout/sessions/cs_123/expire",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/checkout/sessions/cs_123/expire");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
        "Idempotency-Key: " . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => "",
]);
echo curl_exec($ch);
```

*Response (abridged example)*

```json
{
  "amount_subtotal": 2000,
  "amount_total": 2000,
  "created": 1767225600,
  "currency": "usd",
  "expires_at": 1767312000,
  "id": "cs_test_123",
  "livemode": false,
  "metadata": {},
  "mode": "payment",
  "object": "checkout.session",
  "payment_intent": "pi_123",
  "payment_method_types": [
    "card"
  ],
  "payment_status": "unpaid",
  "status": "open",
  "success_url": "https://example.com/thanks",
  "ui_mode": "hosted_page",
  "url": "https://checkout.example.com/c/cs_test_123"
}
```

## Lists a Checkout Session's line items

`GET /v1/checkout/sessions/{session}/line_items`

Permission: [`rak_checkout_session_read`](https://docs.fluveo.com/permissions.md#checkout_session).

**Path parameters**

- `session` (string, required): The Checkout Session's id (cs_test_... in test mode).

**Query parameters**

- `ending_before` (string, optional, preview): Cursor: the id of the first object of the current page, to get the previous page. Do not send it with starting_after.
- `limit` (integer, optional): How many objects to return, from 1 to 100. Default 10.
- `starting_after` (string, optional): Cursor: the id of the last object of the previous page, to get the next page. Do not send it with ending_before.

**Headers**

- `Fluveo-Version` (enum, optional): Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.

  One of: `2026-05-27.dahlia`.

Returns a list of [`item`](https://docs.fluveo.com/api/checkout_sessions.md#object-item) objects.

**Request**

cURL:

```bash
curl https://api.fluveo.com/v1/checkout/sessions/cs_123/line_items \
  -H "Authorization: Bearer sk_test_..."
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/checkout/sessions/cs_123/line_items", {
  method: "GET",
  headers: {
    "Authorization": "Bearer sk_test_...",
  },
});
console.log(await response.json());
```

Python:

```python
import requests

response = requests.get(
    "https://api.fluveo.com/v1/checkout/sessions/cs_123/line_items",
    headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/checkout/sessions/cs_123/line_items");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer sk_test_...",
    ],
]);
echo curl_exec($ch);
```

## The checkout.session object

Ids start with `cs_`.

**Attributes**

- `adaptive_pricing` (object, nullable)
- `after_expiration` (object, nullable)
- `allowed_payment_method_types` (array, nullable)
- `amount_subtotal` (integer, nullable)
- `amount_total` (integer, nullable)
- `automatic_tax` (object)
- `billing_address_collection` (enum, nullable): One of: `auto`, `required`.
- `branding_settings` (object)
- `cancel_url` (string, nullable)
- `client_reference_id` (string, nullable)
- `client_secret` (string, nullable)
- `collected_information` (object, nullable)
- `consent` (object, nullable)
- `consent_collection` (object, nullable)
- `created` (integer)
- `currency` (string, nullable)
- `currency_conversion` (object, nullable)
- `custom_fields` (array)
- `custom_text` (object)
- `customer` (string, nullable, expandable): An id by default; send `expand[]=customer` to get the full customer or deleted_customer object.
- `customer_account` (string, nullable)
- `customer_creation` (enum, nullable): One of: `always`, `if_required`.
- `customer_details` (object, nullable)
- `customer_email` (string, nullable)
- `excluded_payment_method_types` (array)
- `expires_at` (integer)
- `id` (string)
- `integration_identifier` (string, nullable)
- `line_items` (object)
- `livemode` (boolean)
- `locale` (enum, nullable): One of: `auto`, `bg`, `cs`, `da`, `de`, `el`, `en`, `en-GB`, `es`, `es-419`, `et`, `fi`, `fil`, `fr`, `fr-CA`, `hr`, `hu`, `id`, `it`, `ja`, `ko`, `lt`, `lv`, `ms`, `mt`, `nb`, `nl`, `pl`, `pt`, `pt-BR`, `ro`, `ru`, `sk`, `sl`, `sv`, `th`, `tr`, `vi`, `zh`, `zh-HK`, `zh-TW`.
- `managed_payments` (object, nullable)
- `marketing_attributions` (enum, nullable): One of: `null`.
- `metadata` (object, nullable)
- `mode` (enum): One of: `payment`, `setup`.
- `name_collection` (object)
- `object` (enum): One of: `checkout.session`.
- `origin_context` (enum, nullable): One of: `mobile_app`, `web`.
- `payment_intent` (string, nullable, expandable): An id by default; send `expand[]=payment_intent` to get the full payment_intent object.
- `payment_link` (string, nullable, expandable): An id by default; send `expand[]=payment_link` to get the full payment_link object.
- `payment_method_collection` (enum, nullable): One of: `always`, `if_required`.
- `payment_method_configuration_details` (object, nullable)
- `payment_method_options` (object, nullable)
- `payment_method_types` (array)
- `payment_status` (enum): One of: `no_payment_required`, `paid`, `unpaid`.
- `permissions` (object, nullable)
- `phone_number_collection` (object)
- `recovered_from` (string, nullable)
- `redirect_on_completion` (enum): One of: `always`, `if_required`, `never`.
- `return_url` (string)
- `saved_payment_method_options` (object, nullable)
- `setup_intent` (string, nullable, expandable): An id by default; send `expand[]=setup_intent` to get the full setup_intent object.
- `shipping_address_collection` (object, nullable)
- `shipping_cost` (object, nullable)
- `shipping_options` (array)
- `status` (enum, nullable): One of: `complete`, `expired`, `open`.
- `submit_type` (enum, nullable): One of: `auto`, `book`, `donate`, `pay`, `subscribe`.
- `success_url` (string, nullable)
- `tax_id_collection` (object)
- `total_details` (object, nullable)
- `ui_mode` (enum, nullable): One of: `elements`, `embedded_page`, `form`, `hosted_page`.
- `url` (string, nullable)
- `wallet_options` (object, nullable)

## The item object

**Attributes**

- `adjustable_quantity` (object, nullable)
- `amount_subtotal` (integer)
- `amount_tax` (integer)
- `amount_total` (integer)
- `currency` (string)
- `description` (string, nullable)
- `id` (string)
- `metadata` (object, nullable)
- `object` (enum): One of: `item`.
- `price` (object, nullable)
- `quantity` (integer, nullable)
- `taxes` (array)
