Skip to main content

Migrating to v1


The v1 SDK simplifies integration with fewer lines of code, a streamlined API, and features like auto-processing and a full event system. Most migrations involve straightforward method renames — the core flow remains the same.

Summary of Changes

This table summarizes the key differences between the pre-v1 (v0) SDK and the v1 SDK:

Aspectv0v1
Initializationnew Accept(session).unifiedPayments()VAS.UnifiedCheckout(session)
Display the payment UIup.show(options)checkout.mount(target)
Complete a transactionup.complete(token) (manual only)checkout.complete(token) or automatic using autoProcessing
EventsNoneFull event system on client and checkout
Cleanupup.hide() + up.dispose()checkout.unmount() (reversible) + checkout.destroy() (permanent)
Session creation endpoint/up/v1/capture-contexts/uc/v1/sessions
consumerAuthentication fieldBooleanEnum: 3DS, NONE, PASSKEY

Initialization

const accept = new Accept(sessionJWT);const up = accept.unifiedPayments();
const client = await VAS.UnifiedCheckout(sessionJWT);

These are the key differences:

  • v1 is a single async factory call (no intermediate Accept object)
  • v1 validates the JSON Web Token (JWT) signature and target origins during initialization

Session Creation Endpoint

The server-side endpoint your integration calls to create a session changes in v1. Update your server-side code to call the new endpoint:

v0 endpointv1 endpoint
/up/v1/capture-contexts/uc/v1/sessions

The response from the v1 endpoint continues to include the clientLibrary URL and clientVersion value described in Versioning.

Consumer Authentication

In v0, the consumerAuthentication field in the session request is a boolean. In v1, consumerAuthentication is an enum with an expanded set of options:

ValueDescription
3DSUse 3-D Secure authentication.
NONEDo not perform consumer authentication.
PASSKEYUse passkey-based authentication.

Update any code that sets or checks consumerAuthentication as a boolean to use one of the enum values instead.

Displaying Payment UI

// Sidebarconst token = await up.show({  containers: {    paymentSelection: '#buttons'  }});// Embeddedconst token = await up.show({  containers: {    paymentSelection: '#buttons',    paymentScreen: '#form'  }});
// Create the checkout before mounting itconst checkout = await client.createCheckout();// Sidebarconst result = await checkout.mount('#buttons');// Embeddedconst result = await checkout.mount({  paymentSelection: '#buttons',  paymentScreen: '#form'});

These are the key differences:

  • v1 requires a checkout instance, created with client.createCheckout(), before calling mount()
  • v1 passes container selectors directly to mount() instead of nesting inside { containers: { ... } }
  • v1 supports autoProcessing — when enabled, mount() returns the completed payment result instead of a transient token

Completing Transactions

const token = await up.show({  containers: {    paymentSelection: '#buttons'  }});const result = await up.complete(token);
// Automatic (default when completeMandate is in session)const checkout = await client.createCheckout({ autoProcessing: true });const result = await checkout.mount('#buttons');// result is the completed transaction — no need to call complete()// Manual - similar to v0const checkout = await client.createCheckout({ autoProcessing: false });const token = await checkout.mount('#buttons');const result = await checkout.complete(token);

These are the key differences:

  • v1 supports autoProcessing — when enabled, mount() returns the completed transaction result directly, eliminating the separate complete() call
  • v1 mirrors the v0 manual flow when autoProcessing is disabled

Events

v0: No event system — the integration relies on promise resolution or rejection from show() and complete().

v1: Full event system at both client and integration level:

// Client-level — centralized error trackingclient.on('error', (err) => {  console.error(`[${err.source}] ${err.code}: ${err.message}`);});// Checkout-level — granular lifecycle eventscheckout.on('ready', (data) => {  console.log('Available methods:', data.availablePaymentMethods);});checkout.on('paymentMethodSelected', (data) => {  console.log('Selected:', data.type);});checkout.on('error', (err) => {  console.error('Checkout error:', err.code);});

Cleanup

up.hide();     // Hide UIup.dispose();  // Clean up resources
checkout.unmount();   // Remove UI from page (can remount later)checkout.destroy();   // Permanent cleanupclient.destroy();     // Destroy client and clear all event listeners

These are the key differences:

  • v1 distinguishes between unmount() (reversible) and destroy() (permanent)
  • Both destroy() calls are idempotent
  • client.destroy() emits a "destroyed" event before cleanup

Error Handling

try {  const token = await up.show({    containers: {      paymentSelection: '#buttons'    }  });} catch (err) {  console.error(err.reason, err.message);}
// Same error class, same propertiestry {  const checkout = await client.createCheckout();  const result = await checkout.mount('#buttons');} catch (err) {  console.error(err.reason, err.message);}

The UnifiedCheckoutError class and its reason codes are unchanged between v0 and v1.

Migrating Triggers

If your v0 integration uses triggers, the migration is similar to checkout.

const trigger = up.createTrigger('CLICKTOPAY', {  containers: { paymentScreen: '#screen' }});const token = await trigger.show();
const trigger = client.createTrigger('CLICKTOPAY');const result = await trigger.mount('#screen');

These are the key differences:

  • v1 creates triggers from the client, not from UnifiedPayments
  • v1 passes the container to mount(), not to the constructor
  • v1 renames show() to mount()

Quick Migration Checklist

Use this checklist to migrate your integration from v0 to v1:

  • Replace new Accept(session).unifiedPayments() with await VAS.UnifiedCheckout(session)
  • Update your server to call /uc/v1/sessions instead of /up/v1/capture-contexts
  • Update any consumerAuthentication boolean value to one of the v1 enum values (3DS, NONE, PASSKEY)
  • Replace up.show(options) with checkout = await client.createCheckout(); checkout.mount(target)
  • Update container options: { containers: { paymentSelection, paymentScreen } } becomes direct arguments to mount()
  • Replace up.complete(token) with checkout.complete(token) or use autoProcessing: true to complete transactions automatically
  • Replace up.hide() with checkout.unmount()
  • Replace up.dispose() with checkout.destroy() and client.destroy()
  • Add event listeners for observability, such as client.on('error') and checkout.on('ready')

Last published: September 29, 2026