Skip to main content
Elements embeds the payment inputs, wallet buttons, 3DS, QR codes, and third-party payment interactions that Clink manages into your own page. The order summary, page structure, pay button, and status messages stay yours. Use Hosted Checkout when you want money moving fastest. Reach for Elements when you need your own order summary, page structure, and interaction design.
@clink-ai/clink-elements is currently published at 0.0.1 and the API may still change. Pin the version in package.json.

What the full chain looks like

Elements only replaces the frontend segment. Creating the Session still has to happen on your server, because that call uses the Secret Key. Step 1 submits a product identifier, not a final amount computed in the browser. The amount is recalculated server-side in step 2.

Who owns what

1. Server: write your own Session endpoint

This layer is not an optional optimization. It is three boundaries at once: the Secret Key security boundary, the amount validation boundary, and the local order association boundary. The clinkRequest helper below is the authenticated helper from Hosted Checkout; it returns the data field of the response.
Three things to get right:
  • uiMode is elements and returnUrl is required. Put {ELEMENTS_SESSION_ID} in the URL and Clink substitutes the real Session ID
  • The field is returnUrl. Older material calls it redirectUrl, which is wrong — redirectUrl is a response field used in requires_action flows
  • merchantReferenceId is for reconciliation only. It is not an idempotency key; the same value twice gives you two Sessions
The data that clinkRequest hands back looks like this:
That is an excerpt; the full field list is in Create checkout session. Two things to note:
  • The response contains no Publishable Key and no environment. Both come from your own application config — see the next section
  • The response does contain url, the hosted checkout address. An Elements integration does not use it
Do not forward Clink’s raw response to the browser. Your endpoint should return only what the frontend actually needs — ideally just sessionId.

2. Frontend: call your own endpoint, then initialize

The browser does two things: ask your backend for a sessionId, then initialize the SDK with it.
PUBLIC_CLINK_PUBLISHABLE_KEY and environment are your application’s deployment config, taken from the Publishable Key under Developers > API Keys (it starts with pk_uat_). They are safe to expose in the browser, but they do not come from the Create Session response.
The SDK parameter is named publishKey. When this page says Publishable Key, that is the field it means — write publishKey in code.

3. Mounting, submitting, and third-party buttons

Two kinds of button can appear on a checkout page, and they behave differently: Your own pay button — for cards and anything else where the host triggers submission. Call clink.submit() on click. SDK built-in third-party buttons — Apple Pay, Google Pay, PayPal, and similar. The paymentMethod element renders these internally and handles the click itself. When one takes over, the SDK emits submit-visible: false and you hide your own button.
Three things not to do:
  • Do not hardcode button visibility by payment method name. Follow submit-visible
  • Do not draw your own Apple Pay, Google Pay, or PayPal buttons. The SDK renders those; yours would do nothing when clicked
  • Do not call clink.submit() for third-party buttons. The SDK handles their clicks
Which third-party methods appear depends on merchant configuration, the Session, currency, browser, and device. Do not promise a fixed set on your page.
submit-enabled reports whether submission is allowed. Write disabled = !enabled rather than passing the event value straight into disabled, which inverts the logic.

4. Events

Two groups, by what you do with them. Update host UI Flow signals
session-success is not proof of payment, and neither is returnUrl. Browser events can be forged.Do this instead: on session-success, navigate to your own result page, and have that page query your own backend for the order status. Shipping, top-ups, and entitlements are decided by your backend from signature-verified webhooks and server-side queries.Verification, deduplication, and order matching are covered in Hosted Checkout.

5. Promo codes

Optional. Creating Coupons and Promotion Codes server-side is covered in Discounts and promotion codes. This section is frontend only.
The payload is { amount }, with the fields nested under amount. Writing (info) => info.enablePromotionCode yields undefined, and the promo code entry never appears. Discounts and the final amount due come from amount. Do not compute them yourself.

6. Error handling

SessionNotSupportedError is the most common one early on, and almost always means the backend is still sending uiMode: "hostedPage".

7. Implementation constraints

Get these wrong and the integration breaks. Everything else about layout is your own design decision.

Before you ship

  • No Secret Key and no webhook signing key in browser Network traffic or the build output
  • The browser only calls your own Session wrapper endpoint, never Clink’s Create Session directly
  • The backend does not trust a final amount from the browser; it recalculates from the product or cart
  • The local order, merchantReferenceId, and sessionId mapping is stored
  • The Publishable Key and environment come from application config, and are not described as Create Session response fields
  • submit-visible hides your own button when Apple Pay, Google Pay, PayPal, or similar appear
  • session-success does not trigger fulfillment; the final state comes from verified webhooks and backend queries
  • Old instances are destroyed when the Session changes or the page unmounts

Next

Hosted Checkout

The backend and webhook halves are identical to Hosted Checkout.

Go live

The checklist before switching to production.