Skip to main content

Headless Checkout Changelog

v3.74.0

This release introduces new payment integrations for SeQura and Lyra white-label credit cards, alongside crucial updates to improve the reliability and security of payment forms. Buyers will experience more accurate Apple Pay availability, and card forms will adapt better to different screen sizes.

New features
Lyra: The white-label credit card form is now available.
SeQura: The CB3X payment method is now integrated.
Bug fixes
ACI: A race condition that could cause payment display issues for non-vault credit card payments has been prevented.
Apple Pay: Availability is now correctly determined by the wallet SDK, ensuring it only appears when genuinely available to the buyer.
HiPay: The integration no longer contains unused code paths for token-based CVV fields, ensuring all CVV fields are managed by the SDK.
The card form now adapts responsively to narrow containers, ensuring correct display of expiration and CVV fields, particularly in CVV-only mode.
Merchant-supplied text in hosted forms is now sanitised, preventing injection of malicious content.
Minor: Adyen holderName input padding restored; American Express card forms use correct labels and placeholders.
v3.73.0

This release significantly enhances payment reliability and debugging capabilities for your checkout. We've introduced more detailed logging for payment failures and ensured that uncaught SDK errors are properly reported. Additionally, buyers will benefit from improved stability for Apple Pay and PayPal, and a more secure checkout element that no longer exposes sensitive data in the DOM.

New features
Payment failure error logs now include detailed information about the cause of the failure.

The HEADLESS_CHECKOUT_PAYMENT_ERROR event now includes a results array within its payload. This array provides per-attempt details for failed payments, including the payment method, partner, status, plugin_status, and a capped description of the failure. This helps you distinguish between different failure reasons.

interface HeadlessCheckoutPaymentErrorEventDetail {
  // ... other existing fields
  results: Array<{
    method?: string;
    partner?: string;
    status?: string;
    plugin_status?: string;
    description?: string;
  }>;
}

element.on('HEADLESS_CHECKOUT_PAYMENT_ERROR', (event) => {
  console.error('Payment failed:', event.detail.results);
});
Card payments using the Purse vault now perform fewer API calls by skipping an unnecessary /init request.
The card form now intelligently conditions the display of the CVV input based on network token detection.
Bug fixes
Adyen: The underlying Adyen SDK has been updated to version 6.41.0.
Apple Pay: The SDK now negotiates the compatible Apple Pay JS version, allowing more buyers on older devices to complete payments.
Google Pay: The countryCode is now correctly derived from the locale, resolving previous payment failures. Payment sheet failures are also now properly reported instead of being silent.
PayPal: The button is now dimmed and unclickable until the session is fully initialized, and non-fatal errors like popup closures correctly soft-disable the method.
Uncaught SDK errors are now properly reported to your monitoring tools.

Previously, the SDK was swallowing its own unhandled promise rejections and errors, making it difficult to detect issues. Now, uncaught errors originating from the SDK will correctly appear in your browser's console and any window.onerror or window.onunhandledrejection handlers you have implemented. This provides better visibility into potential client-side issues.

Concurrent payment submissions are now correctly prevented, avoiding duplicate /validate calls and incorrect redirections.

The SDK now guards against re-entrant calls to submitPayment. This prevents buyers from accidentally initiating multiple validations, which previously could lead to unnecessary API calls and being redirected to an error page even after a successful payment. A new HEADLESS_CHECKOUT_SUBMIT_BLOCKED event is dispatched when a submission is blocked.

Sensitive session data, payment method tokens, and environment variables are no longer exposed as DOM attributes on the <purse-partner-ui> element.
The payment element now correctly persists across session refreshes, preventing UI components from disappearing and avoiding console errors.

The PaymentElement.on() method now returns an unsubscribe function. Integrators should use this function to clean up event listeners when the element is unmounted to prevent memory leaks and ensure correct behavior across session updates.

const unsubscribe = element.on('ready', () => {
  // Handle ready event
});

// When the component unmounts or the element is no longer needed
unsubscribe();
The card form now correctly displays a numeric keyboard for expiration date inputs on mobile devices and disables autocorrect for holder name.

You can now pass extraProps to customize input attributes for hosted fields, allowing granular control over keyboard types and other HTML input properties.

interface HostedFieldOptions {
  extraProps?: {
    inputmode?: string;
    autocomplete?: string;
    autocorrect?: 'on' | 'off';
    spellcheck?: boolean;
    // ... other HTMLInputElement attributes
  };
}
v3.72.1

The PayPal payment flow is now more robust in webview environments.

Bug fixes
PayPal: The PayPal payment flow now uses 'auto' presentation mode when displayed as a popup, improving compatibility with webviews.
v3.72.0

We've added Stripe Google Pay as a new payment method and upgraded the PayPal SDK to V6 for improved performance and reliability. You now have more control over the display of the CVV field for tokenized payments, alongside several stability enhancements.

New features
PayPal: The PayPal SDK has been upgraded to V6, improving performance and reliability.
Stripe: Google Pay is now available as a payment method.
You can now configure the display of the CVV field for tokenized payments using the merchant_specifics.pay_token_no_cvv setting.

The SDK now correctly respects this setting, ensuring the CVV field is hidden when configured, and the payment element's hasUI() method accurately reflects this state.

Plugins can now react to runtime option changes using the new onOptionsUpdate lifecycle hook.

The new onOptionsUpdate hook allows plugins to dynamically update their UI or behavior when the Payment Element's options change at runtime. This is particularly useful for payment methods with imperatively built UIs, such as Google Pay.

interface Plugin {
  // ... other methods
  onOptionsUpdate?: (context: Context) => Promise<void>;
}
Bug fixes
Adyen: Apple Pay now performs a client compatibility check and degrades gracefully on incompatible browsers.
Alma: The in-page payment calendar now appears only for plans up to 4 instalments.
Maxxing: Missing loyalty accounts are now reported with a specific LOYALTY_ACCOUNT_NOT_FOUND error.

Previously, these were reported as a generic FAILED_TO_INIT_SECONDARY_TOKEN.

PayPal: The PayPal button's appearance and size are now consistent with previous versions when using SDK V6, and it no longer becomes clickable before it is ready to process payments.
Payzen Xpay: Button labels can now be successfully overridden for custom translations.
Tokens now correctly fulfill when their CVV is disabled by configuration.

Previously, tokens with a disabled CVV would not correctly fulfill, preventing the payment from being submitted. The SDK now correctly handles merchant_specifics.pay_token_no_cvv and hostedForm.noCVV to hide the CVV input and ensure the token form validates correctly.

Apple Pay no longer fails the checkout if the button is double-clicked.
Minor: Plugin incompatibility messages are now logged at a warning level instead of an error level.
v3.71.1
Bug fixes
Apple Pay: Double-clicking the Apple Pay button no longer kills the checkout — clicks are ignored while the payment sheet is open.
v3.71.0

Adds Adyen Apple Pay and a normalized partnerError payload. Apple Pay and PayPal initialization failures now surface instead of leaving a dead button.

New features
Adyen: Added Apple Pay.
partnerError payloads are normalized and no longer typed against partner SDK internals.
Card form input survives a session refresh.

Input in the Purse Vault card form is preserved during a session update unless the payment method configuration itself changes.

Minor: Custom apiPaths passed to a bundle that enforces its own API URLs now log a console warning instead of being silently ignored.
Bug fixes
Apple Pay: Initialization failures surface a fatal error instead of rendering a non-responsive button.
Apple Pay (Ingenico): Unsupported clients disable the payment method instead of failing the whole checkout.
PayPal: Initialization failures and unrecoverable errors disable the payment method button and surface a visible error.

SDK errors and init failures — NOT_AUTHORIZED, for example — previously left the button active or froze the checkout silently.

Rapid onAmountUpdate calls no longer exhaust the session step budget and reach SESSION_MAX_STEPS_REACHED.
v3.70.1
Bug fixes
The ESM build no longer fails to load on Safari and iOS 16.3 and below.

The build target is pinned explicitly again. A dependency bump had picked up a narrower default that stopped downleveling ES2022 syntax.

v3.70.0

Validation error keys are renamed. Favorite token management moves to a dedicated endpoint, and getPaymentElement() warns instead of crashing on secondary methods.

Breaking changes
Validation error keys are renamed from *CannotBeEmpty* to *Required*.low impact
Migration guide

The FieldValidationErrors enum and the matching configuration fields are renamed. Deprecated cannotBeEmpty keys still resolve, but will be removed in a future major.

// Before
const config = { cardHolderNameCannotBeEmptyError: 'Cardholder name is mandatory.' };

// After
const config = { cardHolderNameRequiredError: 'Cardholder name is mandatory.' };
New features
Favorite tokens are toggled and fetched through a dedicated endpoint, removing a race between local and server state.
getPaymentElement() on a secondary method warns and returns undefined instead of throwing an opaque TypeError.

Secondary methods — gift cards, vouchers — use getSecondaryToken() or take().

Bug fixes
Apple Pay: Validation no longer sends a request to Adyen when the token is missing, which returned paymentMethod not provided.

Tokens from a previous initialization are cleared. CHECKOUT_API_VALIDATION_SUCCEEDED now carries a per-partner-method statuses map.

interface CheckoutApiValidationSucceededEventPayload {
  statuses: Record<string, { state: string; code?: string; description?: string }>;
}
Lyra: Google Pay, Apple Pay, and XPay initialize when plugin_result.logs is absent.
PayPal: Initialization errors for Wallet and BNPL are re-thrown and dispatched as PluginInitFailed or partnerError instead of being swallowed.
No crash when a payment method is removed from the session while a lethal event listener is attached.
save_token: false overrides any conflicting save_token_mode.
Minor: formDataChanged is logged only once every field is valid, and holderName masking drops the last character; Corrected event categories for VALIDATION_SUCCESS, VALIDATION_FAILED, PAYMENT_ERROR, EXPIRED_SESSION, and CLIENT_HOOK_ERROR.
v3.69.0

Stripe Apple Pay is now available. The getPaymentElement() method is now more flexible, allowing optional method and partner parameters, and provides clearer error messages for incompatible hosted fields requests. Additionally, payment tokens now expose isFavorite, setAsFavorite(), and createdAt properties for enhanced management.

New features
Stripe: Apple Pay is now available as a payment method, leveraging Stripe's Express Checkout Element.

Integrators can now offer Apple Pay via Stripe. The button height is automatically clamped to Stripe's supported range of 40-55px as per Stripe's constraints.

The getPaymentElement() method now features significantly improved resolution logic and optional parameters.

The method and partner parameters are now optional for getPaymentElement():

  • When method is omitted, the SDK automatically selects the first hosted fields-compatible primary method if hostedFields is requested, or the first primary method in the session otherwise.
  • When partner is omitted, the SDK uses the first primary method matching the given method name across all partners. A warning is emitted if multiple partners expose the same method.
  • Requesting hostedFields for an incompatible payment method will now throw a METHOD_DOES_NOT_SUPPORT_HOSTED_FIELDS error instead of silently failing.
Payment tokens now expose isFavorite and a setAsFavorite() method.

The PurseHeadlessCheckoutPrimaryToken type now includes:

interface PurseHeadlessCheckoutPrimaryToken {
  isFavorite: Readable<boolean>;
  setAsFavorite(): Promise<void>;
  // ... other properties
}

Integrators can use these to display and manage a buyer's preferred tokens.

Payment methods and tokens now expose a supportsHostedFields boolean property.

The PurseHeadlessCheckoutPrimaryMethod and PurseHeadlessCheckoutPrimaryToken types now include:

interface PurseHeadlessCheckoutPrimaryMethod {
  supportsHostedFields: boolean;
  // ... other properties
}

interface PurseHeadlessCheckoutPrimaryToken {
  supportsHostedFields: boolean;
  // ... other properties
}

This property indicates whether the method or token is compatible with hosted fields.

Payment tokens now expose a createdAt timestamp.

The PaymentToken type now includes a createdAt: string property, allowing integrators to sort or display tokens by their creation date.

Bug fixes
Ingenico: Google Pay and Apple Pay no longer crash when the API returns incomplete initialization data.

When the Ingenico API returns incomplete data during initialization, the widgets now gracefully fall back to default payment networks (e.g., Mastercard/Visa) and continue to function, preventing a complete checkout blockage.

Hosted fields compatibility is now correctly determined for all payment methods.

This fix ensures that payment methods declaring hosted fields support in their plugin are correctly identified, even when the session vault doesn't explicitly state hosted-fields support.

Token wallet management now gracefully handles unexpected non-array API responses, preventing application crashes.
Apple Pay and Google Pay button customisation options (xPayButton) are now correctly forwarded by getPaymentElement().

Integrators can now use the xPayButton property in PurseHeadlessCheckoutGetPaymentElementOptions to customise the appearance of Apple Pay and Google Pay buttons.

checkout.getPaymentElement({
  partner: 'adyen',
  method: 'googlepay',
  xPayButton: {
    google: {
      buttonColor: 'black',
      buttonType: 'buy'
    }
  }
});
Payment element resolution now prioritises generic (template-driven) plugins over partner-specific plugins when a session template is defined.

This ensures that if your backend defines a custom template for a payment method, the generic plugin will be used even if a partner-specific plugin exists for that method.

v3.68.2
Bug fixes
The wallet now robustly handles API responses for stored payment methods, preventing crashes from malformed data.
v3.68.0
Breaking changes
methodSelected and methodUnselected removed from PaymentElementEventName. For payment methods that open a modal (Apple Pay, Google Pay, Lyra), replace with modalIn and modalOut.
// Before
element.on('methodSelected', handler)
// After
element.on('modalIn', handler)
New features
additionalAssets: PurseHeadlessCheckoutPaymentItemBase now exposes additionalAssets: CardSchemeAsset[] — one entry per supported card scheme (URL + label). iconUrl is still present.
// method.additionalAssets: Array<{ url: string; label: string }>
method.additionalAssets // [{ url: 'https://...', label: 'Visa' }, ...]
Hosted fields — hideHolderName: New option in HostedFieldsOptions to hide the cardholder name field.
method.setOptions({
  hostedForm: { hideHolderName: true },
});
Worldpay: Added direct credit card payment method.
PayPal — disableMaxWidth: New option to override the button's default max-width constraint.
method.setOptions({
  xPayButton: { paypal: { disableMaxWidth: true } },
});
Bug fixes
Google Pay (Ingenico/Worldline): Gateway is now correctly identified when payment product data is unavailable, preventing silent tokenization failures.
Lyra / X-Pay: Validation no longer triggers when the payment sheet failed to open.
Oney: Private card tokens requiring 3DS PIN authentication now complete correctly.
Worldpay: Card brand list is now correctly filtered.
Expiration date field no longer rejects years longer than 4 digits.
Malformed vault expiry dates no longer cause validation errors.
Hosted fields validation now uses getElementInstance() internally, fixing silent skips when rendering via getHostedFields().
Saved tokens now display item.name instead of the masked card number.
v3.67.1

This release enhances the reliability of Google Pay payments for our Ingenico/Worldline merchants by correcting configuration defaults, preventing silent tokenization failures. Additionally, we've fixed an issue ensuring that payment tokens saved in the wallet display their correct names.

Bug fixes
Google Pay: Ingenico/Worldline : Google Pay tokenization now uses the correct default gateway and narrower network list when specific payment product data is unavailable, preventing silent payment failures.
The payment token wallet now correctly uses the name field for saved payment tokens and ensures the editTokenName API path is correct.
v3.67.0

We've added new capabilities for a smoother payment experience and enhanced developer tooling. Buyers can now customize their PayPal button appearance, while developers benefit from a streamlined way to create PaymentElement instances and readily access payment method icons.

New features
PayPal: Developers can now disable the maximum width applied to the PayPal button.

The new disableMaxWidth option can be passed in XPayButtonUIOptions['paypal'] to prevent the PayPal button from expanding to its container's full width.

interface XPayButtonUIOptions {
  paypal?: {
    disableMaxWidth?: boolean;
    // ... other PayPal button options
  };
}

// Example usage:
checkout.getPaymentElement({
  partner: 'paypal',
  method: 'paypal',
  paypal: {
    disableMaxWidth: true,
  },
});
Developers can now create a PaymentElement directly from the checkout instance.

A new shortcut method, checkout.getPaymentElement(), simplifies the creation and rendering of a single payment method's UI.

// Before: More verbose for a single method
// const checkout = new PurseHeadlessCheckout(...);
// const paymentMethods = await checkout.getPaymentMethods();
// const specificMethod = paymentMethods.find(
//   (pm) => pm.partner === 'ingenico' && pm.method === 'creditcard'
// );
// if (specificMethod) {
//   const el = specificMethod.getPaymentElement({ theme: {} });
//   el.appendTo('#container');
// }

// After: Simplified approach
const el = checkout.getPaymentElement({
  partner: 'ingenico',
  method: 'creditcard',
  theme: { /* ... */ },
  hostedForm: { /* ... */ },
  hostedFields: { /* ... */ },
});

el.on('ready', () => console.log('PaymentElement is ready.'));
el.appendTo('#container');
Payment methods and secondary tokens now expose an iconUrl.

Integrators can now easily display official icons for payment methods and secondary tokens by accessing the new iconUrl property.

interface PaymentMethod {
  // ... existing properties
  iconUrl: string | null;
}

interface BuiltSecondaryToken {
  // ... existing properties
  iconUrl: string | null;
}

// Example usage:
const paymentMethods = await checkout.getPaymentMethods();
paymentMethods.forEach((method) => {
  if (method.iconUrl) {
    console.log(`Icon for ${method.name}: ${method.iconUrl}`);
  }
});
Bug fixes
Apple Pay: The payment sheet now handles cancellation gracefully without crashing.
Secondary payment tokens now correctly map payment data from API responses, and currency is consistently sourced from the payment session.

Dedicated mappers ensure accurate data extraction for secondary tokens, including those from partners like Illicado, Easy2play giftcard, Mybeezbox, and Ogloba. This includes migrating from deprecated payment_data.card to payment_data.cards[0] for card-based secondary tokens.

currencyCode has been removed from BuiltSecondaryToken, PurseHeadlessCheckoutSecondaryToken, and PartialSecondaryToken types. Integrators should now retrieve the currency directly from the payment session, which serves as the single source of truth.

The SDK now properly handles redirections, preventing crashes when a validation result lacks a redirect URL.
The cardholder name field no longer accepts semicolons.
Wallet sessions are now correctly parsed from widget_data when available.
Off-session payments no longer incorrectly filter amounts.
v3.66.0

This release expands payment options by introducing Apple Pay and Google Pay for Sogecommerce, PayPal BNPL, and Younited Installments. We've also enhanced Oney card support to correctly collect birthdates for private cards and added a noCVV mode for more flexible card form integrations.

New features
Alma: Alma payment sessions now validate before displaying the popup.

This prevents 'ghost sessions' with Alma when buyers close the popup prematurely, ensuring session consistency between Purse and Alma.

Oney: The card form now correctly collects a birthdate instead of a CVV for Oney private cards.

For Oney private cards, the card form dynamically adapts to collect the buyer's birthdate instead of the CVV. This ensures accurate data collection for Oney payments.

PayPal: Introduce a new BNPL plugin for PayPal payments.
Sogecommerce: Buyers can now pay using Apple Pay and Google Pay via xPay.
Younited: Buyers can now pay using Younited Installments.
Enable an optional noCVV mode for card forms.

Integrators can now configure the card form to optionally collect the CVV by setting the noCVV flag on PaymentElement initialization. This allows for use cases where CVV collection is not always required for specific card brands or payment flows.

const paymentElement = purse.initPaymentElement({
  // ... other config
  card: {
    noCVV: true, // CVV field becomes optional
  },
});
Bug fixes
Adyen: Redirection for 3DS challenges is now handled by the headless checkout manager, ensuring consistent behavior.
ANCV: Cancellation of ANCV Connect polling is now reliable.
ANCV: Correctly handle "Other Transaction Pending" errors for ANCV sessions.
Lyra: Prevent 725 errors when a payment button is not explicitly clicked.
Lyra: 3DS authentication is now correctly skipped when the validation response does not provide an authentication URL.
Maxxing: Correctly generate token IDs for Maxxing loyalty, resolving issues with loyalty program availability.
Support for information requests in the headless checkout.

Payment methods compatible with OFF_SESSION registrations are now correctly displayed and activated, allowing for payments even with zero-amount initial requests.

Ensure payment method splits are correctly processed when using the onBeforeValidate hook.
Centralize final redirection handling within the manager, preventing double redirection calls.
Hosted fields for CVV inputs now use a unique prefix to prevent conflicts between token and new card forms.

This resolves an issue where the CVV field could be duplicated or misbehave when quickly switching between a saved card token form and a new card entry form, especially on slow networks (SDK-11545).

The vault module now waits for the 'ready' event before resolving its boot promise, improving stability.
Card brand names in the vault are now displayed with natural language, instead of SCREAMING_SNAKE_CASE.
The system now emits a 'died' event when a payment plugin is not found, providing clearer error feedback.

This prevents unknown plugins from occupying slots in xPay displays when a template is not properly configured (SDK-11514).