Skip to main content
The Clink JavaScript SDK helps you launch Clink Checkout in browser-based applications. It supports both full-page redirects and embedded checkout, and initializes with a publishable key.
Security Note: Use a publishable key in browser code. Never expose your Secret API keys on the client side.

NPM Package

View the package on npmjs.com

Create Checkout Session

Create a checkout session on your backend before launching checkout.

Checkout Session Guide

Learn how hosted checkout sessions work end to end.

Installation

Install the SDK from npm with your preferred package manager:
npm install @clink-ai/clink-js
If you need a browser global build, the package also ships a UMD bundle. After self-hosting dist/index.umd.js, the SDK is exposed as Clink.loadClink(...) on window.

Initialization

Initialize the SDK with your publishable key:
import { loadClink } from '@clink-ai/clink-js';

const clink = await loadClink('pk_uat_xxxxxxxxx', {
  checkoutEnvironment: 'uat',
  locale: 'en-US',
});
Supported publishable key formats are pk_test_*, pk_uat_*, and pk_prod_*. If you already know the final checkout host, you can skip bootstrap by passing checkoutBaseUrl directly:
import { loadClink } from '@clink-ai/clink-js';

const clink = await loadClink('pk_prod_xxxxxxxxx', {
  checkoutBaseUrl: 'https://checkout.clinkbill.com',
});

Init Options

  • checkoutEnvironment: uat or live. Used when checkoutBaseUrl is not provided.
  • checkoutBaseUrl: Checkout host used directly by the SDK. When set, bootstrap is skipped.
  • locale: Forwarded during bootstrap.
  • origin: Override the current site origin.
  • fetchImpl: Custom fetch implementation for non-browser runtimes.

Redirect Checkout

Use redirect checkout when you want Clink to take over the full page flow.
import { loadClink } from '@clink-ai/clink-js';

const clink = await loadClink('pk_uat_xxxxxxxxx', {
  checkoutEnvironment: 'uat',
});

document
  .getElementById('checkout-button')
  ?.addEventListener('click', async () => {
    await clink.redirectToCheckout({
      // Preferred when your backend returns an opaque session token
      sessionParam: 'sess_xxx#token_xxx',
      replace: false,
    });
  });
redirectToCheckout accepts:
  • sessionParam: Preferred when available.
  • sessionId: Used when you only have the session ID.
  • replace: Uses window.location.replace(...) instead of assign(...).
When both sessionParam and sessionId are provided, sessionParam wins.

Embedded Checkout

Use embedded checkout when you want the payment flow to stay inside your page.
import { loadClink } from '@clink-ai/clink-js';

const clink = await loadClink('pk_uat_xxxxxxxxx', {
  checkoutEnvironment: 'uat',
});

const embedded = await clink.initEmbeddedCheckout({
  async fetchSession() {
    const response = await fetch('/api/clink/checkout-session', {
      method: 'POST',
    });

    return await response.json();
    // {
    //   sessionId: 'sess_xxx',
    //   checkoutUrl: 'https://checkout.clinkbill.com/pay/sess_xxx%23token_xxx',
    //   orderId: 'ord_xxx'
    // }
  },
  onEvent(event) {
    console.log(event.type, event.payload);
  },
  async pollStatus({ sessionId, orderId, attempt }) {
    const response = await fetch(
      `/api/clink/checkout-status?sessionId=${sessionId}`,
    );
    const result = await response.json();

    if (result.state === 'pending' || result.state === 'payment') {
      return null;
    }

    return {
      state: result.state,
      payload: {
        orderId,
        attempt,
      },
    };
  },
});

embedded.mount('#clink-checkout');
fetchSession must create a checkout session on your backend and return the final checkout URL. The SDK mounts that URL as-is and does not rewrite its query parameters.

Embedded Options

  • fetchSession: Required. Must resolve { sessionId, checkoutUrl, orderId? }.
  • onEvent: Receives all checkout lifecycle events.
  • autoResize: Automatically applies iframe height updates. Default: true.
  • autoDestroyOnComplete: Automatically destroys the embedded instance after a successful payment. Default: true.
  • pollStatus: Optional polling hook for terminal state detection.
  • pollIntervalMs: Poll interval in milliseconds. Default: 2000.

Embedded Instance API

  • mount(container): Mount into a CSS selector or HTMLElement.
  • unmount(): Remove the iframe but keep the instance reusable.
  • destroy(): Fully dispose the instance.
  • on(type, handler): Subscribe to a specific event type.
  • getState(): Returns { mounted, destroyed }.

Events and States

Embedded checkout can emit the following events:
EventDescription
readyThe checkout iframe is ready or has finished loading.
resizeThe iframe requests a height update.
state_changeCheckout state changed.
completeA terminal state was reached.
hosted_returnThe hosted checkout returned control to the parent page.
errorSDK or polling error.
Possible embedded states are:
  • payment
  • pending
  • success
  • cancelled
  • error
  • expired

Error Handling

The SDK throws ClinkError for validation, bootstrap, and embedded checkout failures.
import {
  CLINK_ERROR_CODES,
  ClinkError,
  loadClink,
} from '@clink-ai/clink-js';

try {
  const clink = await loadClink('pk_uat_xxxxxxxxx', {
    checkoutEnvironment: 'uat',
  });

  await clink.redirectToCheckout({
    sessionId: 'sess_xxx',
  });
} catch (error) {
  if (error instanceof ClinkError) {
    if (error.code === CLINK_ERROR_CODES.INVALID_PUBLIC_KEY) {
      console.error('Invalid publishable key');
    }
  }
}
Common error codes include:
  • INVALID_PUBLIC_KEY
  • INVALID_CHECKOUT_ENV
  • BOOTSTRAP_REQUEST_FAILED
  • INVALID_REDIRECT_PARAMS
  • INVALID_EMBEDDED_OPTIONS
  • SESSION_ID_FETCH_FAILED
  • EMBEDDED_CHECKOUT_DISABLED
  • CONTAINER_NOT_FOUND

References