> ## 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.

# Choose an Integration

> Three ways to host checkout, four server-side paths, and when each one fits.

Two decisions to make before you write code: where the customer pays, and which endpoint your backend calls. They are independent — pick each one separately.

## Where the customer pays

| Option          | What the customer sees                                                     | Frontend work                                                                                      | Fits                                                               |
| --------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Hosted Checkout | Redirected to Clink's checkout page                                        | Almost none — just redirect                                                                        | New projects, fastest path to live                                 |
| JS SDK          | The same redirect, or the full checkout page as an iframe inside your page | Install a package and call one method; embedding also means managing a container and its lifecycle | Frontends already using the SDK, or keeping customers on your site |
| Elements        | Payment inputs, wallet buttons, and 3DS inside your own checkout page      | You write the order summary, pay button, and promo code input                                      | Branded or multi-step checkout                                     |

<Tip>
  Start with Hosted Checkout unless you have a specific reason not to. It gets the whole chain — order, payment, webhook, fulfillment — working fastest. Once that chain is proven, you can swap the frontend for Elements without rewriting the backend.
</Tip>

### Hosted Checkout

Send `uiMode: "hostedPage"` when creating the Session, hand the returned `url` to your frontend, and redirect.

```javascript theme={null}
// This is all your frontend needs
const { checkoutUrl, merchantOrderId } = await fetch('/api/checkout/create', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ productId: 'prd_xxx', quantity: 1 }),
}).then((r) => r.json());

sessionStorage.setItem('merchantOrderId', merchantOrderId);
window.location.assign(checkoutUrl);
```

After paying, the customer returns to your `successUrl`. On that page, look up your own order by `merchantOrderId` and show the result.

<Warning>
  Showing "payment successful" on the return page is for the customer. It is not what triggers fulfillment — the webhook chain does that. Keep the two separate.
</Warning>

Full server-side code is in [Hosted Checkout](/build-integration).

### JS SDK redirect and embedded

Install [`@clink-ai/clink-js`](/api-reference/javascript_sdk) and initialize it with a Publishable Key.

* `redirectToCheckout()` sends the customer to the full checkout page
* `initEmbeddedCheckout()` mounts that same checkout page as an iframe in a container you provide

In embedded mode your backend still creates the Session; the SDK fetches it through the `fetchSession` callback you supply. Create it with `uiMode: "hostedPage"` — the SDK mounts the full hosted checkout page, so `elements` mode is not involved. The browser only ever sees the Publishable Key and Session-related fields.

Methods, parameters, and events are in the [JavaScript SDK](/api-reference/javascript_sdk) reference.

### Elements

Elements splits the page in two. You own the order summary, pay button, promo code input, and status messages. The SDK owns card entry, wallet buttons, 3DS, and QR codes.

Two backend changes:

* Create the Session with `uiMode: "elements"`
* `returnUrl` becomes required. A typical value is `https://YOUR_DOMAIN/complete.html?session_id={ELEMENTS_SESSION_ID}`, where Clink substitutes the real session ID for `{ELEMENTS_SESSION_ID}`

Your backend returns `publishKey`, `environment`, and `sessionId` to the frontend — not a `url`.

Full usage is in [Elements](/elements).

<Note>
  The embedded mode of `@clink-ai/clink-js` and the `@clink-ai/clink-elements` package are different things. The first mounts a complete checkout iframe; the second mounts composable payment components. Pick one per checkout page.
</Note>

## Which endpoint your backend calls

| What you want to do                                                | Call                     | When                                                                                                                                                 |
| ------------------------------------------------------------------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Send the customer to checkout to pick a payment method             | `POST /checkout/session` | The default for website payments                                                                                                                     |
| Charge once, directly                                              | `POST /payment`          | Your backend already has the customer and a usable payment method                                                                                    |
| Create a subscription                                              | `POST /subscription`     | You have a recurring product and a payment instrument, and want to start the subscription directly. Full flow in [Subscriptions](/subscriptions)     |
| Let customers change cards, cancel, switch plans, or view invoices | `POST /billing/session`  | You have a Clink customer who needs to manage subscriptions, billing, or payment methods — send them to the portal instead of through checkout again |

Most website payments use the first.

`POST /payment` is for charging in the background. It does not open a checkout page, so it has no 3DS interface either. When verification is needed it returns `status: 5` and an `action` that you must guide the customer through yourself.

Cards and similar methods need a stored payment instrument (`paymentInstrumentId`) first. Wallets — CashApp, GCash, TNG, WeChat, Kakao, Alipay, QRIS, PromptPay — are created by the backend from the payment method, so you do not have to set one up in advance.

## How to define products

Two modes, chosen by whether the item is a permanent part of your catalog.

**Registered products** — created ahead of time in the dashboard or through `POST /product` and `POST /price`, then referenced by `productId` and `priceId` when creating a Session. Use this for plans, membership tiers, and anything sold long-term. Subscriptions require it, and the price must be a recurring price.

**Inline products** — not created ahead of time. Describe the name, unit price, and quantity directly in `priceDataList` when creating the Session. Use this for top-ups, custom amounts, and one-off items.

Both can coexist in one system. Choose per item type.

<Note>
  Amounts in both modes use the major currency unit. USD 19.99 is `19.99`, not `1999`.

  **Subscriptions require registered products**, and the price must be recurring (`priceType: "recurring"`). Inline items cannot create one — see [Subscriptions](/subscriptions).
</Note>

## Whether to offer discounts

If you do, decide where the promo code appears:

| Option                    | Configuration                                                            | Fits                               |
| ------------------------- | ------------------------------------------------------------------------ | ---------------------------------- |
| Customer enters it        | `allowPromotionCodes: true` on the Session                               | Public campaigns                   |
| Pre-applied, input hidden | Add `showPromotionCode: false` and `promotionCode`                       | Targeted offers, channel pricing   |
| Custom input in Elements  | Enable it on the Session, then call `promoCodeChange` from your frontend | Checkout pages you design yourself |

Creation rules, validation, and how long a subscription discount lasts are in [Discounts and promotion codes](/promotions).

## Write your choices down

Once decided, record these somewhere your team can find them. They determine most of the code below.

| Decision     | Your choice                                       | Determines                                                                                  |
| ------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Product mode | Registered / inline                               | Whether you send `productId` + `priceId` or `priceDataList`                                 |
| Server path  | Checkout / direct payment / subscription / portal | Which endpoint you call                                                                     |
| Frontend     | Hosted / SDK redirect / SDK embedded / Elements   | The `uiMode` value, which fields your backend returns, which package your frontend installs |

## Next

<CardGroup cols={2}>
  <Card title="Hosted Checkout" icon="wrench" href="/build-integration">
    What to write on the backend, the frontend, and the webhook.
  </Card>

  <Card title="Checkout Session" icon="banknote" href="/guides/payments/checkout_session">
    Every Checkout Session parameter, in detail.
  </Card>

  <Card title="Integrate with an AI agent" icon="bot" href="/agent-integration">
    If an agent is already writing your code, let it do the integration.
  </Card>
</CardGroup>
