Skip to main content

Headless Checkout Changelog

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).