Skip to Content
SDKsJavaScript / Browser

JavaScript / Browser SDK

@lartech/infraio-checkout-js is the only SDK we publish today. It runs in the browser and opens our hosted checkout. Backend SDKs (Node, Go, Python) are on the roadmap; until then, talk to the gateway directly — see the Quickstart for a HMAC signing helper.

  • Current version: 0.1.1-beta.17 (pre-1.0; expect minor breaks)
  • Formats: ESM (index.js), CJS (index.cjs), IIFE (index.global.js)
  • Types bundled (index.d.ts)
  • Zero runtime peers — no React, jQuery, or other deps

There is no server-side entry. Signature verification helpers for webhooks are not bundled — implement them yourself with crypto (the signature verification page has copy-paste code in 4 languages).

Install

npm install @lartech/infraio-checkout-js

loadInfraIo(publicKey, options?)

Returns a Promise<InfraIoInstance>.

import { loadInfraIo } from "@lartech/infraio-checkout-js"; const sdk = await loadInfraIo("pk_live_yourkeyhere", { // Optional. Override only when pointing at a non-prod environment. checkoutUrl: "https://checkout-dev.infraio.xyz", });
ParamTypeRequiredNotes
publicKeystringMust match pk_(live|test)_…
options.checkoutUrlstringOverride base checkout URL. Default: https://checkout.infraio.xyz. The matching gateway URL is determined by the checkout page at runtime — each checkout(-dev).infraio.xyz deploy carries its compile-time NEXT_PUBLIC_API_URL, so picking the right hostname here picks the right backend automatically. There is no separate gatewayUrl option.

sdk.checkout({ … })

Opens the hosted checkout. Returns void (use callbacks for state).

FieldTypeRequiredNotes
sessionIdstringsession_key returned by POST /b2b/v1/checkout-sessions/quick
checkoutUrlstringFull URL returned by the same endpoint. If omitted, SDK constructs it from loadInfraIo()’s checkoutUrl (or default) + sessionId
mode"popup" | "redirect" | "embed"Default "popup"
containerstring | HTMLElementembed onlyCSS selector or DOM element where the iframe mounts
widthnumberPopup only. Default 560. Clamped [320, 1280]
heightnumberPopup only. Default 780. Clamped [400, 1000]
timeoutMsnumberPopup only. Iframe load timeout. Default 30000. Pass 0 to disable
localestringBCP-47 tag forwarded as ?locale= to the checkout page (en, ja, zh-CN, zh-TW)
hideSummarybooleanHide the order-summary column. Default false
hideHeaderbooleanHide the InfraIO header and built-in wallet-connect button. Default false. Pair with walletAddress for full white-label
walletAddressstringPre-connect a buyer wallet. Requires onSignRequest
walletChainIdnumberEVM chain ID for the pre-connected wallet
onReady() => voidFires once the iframe is interactive. Popup/embed only
onSignRequest(req: { method: string; params: unknown[] }) => Promise<string>when walletAddress setThe SDK proxies wallet RPCs to your handler; return the signed hex
onSuccess({ sessionId }) => voidFires on successful payment. Not authoritative — webhook is
onCancel() => voidFires when the buyer closes the popup/embed without paying
onError(err: InfraIoError) => voidFires on iframe load failure (popup + embed modes). Invalid arguments are thrown synchronously, not delivered here. Redirect mode has no runtime error surface — failure is observed in the redirected page.

onSuccess is not authoritative. It can fire even when the webhook later determines the payment failed (testnet reorgs, buyer-side timing). Use it only for UX (show “Thanks!”, redirect). Always confirm via webhook before fulfilling.

sdk.close()

Programmatically dismiss an open popup or embed. No-op for redirect mode.

sdk.checkout({ sessionId, mode: "popup", /* … */ }); // later, e.g. when user navigates away sdk.close();

sdk.openRefundRequest({ … })

Opens the hosted refund-request form for a one-time token your backend minted via POST /b2b/v1/merchants/{merchant_id}/refund-requests. The buyer fills in their refund destination address + reason + (optional) metadata on our page; your page only handles the open/close lifecycle. Returns a close() function — call it to programmatically dismiss the popup or detach the embed iframe. In redirect mode the returned function is a no-op.

The form lives at https://checkout.infraio.xyz/refund-request/:token. This method just wraps that URL in a popup / redirect / embed so the buyer never leaves your domain (in popup / embed) or returns to it automatically (in redirect). The endpoint your backend hits to mint the token is POST /b2b/v1/merchants/{merchant_id}/refund-requests — HMAC-signed with your secret key, same auth as the rest of the B2B surface. See Concepts → Refunds.

import { loadInfraIo } from "@lartech/infraio-checkout-js"; const sdk = await loadInfraIo("pk_live_yourkeyhere"); // Mint the token server-side, then hand it to the SDK in the browser. const { token } = await fetch("/api/mint-refund-token", { method: "POST" }).then(r => r.json()); const close = sdk.openRefundRequest({ token, mode: "popup", onSuccess: ({ linkToken, refundId }) => { // Buyer submitted the form. // linkToken → /r/:linkToken status page (share with the buyer). // refundId → use with B2B API to approve / reject. window.location.href = `/r/${linkToken}`; }, onCancel: () => { /* buyer closed without submitting */ }, }); // Programmatically dismiss the popup later if needed: // close();
FieldTypeRequiredNotes
tokenstringThe rfqt_… token returned by POST /b2b/v1/merchants/{merchant_id}/refund-requests
mode"popup" | "redirect" | "embed"Default "popup". Same surface semantics as sdk.checkout() — see Mode notes
containerstring | HTMLElementembed onlyCSS selector or DOM element where the iframe mounts
localestringBCP-47 tag forwarded as ?locale= (en, ja, zh-CN, zh-TW)
hideHeaderbooleanHide the InfraIO header inside the iframe. In popup/embed the SDK draws its own modal chrome, so the page header is typically noise. Default false
hideSummarybooleanHide the Order Summary column, showing only the refund form. Default false
walletAddressstringPre-fill the destination wallet field (?wallet_address=). Lets a merchant that already knows the buyer’s wallet skip the manual re-type
onSuccess(data: { linkToken: string; refundId: string }) => voidFires after the buyer submits the form. linkToken/r/:linkToken status page to share with the buyer. refundId → use with the B2B API to approve / reject
onCancel() => voidFires when the buyer closes the popup/embed without submitting
onError(err: InfraIoError) => voidFires on iframe load failure or invalid args. Token-expiry / cancellation is handled by the hosted page, not via onError

Token states surfaced via onError

If the buyer opens a stale token, the page itself handles the display (renders an “Expired — request new link” prompt, etc.), and the SDK does not fire onError for those cases — the buyer is inside the form flow and your code doesn’t need to react. onError only fires for things your code can act on (bad arguments, network failure loading the iframe).

openRefundRequest records the refund intent — it does not move funds. After onSuccess, the refund row is PENDING (or APPROVED if your merchant config auto-approves customer refunds). You still need to sign and broadcast the on-chain transfer from your merchant wallet, then post the tx hash to POST /b2b/v1/refunds/:id/submit-tx. See Concepts → Refunds for the full lifecycle.

Error class

import { InfraIoError } from "@lartech/infraio-checkout-js"; sdk.checkout({ sessionId, onError: (err: InfraIoError) => { switch (err.code) { case "invalid_request_error": /* bad sessionId / args */ break; case "iframe_load_error": /* iframe failed to load */ break; case "iframe_timeout_error": /* exceeded timeoutMs */ break; case "already_open_error": /* another checkout is already open */ break; case "network_error": /* transient network problem talking to the checkout origin */ break; case "api_error": /* backend returned a non-2xx for an SDK-issued call */ break; } }, });

sdk.openRefundRequest() throws only invalid_request_error (missing or invalid token / args), synchronously. iframe_load_error (the refund-request iframe failed to load) is delivered asynchronously via onError, not thrown. It does not emit iframe_timeout_error or already_open_error — the refund-request popup has no load-timeout and allows multiple concurrent popups.

Mode notes

  • Centered overlay with a dark semi-transparent backdrop
  • z-index: 2147483647 (max int32) — sits above everything else
  • Body scroll is locked while open; restored on close
  • Close button gets initial focus; Tab is trapped in the popup
  • Closed by: close button, Escape, click outside, sdk.close(). All of them call onCancel
  • The checkout page can request resize via postMessage — the SDK clamps within width/height limits

Redirect

  • Hard navigation via window.location.href
  • Automatically appends ?return_url=<current-page> so the buyer returns where they came from. If your success_url / cancel_url on the session already cover this, the round-trip ignores return_url

Embed

  • iframe with allow="payment; clipboard-write" (HTML5 Feature Policy directives — not the sandbox attribute). The iframe is served from the checkout origin, so wallet popups and clipboard writes from the buyer side work without further opt-in.
  • Container width is 100%; height auto-sizes via INFRAIO_RESIZE postMessage, clamped [200, 2000]px
  • No CSS isolation beyond the iframe boundary — your parent page styles do not bleed in
  • Always wire onReady so you can hide your own loading state when the checkout becomes interactive

TypeScript

All types are bundled. Most useful exports:

import type { CheckoutOptions, RefundRequestOptions, LoadOptions, InfraIoInstance, InfraIoErrorCode, } from "@lartech/infraio-checkout-js"; import { loadInfraIo, InfraIoError, VERSION } from "@lartech/infraio-checkout-js";

VERSION is the SDK’s own version string — useful in bug reports.

What’s next

  • React / Vue framework wrappers — planned for the post-launch iteration once the vanilla JS surface stabilises across the pilot merchants. The vanilla SDK works fine inside React today; the wrappers will just remove the manual useRef + lifecycle plumbing.
  • Cross-tab session resumption — open the checkout in tab A, finish in tab B. Useful when a buyer follows a magic-link mid-flow. Tracked for the next minor release.
  • Theming via CSS variables — surface a small set of design tokens (radius, accent colour) on the iframe so merchants can match their brand without forking the page.
  • Server-side helpers — a tiny @lartech/infraio-server package exposing verifyWebhook() + signedRequest() so backend code doesn’t need to copy the HMAC ritual. Until it ships, the signature verification page lists drop-in implementations in TypeScript, Go, Python, and Ruby.