> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ionicfi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Create a checkout session and complete a hosted payment.

This guide gets one hosted checkout payment moving end to end. It uses inline line items so you can integrate first and add catalog objects later.

## Prerequisites

* A test-mode secret key (`sk_v1_test_...`), created in the Dashboard.
* A backend route that can call Ionic without exposing the secret key to the browser.
* A success URL and cancel URL in your application.

<Warning>
  Never create checkout sessions directly from browser code with a secret key. Your frontend should call your server, and your server should call Ionic.
</Warning>

If your backend runs Node, install the server SDK. It carries typed request
and response shapes for every endpoint, generates an idempotency key for each
mutating call, and retries transient failures with backoff. Every step below
also shows the raw HTTP call for other stacks.

```bash theme={null}
npm install @ionicfi/sdk
```

## 1. Create a session

Create the session from your server.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { Ionic } from "@ionicfi/sdk";

  const ionic = new Ionic({ token: process.env.IONIC_SECRET_KEY });

  const session = await ionic.checkout.sessions.create({
    "Idempotency-Key": "order_1001-checkout",
    mode: "payment",
    line_items: [
      {
        name: "Pro onboarding",
        amount: 15000,
        currency: "usd",
        quantity: 1,
      },
    ],
    customer_email: "buyer@example.com",
    client_reference_id: "order_1001",
    success_url: "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
    cancel_url: "https://example.com/cart",
    metadata: {
      order_id: "order_1001",
    },
  });
  ```

  ```bash curl theme={null}
  curl https://api.ionicfi.com/v1/checkout/sessions \
    -H "Authorization: Bearer $IONIC_SECRET_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: order_1001-checkout" \
    -d '{
      "mode": "payment",
      "line_items": [
        {
          "name": "Pro onboarding",
          "amount": 15000,
          "currency": "usd",
          "quantity": 1
        }
      ],
      "customer_email": "buyer@example.com",
      "client_reference_id": "order_1001",
      "success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
      "cancel_url": "https://example.com/cart",
      "metadata": {
        "order_id": "order_1001"
      }
    }'
  ```
</CodeGroup>

`amount` is in cents: `15000` is \$150.00. Repeating the request with the same
`Idempotency-Key` and body returns the original session instead of creating a
duplicate; the SDK generates a key per call when you omit the field. The
response includes a session `id`, status fields, line item totals, and a hosted
checkout `url` when the session can be opened by the buyer.

```json theme={null}
{
  "id": "cs_000000000000000000001001",
  "object": "checkout_session",
  "mode": "payment",
  "status": "open",
  "payment_status": "unpaid",
  "amount_total": 15000,
  "currency": "USD",
  "url": "https://checkout.ionicfi.com/c/hcs_..."
}
```

## 2. Redirect the buyer

On your frontend, redirect to the returned `url`.

```ts theme={null}
const response = await fetch("/api/checkout", {
  method: "POST"
});

const session = await response.json();
window.location.assign(session.url);
```

## 3. Verify the result

After the buyer returns to your success page, use the `session_id` from the URL to look up the session from your server.

<CodeGroup>
  ```ts TypeScript theme={null}
  const session = await ionic.checkout.sessions.retrieve({
    id: "cs_000000000000000000001001",
  });

  const paid = session.status === "complete" && session.payment_status === "paid";
  ```

  ```bash curl theme={null}
  curl https://api.ionicfi.com/v1/checkout/sessions/cs_000000000000000000001001 \
    -H "Authorization: Bearer $IONIC_SECRET_KEY"
  ```
</CodeGroup>

Treat the redirect as a user experience step, not confirmation of payment. Fulfill
from a verified `checkout.session.completed` webhook only when the session is
both `complete` and `paid`. The [webhook quickstart](/webhooks/quickstart)
sets one up in about five minutes.

## What to build next

* Fulfill orders from the `checkout.session.completed` webhook; the [Hosted Checkout guide](/guides/checkout#3-fulfill-from-the-webhook) shows the handler.
* Keep buyers on your own domain with [embedded checkout](/guides/embedded-checkout), or compare all three surfaces in [Ways to accept payments](/guides/accept-payments).
* Add products and prices when inline amounts become hard to manage.
* Add optional items for add-ons and upgrades at checkout.
* Add payment links when the same payment surface should be reused or shared.
