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

# Checkout

> **Status: `contracted_test`.** Checkout Sessions are in the generated API
> Reference and the hosted page is available for test-mode flows. Production
> mode is not promoted.

Fluveo Checkout is **hosted**: your server creates a session, you redirect the
customer to a Fluveo-hosted page, they pay there, and Fluveo redirects them back.
The card fields, PCI scope, and 3-D Secure all live on Fluveo's page — you never
handle a PAN.

> **Coming from Stripe? There is no Fluveo.js and no Elements.** Fluveo does **not**
> ship a client-side card SDK or a mountable `<PaymentElement/>`. Card entry happens
> on the Fluveo-hosted page (powered by [FluveoLoader](/checkout/hosted-payment-page)),
> and you integrate by **redirect**, not by embedding a component. If you were using
> Stripe Elements, this is the part of your integration that changes.

## Hosted Checkout vs. direct Payment Intents

There are two ways to take a payment with Fluveo. Pick one per flow:

|                 | Hosted Checkout                   | Direct [Payment Intents](/resources/payments)   |
| --------------- | --------------------------------- | ----------------------------------------------- |
| Front-end work  | None — Fluveo hosts the page      | You build and collect card data (via the vault) |
| PCI scope       | Lowest (SAQ A)                    | Higher                                          |
| Control over UI | Fluveo-hosted page                | Full                                            |
| Best for        | Getting live fast, low PCI burden | Custom checkout, in-app flows                   |

The rest of this page is the hosted-Checkout golden path. For the direct API, start
with the [Quickstart](/quickstart) and [Payments](/resources/payments).

## Take your first payment with Checkout

Four steps take you from nothing to a completed hosted payment.

**1. Create a Checkout Session** on your server with the line items and where to send
the customer afterward. The response includes a hosted `url`.

**`curl`**

```bash title="curl"
KEY=$FLUVEO_API_KEY
curl -s -X POST https://api.devfluveo.com/v1/checkout/sessions \
  -u "$KEY:" -H "Content-Type: application/json" \
  -d '{
    "mode": "payment",
    "success_url": "https://example.com/thanks?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url":  "https://example.com/cart",
    "line_items":  [{
      "price_data": { "currency": "usd", "unit_amount": 4242, "product_data": { "name": "Demo Plan" } },
      "quantity":   1
    }]
  }'
# → { "id": "cs_…", "url": "https://pay.fluveo.dev/c/cs_…", "status": "open", "payment_status": "unpaid", … }
```

**2. Redirect the customer to the session `url`.** They complete payment on the
Fluveo-hosted page — see [the hosted page](/checkout/hosted-payment-page) for what
they see and how card data is collected.

**3. Handle the return at your `success_url`.** When the customer comes back, **do not
trust the redirect alone** — re-retrieve the session server-side and check its status
before fulfilling:

**`curl`**

```bash title="curl"
curl -s https://api.devfluveo.com/v1/checkout/sessions/cs_… -u "$FLUVEO_API_KEY:"
# fulfill only when "payment_status": "paid"
```

**4. Reconcile from your server.** Merchant-public Events and WebhookEndpoints
are unavailable. If the customer never returns, poll the Checkout Session from
your server until it reaches a terminal state. Keep fulfillment idempotent on
the PaymentIntent id. A webhook you verified yourself (HMAC-SHA256 over
`<t>.<raw body>`, see [Verify a webhook signature](/cookbooks/verify-a-webhook))
proves the sender, not that the payment finished: re-retrieve the session first.

That's the whole loop. Details per step:

* [Checkout Sessions](/checkout/checkout-sessions) — the create + retrieve API.
* [Payment Links](/checkout/payment-links) — reusable hosted links you can share.
* [The hosted page](/checkout/hosted-payment-page) — FluveoLoader, card vault, redirect.
* [Webhooks](/webhooks) — current quarantine and promotion boundary.

## Hidden from the public API

Each item below is hidden because it does not follow the Stripe parity ADR (ADR 0004 as amended). The [hidden public `/v1` registry](https://github.com/fluveohq/fluveo/blob/main/tests/api-contract/stripe/hidden-public-v1.json) lists every
hidden item. Public `/v1` answers a hidden operation as an unknown URL, refuses a hidden request
parameter or value with Stripe's `invalid_request_error`, and omits a hidden response key.

* the operation `GET /v1/checkout/branding` (HIDE0-062)
* the operation `PUT /v1/checkout/branding` (HIDE0-073)