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

# Create a Checkout Session

> Generate a checkout session to accept payments from your customers

Before a customer can pay, you create a "session" that holds all the payment details.

## Quick Start (30 seconds)

Create a session and redirect your customer:

```bash theme={null}
curl -X POST https://checkout.ozura.com/api/sessions/create \
  -H "X-API-KEY: your_vault_key" \
  -H "X-OZURA-API-KEY: your_merchant_key" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "your_merchant_id",
    "merchantName": "My Store",
    "amount": "25.00",
    "currency": "USD",
    "successUrl": "https://yoursite.com/success",
    "cancelUrl": "https://yoursite.com/cancel",
    "errorUrl": "https://yoursite.com/error"
  }'
```

Then redirect your customer to the returned `checkoutUrl`. Done!

## The Basics

| What             | Value                                                 |
| :--------------- | :---------------------------------------------------- |
| **API URL**      | `POST https://checkout.ozura.com/api/sessions/create` |
| **Content-Type** | `application/json`                                    |
| **Called From**  | Your server (never from browser JavaScript)           |

<Note>
  **What's "your server"?** Backend code like Node.js, PHP, Python, Ruby, etc.
  If you're using a website builder (Shopify, Wix), check if they offer
  serverless functions. If you only have static HTML, use [Payment
  Links](/guides/payments/checkout/payment-links) instead.
</Note>

## Required Headers

Every request needs these two headers:

```
X-API-KEY: your_vault_api_key
X-OZURA-API-KEY: your_merchant_api_key
```

<Note>
  **What's a header?** Headers are extra information sent with your request (like an ID badge). They're set separately from the request body — see the code examples below.

  **Vault API Key:** Developers → Vault Key.

  **Merchant API Key:** Developers → API Keys.
</Note>

## Required Fields

Your request body **must** include these fields:

```json theme={null}
{
  "merchantId": "your_merchant_id",
  "merchantName": "Your Store Name",
  "amount": "25.00",
  "successUrl": "https://yoursite.com/success",
  "cancelUrl": "https://yoursite.com/cancel",
  "errorUrl": "https://yoursite.com/error"
}
```

| Field          | What to Put                             | Example                                          |
| :------------- | :-------------------------------------- | :----------------------------------------------- |
| `merchantId`   | Your Merchant ID from Dashboard         | `"merchant_abc123"`                              |
| `merchantName` | Your business name (customer sees this) | `"Bob's Coffee Shop"`                            |
| `amount`       | How much to charge (string or number)\* | `"25.00"` or `25.00`                             |
| `successUrl`   | Confirmation page after payment         | `"https://yoursite.com/thank-you"`               |
| `cancelUrl`    | Return destination (cart page)          | `"https://yoursite.com/cart"`                    |
| `errorUrl`     | System error handler                    | `"https://yoursite.com/cart?checkoutError=true"` |

<Warning>
  **Why full URLs?** Use absolute URLs like `https://yoursite.com/success`, not
  just `/success`. The redirect happens from Ozura's servers, so we need the
  full URL to find your website.
</Warning>

\*`amount` is required for standard payments. Accepts string (e.g., `"25.00"`) or number (e.g., `25.00`). Not needed when using `items` or `checkoutMode: "donation"`.

## Understanding the Three URLs

These three URLs control where customers end up after checkout.

### Quick Summary

| URL          | Purpose                   | When Used                       | What You Receive                |
| :----------- | :------------------------ | :------------------------------ | :------------------------------ |
| `successUrl` | Show receipt/confirmation | Payment successful              | Transaction details, card info  |
| `cancelUrl`  | Return to shopping        | User cancels OR session expires | Nothing (just a return path)    |
| `errorUrl`   | Handle system errors      | Server/connectivity failures    | Error code, message, return URL |

### successUrl – Your Confirmation Page

**Purpose:** Where customers land after successful payment to see their receipt/confirmation.

**When it's used:** After payment is processed and confirmed.

**What you receive:** Transaction details and card info as URL parameters:

```
https://yoursite.com/success?success=true&sessionId=session_xxx&checkoutMode=payment&transactionId=2603130000113B86C&transactionType=sale&amount=25.00&currency=USD&ozuraMerchantId=ozu_abc&cardLastFour=4242&cardBrand=VISA
```

See [Handle the Payment Result](/guides/payments/checkout/handle-result#success-url-parameters) for the full parameter reference.

### cancelUrl – Your "Go Back" Destination

**Purpose:** Where customers return when they don't complete checkout.

**When it's used:** Customer clicks "Cancel", session expires (30 min), or customer visits old/bookmarked checkout URL.

**What you receive:** Nothing – it's just a return path.

**Best Practice:** Point to your **cart page** or wherever the customer was before checkout.

### errorUrl – Your System Error Handler

**Purpose:** Handle unrecoverable errors (NOT card declines).

**When it's used:** Server failures, connectivity issues, authentication errors. **NOT** for card declines – those show inline messages and let customers retry.

**What you receive:** Error details as URL parameters:

```
https://yoursite.com/error?success=false&errorCode=SYSTEM_ERROR&error=Payment+service+unavailable&cancelUrl=https://yoursite.com/cart
```

## Optional Fields

### Common Options

| Field                | Default       | What It Does                                                                                                                                                                  |
| :------------------- | :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `currency`           | `"USD"`       | Currency code (e.g., `"USD"`, `"EUR"`, `"GBP"`, `"CAD"`)                                                                                                                      |
| `metadata`           | `{}`          | Your custom data (JSON object, returned in success URL)                                                                                                                       |
| `appearance`         | `{}`          | Custom styling (see [Appearance](/guides/payments/checkout/appearance))                                                                                                       |
| `checkoutMode`       | `"payment"`   | `"payment"`, `"donation"`, or `"recurring"`                                                                                                                                   |
| `embedMode`          | `"redirect"`  | `"redirect"`, `"popup"`, `"iframe"`, or `"new_tab"`. See [Integration Modes](/guides/payments/checkout/integration-modes)                                                     |
| `parentOrigin`       | —             | Required when `embedMode` is `"popup"` or `"iframe"`. Must be a valid URL                                                                                                     |
| `allowPopup`         | `true`        | When `false`, disables the popup upgrade path if iframe is blocked                                                                                                            |
| `hideHeader`         | `false`       | Hides the merchant name and logo strip at the top of checkout                                                                                                                 |
| `surchargePercent`   | —             | Credit card surcharge passed to the processor. String or number, max `"3.00"` (Florida cap). E.g. `"2.50"` adds a 2.5% surcharge line to the order summary.                   |
| `transactionChannel` | `"ecommerce"` | `"ecommerce"` (customer self-serve) or `"moto"` (merchant-entered on customer's behalf). Forwarded directly to the payment processor — the checkout UI is identical for both. |
| `taxExempt`          | `false`       | Skip sales tax calculation for this session                                                                                                                                   |
| `idempotencyKey`     | —             | Unique string for network retry protection — replaying a request with the same key returns the original response without creating a duplicate session                         |
| `recurringConfig`    | —             | Required when `checkoutMode: "recurring"`. See [Recurring Mode](/guides/payments/checkout/recurring-mode) for the full field reference.                                       |
| `donationConfig`     | —             | Donation preset amounts and configuration. See [Donation Mode](/guides/payments/checkout/donation-mode).                                                                      |

### Tax-exempt checkout experience

When `taxExempt` is `false` (the default), the customer enters their billing details on the checkout page first — Ozura uses these to calculate sales tax — then continues to the secure payment step.

When `taxExempt` is `true`, there's no tax to calculate, so checkout skips the billing-details step and takes the customer **straight to the secure payment step** — a faster, more direct flow for your customers.

<Warning>
  **Only set `taxExempt: true` when the products or customer are genuinely tax-exempt.** A tax-exempt session calculates and collects **no** sales tax. If you mark a taxable order as tax-exempt, no tax is collected and **you remain responsible for any sales tax that should have been collected**. When in doubt, leave `taxExempt` as `false`.
</Warning>

### Cart Items (Alternative to Amount)

Instead of a flat `amount`, you can send an array of cart items for a rich, itemized checkout display.

```json theme={null}
{
  "items": [
    {
      "productId": "sku_001",
      "name": "Blue T-Shirt",
      "price": 29.99,
      "quantity": 2,
      "imageUrl": "https://cdn.example.com/tshirt.jpg"
    }
  ]
}
```

**Limits:** Maximum 100 items per cart, maximum cart total: \$999,999,999.99.

See the full [Cart Item Fields](#cart-item-fields) section below for all options.

### Checkout Modes

| Mode              | How to Use                                      | Best For                          |
| :---------------- | :---------------------------------------------- | :-------------------------------- |
| **Simple Amount** | Pass `amount` only                              | Quick payments, invoices          |
| **Itemized Cart** | Pass `items` array only                         | E-commerce with multiple products |
| **Donation**      | `checkoutMode: "donation"`                      | Charities, non-profits, tips      |
| **Recurring**     | `checkoutMode: "recurring"` + `recurringConfig` | Subscriptions, memberships        |

<Warning>
  Mutual exclusivity rules: - Cannot use `amount` + `items` together - Cannot
  use `items` + `checkoutMode: "donation"` together - Cannot use `items` +
  `checkoutMode: "recurring"` — recurring requires a scalar `amount` - Can use
  `amount` + `checkoutMode: "donation"` (sets the default pre-selected donation
  amount)
</Warning>

See [Donation Mode](/guides/payments/checkout/donation-mode) and [Recurring Mode](/guides/payments/checkout/recurring-mode) for full guides.

## Cart Item Fields

Each item in the `items` array supports:

### Required Fields

| Field       | Type    | Description                                    |
| :---------- | :------ | :--------------------------------------------- |
| `productId` | string  | Your product SKU or ID (max 100 chars)         |
| `name`      | string  | Product name shown to customer (max 200 chars) |
| `price`     | number  | Unit price (e.g., `29.99`). Must be ≥ 0        |
| `quantity`  | integer | Quantity (1-10,000)                            |

### Visual Display Fields (Optional)

| Field         | Type   | Description                                                         |
| :------------ | :----- | :------------------------------------------------------------------ |
| `imageUrl`    | string | Product image URL (HTTPS recommended)                               |
| `description` | string | Short product description (max 500 chars)                           |
| `variant`     | string | Variant details, e.g., `"Size: L, Color: Blue"`                     |
| `brand`       | string | Brand name displayed above product name                             |
| `category`    | string | Product category shown as a badge on the item                       |
| `sku`         | string | Internal SKU or barcode shown beneath the item name (max 100 chars) |
| `url`         | string | URL that the product name links to (HTTPS, opens in new tab)        |

### Pricing & Discount Fields (Optional)

| Field           | Type    | Description                                                                       |
| :-------------- | :------ | :-------------------------------------------------------------------------------- |
| `originalPrice` | number  | Original price before discount (renders as strikethrough next to the final price) |
| `discountLabel` | string  | Discount badge text shown beside the item name, e.g., `"SALE"`, `"20% OFF"`       |
| `taxExempt`     | boolean | If `true`, item displays a "Tax Free" badge                                       |
| `discount`      | object  | Shorthand to compute the discounted price automatically — see below               |

**`discount` object** — pass this instead of computing `price`/`originalPrice`/`discountLabel` yourself:

| Sub-field | Type   | Description                                                                |
| :-------- | :----- | :------------------------------------------------------------------------- |
| `type`    | string | `"percentage"` or `"fixed"`                                                |
| `value`   | number | For `percentage`: 0–100. For `fixed`: amount to subtract in currency units |
| `label`   | string | Badge text. Auto-generated (e.g. `"20% OFF"`) if omitted                   |

When `discount` is provided, the `price` field is treated as the **original** price. Checkout computes the final charge price, sets the strikethrough `originalPrice`, and generates a `discountLabel` badge automatically.

```json theme={null}
{
  "productId": "prod_annual",
  "name": "Annual Plan",
  "price": 99.0,
  "quantity": 1,
  "discount": {
    "type": "percentage",
    "value": 20,
    "label": "SAVE 20%"
  }
}
```

## Response

```json theme={null}
{
  "success": true,
  "data": {
    "sessionId": "session_xxxxxxxxxxxxxx",
    "checkoutUrl": "https://checkout.ozura.com/checkout/session_xxxxxxxxxxxxxx",
    "expiresAt": "2025-01-07T12:15:00.000Z",
    "embedCode": "<script>...</script>",
    "pricing": {
      "subtotal": 25.0,
      "tax": 0,
      "shipping": 0,
      "total": 25.0,
      "currency": "USD"
    }
  }
}
```

| Field         | What It Is                                                 |
| :------------ | :--------------------------------------------------------- |
| `checkoutUrl` | **Send your customer here!** This is the payment page URL. |
| `sessionId`   | Save this – you'll need it to verify the payment later.    |
| `expiresAt`   | When the session expires (customer must pay before this).  |
| `embedCode`   | Ready-to-use HTML/JS for popup/iframe modes.               |
| `pricing`     | Calculated totals (subtotal, tax, total).                  |

## What's Next?

You have a `checkoutUrl`. Now [redirect your customer to checkout](/guides/payments/checkout/redirect-customer).
