Last updated

Walley Checkout Adapter

Overview Document: Payment Adapters Overview

Overview and Unique Capabilities

The Walley Checkout Adapter integrates Walley Checkout with Norce Checkout. This page focuses on the unique technical details and configuration for Walley.

Supported payment methods and other features: Features Overview

Configuration in Norce Admin

The adapter is configured using the following unique details obtained from Walley:

FieldDescriptionExample Value
apiUrlWalley Checkout API URL (test or production).https://api.uat.walleydev.com
authenticationUrlWalley OAuth authentication URL.https://api.uat.walleydev.com
frontEndUrlWalley frontend URL for the checkout iframe loader script.https://checkout.uat.walleydev.com
scopeWalley OAuth scope (environment-specific constant). UAT: 705798e0-8cef-427c-ae00-6023deba29af/.default, Production: a3f3019f-2be9-41cc-a254-7bb347238e89/.default705798e0-8cef-427c-ae00-6023deba29af/.default
clientIdYour Walley client identifier.your-client-id
apiSecretYour Walley API secret key.your-api-secret

Store ID Configuration

Configure Store IDs for each country and customer type combination:

FieldDescription
storeId-SE-B2CStore ID for Sweden B2C customers
storeId-SE-B2BStore ID for Sweden B2B customers
storeId-NO-B2CStore ID for Norway B2C customers
storeId-NO-B2BStore ID for Norway B2B customers
storeId-FI-B2CStore ID for Finland B2C customers
storeId-FI-B2BStore ID for Finland B2B customers
storeId-DK-B2CStore ID for Denmark B2C customers
storeId-DK-B2BStore ID for Denmark B2B customers

Feature Toggles

FieldDescriptionDefault
useDeliveryModuleEnable Walley Delivery Module for integrated shipping.false
useCustomerPrefillEnable customer information prefill for returning customers.false
profileNameWalley profile name for customized checkout experience (configured by Walley Merchant Services).—
useUpsellEnable upsell offers to be added to a completed Walley Checkout order. When enabled, orders eligible for upsell remain in Accepted state instead of Completed, allowing reauthorization before capture.false
upsellTimeoutSecondsMaximum time window in seconds during which upsell offers can be added before completing the order.300

Redirect URLs

Configure the URLs that Walley uses for callbacks and redirects:

FieldDescriptionExample Value
merchantTermsUriURL to merchant terms displayed and linked in the checkout.https://example.com/terms
redirectPageUriURI to redirect to after checkout completion.https://example.com/confirmation
notificationUriURI for Walley notification callbacks (order completion).https://{slug}.api-se.norce.tech/checkout/walley-adapter
validationUriURI for Walley validation callbacks (pre-purchase validation).https://{slug}.api-se.norce.tech/checkout/walley-adapter
checkoutAbortedRedirectPageUriURI to redirect to if checkout is aborted.https://example.com/checkout-aborted

Styling Options

Customize the appearance of the Walley Checkout iframe:

FieldDescriptionExample Value
dataPaddingSet to none to cancel out the left and right padding inside the iframe (by adjusting its margins and width).none
dataContainerIdID of an element on the page where the iframe will render instead of immediately above the script element.walley-checkout-container
dataActionColorHexadecimal color code for the background color of call-to-action buttons. Button text color is automatically set based on WCAG 2.0 contrast requirements.#582f87
dataActionTextColorOverride the automatic text color of call-to-action buttons. Valid values: black, white, #000000, #ffffff.#FFFFFF

Mapping Options

Configure how order data is mapped to Walley:

FieldDescriptionDefault
referenceSourceSelects the order property mapped to Walley Merchant Reference. Options: orderId, cartReference.orderId
shippingReferenceSourceSelects the shipping property mapped to Walley Shipping Fee ID. Options: ShippingId, CustomValue.ShippingId
customShippingReferenceCustom value for shipping reference (required when shippingReferenceSource is CustomValue).—
mapDiscountPerRowIf true, applied discounts are included directly in item row prices instead of being represented as separate discount order lines.false

Localization Options

Configure localized text for discounts and vouchers:

FieldDescriptionExample Value
discountTextLocalized discount text by culture code.{"sv-SE": "Rabatt", "en-US": "Discount"}
voucherTextLocalized voucher text by culture code.{"sv-SE": "Presentkort", "en-US": "Gift Card"}

Frontend Integration Requirements

Required Client-Side Event Handling

Walley will not inform the Norce adapter directly of customer changes made through the Walley checkout widget. When a user enters or updates their customer information in the Walley widget, the widget triggers client-side events. You must listen for these events and call the Norce Walley Adapter API to update the order in real-time.

Failure to implement these event handlers will result in:

  • Email-based discounts not being validated correctly
  • Customer information not being synchronized with Norce until purchase completion
  • Potential order validation failures when the order is locked during payment processing

Required Event: Customer Update

Before implementing the Walley Checkout customer update event handler, ensure you have:

  • The Walley Checkout script loaded on your page
  • A valid Norce Checkout order ID and payment ID
  • Your Norce merchant and channel identifiers
  • A valid Norce authentication token (Bearer token)
  • The base URL of the Walley Checkout Adapter for your environment, for example https://{slug}.api-se.norce.tech/checkout/walley-adapter

Walley Checkout dispatches all client-side events on the global document object, and the events neither bubble nor can be cancelled. Register listeners with document.addEventListener(...); listeners registered on window are never invoked.

Listen for the walleyCheckoutCustomerUpdated event from Walley and call the customer update endpoint:

// Initialize Walley event listener (after the Walley checkout script loads)
document.addEventListener('walleyCheckoutCustomerUpdated', async function(event) {
  const orderId = /* your Norce Checkout order ID */;
  const paymentId = /* your Norce Checkout payment ID */;
  const merchant = /* your merchant ID */;
  const channel = /* your channel ID */;
  const walleyAdapterBaseUrl = /* Walley Checkout Adapter base URL */;
  const token = /* your Norce authentication token */;

  try {
    const response = await fetch(
      `${walleyAdapterBaseUrl}/api/checkout/v1/callback/orders/${orderId}/payments/${paymentId}/customer-update` +
      `?merchant=${merchant}&channel=${channel}`,
      {
        method: 'POST',
        headers: {
          'x-merchant': merchant,
          'x-channel': channel,
          'Authorization': 'Bearer ' + token
        }
      });

    if (!response.ok) {
      throw new Error(`customer-update failed with status ${response.status}`);
    }
  } catch (error) {
    // Log and monitor the failure: the Norce order may now hold stale customer data.
    // Validation does not compare customer fields directly, so this alone will not
    // fail walley-validation; but an email-based discount can be evaluated against
    // the wrong address until the order is synchronized.
    console.error(error);
  }
});

Endpoint:

POST /api/checkout/v1/callback/orders/{order_id}/payments/{payment_id}/customer-update?merchant={merchant}&channel={channel}

The customer-update and shipping-option-update endpoints of the Walley Checkout Adapter read merchant and channel from the query parameters, not from headers — send them as the merchant and channel query parameters. Also send the x-merchant and x-channel headers alongside the query parameters: the adapter does not require them on these two endpoints, but it picks them up for request logging and tracing, so including them keeps these calls consistent with the rest of your Norce Checkout integration. Send your Norce authentication token in the Authorization: Bearer {token} header as for other Norce Checkout calls.

This endpoint updates the Norce order with the latest customer information from Walley, including email address (critical for discount validation), billing address, delivery address, and loyalty membership data.

Failure to implement this event handler will result in:

  • Email-based discounts not being validated correctly
  • Customer information not being synchronized with Norce until purchase completion
  • Potential order validation failures when the order is locked during payment processing

Required Event: Shipping Option Update

When using Walley's delivery module (useDeliveryModule enabled), listen for shipping option changes to keep the Norce order synchronized:

The event name dispatched by Walley Checkout when the delivery selection changes is walleyCheckoutShippingUpdated.

document.addEventListener('walleyCheckoutShippingUpdated', async function(event) {
  const orderId = /* your Norce Checkout order ID */;
  const paymentId = /* your Norce Checkout payment ID */;
  const merchant = /* your merchant ID */;
  const channel = /* your channel ID */;
  const walleyAdapterBaseUrl = /* Walley Checkout Adapter base URL */;
  const token = /* your Norce authentication token */;

  try {
    const response = await fetch(
      `${walleyAdapterBaseUrl}/api/checkout/v1/callback/orders/${orderId}/payments/${paymentId}/shipping-option-update` +
      `?merchant=${merchant}&channel=${channel}`,
      {
        method: 'POST',
        headers: {
          'x-merchant': merchant,
          'x-channel': channel,
          'Authorization': 'Bearer ' + token
        }
      });

    if (!response.ok) {
      throw new Error(`shipping-option-update failed with status ${response.status}`);
    }
  } catch (error) {
    // Log and monitor the failure: the Norce shipping line may now be out of sync
    // with the Walley delivery selection. If useDeliveryModule is enabled and the
    // customer actually changed the delivery option, the next purchase attempt will
    // fail validation with walley-validation-shipping-mismatch until the order is
    // synchronized; otherwise the shipping line simply stays stale until then.
    console.error(error);
  }
});

Endpoint:

POST /api/checkout/v1/callback/orders/{order_id}/payments/{payment_id}/shipping-option-update?merchant={merchant}&channel={channel}

This endpoint updates the Norce order with the selected shipping option from Walley, including shipping method, shipping cost, and delivery address.

Failure to implement this event handler will result in:

  • Shipping costs not being synchronized with Norce until purchase completion
  • Order totals being incorrect due to mismatched shipping prices
  • Potential order validation failures when the order is locked during payment processing
  • Customer experiencing unexpected price differences between Walley and the order confirmation
No Request Body Required

The customer-update and shipping-option-update endpoints do not require a request body. The adapter fetches the current session state directly from Walley when called.

Required Event: Order Validation Failed (walleyCheckoutOrderValidationFailed)

Walley Checkout dispatches the walleyCheckoutOrderValidationFailed event on document when the validation callback of the Walley Checkout Adapter returns a non-2xx response, and the purchase is stopped. The most common cause is that the Norce Checkout order and the Walley Checkout session are out of sync, for example because a walleyCheckoutShippingUpdated or walleyCheckoutCustomerUpdated event was missed, or because the cart changed in another browser tab. Your frontend must handle this event, re-synchronize the Norce order, and reload its own order summary. Without this handling the customer is stuck: Walley shows a validation message, but pressing the purchase button again fails the same way.

How validation works in Walley Checkout with Norce Checkout. When the Walley Checkout Adapter initializes a Walley session it registers a validation URI on the session that points at its own validation callback:

GET /api/checkout/v1/callback/orders/{order_id}/payments/{payment_id}/validation?merchant={merchant}&channel={channel}

Walley calls this URI before completing the purchase. Walley applies a 10 second timeout, follows redirects, and may call it several times for the same order (for example when the customer fails a credit check and then pays by card instead). See the Walley documentation for Validate order and Client-side events.

What the Walley Checkout Adapter validates. The validation callback fails with HTTP 400 when any of the following checks does not pass:

  1. Walley requirements on the Norce order: currency, culture and country must be set, the cart must contain at least one item, every item must have a name, a quantity between 1 and 99999999, a non-negative VAT rate and non-negative prices, and every shipping must have a name, a non-negative VAT rate and non-negative prices.
  2. Generic Norce Checkout order validations, such as stock availability and price checks, executed through the Norce Checkout Order API.
  3. The Walley payment on the Norce order must have a payment reference (Walley privateId) and the Walley session must not have expired.
  4. The Norce order must still match the Walley session: the Norce amount to cover must equal the Walley order total, and the mapped cart must match the Walley cart on line ID, quantity and unit price. Shipping is compared as the shipping fee and the shipping name; when useDeliveryModule is enabled the comparison uses the delivery module selection on the Walley session instead of the Walley shipping fee item.

The adapter returns the failure to Walley as a custom validation error, which Walley displays inside the iframe:

{
  "title": "Unable to complete payment",
  "message": "walley-validation-shipping-mismatch"
}

Any error that is not a validation error, for example a missing Walley payment reference on the Norce order, is returned as the untranslated title Validation Error with the message An unexpected error occurred during validation. This indicates a configuration or integration problem rather than something the customer can fix, and the details are available in the adapter logs.

The title and message are resolved through the Norce Checkout Translation API for the merchant and the culture of the order. The title uses the translation key validation-walley-complete-payment-error and falls back to Unable to complete payment. The message uses the error code as translation key and falls back to the error code itself, so configure translations for the error codes listed below, otherwise the customer sees the raw error code.

The walleyCheckoutOrderValidationFailed event itself carries no error code, so the recovery guidance in the following table cannot be selected from the event: use it when you already know the error code, for example from the translated validation message that Walley shows in the iframe, from the Validation payment transaction on the Walley payment of the Norce order, or from the Walley Checkout Adapter logs. In the event handler, re-synchronize both shipping and customer data as described in the recommended frontend handling of this section.

Error code (message translation key)MeaningRecovery for this error code (not selectable from the event)
walley-validation-shipping-mismatchuseDeliveryModule is enabled and the order total differs by exactly the shipping fee difference: the shipping line on the Norce order does not match the delivery option selected in Walley.Call the shipping-option-update endpoint of the Walley Checkout Adapter, then reload your order summary.
walley-validationAny other mismatch between the Norce order and the Walley session (cart line added, removed, quantity or price changed, shipping name or fee changed without the delivery module), or the Norce order does not meet the Walley requirements listed above.Call the shipping-option-update and customer-update endpoints, reload the Norce order, and show the customer what changed in the cart.
walley-order-expiredThe Walley session has expired.Remove the existing Walley payment (POST /api/checkout/v1/orders/{order_id}/payments/{payment_id}/remove), initialize a new Walley payment for the order, and re-render the checkout iframe.
The error code of the failing Norce validator, or order-unknown-validation-errorA generic Norce Checkout order validation failed, for example an item is out of stock. The Walley Checkout Adapter forwards the error code returned by the Norce Checkout Order API validate endpoint, and uses order-unknown-validation-error when the response contains no code.Reload the Norce order and show the reason to the customer; the customer must change the cart before retrying.
order-validationThe Norce Checkout Order API validate endpoint answered with an unexpected error instead of a validation result.Reload the Norce order, let the customer retry, and check the adapter logs if it keeps failing.
No clientPayload from the Walley Checkout Adapter

The Walley Checkout Adapter returns only title and message in the validation error response, it does not return a clientPayload. The payload parameter of the walleyCheckoutOrderValidationFailed event is therefore always empty, and your frontend cannot branch on a specific error code from the event. Handle the event generically: re-synchronize the order from Walley and reload the Norce order, then let the customer retry.

Order state after a failed validation. The Walley Checkout Adapter moves the Norce order to the processing state and the Walley payment to the processing payment state only after all validation checks have passed. When validation fails, the Norce order therefore keeps its current state, normally checkout, and stays editable, so the frontend can re-synchronize it and the customer can retry the purchase without any state transition. Every validation attempt is written as a payment transaction on the Walley payment of the Norce order with the PSP event Validation, and a failed attempt carries the failure message in the error detail, which makes it possible to see afterwards why validation failed. See States for the Norce Checkout order states.

Recommended frontend handling. Before implementing the handler, ensure you have the Walley Checkout script loaded, the Norce Checkout order ID and payment ID, your merchant and channel identifiers, a valid Norce authentication token (Bearer token), and the base URL of the Walley Checkout Adapter. Because the handler calls the Norce backend while the Walley Checkout iframe is visible, suspend the iframe before the calls and resume it afterwards, as described in the Walley Client-side API documentation. Calling window.walley.checkout.api.resume() also makes Walley reload the session data.

The handler below calls both shipping-option-update and customer-update on every walleyCheckoutOrderValidationFailed event rather than only the one that actually went out of sync. That is a direct consequence of the empty event payload described above: without an error code to branch on, the handler cannot tell whether the failure was caused by the shipping selection, the customer data, or something else, so it re-synchronizes both. Calling either endpoint when nothing changed on that side is harmless — the adapter re-reads the current Walley session and writes the same data back.

document.addEventListener('walleyCheckoutOrderValidationFailed', async function(event) {
  const orderId = /* your Norce Checkout order ID */;
  const paymentId = /* your Norce Checkout payment ID */;
  const merchant = /* your merchant ID */;
  const channel = /* your channel ID */;
  const walleyAdapterBaseUrl = /* Walley Checkout Adapter base URL */;

  const token = /* your Norce authentication token */;

  // The adapter endpoints require merchant and channel as query parameters (not
  // headers). postToAdapter also sends x-merchant/x-channel headers for consistent
  // request logging, though the adapter does not require them on these endpoints.
  const callbackUrl = (action) =>
    `${walleyAdapterBaseUrl}/api/checkout/v1/callback/orders/${orderId}/payments/${paymentId}/${action}` +
    `?merchant=${merchant}&channel=${channel}`;

  // Suspend the Walley iframe while the Norce order is re-synchronized.
  window.walley.checkout.api.suspend();

  try {
    // 1. Pull the delivery selection from Walley into the Norce order
    //    (required when useDeliveryModule is enabled).
    await postToAdapter(callbackUrl('shipping-option-update'), merchant, channel, token);

    // 2. Pull the latest customer information from Walley into the Norce order.
    await postToAdapter(callbackUrl('customer-update'), merchant, channel, token);

    // 3. Re-read the Norce order and re-render your own cart and order summary,
    //    so the customer sees the same totals as Walley.
    await reloadNorceOrder(orderId);
  } catch (error) {
    // Show the customer that the checkout could not be synchronized and offer a
    // retry or a fresh checkout, and log the failure for monitoring.
    console.error(error);
  } finally {
    // 4. Resume the Walley iframe, which reloads the session and lets the
    //    customer press the purchase button again.
    window.walley.checkout.api.resume();
  }
});

postToAdapter is your own helper that sends the POST request with the x-merchant, x-channel and Authorization: Bearer {token} headers and throws when the response status is not successful, and reloadNorceOrder is your own function that reads the order from the Norce Checkout Order API and updates your cart and order summary UI. Handle failures of these calls explicitly: if the re-synchronization itself fails, the Norce order is still out of sync and the next purchase attempt fails validation again. The console.error calls in the examples are placeholders for your own error handling; log the failure for monitoring and also show the customer a message with a retry option, because the customer cannot complete the purchase until the order is synchronized.

Out-of-sync scenario: shipping selected inside the Walley delivery module. When useDeliveryModule is enabled, Walley owns the shipping selection and the Norce order only learns about it when your frontend calls the shipping-option-update endpoint of the Walley Checkout Adapter. If the customer changes the delivery option and the walleyCheckoutShippingUpdated event is missed, or the call to the adapter fails, the Norce order keeps the previous shipping fee. The validation callback then fails with walley-validation-shipping-mismatch, because the total difference is exactly the shipping fee difference. Calling the shipping-option-update endpoint after receiving walleyCheckoutOrderValidationFailed writes the Walley delivery option, its fee and the delivery address to the Norce order, updates the Norce payment amount, and the next purchase attempt succeeds.

Out-of-sync scenario: cart changed after the Walley session was created. When the Norce cart changes, the Norce Checkout Order API calls the update-payment hook of the Walley Checkout Adapter, which updates the Walley session. If that update could not be applied, for example because the Walley session was temporarily locked while the purchase was being processed (the adapter answers HTTP 423 in that case), the Walley cart still holds the old lines and validation fails with walley-validation. Reload the Norce order in your frontend, present the current cart contents and totals to the customer, and let the customer confirm before retrying. If the totals in the Walley iframe still differ from the Norce order after resuming, remove the existing Walley payment (POST /api/checkout/v1/orders/{order_id}/payments/{payment_id}/remove) and initialize a new one for the order, since Initialize rejects the same order ID while a Walley payment is still attached to it, so a new Walley session is created from the current Norce order.

A successful validation is not a completed purchase. A 2xx response from the validation callback of the Walley Checkout Adapter only means that the Norce order and the Walley session matched at that moment, and Walley may call the validation URI again for the same order, for example when the customer switches payment method after a failed credit check. The purchase is completed when Walley calls the notification callback of the Walley Checkout Adapter, which is the authoritative signal, and the adapter then confirms the payment on the Norce order. Use the client-side walleyCheckoutPurchaseCompleted event only to move your UI forward, for example to a confirmation page that reads the order from the Norce Checkout Order API, and never to trigger business-critical logic such as fulfilment or e-mail confirmations.

Do not let the customer retry blindly. The validation callback of the Walley Checkout Adapter is called on every purchase attempt. If your frontend does nothing when walleyCheckoutOrderValidationFailed is received, every attempt fails identically and the customer cannot complete the purchase. Always re-synchronize and reload before allowing another attempt, and if validation keeps failing after a re-synchronization, offer the customer a fresh checkout by removing the existing Walley payment and initializing a new one for the order — Initialize rejects an order that still has a Walley payment attached, even an expired one, so the old payment must be removed first.

Walley Checkout UI Locking During Payment Processing

When the customer initiates payment (clicks the purchase button), your checkout frontend should enter a locked state where:

  • All form inputs are disabled
  • Shipping options cannot be changed
  • Cart modifications are prevented
  • A loading indicator is displayed

This prevents race conditions where the customer might modify the order while payment is being processed, which can cause validation failures or unexpected order states.

For more details on Walley client-side events, see the Walley Checkout Client Events documentation.

Loyalty Integration

The Walley adapter automatically captures loyalty membership data from Walley orders. No configuration is required to enable this feature.

When a completed Walley order includes a loyaltyMembership on the customer object, the adapter reads this value and stores it as a Norce customer attribute with the key walleyCustomerLoyaltyMembership.

Unlike other features such as useDeliveryModule or useUpsell, there is no feature toggle for loyalty — the capture happens passively whenever Walley provides membership data on the order.

Walley API Environments

In addition to the generic Norce Adapter URLs (see Payment Adapters Overview), Walley uses the following external API environments:

EnvironmentWalley API Base URLWalley Frontend URL
Productionhttps://api.walleypay.comhttps://checkout.walleypay.com
Test (UAT)https://api.uat.walleydev.comhttps://checkout.uat.walleydev.com

Idempotency and Retries

Walley may send multiple notification callbacks for the same event. The adapter handles idempotency to ensure that duplicate notifications do not result in duplicate order processing. For detailed information about Walley's retry behavior, see the Walley Checkout documentation on Idempotency and retries.

Troubleshooting (Walley Specific)

In addition to the generic troubleshooting steps:

  • Review the order status directly in Walley's merchant portal.
  • If Capture fails, verify the Norce order is in the reserved state and that the Walley order status allows capture.
  • If Refund fails, ensure the order has been captured and has not already been returned.
  • If the customer cannot complete the purchase and Walley shows the title "Unable to complete payment", inspect the payment transactions with the PSP event Validation on the Walley payment of the Norce order. The error detail contains the exact validation failure, see the validation errors below.
  • Use the refresh call to update available payment actions:
POST /api/order/v1/orders/{order_id}/payments/{payment_id}/refresh
Host: {slug}.api-se.norce.tech
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

Error: "Order total mismatch between Norce and Walley caused by shipping selection."

The full message of the Walley Checkout Adapter is Order total mismatch between Norce and Walley caused by shipping selection. Norce: {norceAmount}, Walley: {walleyAmount}. Norce shipping: '{norceShippingOption}' {norceShippingFee}, Walley shipping: '{walleyShippingOption}' {walleyShippingFee}. Walley owns the shipping selection when the delivery module is enabled, the Norce shipping line is out of sync. and the error code returned to Walley is walley-validation-shipping-mismatch. The delivery option selected in the Walley delivery module was never written to the Norce order. Make sure the frontend calls the shipping-option-update endpoint of the Walley Checkout Adapter on the walleyCheckoutShippingUpdated event and on the walleyCheckoutOrderValidationFailed event.

Error: "Order total mismatch between Norce and Walley."

The full message of the Walley Checkout Adapter is Order total mismatch between Norce and Walley. Norce: {norceAmount}, Walley: {walleyAmount}. and the error code returned to Walley is walley-validation. The Norce amount to cover and the Walley order total differ by something other than the shipping fee, normally because the Norce cart changed without the Walley session being updated. Re-synchronize the order and, if the amounts still differ, remove the existing Walley payment and initialize a new one for the order — Initialize rejects the order while the old Walley payment is still attached.

Error: "Current Norce order does not match Walley Checkout order."

The Walley Checkout Adapter returns the error code walley-validation. The totals match, but the cart lines or the shipping line differ between the Norce order and the Walley session, for example a different line quantity, unit price or shipping name. Re-synchronize the order, reload the Norce order in the frontend, and show the customer the current cart before a new purchase attempt.