SDK
Web
Overview

Web SDK — Overview

Lunixi publishes eight browser SDKs. They share one core; what differs is what they do and how they authenticate.

SDKWhat it doesPage
checkoutPayment formCheckout Form
fieldHosted card field (narrows PCI scope)Hosted Card Field
identityDevice and behavioural telemetryIdentity Web SDK
kycGuided identity verification flowKYC SDK
portalCustomer portal — plans, subscriptions, cardsPortal SDK
marketplaceSub-merchant application and management flowMarketplace SDK
paymentLinkThe payment link screen — run by Lunixi on pay.lunixi.com, nothing for you to install; embedding it in your site is coming soonPayment Page
loaderEntry point that lazy-loads the othersBelow

Loader — one script, all of them

You do not have to load each SDK with its own <script>. Include the loader, and the module you call is fetched on first use.

<script src="https://cdn.lunixi.com/lunixi-loader.min.js"></script>
// lunixi-kyc.min.js is downloaded on this line, not before
await Lunixi.kyc.mount('#kyc', { … });

The loader installs a proxy: calling Lunixi.<module>.<method>(...) downloads the module, then forwards the call. A second call to the same module does not download it again.

If you need to change the CDN address, define window.Lunixi = { config: { cdnBaseUrl: '…' } } before loading and the loader will use it. Otherwise it derives the base from its own <script src>.

Four integration modes

The SDKs do not force one usage style. You pick based on how much control you want:

ModeWhat you getCall
Mode 0 — CatalogRead-only data via a publishable key; no session, anonymous visitorLunixi.portal.catalog({...})
Mode 1 — Pre-built UIWe render the whole screen; you supply a DOM target.mount(target, {...}) · .form({...})
Mode 2 — HeadlessYou write the UI; the SDK is only the data layer.create({...})
Mode 3 — HybridYou mount individual pieces of the screenLunixi.portal.plans.mount(...)

You can move between Mode 1 and Mode 2. Ship quickly with the pre-built UI, then switch to the same SDK's headless client when your branding needs grow — the endpoints and the session model do not change.

The difference between .mount() and .form(): mount attaches directly, form returns a handle so you can unmount later.

Authentication — it differs per SDK

This is the most important table on the page. A secret key is never present in the browser; each SDK has its own safe route.

SDKWhat travels in the browserHow it is verified
portal catalog (Mode 0)Bearer mk_live_pk_…Publishable key plus an Origin match
kycPublishable key → signed sessionPOST /api/v1/kyc/sdk/init
identitySession token minted by your serversessionBootstrapUrl (your endpoint)
portal (Mode 2)X-Portal-Session (JWT)Portal session
marketplaceX-Marketplace-Token (mp_…)Not Bearer — a portal-token pattern
checkoutCheckout token plus a session-proof cookiePayment session
paymentLinkNo key — the link's short code; a bot check (Turnstile) and a short-lived payment session cookie when starting a payment, then a checkout token at the payment stepPayment link session (/api/public/v1/pay/*)

How a publishable key is protected

A publishable key is not a secret — it is visible in your page source. The protection is not in the key but in where it can be used from:

  1. The key is shaped mk_{environment}_pk_…; the server checks the prefix.
  2. The request must carry an Origin header — the browser sets it, and JavaScript on the page cannot forge it.
  3. That Origin must be an exact match in the allow-list registered for the key.
  4. No match, 401.
⚠️

So even a stolen key cannot be used from outside your domain. But if you keep the origin allow-list wide — wildcard-like patterns, test domains left in production — you weaken that protection yourself.

Hosted card field (field)

For cases where the card number must never enter your page, there is a separate SDK: the field is embedded as an iframe served from fields.lunixi.com. Card data never touches your DOM, which narrows your PCI scope.

It is also reachable from the checkout SDK via Lunixi.checkout.createCardField(...).

Shared behaviour

  • Lazy loading — the heavy UI (React plus the flow screens) is downloaded only in Mode 1, on first mount. Go headless and it never enters your bundle.
  • Not fail-open — SDK calls do not silently return a pass on failure; they throw. You own the fallback.
  • Environment separation — the SDK talks to whichever environment your key was issued for.
🚫

Never put a secret key in the browser. The only key that belongs on a page is a publishable key. If an SDK is asking you for a secret key, you are using the wrong mode.

Where to start