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

# Create Checkout Session

> Create a checkout session and get a hosted checkout URL

# Create Checkout Session

Create a checkout session for a customer. Returns a checkout URL where the customer completes payment on Gale's hosted page. Gale handles card collection, eligibility detection, and LMN flow automatically.

<Note>All monetary amounts are integers in cents (e.g., 4995 = \$49.95).</Note>

## Endpoint

```
POST /api/v2/checkout
```

## Authentication

```bash theme={null}
Authorization: Bearer glm_test_YOUR_API_KEY
```

## Request Body

```json theme={null}
{
  "reference_id": "your-order-123",
  "customer": {
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "phone": "+1-555-123-4567"
  },
  "line_items": [
    {
      "product_id": "BP-MONITOR-001",
      "name": "Digital Blood Pressure Monitor",
      "image_url": "https://yourcdn.com/bp-monitor.jpg",
      "price": 4995,
      "quantity": 1,
      "currency": "USD"
    },
    {
      "product_id": "VITAMINS-030",
      "name": "Daily Multivitamins (30-day)",
      "image_url": "https://yourcdn.com/vitamins.jpg",
      "price": 1999,
      "quantity": 2,
      "currency": "USD"
    }
  ],
  "shipping_info": {
    "address_line_1": "123 Main St",
    "address_line_2": "Apt 4B",
    "city": "New York",
    "state": "NY",
    "postal_code": "10001",
    "country": "US"
  },
  "billing_info": {
    "address_line_1": "123 Main St",
    "city": "New York",
    "state": "NY",
    "postal_code": "10001",
    "country": "US"
  },
  "shipping": 500,
  "tax": 410,
  "discount": 0,
  "success_url": "https://yoursite.com/order/success",
  "failure_url": "https://yoursite.com/order/failed",
  "metadata": {
    "platform": "CUSTOM",
    "webhook_url": "https://your-server.com/webhooks/gale"
  }
}
```

## Parameters

| Parameter                      | Type    | Required | Description                                       |
| :----------------------------- | :------ | :------- | :------------------------------------------------ |
| `reference_id`                 | string  | Yes      | Your order or cart ID for correlation             |
| `customer`                     | object  | Yes      | Customer information                              |
| `customer.email`               | string  | Yes      | Customer email                                    |
| `customer.first_name`          | string  | Yes      | Customer first name                               |
| `customer.last_name`           | string  | Yes      | Customer last name                                |
| `customer.phone`               | string  | No       | Customer phone number                             |
| `line_items`                   | array   | Yes      | Products being purchased                          |
| `line_items[].product_id`      | string  | Yes      | Your product ID (must match synced product)       |
| `line_items[].name`            | string  | Yes      | Product name                                      |
| `line_items[].image_url`       | string  | No       | Product image URL                                 |
| `line_items[].price`           | integer | Yes      | Unit price in cents                               |
| `line_items[].quantity`        | integer | Yes      | Quantity                                          |
| `line_items[].currency`        | string  | Yes      | Currency code (e.g., `"USD"`)                     |
| `shipping_info`                | object  | Yes      | Shipping address                                  |
| `shipping_info.address_line_1` | string  | Yes      | Address line 1                                    |
| `shipping_info.address_line_2` | string  | No       | Address line 2                                    |
| `shipping_info.city`           | string  | Yes      | City                                              |
| `shipping_info.state`          | string  | Yes      | State                                             |
| `shipping_info.postal_code`    | string  | Yes      | ZIP/Postal code                                   |
| `shipping_info.country`        | string  | Yes      | Country code (e.g., `"US"`)                       |
| `billing_info`                 | object  | No       | Billing address (defaults to shipping if omitted) |
| `billing_info.address_line_1`  | string  | Yes      | Address line 1                                    |
| `billing_info.address_line_2`  | string  | No       | Address line 2                                    |
| `billing_info.city`            | string  | Yes      | City                                              |
| `billing_info.state`           | string  | Yes      | State                                             |
| `billing_info.postal_code`     | string  | Yes      | ZIP/Postal code                                   |
| `billing_info.country`         | string  | Yes      | Country code (e.g., `"US"`)                       |
| `shipping`                     | integer | No       | Shipping amount in cents                          |
| `tax`                          | integer | No       | Tax amount in cents                               |
| `discount`                     | integer | No       | Discount amount in cents                          |
| `success_url`                  | string  | Yes      | Redirect URL after successful payment             |
| `failure_url`                  | string  | Yes      | Redirect URL if payment fails or customer cancels |
| `metadata`                     | object  | No       | Custom key-value pairs                            |
| `metadata.webhook_url`         | string  | No       | URL to receive payment webhooks (recommended)     |

<Warning>
  `product_id` is **your** product identifier — the one you supplied when syncing products (`merchant_product_id`), not the numeric id displayed in the dashboard. Line items that don't match a synced product are accepted as **pass-through items and treated as non-HSA/FSA-eligible**, so an unmatched id silently produces a regular (non-eligible) checkout. Your own product ids are identical across test and live, so the same integration carries to go-live unchanged.
</Warning>

## Response

```json theme={null}
{
  "success": true,
  "message": "Checkout created",
  "data": {
    "checkout_id": "cs_a1b2c3...",
    "checkout_url": "https://checkout.withgale.com/checkout/cs_a1b2c3...?token=...",
    "reference_id": "order-789",
    "status": "open",
    "type": "eligible",
    "customer": { "email": "jane@example.com", "first_name": "Jane", "last_name": "Doe" },
    "line_items": [ ... ],
    "amounts": {
      "subtotal": 4995,
      "hsa_amount": 4995,
      "regular_amount": 0,
      "shipping": 995,
      "tax": 410,
      "discount": 0,
      "total": 6400
    },
    "success_url": "https://yourapp.com/checkout/success",
    "failure_url": "https://yourapp.com/checkout/cancel",
    "expires_at": "2026-02-26T14:30:00Z",
    "created_at": "2026-02-26T13:30:00Z"
  },
  "metadata": { "request_id": "..." }
}
```

Fields are returned under `data`.

| Field               | Type      | Description                                                                                              |
| :------------------ | :-------- | :------------------------------------------------------------------------------------------------------- |
| `data.checkout_id`  | string    | Unique checkout session identifier (`cs_...`)                                                            |
| `data.checkout_url` | string    | Hosted checkout page URL (includes access token) — redirect customer here                                |
| `data.status`       | string    | Session status (`open`)                                                                                  |
| `data.type`         | string    | Cart type (`eligible`, `split`, `regular`)                                                               |
| `data.amounts`      | object    | All amounts in cents: `subtotal`, `hsa_amount`, `regular_amount`, `shipping`, `tax`, `discount`, `total` |
| `data.expires_at`   | timestamp | When session expires                                                                                     |

## Example

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/checkout \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "order-789",
    "customer": {
      "email": "jane@example.com",
      "first_name": "Jane",
      "last_name": "Doe"
    },
    "line_items": [
      {
        "product_id": "BP-MONITOR-001",
        "name": "Digital Blood Pressure Monitor",
        "price": 4995,
        "quantity": 1,
        "currency": "USD"
      }
    ],
    "shipping_info": {
      "address_line_1": "123 Main St",
      "city": "New York",
      "state": "NY",
      "postal_code": "10001",
      "country": "US"
    },
    "shipping": 500,
    "tax": 410,
    "success_url": "https://yoursite.com/order/success",
    "failure_url": "https://yoursite.com/order/failed"
  }'
```

### Subscription Checkout <sup>Beta</sup>

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/checkout \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "membership-456",
    "customer": {
      "email": "member@example.com",
      "first_name": "Jane",
      "last_name": "Doe"
    },
    "line_items": [
      {
        "product_id": "MEMBERSHIP-PREMIUM",
        "name": "Premium Membership",
        "price": 9900,
        "quantity": 1,
        "currency": "USD"
      }
    ],
    "payment_type": "subscription",
    "subscription": {
      "interval": "monthly",
      "trial_period_days": 14
    },
    "success_url": "https://yoursite.com/welcome",
    "failure_url": "https://yoursite.com/pricing"
  }'
```

## Checkout Types

Gale automatically determines the checkout type based on product eligibility:

| Type       | Description                            |
| :--------- | :------------------------------------- |
| `eligible` | All items are HSA/FSA eligible         |
| `split`    | Mix of eligible and non-eligible items |
| `regular`  | No items are eligible                  |

You don't need to specify the type — Gale handles this automatically based on the products in the checkout.

## Checkout Status

| Status    | Description                                 |
| :-------- | :------------------------------------------ |
| `open`    | Checkout session created, awaiting customer |
| `paid`    | Customer completed payment, order created   |
| `expired` | Session expired (24 hours)                  |

## Webhooks

When payment completes, you receive an `order.created` webhook:

```json theme={null}
{
  "type": "order.created",
  "data": {
    "id": "ord_abc123",
    "checkout_id": "01HXYZ...",
    "reference_id": "your-order-123",
    "status": "completed",
    "customer": {
      "email": "jane@example.com"
    }
  }
}
```

See [Webhooks Reference](/developer-manual/webhooks) for setup and all event types.

## Errors

| Status Code | Error Code         | Description                   |
| :---------- | :----------------- | :---------------------------- |
| 400         | `bad_request`      | Missing or invalid parameters |
| 401         | `unauthorized`     | Invalid API key               |
| 422         | `validation_error` | Field validation failed       |

See [Error Reference](/developer-manual/errors) for details.

## Related

* [Get Checkout Session](/api-reference/endpoint/get-checkout)
* [Checkout Session Object](/api-reference/objects/checkout-session)
* [Checkout Integration Guide](/integration/checkout)
* [Order Object](/api-reference/objects/order)
* [Webhooks](/developer-manual/webhooks)
