Skip to content

@openrampkit/web ​

The <openramp-modal> web component (Lit, Shadow DOM), openDeposit(), openWithdraw(), themes and message catalogs.

ts
import { openDeposit, openWithdraw, createDepositController, lightTheme, darkTheme, autoTheme, defaultMessages } from '@openrampkit/web'

In code that runs on the server, import themes from @openrampkit/web/theme. It has the theme functions only, with no Lit:

ts
import { lightTheme, darkTheme, autoTheme } from '@openrampkit/web/theme'

Importing @openrampkit/web registers the element in the browser. On the server the registration is a no-op.

openDeposit(options) ​

Mounts <openramp-modal>, starts a session and returns a handle. Browser only.

OptionTypeDefaultDescription
baseUrlstringrequiredBase URL of your OpenRampKit server
clientSecretstring | () => Promise<string>requiredA client secret, or a function that fetches one
walletWalletAdapternoneEnables "Pay with wallet"
themeThemelightSee Theming
appearanceAppearancenoneSee Theming
localestringsession locale, then enBCP 47 tag. Built-in catalogs: en, vi, id, th, ms, fil. The browser language is not used.
messagesPartial<Messages>noneOverrides the locale catalog key by key
containerHTMLElementdocument.bodyWhere to mount the element
embeddedbooleanfalseRender inline, without the overlay
flowFlowOptionsnoneHow the flow opens: first tab, a method to open at once, amount, presets, default tokens, a withdraw balance. See Flow options.
autoClosebooleanfalseClose as soon as the payment completes, with no success screen. done and onClose still get the session.
onEvent(e: ClientEvent) => voidnoneBrowser events
onClose(session?: PublicSession) => voidnoneCalled once when the modal closes, with the last session
fetchtypeof fetchglobalCustom fetch, for tests and demos
providerRenderersRecord<string, ProviderRenderer>noneRenderers for PROVIDER_SDK surfaces, keyed by the surface provider. When set, PROVIDER_SDK is added to the surfaces the client can draw. See PROVIDER_SDK.

Returns a DepositHandle:

ts
type DepositHandle = {
  element: OpenRampModal
  ready: Promise<DepositController>              // once the client secret is known
  readonly controller: DepositController | undefined
  done: Promise<PublicSession>                   // resolves on COMPLETED; rejects with an OpenRampError when closed first
  close(): void
}

When the modal closes before completion, done rejects with the step's error if there is one, else the controller's error, else an OpenRampError with code CLOSED (CLOSED_CODE). If the client secret function throws, the modal shows the error screen.

Flow options ​

flow (FlowOptions from @openrampkit/client) sets how one session opens. Every option is optional. An option that does not fit the session is ignored: a method the plan does not have, a tab with no methods, or a chain the withdrawal does not allow.

OptionTypeDescription
initialTab'crypto' | 'cash'The tab to show first. Deposit: crypto (wallet, transfer, exchanges) or cash. Withdraw: crypto (To wallet) or cash (To cash).
initialMethodstringDeposit: open this method at once, for example qris, transfer, or exchanges (the exchange picker)
lockMethodbooleanWith initialMethod: hide the way back to the method list
amountstringAmount to fill in, for example '50'
presetsRecord<string, string[]>Amount chips per currency code: a fiat code, or a token symbol for a wallet deposit. At most 4 show, with no repeats, and only values inside the bounds of the same currency. Without presets for the currency, the built-in chips show.
defaultSource{ chain, token? }Deposit: the token the user pays with first, for wallet and transfer. Without token: USDC on the chain, else the native token.
defaultTarget{ chain, token? }Withdraw: the chain and token to receive first on the "To wallet" tab
balancestringWithdraw: the amount the user can withdraw, in the source token, when no wallet reports it (for example custody: 'app'). It turns on the MAX chip and the check against the balance.
gasless'auto' | 'always' | 'never'Deposit with a wallet: gas abstraction. The wallet signs a message instead of a transaction, so it needs no native gas. 'auto' (default): only when the wallet reports a zero native balance on the chain it pays from. 'always': also when it has gas. 'never': off. It needs a wallet with signTypedData and a route that supports it. See Relay: Gas abstraction.
ts
openDeposit({
  baseUrl: '/api/openramp',
  clientSecret,
  flow: { initialTab: 'cash', initialMethod: 'qris', amount: '100000', presets: { IDR: ['50000', '100000', '250000'] } },
  autoClose: true,
})

openWithdraw(options) ​

Mounts <openramp-modal> for a withdraw session and returns a handle. Browser only. Create the session on your server with direction: 'withdraw' and a source (see Withdrawals).

ts
const handle = openWithdraw({ baseUrl: '/api/openramp', clientSecret: getClientSecret, wallet })
handle.done.then((session) => refreshBalance(), (error) => console.log(error.code))

The options are the same as openDeposit (OpenWithdrawOptions), and it returns a WithdrawHandle (the same shape as DepositHandle). done resolves when the withdrawal completes and rejects when the modal closes first. The modal refuses a deposit session: it shows "This is not a withdraw session.".

wallet is required when the source custody is 'user_wallet': the user signs the withdrawal with it. It also prefills the address and shows the source token balance.

createDepositController(options) ​

Builds a DepositController for one session, with surfaces defaulting to SUPPORTED_SURFACES. Call start() on it.

OptionTypeDescription
baseUrlstringServer base URL
clientSecretstringThe client secret (already resolved)
walletWalletAdapterOptional
onEvent(e) => voidOptional
fetchtypeof fetchOptional
surfacesstring[]Default SUPPORTED_SURFACES
expect'deposit' | 'withdraw'Refuse a session of the other direction. Default: follow the session.
flowFlowOptionsOptional. See Flow options.

createWithdrawController(options) is the same with expect: 'withdraw'.

resolveClientSecret(src) resolves a string or a function to a string.

The element: <openramp-modal> ​

The element renders a controller snapshot and calls its actions. It never talks to the server itself. For a withdraw session it shows the "Withdraw" title, the "To wallet" and "To cash" tabs, and the target form.

Properties and attributes ​

NameKindTypeDescription
controllerpropertyDepositControllerThe controller to render
themepropertyThemeTheme
appearancepropertyAppearanceAppearance
messagespropertyPartial<Messages>Message overrides
localeproperty and attributestringBCP 47 locale
providerRendererspropertyRecord<string, ProviderRenderer>Renderers for PROVIDER_SDK surfaces. Without one, the modal links to params.redirectUrl when it can.
errorpropertyOpenRampErrorError shown when there is no controller (for example the secret failed to load)
openproperty and boolean attribute (reflected)booleanShow the modal (not embedded)
embeddedproperty and boolean attribute (reflected)booleanInline mode: no overlay, no close button, Escape does not close
autoCloseproperty, boolean attribute auto-closebooleanClose as soon as the payment completes, with no success screen

Methods ​

MethodDescription
close()Closes: tells the controller (controller.close()), sets open = false, fires openramp-close, and returns focus to the element that had it

Events ​

EventDetailDescription
openramp-close{ session?: PublicSession }The user closed the modal (close button, Escape, overlay click, Done). Bubbles and is composed.

The overlay click does not close the modal while a payment step is on screen.

History ​

With the server option history, the methods screen (and the withdraw "To wallet" form) shows a History link. It opens a list of the user's past sessions: the kind, the amount, the asset that arrives, a relative date ("5 minutes ago"), a status badge and a "View transaction" link to the block explorer when the server knows the transaction. Back returns to the screen before. The link shows only when GET /sessions/:id/history answers with at least one item: with the option off, the server answers 404 and the link stays hidden. A new user has no item, so the link shows after the user's first payment (the widget loads the history again when a payment reaches a final status). See History.

Parts and styles ​

Parts: overlay, card, header, body, footer. The element sets --ork-* CSS variables inline and data-mode="light" or "dark" on itself. See Theming.

Accessibility ​

The modal is a dialog with aria-modal (a region when embedded). It traps focus with Tab, closes on Escape, moves focus to each new screen's title, and announces loading, errors and step progress in a polite live region.

Provider iframe messages ​

For an IFRAME surface, the element listens for message events. It accepts a message only when event.origin equals the surface's allowed origin and event.source is its own iframe. It then calls controller.notifySurface(). Helpers: classifyIframeMessage(data, cfg), iframeOrigin(surface), EMBED_SOURCE ('openramp-embed'). See Surfaces and the iframe message protocol.

Themes ​

ExportDescription
lightTheme(opts?), darkTheme(opts?), autoTheme(opts?)Build a Theme. opts: accent, accentText, radius, fontFamily, colors.
themeVariables(theme, appearance, mode)The --ork-* variables for one mode
lightColors, darkColorsDefault ThemeColors
RADIIRadius scales
DEFAULT_FONT, DEFAULT_MONODefault font stacks

Types: Theme, ThemeOptions, ThemeColors, ThemeMode, RadiusScale, Appearance.

Messages ​

ExportDescription
defaultMessagesThe English catalog
catalogs{ en, vi, id, th, ms, fil }
catalogFor(tag)The built-in catalog id for a BCP 47 tag, or undefined
resolveLocale({ locale?, sessionLocale? }){ catalog, tag }: explicit, then session, then en. The browser language is not used. Aliases: tl is fil, in is id, zsm is ms.
resolveMessages({ ...sources, messages? })The messages to render
mergeMessages(overrides?)Shallow merge over English

Types: Messages, CatalogLocale, LocaleSources.

messages.stepDetail has one label for each value of Step.detail.code (STEP_DETAIL_CODES in @openrampkit/core), in every catalog. The processing screen shows it. Without a known code, the screen shows the state title (messages.stepTitle). It never shows a raw provider status. To change a label, override the whole stepDetail object.

The quote row never says "No fees" when a fee has no stated amount (amount: null). It shows messages.feesInRate ("Fees included in the rate"), or the known fees followed by messages.feeInRate ("+ a fee in the rate"). The step screen shows the legs of session.payment with the main transaction of each leg (the delivery, else the source).

Provider renderers ​

ExportDescription
stripeOnrampRenderer({ load? })A renderer for the Stripe onramp element (@openrampkit/adapter-stripe with the default PROVIDER_SDK surface)
loadScript(src)Loads a script once per page, in the document head
STRIPE_SCRIPTSThe Stripe script URLs that stripeOnrampRenderer loads

Types: ProviderRenderer, ProviderRendererContext, ProviderSdkSurface.

ProviderRendererContext has surface, mode, completed(detail?), failed(detail?) and submit(name, inputs?). submit calls a transition with inputs and resolves to the next Step. It rejects with the OpenRampError, which the modal also shows. See PROVIDER_SDK.

A separate entry for the Stripe Link headless flow. The main entry never imports it.

bash
npm install @stripe/crypto   # optional peer dependency, loaded with a dynamic import
ts
import { openDeposit } from '@openrampkit/web'
import { stripeLinkRenderer } from '@openrampkit/web/stripe-link'

openDeposit({ baseUrl: '/api/openramp', clientSecret, providerRenderers: { 'stripe-link': stripeLinkRenderer() } })
ExportDescription
stripeLinkRenderer(options?)The renderer for provider: 'stripe-link' steps. Use one per modal.
makeClientKey()A random client key: 32 bytes from crypto.getRandomValues, in base64url
toE164(phone)A phone number in E.164 (a 10 digit US number gets +1), or undefined
STRIPE_LINK_TRANSITION_NAMESThe transition names that the renderer calls
OptionTypeDefaultDescription
load(publishableKey, options) => Promise<onramp | null>loadCryptoOnrampAndInitialize from @stripe/cryptoReplace the SDK loader
appearanceobjectnoneMore CryptoOnrampInitOptions (variables, rules, ...). The theme is night in dark mode, else stripe.
collectKyc(container) => Promise<KycInfo>a built-in formYour own KYC form. The data goes to Stripe only.
collectRegistration(container, { email, country }) => Promise<{ phone, fullName? }>a built-in formYour own Link sign-up form. The data goes to Stripe only.
textobjectEnglishOverride the renderer's UI text

Size: about 3.1 kB min+gzip, without @stripe/crypto.

Constants and other exports ​

ExportDescription
SUPPORTED_SURFACESREDIRECT, IFRAME, QR, DEEPLINK, BANK_FIELDS, DEPOSIT_ADDRESS, WALLET_TX, WALLET_SIGN, OTP, FORM
CLOSED_CODE'CLOSED'
TAG_NAME'openramp-modal'
OpenRampModalThe element class
defineOpenRampModal()Registers the element if it is not registered
DepositController, WithdrawController, RampControllerRe-exported from @openrampkit/client (one class)

Re-exported types: Snapshot, ScreenName, SurfaceSignal, Tab, TargetDraft, IframeMessages, IframeSignal, MethodOption, PlanResult, PublicLegQuote, PublicQuote, PublicSession, Step, Surface, OpenRampError, ClientEvent, WalletAdapter, OpenDepositOptions, OpenWithdrawOptions, DepositHandle, WithdrawHandle, CreateControllerOptions, ClientSecretSource.

MIT licensed