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

# Checkout Session

> A hosted checkout page experience

## Overview

A Checkout Session is dynamically generated through the POST Session API. The API provides a time-limited link to a Clink-hosted checkout page with pre-filled customer information. We recommend creating a new Session for each customer payment intention.

Each checkout session can accommodate multiple payment attempts until a successful transaction is completed. Successful transactions can represent either one-time purchases or subscriptions.

## Session Data

### Status

* Open: The checkout session is created but no successful payment has been received
* Complete: The checkout session has concluded with a successful payment
* Expired: The checkout session has expired and no further payment attempts are allowed

### Product & Price

If you have configured products and prices in the dashboard, you can simply reference them using their IDs. For subscription-based recurring payments, pre-created products are mandatory.

For one-time purchase products, you can define product details (name, unit price, quantity, etc.) in the priceDataList. The checkout session will display these product details accordingly.

### Subscription Scheduled Phases

For subscription checkout sessions, send `scheduledPhases` as a top-level request field when you want the subscription created after checkout to change plans at future renewal boundaries.

The initial subscription is still created from `productId` and `priceId`. Each scheduled phase references a subscription `priceSnapshotId`, sets the target `quantity`, and uses `effectiveCycle` to say which renewal cycle activates the phase. `sequence` and `effectiveCycle` both start at `1` and must be strictly increasing. You can include up to 10 phases.

Use the `priceSnapshotId` returned by the Product or Price APIs. Phase snapshots must be subscription prices with valid recurring details and must support the checkout payment currency. `metadata` is optional and is limited to 10 keys, 40 characters per key, and 500 characters per value.

### Customer

Checkout sessions include pre-filled customer information. Provide at least one of `customerId`, `customerEmail`, or `referenceCustomerId`. If all three are empty, the request fails with `CUSTOMER_NOT_FOUND`.

`referenceCustomerId` is the merchant-side customer ID. It can be used to locate, validate, create, or bind a Clink customer.

When `customerId` is provided, it is the primary identifier. Clink first looks up the customer by `customerId`. If `customerEmail` is also provided, it must match that customer. If `referenceCustomerId` is also provided, it must match that customer; when the customer does not already have a `referenceCustomerId` and the reference ID is not used by another customer, Clink automatically binds it to the customer.

When `customerId` is not provided, Clink resolves the customer by `customerEmail` and/or `referenceCustomerId`:

* Only `customerEmail`: Clink finds an existing customer by email, or creates a new customer if none exists.
* Only `referenceCustomerId`: Clink finds an existing customer by the merchant-side customer ID, or creates a new customer if none exists.
* Both `customerEmail` and `referenceCustomerId`: both identifiers must resolve to the same customer. If the email resolves to customer A and the reference ID resolves to customer B, and A is not B, the request fails with `CUSTOMER_IDENTIFIER_NOT_MATCHED`. If only one identifier matches an existing customer, the request also fails with `CUSTOMER_IDENTIFIER_NOT_MATCHED`. If neither identifier matches an existing customer, Clink creates a new customer with both identifiers.

The checkout session stores the resolved `customerId`. `customerEmail` and `referenceCustomerId` are used to locate, validate, create, or bind the customer.

### URLs

Use `uiMode` to control how the checkout session is rendered:

* `hostedPage`: hosted checkout page
* `elements`: embedded checkout

For hosted checkout, we strongly recommend providing `successUrl` and `cancelUrl` for post-checkout navigation.

When `uiMode` is `elements`, `returnUrl` is required.

### Direct QR Launch

`directPaymentQrCodePaymentMethodType` controls whether the QR code payment flow is launched directly when opening checkout.

Currently supports `CASHAPP` and `QRIS`.

This parameter takes effect only when:

* `paymentMethodType` is set to the same value as `directPaymentQrCodePaymentMethodType`
* The selected payment method is available in the checkout session

Behavior:

* When effective, checkout directly initiates the QR code payment flow
* In no-password scenarios, payment will not be automatically completed

Ignored when:

* The selected payment method is not available in checkout
* `paymentMethodType` does not match `directPaymentQrCodePaymentMethodType`

Allowed values:

* `CASHAPP`
* `QRIS`

### Promotion Code Display

Set `allowPromotionCodes` to `true` to enable promotion code support in checkout. By default, checkout shows the promotion code input.

To apply a promotion code without showing the input box, set `showPromotionCode` to `false` and provide `promotionCode`. In this mode, `promotionCode` is required and Clink validates it when the session is created.

### Merchant Reference

The merchant reference serves as your internal identifier for tracking purposes. This reference will be recorded on orders created through the checkout session.

<Warning>
  **Idempotency**: Clink does not maintain idempotency based on merchant reference IDs. <br />
  These IDs are solely for reconciling Sessions with your internal systems. Multiple checkout sessions created with the same merchant reference ID will be treated as distinct sessions.
</Warning>

## Return and Redirect URLs

For hosted checkout sessions created with `uiMode: hostedPage`, Clink redirects customers to `successUrl` after a successful payment and to `cancelUrl` when they leave the flow.

During the hosted success redirect, Clink appends the session ID as a URL parameter, allowing you to retrieve session data via the Session#Get API.

Hosted success URL examples:

<Tip>
  * https\://your\_success\_url.com?sessionId=sess\_randoms <br />
  * https\://your\_success\_url.com?custom=xxxxxxxx\&sessionId=sess\_randoms
</Tip>

For embedded checkout sessions created with `uiMode: elements`, `returnUrl` is required. You can include `{ELEMENTS_SESSION_ID}` in the URL, and Clink will replace it with the created session ID before returning control to your site.

Example `returnUrl`:

<Tip>
  https\://YOUR\_DOMAIN/complete.html?session\_id={ELEMENTS_SESSION_ID}
</Tip>

## Customer Experience

Clink provides a streamlined solution with a standardized checkout experience. While customization options are limited, the interface maintains a clean, professional design.

Merchant information and the cancel URL are accessible from the top left. Product and price information is displayed based on either dashboard configurations or API inputs.

Available payment methods and currencies adapt automatically based on:

* Purchase type (one-time or subscription)
* Customer's geographical location

## Quick Start Examples

Reference these code snippets to get started:

<AccordionGroup>
  <Accordion icon="file-json" title="Sample Code">
    <Danger>Always test your code thoroughly before deploying to production!</Danger>

    <CodeGroup>
      ```json One-time Purchase Without Product theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerEmail": "customer@example.com",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceDataList":[
              {
                  "name":"A one-time purchase",
                  "quantity": 1,
                  "unitAmount":${unitAmount},
                  "currency":"USD"
              }
          ]
      }'
      ```

      ```json Purchase With Pre-created Product theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerEmail": "customer@example.com",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceId": "${price_id}",
          "productId": "${prd_id}"
      }'
      ```

      ```json Hidden Promotion Code theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerId": "cus_xxxxx",
          "originalAmount": 19.99,
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceId": "price_xxxxx",
          "productId": "prd_xxxxx",
          "allowPromotionCodes": true,
          "showPromotionCode": false,
          "promotionCode": "SAVE10"
      }'
      ```

      ```json Subscription With Scheduled Phases theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerId": "cus_xxxxx",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceId": "${initial_price_id}",
          "productId": "${prd_id}",
          "successUrl": "https://YOUR_DOMAIN/success",
          "cancelUrl": "https://YOUR_DOMAIN/cancel",
          "scheduledPhases": [
              {
                  "sequence": 1,
                  "effectiveCycle": 2,
                  "priceSnapshotId": "${growth_price_snapshot_id}",
                  "quantity": 1,
                  "metadata": {
                      "source": "checkout_schedule"
                  }
              },
              {
                  "sequence": 2,
                  "effectiveCycle": 4,
                  "priceSnapshotId": "${scale_price_snapshot_id}",
                  "quantity": 2
              }
          ]
      }'
      ```

      ```json Embedded Checkout (Elements) theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerEmail": "customer@example.com",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "elements",
          "returnUrl": "https://YOUR_DOMAIN/complete.html?session_id={ELEMENTS_SESSION_ID}",
          "priceDataList":[
              {
                  "name":"Embedded checkout purchase",
                  "quantity": 1,
                  "unitAmount":${unitAmount},
                  "currency":"USD"
              }
          ]
      }'
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>
