> ## 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 (payments fail with any other value) | `"merchant_abc123"` |
| `merchantName` | Your business name (customer sees this) | `"Bob's Coffee Shop"` |
| `amount` | How much to charge, in dollars (not cents)\* | `"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`), in major currency units: `25.00` is $25.00, and `10000` is $10,000.00 (not \$100). 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"`, or `"new_tab"`. `"iframe"` is coming soon; for now it runs as `"redirect"` and the response includes an `EMBED DOWNGRADE` warning. See [Integration Modes](/guides/payments/checkout/integration-modes#iframe-mode-coming-soon) |
| `parentOrigin` | — | Exact origin of the page that opens checkout, e.g. `"https://yoursite.com"`. Required for `"popup"`; needed for `"new_tab"` to receive events. Result events are sent only to this origin |
| `allowPopup` | `true` | Accepted for compatibility; currently has no effect |
| `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 the session's `embedMode`. |
| `embedMode` | The mode the session actually runs in. A request for `"iframe"` comes back as `"redirect"`. |
| `warnings` | Present when something in your request was adjusted, e.g. the `EMBED DOWNGRADE` message for `"iframe"`. |
| `pricing` | Calculated totals (subtotal, tax, total). |

## What's Next?

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


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.