Onerway
Online Payments

Web SDK integration

Create a server-side payment, initialize the Web SDK with paymentId, and handle custom buttons, wallets, redirects, and final result verification.

A Web SDK integration has two parts: your server creates the payment and stores the order-to-paymentId mapping; the browser loads the SDK and creates Checkout with that paymentId. Keep the secret, request signing, customer mapping, and final payment verification on the server.

Before you begin, follow Setup to obtain your API credentials and add your server's public outbound IP addresses to the allowlist for the target environment. Generate sign for each request according to Request signing. Before going live, follow Sandbox testing to verify all scenarios used by your integration in the sandbox.

The Web SDK uses Onerway's Google Pay integration, so no Google Pay website registration is needed; that applies only to Direct API integrations.

Integration flow

  1. Call Create SDK transaction from your server and store the returned paymentId.
  2. Load the CDN script that matches the transaction environment.
  3. Create Checkout with paymentId, subscribe to events, and then mount the Payment Element.
  4. Call confirmPayment() for cards, each local payment method, and other custom payment buttons. For SDK-owned Apple Pay and Google Pay buttons, listen only for payment_result.
  5. Use client events to update the page. Confirm the final status on your server through Query payments or a payment webhook.

Create a payment on your server

For an ordinary Web SDK v4 payment, submit productType=ALL, subProductType=DIRECT, and txnType=SALE to Create SDK transaction. The standard one-time payment example omits billingInformation, shippingInformation, paymentMode, and osType.

Both billingInformation and shippingInformation are optional when you create the transaction. You can provide either object when the information is available, or add it through Update SDK order before payment confirmation when your business flow requires it. If you submit an object, its nested required fields and conditions still apply. When updating the order, reuse the merchantTxnId of the original transaction creation on your server, and wait for a successful update response before the customer confirms payment.

For the current Web SDK, txnOrderMsg contains only returnUrl, products, appId, customerPlatform, periodValue, and notifyUrl. See the API Reference for whether each field is required and its conditions. Do not collect or send browser, device, or cardholder IP fields from your server; the Web SDK collects that context.

Omit paymentMode for ordinary Web SDK payments; you do not need to distinguish desktop and mobile browsers. If you send a value other than WEB, you must also send osType.

Pass only the paymentId from the create-payment response to the browser. You may use transactionId for server-side order correlation, but it cannot replace paymentId when initializing the SDK. The response also still returns redirectUrl; the current Web SDK does not consume it during initialization.

Load the SDK

The CDN and environment must match:

EnvironmentCDNenvironment
Sandboxhttps://sandbox-checkout-sdk.onerway.com/v4/latest/onerway.jssandbox
Productionhttps://checkout-sdk.onerway.com/v4/latest/onerway.jsproduction, the default

v4/latest is the officially recommended long-term Production URL. Although environment defaults to production, pass it explicitly to prevent environment mix-ups when copying configuration.

<script src="https://checkout-sdk.onerway.com/v4/latest/onerway.js"></script>

<div id="onerway_checkout"></div>
<button id="pay_button" type="button">Pay now</button>

Initialize, subscribe, and mount

const checkout = await Onerway.createCheckout(paymentId, {
  environment: 'production',
  locale: 'en'
})

const paymentElement = checkout.createPaymentElement()

paymentElement.on('ready', (event) => {
  console.log(event.availablePaymentMethods)
})

paymentElement.on('loaderror', (event) => {
  console.error(event.error.code, event.error.message)
})

checkout.on('payment_result', handlePaymentResult)

paymentElement.mount('#onerway_checkout')

Subscribe before calling mount():

  • ready.availablePaymentMethods is the displayable set determined by the order, server configuration, and browser wallet capabilities. Do not treat example values as a fixed enum. The SDK hides wallet buttons when a wallet is unavailable.
  • loaderror means that Checkout initialization failed. Branch on event.error.code; use event.error.message for display only. The only public codes are checkout_load_failed (the first load of payment methods failed; let the customer reinitialize) and no_available_payment_methods (no payment method remains after filtering; check the server-side configuration and paymentMethod).
  • Validation failures, payment API errors, wallet cancellation, and 3DS or redirect errors are not loaderror events. Handle them through the confirmPayment() result or payment_result.

Configure the Payment Element

Every child field of config is optional, but each merchant should decide which fields to provide based on its payment-method, form, and branding requirements. Do not assume that the default presentation fits every integration. The SDK reads the configuration when paymentElement.mount() runs. Recreate and remount the Payment Element after changing it.

FieldTypeDefaultPurpose
paymentMethodString[]OmittedDisplay allowlist that retains only methods also returned by the server
showBillingAddressBooleantrueWhether to display and validate the billing-address form
displayCardholdernameBooleantrueWhether to display and validate the cardholder-name input
walletButtonsObjectSee belowSupported appearance settings for the official Apple Pay and Google Pay buttons
checkoutThemeStringlightSDK theme preset; light is currently the only public theme
variablesObject{}Theme-variable overrides and the recommended customization layer
stylesObject{}CSS-selector overrides with the highest priority
customCssURLStringSDK default CSSReplaces the SDK base stylesheet; variables and styles still apply

For example, a merchant can display only the methods accepted by its checkout, hide the SDK billing-address form, and apply branding to SDK-controlled content:

const checkout = await Onerway.createCheckout(paymentId, {
  environment: 'production',
  locale: 'en',
  config: {
    paymentMethod: ['CARD', 'DOKU_VA', 'GooglePay'],
    showBillingAddress: false,
    displayCardholdername: true,
    checkoutTheme: 'light',
    variables: {
      colorPrimary: '#2563eb',
      colorText: '#1a202c',
      borderRadius: '8px'
    },
    walletButtons: {
      googlePay: { type: 'pay', color: 'black', height: '44px' },
      applePay: { type: 'pay', color: 'black', height: '44px' }
    }
  }
})

Restrict payment methods

paymentMethod only filters the browser presentation. It does not enable a payment method for the merchant:

ValueBehavior
OmittedDisplay every server-returned method that is available on the current device
['CARD', 'FPX', 'GooglePay']Display CARD, FPX, and GooglePay only when the server also returns them
[]Display no methods and emit loaderror with event.error.code set to no_available_payment_methods

Each value must exactly match the payment-method identifier returned by the server. Array order does not control display order; the server payment-method configuration and the SDK wallet region still determine the actual order. Use ready.availablePaymentMethods as the final indication that a method loaded successfully.

Configure form visibility

  • showBillingAddress: false hides the billing address and stops its client-side validation. It does not change server-side field requirements for Create transaction or Update order. If your business requires billing information, collect it and update the order before payment confirmation.
  • displayCardholdername: false hides the cardholder name and stops its client-side validation.

Configure wallet buttons

FieldDefaultSupported values or rule
googlePay.typepaybook, buy, checkout, donate, order, pay, plain, subscribe
googlePay.colorblackblack, white
applePay.typepayadd-money, book, buy, check-out, continue, contribute, donate, order, plain, reload, rent, subscribe, support, tip, top-up, pay
applePay.colorblackblack, white, white-outline
googlePay.width / applePay.width100%CSS size string
googlePay.height / applePay.height44pxCSS size string
googlePay.radius / applePay.radius8pxCSS size string; the Apple / Google platforms may constrain the final appearance

These options customize only the supported appearance of official SDK wallet buttons. They cannot make a wallet available on an unsupported device, and variables, styles, or custom CSS cannot force an appearance that the wallet platform does not allow. Setup for wallets, such as Apple Pay domain verification, is covered in Payment methods.

Configure themes and styles

  • checkoutTheme currently supports only light.
  • variables is the recommended branding layer. Common supported variables are containerBackground, cardBackground, inputBackground, inputBrandBackground, aggregateHeaderBackground, dialogBackground, colorText, colorPrimary, colorDanger, fontFamily, fontSizeBase, and borderRadius. fontSizeBase accepts 12px–24px; borderRadius accepts 0px–24px.
  • styles maps CSS selectors to CSS property objects, such as { '.onerway-checkout__input': { color: '#1a202c' } }, for local adjustments that variables cannot express.
  • customCssURL replaces the SDK base stylesheet; variables and styles can still override it.

Themes and styles affect SDK-controlled content only. The legacy showPayButton and payButtonText options are no longer supported and are ignored by the SDK.

Locale

When locale is omitted, the SDK uses the browser language. If the explicit value or browser language is not supported by the current payment method, the SDK falls back to English (en).

Non-wallet payment methods support the following locale values (alphabetical):

CodeLanguageCodeLanguage
arArabicdeGerman
enEnglishesSpanish
fiFinnishfrFrench
itItalianjaJapanese
koKoreannlDutch
noNorwegianplPolish
ptPortugueseruRussian
svSwedishthThai
zh-cnSimplified Chinesezh-twTraditional Chinese

Wallets use their own locale enums and casing. The two wallets support the same locales except for these differences:

SupportLocales
Both walletsar, ca, cs, da, de, el, en, es, fi, fr, hr, id, it, ja, ko, ms, nl, no, pl, pt, ru, sk, sv, th, tr, uk, zh
Google Pay onlybg, et, sl, sr
Apple Pay onlyhe, hi, hu, ro, vi, zh-TW

Wallets also fall back to English (en) when a locale is unsupported. For example, Simplified Chinese is zh-cn for non-wallet methods and zh for wallets; Traditional Chinese is zh-tw for non-wallet methods and zh-TW for wallets. Do not invent conversions for values that are not listed.

Confirm the payment

Cards, local payment method flows, and custom buttons

These payment methods require your button to call confirmPayment():

document.querySelector('#pay_button').addEventListener('click', async () => {
  const result = await checkout.confirmPayment()
  handleConfirmResult(result)
})

Do not create another Checkout or another order when retrying. Keep the same paymentId, Checkout, and Payment Element while the payment remains retryable.

SDK-owned Apple Pay and Google Pay buttons

SDK-owned wallet buttons cannot call confirmPayment(). After the customer clicks an official button rendered by the SDK, receive the client result only through payment_result:

checkout.on('payment_result', (result) => {
  if (result.reason?.type === 'canceled') {
    // The customer closed the wallet. Restore the UI; do not map this to a payment failure.
    return
  }

  renderClientResult(result)
})

Wallet visibility also depends on server configuration, browser, device, and wallet capabilities.

Google Pay in embedded app WebViews

Google Pay availability is capability-detected: when the requirements are not met, ready.availablePaymentMethods does not include GooglePay and the SDK does not render its button. This is expected behavior, not a failure.

  • Android WebView officially supports Google Pay, but the host app must cooperate: Android WebView 137+, Google Play services 25.18.30+, the androidx.webkit:webkit:1.14.0 dependency, the Chromium payment intent actions declared in the manifest, the Payment Request API enabled, and the app integration published to Google. A custom User-Agent must append GOOGLE_PAY_SUPPORTED. See the official Google WebView guide.
  • Embedded WebViews on iOS do not support Google Pay.
  • When the host app does not meet these requirements, break the payment flow out to the system browser and make sure the customer is guided back to the app after payment.

paymentStatus and nextAction

The SDK returns nextAction only when paymentStatus === 'R':

nextAction.typeSDK behaviorMerchant action
PresentToShopperThe SDK presents a QR code, local payment page, or another handoff UI on the current page. There is no final result yet.Keep the current Checkout and wait for payment_result. Do not call confirmPayment() again.
RedirectShopperThe SDK is about to redirect to an external payment page. There is no final result yet. 3DS uses this flow.Wait for Onerway to return the customer to the request's returnUrl, then call Query payments on the server using the stored paymentId.

R means that the payment flow must continue; it does not mean success or failure. nextAction is absent when paymentStatus !== 'R'.

See the paymentStatus response field for the full set of values and their definitions. Use client statuses only to update the page; do not fulfill, credit, or account for an order from them alone:

paymentStatusMerchant action
I, U, P, ANot a final state. Keep the order pending; do not fulfill.
RThe flow continues in an SDK handoff or redirect. Read nextAction.type and follow the table above.
OThe payment can continue or be retried. Keep the same paymentId, Checkout, and Payment Element; do not create another order.
S, NA client-received result. Verify on the server before completing the order or updating its display.

Client exceptions that do not produce a payment status are described by reason:

reason.typeMeaning
validation_errorLocal form validation failed; no payment status was produced
sdk_errorAn SDK local state, configuration, or invocation problem
api_errorThe payment API or a backend business call failed; reason.code is the backend's original respCode — see Response codes
canceledThe customer canceled the current interaction; reason.code is presenter_closed (closed the SDK-presented QR code or local payment dialog), cvv_closed (closed the second card verification code dialog after Google Pay authorization), or wallet_canceled (canceled the Apple Pay or Google Pay authorization sheet)

A cancellation may carry no paymentStatus, only reason.type === 'canceled'. Canceling the client flow is not a final payment failure; restore the page so the customer can retry.

Verify the final payment result

The confirmPayment() result, payment_result, and returnUrl can drive client navigation only; the final result is determined by webhooks: the payment result webhook for ordinary payments, the saved payment method result webhook when the customer opts in to saving a card, the subscription payment webhook for subscriptions, and the authorization, capture, and void webhook for pre-authorizations. Signature verification, acknowledgement and retries, deduplication, status interpretation, and query fallback follow the shared rules in Webhooks.

Additional considerations for the Web SDK integration: store the merchant-order-to-paymentId mapping on your server. After a redirect returns to returnUrl, do not trust a payment status in the URL — restore the page to a “confirming” state and, if no webhook has arrived, fall back to Query payments with the paymentId from your server and return the business result to the client. Do not store unredacted rawResult, request or response payloads, or payment data in browser logs, persistent storage, or analytics.

Saved cards and subscriptions

Let the customer choose whether to save a card

Keep subProductType at DIRECT and provide a stable merchantCustId. The SDK presents the save-card choice to the customer; it is not selected by default. Reuse the same merchantCustId for later payments, and the SDK displays the customer's saved cards and completes saved-card selection and payment internally; your client does not need a tokenId for that flow.

Additional considerations for the Web SDK integration: subProductType=TOKEN belongs to the legacy Web SDK save-card flow and is not used for the current Web SDK's customer-controlled save-card flow. The requirements for merchantCustId, the saved payment method result webhook, and listing and deleting saved tokens are covered in Saved payment methods.

Create the initial payment for a fixed plan

Use subProductType=SUBSCRIBE for the initial subscription payment. Keep the allowed plan mapping on your server and send a stable, readable subscription.productName; the billing model is determined by subscription.selfExecute. For a managed card subscription, you can also send subscription.bindCard as true to save the customer card when the subscription succeeds, in which case you receive two separate notifications.

Choosing between managed and self-managed subscriptions, contract credentials, lifecycle notifications, renewals and plan changes, and handling the two notifications of a subscription that also saves the card are covered in Subscription payments.

Pre-authorization

Send txnType as AUTH and keep subProductType at DIRECT to perform a pre-authorization: the order amount is held on the customer's card without an immediate charge, and the SDK integration flow is the same as an ordinary payment. After the pre-authorization succeeds, store the transactionId and paymentId from the response; your server later captures or voids through Capture or void authorization.

Scope, the lifecycle from authorization to capture or void, notifications, boundaries, and status handling are covered in Pre-authorization and capture.

Profit sharing

Profit sharing applies to the platform model: the platform merchant creates the payment with the receiving sub-merchant's merchantNo, and the payment is eligible for profit sharing only when you submit the paymentMethodOptions with profitShare=true in its share object; the SDK integration flow is the same as an ordinary payment. When you also set profitShareRate, Onerway allocates funds automatically after a successful SALE or CAPTURE; without it, your server initiates profit sharing through the API. To receive automatic profit share and reversal notifications, also set profitShareNotifyUrl. Submit paymentMethodOptions as a JSON string as required by the API.

Choosing between automatic and API-initiated profit sharing, result notifications, queries, and reversals are covered in Profit sharing.