Skip to main content
Two decisions come before any code: where the customer pays, and which endpoint the backend calls. They are independent — pick each one separately.

Where the customer pays

Start with Hosted Checkout unless there is a specific reason not to. It gets the whole chain — order, payment, webhook, fulfillment — working fastest. Once that chain is proven, the frontend can be swapped for Elements without rewriting the backend.

Hosted Checkout

Send uiMode: "hostedPage" when creating the Session, hand the returned url to the frontend, and redirect.
After paying, the customer returns to the configured successUrl. On that page, look up the local order by merchantOrderId and show the result.
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.
Full server-side code is in Hosted Checkout.

JS SDK redirect and embedded

Install @clink-ai/clink-js 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 supplied container
In embedded mode the backend still creates the Session; the SDK fetches it through the supplied fetchSession callback. 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 reference.

Elements

Elements splits the page in two. The merchant owns 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}
The backend returns only sessionId to the frontend — not a url, and not Clink’s raw response passed straight through. publishKey and environment are not part of the Create Session response. They are frontend deployment config, held in a VITE_ or NEXT_PUBLIC_ style environment variable. Full usage is in Elements.
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.

Which endpoint the backend calls

Most website payments use the first. POST /payment creates a payment server-side without providing a full Checkout UI. It covers more than background charging — customer-present payments, wallets, and QR codes all go through it. What it does not provide is the payment interface, which the merchant builds. Because there is no hosted UI, when 3DS or another verification is required it returns status: 5 and an action the customer has to be guided through. 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 none has to be set up in advance.

How to define products

Two modes, chosen by whether the item is a permanent part of the 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.
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.

Whether to offer discounts

If so, decide where the promo code appears: Creation rules, validation, and how long a subscription discount lasts are in Discounts and promotion codes.

Write the choices down

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

Next

Hosted Checkout

What to write on the backend, the frontend, and the webhook.

Checkout Session

Every Checkout Session parameter, in detail.

Integrate with an AI agent

If an agent is already writing the code, let it do the integration.