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

# Checkout Features

> Conversion-optimized, globally compliant checkout with multi-currency, multi-language support, automatic tax calculation, discount codes, add-ons, and smart address collection.

<Frame>
  <img src="https://mintcdn.com/dodopayments/Vafy52417ELLVDIx/images/checkout/cover.png?fit=max&auto=format&n=Vafy52417ELLVDIx&q=85&s=2dc0a0db8e021e39fb17e84fc12eb5f9" alt="Checkout page" style={{ maxHeight: '500px', width: 'auto' }} width="2844" height="1556" data-path="images/checkout/cover.png" />
</Frame>

<Info>
  Dodo Payments checkout is a conversion-optimized, globally compliant checkout designed for digital products and SaaS businesses. It supports multiple currencies, languages, taxes, discounts, add-ons, and business-friendly compliance workflows.
</Info>

<CardGroup cols={2}>
  <Card title="Checkout Sessions API" icon="code" href="/api-reference/checkout-sessions/create">
    Create hosted checkout sessions programmatically.
  </Card>

  <Card title="Preview Checkout" icon="eye" href="/api-reference/checkout-sessions/preview">
    Calculate pricing and taxes before creating a session.
  </Card>

  <Card title="Payment Methods" icon="credit-card" href="/features/payment-methods">
    Supported payment methods and configuration options.
  </Card>
</CardGroup>

## Adaptive Currency

Adaptive Currency allows customers to pay in their preferred local currency, improving trust and conversion rates.

### How It Works

1. **Enable**: Enable Adaptive Currency from **Settings → Business**
2. **Select**: Customers can switch currencies directly on checkout
3. **Convert**: Prices are dynamically converted using real-time FX rates
4. **Display**: Final payable amount is shown transparently before payment

<Frame>
  <img src="https://mintcdn.com/dodopayments/Vafy52417ELLVDIx/images/checkout/c1.png?fit=max&auto=format&n=Vafy52417ELLVDIx&q=85&s=c2f9ee4b1748448d4ab7ab23954dcc64" alt="Currency selector on checkout" style={{ maxHeight: '500px', width: '70%' }} width="794" height="858" data-path="images/checkout/c1.png" />
</Frame>

<Card title="Adaptive Currency" icon="money-bill-transfer" href="/features/adaptive-currency">
  Learn more about supported currencies, conversion fees, and refund handling.
</Card>

## Multi-Language Checkout

Dodo Payments supports multiple languages on the checkout page, allowing customers to complete payments in a language they're comfortable with.

<Frame>
  <img src="https://mintcdn.com/dodopayments/Vafy52417ELLVDIx/images/checkout/c2.png?fit=max&auto=format&n=Vafy52417ELLVDIx&q=85&s=ecc6eb8db604e37433d8797c51768577" alt="Language selector on checkout" style={{ maxHeight: '500px', width: '70%' }} width="794" height="858" data-path="images/checkout/c2.png" />
</Frame>

### Key Highlights

* Language selector available directly on checkout
* UI text, labels, and system messages are localized
* Improves accessibility and international conversion

### Supported Languages

The checkout page supports 21 languages:

| Language   | Code |
| ---------- | ---- |
| Arabic     | `ar` |
| Catalan    | `ca` |
| Chinese    | `zh` |
| Dutch      | `nl` |
| English    | `en` |
| French     | `fr` |
| German     | `de` |
| Hebrew     | `he` |
| Indonesian | `id` |
| Italian    | `it` |
| Japanese   | `ja` |
| Korean     | `ko` |
| Malay      | `ms` |
| Polish     | `pl` |
| Portuguese | `pt` |
| Romanian   | `ro` |
| Russian    | `ru` |
| Spanish    | `es` |
| Swedish    | `sv` |
| Thai       | `th` |
| Turkish    | `tr` |

<Tip>
  You can force a specific language on the checkout by setting the `force_language` parameter when creating a checkout session. See the [Checkout Sessions API](/developer-resources/checkout-session#14-forcing-a-language) for details.
</Tip>

## Automatic Tax Calculation

Taxes are automatically calculated based on the customer's billing location, ensuring compliance with GST, VAT, and sales tax requirements without manual setup.

### How Tax Calculation Works

<Steps>
  <Step title="Location Detection">
    Tax rules are applied based on the customer's country (and region where applicable).
  </Step>

  <Step title="Dynamic Updates">
    Tax amount updates automatically when:

    * Country changes
    * Address is updated
  </Step>

  <Step title="Transparent Display">
    Final tax breakdown is shown clearly before payment.
  </Step>
</Steps>

<Tip>
  Tax calculation is fully automated. No manual configuration required for standard digital goods and SaaS products.
</Tip>

## Business Tax ID Support

For registered businesses, the checkout allows customers to enter their Business Tax ID (e.g., VAT/GST number).

### What Happens When a Tax ID Is Entered

* Tax eligibility is validated in real-time
* Applicable tax exemptions or reverse-charge rules are applied
* Tax amount updates instantly on checkout

<Frame>
  <img src="https://mintcdn.com/dodopayments/Vafy52417ELLVDIx/images/checkout/c3.png?fit=max&auto=format&n=Vafy52417ELLVDIx&q=85&s=76451fed5636a6ef3e5c3ec7f6a96c9f" alt="Business Tax ID entry on checkout" style={{ maxHeight: '500px', width: '70%' }} width="1440" height="1716" data-path="images/checkout/c3.png" />
</Frame>

<Info>
  This is especially useful for B2B SaaS and digital services where business customers may be eligible for tax exemptions.
</Info>

## Discount Codes

Customers can apply discount or promo codes you've created in the dashboard directly on the checkout page.

### Checkout Experience

1. Customer enters the discount code
2. Discount is validated instantly
3. Updated price and savings are shown clearly

<Frame>
  <img src="https://mintcdn.com/dodopayments/Vafy52417ELLVDIx/images/checkout/c4.png?fit=max&auto=format&n=Vafy52417ELLVDIx&q=85&s=639dcc94ddd1b41fdd6ff200c2a28e47" alt="Discount code entry on checkout" style={{ maxHeight: '500px', width: '70%' }} width="794" height="858" data-path="images/checkout/c4.png" />
</Frame>

### API Integration

Pre-apply one or more stacked discount codes or enable the discount input field:

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_abc', quantity: 1 }
  ],
  discount_codes: ['WELCOME20'], // Pre-apply one or more codes (max 20, applied in order)
  feature_flags: {
    allow_discount_code: true // Show discount input field
  },
  return_url: 'https://yoursite.com/return'
});
```

<Info>
  `discount_codes` accepts an array of up to 20 codes that stack in order. The singular `discount_code` field is deprecated but still works — existing integrations don't need to change immediately. Migrate to `discount_codes` when convenient to use stacking and the richer response shape.
</Info>

<Card title="Discount Codes" icon="percent" href="/features/discount-codes">
  Learn how to create and manage discount codes.
</Card>

<Card title="Validate Discount by Code" icon="tag" href="/api-reference/discounts/get-discount-by-code">
  Look up and validate discounts using code names.
</Card>

## Smart Address Collection

The checkout supports flexible address entry for faster completion.

### Options Available

| Option                      | Description                                                                                               |
| --------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Google Address Autofill** | Quick selection with autocomplete                                                                         |
| **Manual Entry**            | Full control for complete addresses                                                                       |
| **Country Selection**       | Drives tax and compliance logic                                                                           |
| **Minimal Address**         | Collect only country (and ZIP where required for tax) — see [Minimal Address Mode](#minimal-address-mode) |

<Tip>
  Address collection balances speed, accuracy, and global coverage to maximize conversion while ensuring compliance.
</Tip>

### Minimal Address Mode

For maximum conversion, enable minimal address collection to reduce checkout friction. When `minimal_address` is set to `true`, the checkout only collects:

* **Country** — always required for tax determination
* **ZIP/Postal code** — only in regions where it's necessary for sales tax, VAT, or GST calculation

All other address fields (street, city, state) are skipped, significantly speeding up checkout completion.

<Frame>
  <img src="https://mintcdn.com/dodopayments/7dyPZdWH7JucnLrT/images/changelog/minimal-address.png?fit=max&auto=format&n=7dyPZdWH7JucnLrT&q=85&s=cd0e5d6f8c32e052c7ab93a88d841fb8" alt="Minimal address mode showing only country and ZIP/postal code fields on checkout" style={{ maxHeight: '500px', width: 'auto' }} width="1459" height="817" data-path="images/changelog/minimal-address.png" />
</Frame>

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_abc', quantity: 1 }
  ],
  minimal_address: true,
  return_url: 'https://yoursite.com/return'
});
```

<Info>
  Full address collection remains the default. Enable `minimal_address` for digital products and SaaS flows where complete billing details aren't required.
</Info>

<Card title="Minimal Address Reference" icon="address-card" href="/developer-resources/checkout-session#request-body">
  See the full `minimal_address` parameter reference in the Checkout Sessions API guide.
</Card>

## Phone Number Collection

Control whether the phone number field appears on checkout — and whether it's required — using checkout session feature flags.

| Flag                            | Default | Behavior                                                                           |
| ------------------------------- | ------- | ---------------------------------------------------------------------------------- |
| `allow_phone_number_collection` | `true`  | Shows the phone number field on the checkout form                                  |
| `require_phone_number`          | `false` | Makes the phone number field required (form validation enforces a non-empty value) |

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_abc', quantity: 1 }],
  feature_flags: {
    allow_phone_number_collection: true,
    require_phone_number: true
  },
  return_url: 'https://yoursite.com/return'
});
```

<Warning>
  `require_phone_number: true` requires `allow_phone_number_collection: true`. The API rejects sessions where phone collection is disabled while phone number is required.
</Warning>

<Tip>
  Use `require_phone_number` for B2B SaaS, regulated industries, or any flow where you need a verified contact channel for support, fraud review, or compliance.
</Tip>

## Custom Fields

Collect additional information from customers during checkout by defining custom form fields. This is useful for gathering data like company name, team size, referral source, or any other business-specific information.

### Available Field Types

| Type       | Description                    |
| ---------- | ------------------------------ |
| `text`     | Single-line text input         |
| `number`   | Numeric input                  |
| `email`    | Email address with validation  |
| `url`      | URL with validation            |
| `date`     | Date picker                    |
| `dropdown` | Select from predefined options |
| `boolean`  | Yes/No toggle                  |

### Example

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_abc', quantity: 1 }
  ],
  custom_fields: [
    {
      key: 'company_name',
      label: 'Company Name',
      field_type: 'text',
      required: true
    },
    {
      key: 'team_size',
      label: 'Team Size',
      field_type: 'dropdown',
      required: true,
      options: ['1-10', '11-50', '51-200', '200+']
    }
  ],
  return_url: 'https://yoursite.com/return'
});
```

<Info>
  Customer responses are automatically included in webhook payloads (`payment.succeeded`, `subscription.active`) and API responses via the `custom_field_responses` array. You can define up to 5 custom fields per checkout session.
</Info>

<Card title="Custom Fields Guide" icon="input-text" href="/developer-resources/checkout-session#15-collecting-custom-fields">
  Learn more about custom field configuration and accessing responses.
</Card>

## Privacy Policy & Terms Acceptance

To ensure legal and compliance transparency:

* [Privacy Policy](https://dodopayments.com/privacy-policy) and [Buyer Terms](https://dodopayments.com/buyer-terms) links are clearly displayed on checkout
* Customers explicitly acknowledge these before completing payment

<Info>
  This helps meet global consumer protection and data privacy requirements including GDPR compliance.
</Info>

## Collection Checkout

Product Collections enable a unified checkout experience where customers can view and select from multiple related products (e.g., Starter, Pro, Enterprise plans) in a single checkout.

### How It Works

1. **All products displayed**: Customers see every active product in the collection
2. **First product pre-selected**: The first product in the collection is automatically selected
3. **Compare options**: Customers can compare pricing and features before choosing
4. **Single selection**: After selecting a product, checkout proceeds with standard payment flow

### Creating a Collection Checkout

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_collection_id: 'pdc_abc123',
  product_cart: [], // Required: pass an empty array for collection checkout
  return_url: 'https://yoursite.com/return'
});
```

<Warning>
  When using `product_collection_id`, pass an empty `product_cart` array. Discount codes cannot be pre-applied at session creation.
</Warning>

<Card title="Product Collections" icon="layer-group" href="/features/product-collections">
  Learn how to create and manage product collections for unified checkout experiences.
</Card>

## Checkout Session Configuration

Control checkout behavior using the Checkout Sessions API:

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_abc', quantity: 1 }
  ],
  customer: {
    email: 'customer@example.com',
    name: 'Jane Doe'
  },
  billing_currency: 'EUR', // Set specific currency
  discount_codes: ['PROMO10'],
  feature_flags: {
    allow_discount_code: true
  },
  return_url: 'https://yoursite.com/return',
  cancel_url: 'https://yoursite.com/pricing', // Optional: where to redirect on cancel
  metadata: {
    order_ref: 'ORD-12345'
  }
});
```

<Info>
  After payment, customers are redirected to your `return_url` with query parameters appended automatically -- including `payment_id` or `subscription_id`, `status`, `email`, and `license_key` (if applicable). See the [Checkout Sessions guide](/developer-resources/checkout-session#request-body) for the full list.
</Info>

<CardGroup cols={2}>
  <Card title="Checkout Sessions API" icon="code" href="/api-reference/checkout-sessions/create">
    Complete API reference for checkout sessions.
  </Card>

  <Card title="Checkout Integration Guide" icon="book" href="/developer-resources/checkout-session">
    Step-by-step guide to integrating checkout.
  </Card>
</CardGroup>

## Checkout Theme Customization

Customize the checkout page appearance to match your brand using the `customization.theme_config` parameter when creating a checkout session via the API. Configure colors, fonts, border radius, and button text for both light and dark modes.

<Frame>
  <img src="https://mintcdn.com/dodopayments/rTHkQICkStFgSdh-/images/checkout/theme-example.png?fit=max&auto=format&n=rTHkQICkStFgSdh-&q=85&s=5277b69d67c90fd87e7c5d9c125fee12" alt="Custom themed checkout page" style={{ maxHeight: '500px', width: 'auto' }} width="2856" height="1490" data-path="images/checkout/theme-example.png" />
</Frame>

<Card title="Design & Theme Customization" icon="palette" href="/features/design">
  Configure themes visually from the dashboard with pre-built themes, typography, colors, and live preview.
</Card>

<Info>
  This section covers the **server-side API** theme configuration using `customization.theme_config`. If you're using the **Checkout SDK** (overlay or inline checkout), see the theme customization sections in [Overlay Checkout](/developer-resources/overlay-checkout#theme-customization) or [Inline Checkout](/developer-resources/inline-checkout#theme-customization) which use camelCase properties (e.g., `bgPrimary` instead of `bg_primary`).
</Info>

### Theme Configuration Options

| Property             | Description                                                                 |
| -------------------- | --------------------------------------------------------------------------- |
| `light`              | Color configuration for light mode                                          |
| `dark`               | Color configuration for dark mode                                           |
| `font_primary_url`   | URL for the primary font                                                    |
| `font_secondary_url` | URL for the secondary font                                                  |
| `font_size`          | Font size: `xs`, `sm`, `md`, `lg`, `xl`, `2xl`                              |
| `font_weight`        | Font weight: `normal`, `medium`, `bold`, `extraBold`                        |
| `radius`             | Border radius for UI elements (e.g., `4px`, `0.5rem`, `8px`)                |
| `pay_button_text`    | Custom text for the pay button (e.g., "Complete Purchase", "Subscribe Now") |

### Color Configuration (Light/Dark Mode)

Each mode (`light` and `dark`) supports the following color properties:

| Property                 | Description                       |
| ------------------------ | --------------------------------- |
| `bg_primary`             | Background primary color          |
| `bg_secondary`           | Background secondary color        |
| `text_primary`           | Text primary color                |
| `text_secondary`         | Text secondary color              |
| `text_placeholder`       | Text placeholder color            |
| `text_error`             | Text error color                  |
| `text_success`           | Text success color                |
| `border_primary`         | Border primary color              |
| `border_secondary`       | Border secondary color            |
| `button_primary`         | Primary button background color   |
| `button_primary_hover`   | Primary button hover color        |
| `button_secondary`       | Secondary button background color |
| `button_secondary_hover` | Secondary button hover color      |
| `button_text_primary`    | Primary button text color         |
| `button_text_secondary`  | Secondary button text color       |
| `input_focus_border`     | Input focus border color          |

<Info>
  All color fields accept standard CSS color formats:

  * Hex: `#fff`, `#ffffff`, `#ffffffff`
  * RGB/RGBA: `rgb(255, 255, 255)`, `rgba(255, 255, 255, 0.5)`
  * HSL/HSLA: `hsl(120, 100%, 50%)`, `hsla(120, 100%, 50%, 0.5)`
  * Named colors: `red`, `blue`, `transparent`
</Info>

### Example

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    { product_id: 'prod_abc', quantity: 1 }
  ],
  customization: {
    theme_config: {
      // Custom fonts
      font_primary_url: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap',
      font_size: 'md',
      font_weight: 'medium',
      radius: '8px',
      pay_button_text: 'Complete Purchase',
      
      // Light mode colors
      light: {
        bg_primary: '#ffffff',
        bg_secondary: '#f5f5f5',
        text_primary: '#1a1a1a',
        text_secondary: '#666666',
        button_primary: '#0066ff',
        button_primary_hover: '#0052cc',
        button_text_primary: '#ffffff',
        border_primary: '#e0e0e0'
      },
      
      // Dark mode colors
      dark: {
        bg_primary: '#1a1a1a',
        bg_secondary: '#2d2d2d',
        text_primary: '#ffffff',
        text_secondary: '#a0a0a0',
        button_primary: '#3385ff',
        button_primary_hover: '#4d99ff',
        button_text_primary: '#ffffff',
        border_primary: '#404040'
      }
    }
  },
  return_url: 'https://yoursite.com/return'
});
```

<Tip>
  You don't need to specify all color properties. Any unspecified properties will use the default theme values.
</Tip>
