Using a Payment Provider adapter

In this tutorial, we'll learn how to configure the Klarna Checkout Adapter, create a Klarna Checkout payment, update the order and finally complete the order. The steps are very similar for most PSP adapters.

Klarna Checkout can also provide shippings using the Klarna Shipping Assistant and we'll use that in this tutorial.

Prerequisites

Before we begin, ensure the following:

  • Access to Norce Commerce.
  • Payment method Norce Checkout (239) set up.
  • Delivery method External Delivery (128) set up.
  • The Norce adapter configured in our channel.
  • A Klarna Checkout account that we can use for testing, configured with Klarna Shipping Assistant.
Note

There's no tutorial folder in the bruno collection for this tutorial. You'll still be able to find example requests in the collection, but you might have to modify them.

Preparing a Basket in Norce Commerce

  1. Create a basket
  2. Insert a basket item
  3. Set payment method to 239
  4. Set delivery method to 128

Creating an Order in Norce Checkout

Create an order by providing the basket ID, culture, and currency.

Create order

Create order requestCreate order response
Copy
Copied
POST /api/v1/orders
X-Merchant: <merchant>
X-Channel: <channel>
Authorization: Bearer <token>
Host: <slug>.api-se.playground.norce.tech/checkout/norce-adapter
Content-Type: application/json

{
  "cartReference": <basketId>,
  "culture": "sv-SE",
  "currency": "SEK"
}
Copy
Copied
201 Created
Content-Type: application/json

{
  "id": "<orderId>"
}

Configuring the Klarna Checkout adapter

Very similar to when we configured our Non-PSP adapter with the addition of apiSettings to reach our provider and some delivery related configuration since we're using Klarna Checkout to provide shipping for this example.

  • Basic configuration fields : We'll recognize fields like $schema , id , active and adapter as they are used in all configurations.
  • apiSettings : Provides the Klarna adapter with information about where and how to reach the Klarna API.
  • redirectUrls : Similar to what you might provide when using Klarna Checkout directly, where to redirect the user.
  • shippingOptions : Required for using Klarna Shipping Assistant, either as your primary delivery methods or as fallback.
  • providesShipping : If you're using Klarna Shipping Assistant, set this to true.

Set configuration

Copy
Copied
PUT /api/v1/configuration/merchants/thingsandstuff/channels/se/configurations/klarna_checkout_adapter
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/configuration
Content-Type: application/json

{
  "$schema": "https://<slug>.api-se.playground.norce.tech/checkout/klarna-adapter/openapi/v1/schemas/klarna_checkout_adapter.json",
  "id": "klarna_checkout_adapter",
  "active": true,
  "adapter": {
    "internalUrl": "https://klarna-adapter.checkout.playground.internal.norce.tech",
    "publicUrl": "https://<slug>.api-se.playground.norce.tech/checkout/klarna-adapter"
  },
  "apiSettings": {
    "apiUrl": "https://api.playground.klarna.com",
    "username": "<klarna-username>",
    "password": "<klarna-password>"
  },
  "redirectUrls": {
    "termsUrl": "https://example.com/terms",
    "checkoutUrl": "https://example.com/checkout?orderId={orderId}&merchant={merchant}&channel={channel}",
    "confirmationUrl": "https://example.com/confirmation?orderId={orderId}&merchant={merchant}&channel={channel}",
    "validationErrorUrl": "https://example.com/checkout?orderId={orderId}&merchant={merchant}&channel={channel}&error=true"
  },
  "shippingCountries": [
    "SE"
  ],
  "shippingOptions": [
    {
      "id": "thing-to-home-delivery",
      "name": "Thing to Home Delivery",
      "description": "Delivers things.",
      "price": 2000,
      "taxAmount": 400,
      "taxRate": 2500,
      "preselected": true,
      "shippingMethod": "Postal"
    },
    {
      "id": "bring-stuff",
      "name": "Bring Stuff",
      "description": "Brings stuff.",
      "price": 4000,
      "taxAmount": 800,
      "taxRate": 2500,
      "preselected": false,
      "shippingMethod": "Postal"
    }
  ],
  "providesShipping": true
}

Create a Klarna Checkout payment

When we create a payment using the Klarna adapter the only context we need to provide is the orderId.

Create payment

Create Non-psp payment requestCreate Non-psp payment response
Copy
Copied
POST /api/checkout/v1/orders/<orderId>/payments
X-Merchant: <merchant>
X-Channel: <channel>
Authorization: Bearer <token>
Host: <slug>.api-se.playground.norce.tech/checkout/klarna-adapter
Copy
Copied
200 OK
Content-Type: application/json

{
  "id": "<paymentId>",
  "status": "checkout_incomplete",
  "htmlSnippet": "<div id=\"klarna-checkout-container\" style=\"overflow: hidden;\">\n  <div id=\"klarna-unsupported-page\">\n  <style type=\"text/css\">\n  @-webkit-keyframes klarnaFadeIn{from{opacity:0}to{opacity:1}}@-moz-keyframes klarnaFadeIn{from{opacity:0}to{opacity:1}}@keyframes klarnaFadeIn{from{opacity:0}to{opacity:1}}#klarna-unsupported-page{opacity:0;opacity:1\\9;-webkit-animation:klarnaFadeIn ease-in 1;-moz-animation:klarnaFadeIn ease-in 1;animation:klarnaFadeIn ease-in 1;-webkit-animation-fill-mode:forwards;-moz-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-duration:.1s;-moz-animation-duration:.1s;animation-duration:.1s;-webkit-animation-delay:5s;-moz-animation-delay:5s;animation-delay:5s;text-align:center;padding-top:64px}#klarna-unsupported-page .heading{font-family: \"Klarna Headline\", Helvetica, Arial, sans-serif;color: rgb(23, 23, 23);font-size: 36px;letter-spacing: -0.2px;-webkit-font-smoothing: antialiased;}#klarna-unsupported-page .subheading{font-family: \"Klarna Text\", \"Klarna Sans\", Helvetica, Arial, sans-serif;color: rgb(23, 23, 23);-webkit-font-smoothing: antialiased;line-height: 28px;font-weight: 400;font-size: 19px;max-width: 640px;margin: 20px auto;}#klarna-unsupported-page .reload {cursor: pointer;outline: none;-webkit-tap-highlight-color: rgba(255, 255, 255, 0);border-width: 1px;background-color: rgb(38, 37, 37);border-color: rgb(38, 37, 37);padding: 15px 24px;margin-top: 15px;color: rgb(255, 255, 255);font-family: \"Klarna Text\", \"Klarna Sans\", Helvetica, Arial, sans-serif;font-weight: 500;text-rendering: geometricprecision;font-size: 100%;}\n  </style>\n  <h1 class=\"heading\">Something went wrong</h1>\n  <p class=\"subheading\">Sorry for any inconvenience, please try reloading the checkout page or try again later.</p>\n  <p class=\"subheading\">If the problem persists it maybe be because you are using an old version of the web browser which is not safe nor compatible with modern web sites. For a smoother checkout experience, please install a newer browser.</p>\n  <button class=\"reload\" onclick=\"reloadCheckoutHandler && reloadCheckoutHandler()\">Reload checkout</button>\n  </div>\n  <script id=\"klarna-checkout-context\" type=\"text/javascript\">\n  /* <![CDATA[ */\n  var reloadCheckoutHandler;\n  (function(w,k,i,d,n,c,l){\n    w[k]=w[k]||function(){(w[k].q=w[k].q||[]).push(arguments)};\n    l=w[k].config={\n      container:w.document.getElementById(i),\n      ORDER_URL:'https://js.playground.klarna.com/eu/kco/checkout/orders/<klarnaOrderId>',\n      AUTH_HEADER:'KlarnaCheckout excm1q49fqsanz7q83ny',\n      IS_CANARY:false,\n      IS_IN_CLIENT_ROLLOUT:false,\n      LOCALE:'<culture>',\n      ORDER_STATUS:'checkout_incomplete',\n      MERCHANT_NAME:'<yourKlarnaMerchantName>',\n      GUI_OPTIONS:[],\n      ALLOW_SEPARATE_SHIPPING_ADDRESS:false,\n      PURCHASE_COUNTRY:'<purchaseCountry>',\n      PURCHASE_CURRENCY:'<purchaseCurrency>',\n      TESTDRIVE:true,\n      BOOTSTRAP_SRC:'https://js.playground.klarna.com/kcoc/240913-60eb5ae/checkout.bootstrap.js',\n      FE_EVENTS_DISABLED:'false',      CLIENT_EVENT_HOST:'https://eu.playground.klarnaevt.com'\n    };\n    n=d.createElement('script');\n    c=d.getElementById(i);\n    n.async=!0;\n    n.src=l.BOOTSTRAP_SRC;\n    c.appendChild(n);\n    try{\n      ((w.Image && (new w.Image))||(d.createElement && d.createElement('img'))||{}).src =\n        l.CLIENT_EVENT_HOST + '/v1/checkout/snippet/load' +\n        '?sid=' + l.ORDER_URL.split('/').slice(-1) +\n        '&order_status=' + w.encodeURIComponent(l.ORDER_STATUS) +\n        '&timestamp=' + (new Date).getTime();\n    }catch(e){}\n    reloadCheckoutHandler = function () {\n        try{\n            ((w.Image && (new w.Image))||(d.createElement && d.createElement('img'))||{}).src =\n            l.CLIENT_EVENT_HOST+'/v1/checkout/snippet/reload?sid='+l.ORDER_URL.split('/').slice(-1)+\n            '&order_status='+w.encodeURIComponent(l.ORDER_STATUS)+'&timestamp='+(new Date()).getTime();\n            window.location.reload();\n        }catch(e){}\n    }\n  })(this,'_klarnaCheckout','klarna-checkout-container',document);\n  /* ]]> */\n  </script>\n  <noscript>\nPlease <a href=\"http://enable-javascript.com\">enable JavaScript</a>.\n  </noscript>\n</div>"
}

Creating a payment will trigger the following sequence:

Klarna adapter

  1. The checkout creates a payment using the Klarna adapter.
  2. The Klarna adapter retrieves its configuration.
  3. The Klarna adapter fetches the associated Norce Checkout order.
  4. The Klarna adapter maps the Norce Checkout order to a Klarna Checkout session and submits it to Klarna.
  5. The Klarna adapter maps the Klarna Checkout session details to a shipping and payment, adds them to the Norce Checkout order, and creates any necessary hooks and notifications. Finally the adapter will provide the checkout with a response containing Norce Checkout payment id as well as the Klarna Checkout session status and snippet.

If we fetch the Norce Checkout order we can see what has happened. The example response has been simplified slightly by removing some fields not relevant right now. We can see that the Klarna adapter has created a shipping for the preselected option we had in our configuration. It has also created a payment covering the full amount and we can find the Klarna Checkout session id under reference. Hooks have been added for changes to cart or state. The cart hook allows the Klarna adapter to update the Klarna Checkout session if any changes occurs and block any changes that Klarna couldn't support. The state hook allows the Klarna adapter to block changing the state back to checkout from processing, in case the payment is being processed. The adapter has also added a notification for changes to order reference, this is used after the order has been exported and a platform adapter has provided an external order id that we want to provide to Klarna Order Management.

Get order

Get order requestGet order response
Copy
Copied
GET /api/v0/checkout/orders/<orderId>
X-Merchant: <merchant>
X-Channel: <channel>
Authorization: Bearer <token>
Host: <slug>.api-se.playground.norce.tech/checkout/order
Copy
Copied
200 OK
Content-Type: application/json

{
  "id": "<orderId>",
  "merchant": "<merchant>",
  "channel": "<channel>",
  "state": {
    "currentStatus": "checkout"
  },
  "culture": "sv-SE",
  "currency": "SEK",
  "country": "SE",
  "cart": {
    "total": {
      "includingVat": 125,
      "excludingVat": 100
    }
  },
  "shippings": [
    {
      "id": "<shippingId>",
      "reference": "thing-to-home-delivery",
      "adapterId": "klarna_checkout_adapter",
      "name": "Thing to Home Delivery",
      "total": {
        "includingVat": 20,
        "excludingVat": 16
      },
      "vatRate": 0.25
    }
  ],
  "payments": [
    {
      "id": "<paymentId>",
      "reference": "<klarnaCheckoutSessionId>",
      "adapterId": "klarna_checkout_adapter",
      "name": "Klarna Checkout",
      "currency": "SEK",
      "type": "default",
      "amount": 145
    }
  ],
  "customer": {
    "billing": {
      "type": "person",
      "country": "SE"
    },
    "shipping": {
      "type": "person",
      "country": "SE"
    },
    "type": "person"
  },
  "hooks": [
    {
      "id": "ohUhSjyzUNhXjXMPyksikMbaoUgC",
      "adapterId": "norce_adapter",
      "subscribeTo": "/shippings",
      "invoke": "https://norce-adapter.checkout.test.internal.norce.tech/api/v1/orders/<orderId>/shipping-changed"
    },
    {
      "id": "ohaDfQzgQcXQxdPvgOEEPDIqtCsZ",
      "adapterId": "norce_adapter",
      "subscribeTo": "/state",
      "invoke": "https://norce-adapter.checkout.test.internal.norce.tech/api/v1/orders/<orderId>/state-changed"
    },
    {
      "id": "ohKetDTqlTMKwoqqOtMYEfVWoIeW",
      "adapterId": "norce_adapter",
      "subscribeTo": "/customer",
      "target": "/cart",
      "invoke": "https://norce-adapter.checkout.test.internal.norce.tech/api/v1/orders/<orderId>/customer-changed"
    },
    {
      "id": "ohsfgpBlSgGJpXDIlCYbHZZyrdKS",
      "adapterId": "klarna_checkout_adapter",
      "subscribeTo": "/state",
      "target": "/payments",
      "invoke": "https://klarna-adapter.checkout.test.internal.norce.tech/api/checkout/v1/callback/orders/<orderId>/payments/<paymentId>/state-changed"
    },
    {
      "id": "ohhMQmyZuKeWCwdwFmEPUwXMnHkO",
      "adapterId": "klarna_checkout_adapter",
      "subscribeTo": "/cart",
      "target": "/payments",
      "invoke": "https://klarna-adapter.checkout.test.internal.norce.tech/api/checkout/v1/callback/orders/<orderId>/payments/<paymentId>/cart-changed"
    }
  ],
  "notifications": [
    {
      "id": "onqItrNSwvdQptxwLXLEkGGaSQqU",
      "adapterId": "norce_adapter",
      "reference": "018f1459-c8e5-7aef-a4c5-cd7a60bc7c57",
      "description": "Complete payment on Completed",
      "scope": "/state/currentStatus",
      "schema": {
        "enum": [
          "completed"
        ]
      },
      "invoke": "https://norce-adapter.checkout.test.internal.norce.tech/api/v1/orders/<orderId>/export-order"
    },
    {
      "id": "onKPbXfSZilHwQiUydFVTDYHXJpz",
      "adapterId": "klarna_checkout_adapter",
      "scope": "/reference",
      "invoke": "https://klarna-adapter.checkout.test.internal.norce.tech/api/checkout/v1/callback/orders/<orderId>/payments/<paymentId>/reference-changed"
    }
  ],
  "total": {
    "includingVat": 145,
    "excludingVat": 116
  }
}

Render Checkout snippet

Having received the Klarna Checkout session snippet we can render it in our checkout. You can find out more about how to do this properly in the Klarna Documentation.

Quick test

attention

Rendering the snippet in this way can be quite shaky, often resulting in weird timeouts and glitches.

A workaround you can use to try this out quickly is visiting the undocumented testing endpoint on our adapter in your browser or a rest client that supports rendering html with javascript (bruno currently does not support this.)

Copy
Copied
https://<slug>.api-se.playground.norce.tech/checkout/klarna-adapter/api/checkout/v1/orders/<orderId>/payments/<paymentId>/html
X-Merchant: <merchant>
X-Channel: <channel>
Authorization: Bearer <token>

Using a browser

We need an extension that allows us to set headers. Using your favorite search engine, you're likely to find one that works with your browser of choice. Create a rule for any request for the host <slug>.api-se.playground.norce.tech to add the headers x-merchant, x-channel, and Authorization: Bearer <token>. Visit the url and the snippet should render.

Using a rest client

There are several online rest clients that uses ajax to make the request from your browser but still supports rendering the response, restninja.io is one such example. Simply provide the url, the headers and your auth and make a GET request. The snippet should render.

Whatever option we use to render the snippet, we'll notice that it has a direct effect on our Norce Checkout order. Following this sequence:

Klarna adapter

  1. The Klarna snippet is rendered and fetches shipping options available for this customer. The default shipping option is selected. Klarna invokes the shipping changed callback.
  2. The Klarna adapter retrieves its configuration.
  3. The Klarna adapter fetches the associated Norce Checkout order, updates it with the new shipping option and updates the amount covered in its payment based on the new order total. It responds to klarna with the updated amount.

We can fetch the order to see these changes. Again, in the response example below we've removed parts not relevant right now. We see that the shipping has been updated with a new delivery method. This is because our Klarna account is set up to use a Transport management system through Klarna, providing other options than the ones we configured as fallback. Since this new option has no cost, the payment is updated with a new amount.

Get order post render requestGet order poset render response
Copy
Copied
GET /api/v0/checkout/orders/<orderId>
X-Merchant: <merchant>
X-Channel: <channel>
Authorization: Bearer <token>
Host: <slug>.api-se.playground.norce.tech/checkout/order
Copy
Copied
200 OK
Content-Type: application/json

{
  "cart": {
    "total": {
      "includingVat": 125,
      "excludingVat": 100
    }
  },
  "shippings": [
    {
      "id": "<shippingId>",
      "reference": "option-607-37073|37007",
      "adapterId": "klarna_checkout_adapter",
      "name": "PostNord MyPack",
      "total": {
        "includingVat": 0,
        "excludingVat": 0
      },
      "vatRate": 0,
      "deliveryDetails": {
        "carrier": "postnord",
        "class": "standard"
      }
    }
  ],
  "payments": [
    {
      "id": "<paymentId>",
      "reference": "ddb3baca-8a70-49d4-bac2-335a807fc63b",
      "adapterId": "klarna_checkout_adapter",
      "name": "Klarna Checkout",
      "currency": "SEK",
      "type": "default",
      "amount": 125
    }
  ],
  "total": {
    "includingVat": 125,
    "excludingVat": 100
  }
}

Provide customer information

Using the snippet we can now provide some customer information. Klarna will inform the adapter with a callback and the order is updated with any customer information.

Change shipping option

Same thing as when we first rendered the snippet, this will trigger a shipping changed callback to our adapter.

Clicking "buy"

When we click the buy button Klarna will ask the adapter to validate the order before proceeding. The adapter will change the order status to processing triggering the following sequence (we'll skip the step where adapters fetch their configuration):

Klarna adapter processing

  1. Klarna sends a request to validate the order.
  2. The Klarna adapter fetches the order, validates that it matches the Klarna Checkout Session and changes the order status to processing .
  3. The order service calls the Norce adapter status hook.
  4. The Norce adapter fetches the Norce Commerce basket and validates that it matches the Norce Checkout order, it then validates the payment in Norce Commerce and accepts the status change. The Klarna adapter will in turn accept the validation callback.

Confirming the purchase

If we complete the process and confirm the payment Klarna will redirect the user to the Klarna adapter, triggering this massive sequence:

Klarna adapter completed

  1. Klarna redirects the user to the Klarna adapter.
  2. The Klarna adapter acknowledges the payment in Klarna, triggering a Klarna Order to be created.
  3. The adapter fetches the Klarna Order from the Klarna Order Management API.
  4. The adapter updates the shipping with any additional information provided by the TMS and updates the payment with any additional information and maps the current payment state. Seeing that the Klarna order is already authorized, the adapter changes the order state to completed (in effect changing it first to accepted and then completed ).
  5. Since the Norce adapter has registered a notification for state being changed to completed a notification is created.
  6. The Klarna adapter redirects the user to the confirmation page.
  7. The notification service calls the Norce adapter to inform it that the state has been changed to completed .
  8. The Norce adapter completes the payment in Norce Commerce, triggering the basket to become an order.
  9. The Norce adapter updates the order reference to the newly created Norce Commerce order id.
  10. The order service creates a notification to inform the Klarna adapter that reference has been updated.
  11. The notification service calls the Klarna adapter to inform it that the reference has been updated.
  12. The Klarna adapter sets the merchant reference in the Klarna Order Management API.

(Norce adapter is not interested in hooks for state changes to accepted or completed.)

Power of notifications

The user was redirected to the confirmation page early in this sequence and did not need to wait for everything else.

Fetching the order again we'll see some of this new information we talked about.

  • We've received an order reference with the Norce Commerce order id.
  • The order state has transitions to completed .
  • The shipping has received a tms reference as well as an exact pick-up location.
  • The payment now has three payment actions available. The order service does not provide an enum for the different types, instead these reflect the actions the PSP provide for this payment.
    • Cancel : Called to cancel the payment in Klarna and update the payment in Norce Checkout.
    • Capture : Called to capture the payment in Klarna and update the payment in Norce Checkout.
    • Refresh : Refreshes available actions on the payment, useful if you expect to do some actions through the provider directly.
Get completed order requestGet completed order response
Copy
Copied
GET /api/v0/checkout/orders/<orderId>
X-Merchant: <merchant>
X-Channel: <channel>
Authorization: Bearer <token>
Host: <slug>.api-se.playground.norce.tech/checkout/order
Copy
Copied
200 OK
Content-Type: application/json

{
  "id": "<orderId>",
  "reference": "<norceCommerceOrderId>",
  "state": {
    "currentStatus": "completed",
    "transitions": [
      {
        "status": "checkout"
      },
      {
        "status": "processing"
      },
      {
        "status": "accepted"
      },
      {
        "status": "completed"
      }
    ]
  },
  "cart": {
    "reference": "<basketId>",
    "total": {
      "includingVat": 125,
      "excludingVat": 100
    }
  },
  "shippings": [
    {
      "id": "<shippingId>",
      "reference": "<shippingReference>",
      "tmsReference": "<tmsReference>",
      "adapterId": "klarna_checkout_adapter",
      "name": "PostNord MyPack",
      "total": {
        "includingVat": 0,
        "excludingVat": 0
      },
      "vatRate": 0,
      "deliveryDetails": {
        "carrier": "postnord",
        "class": "standard",
        "product": {},
        "pickupLocation": {
          "reference": "<pickupLocationId>",
          "name": "...",
          "address": {
            "streetAddress": "...",
            "city": "...",
            "postalCode": "..",
            "country": "se"
          }
        }
      }
    }
  ],
  "payments": [
    {
      "id": "<paymentId>",
      "reference": "<klarnaCheckoutSessionId>",
      "adapterId": "klarna_checkout_adapter",
      "name": "Klarna Checkout",
      "currency": "SEK",
      "type": "default",
      "amount": 125,
      "state": "reserved",
      "actions": [
        {
          "adapterId": "klarna_checkout_adapter",
          "type": "Cancel",
          "url": "https://klarna-adapter.checkout.test.internal.norce.tech/api/order/v1/orders/<orderId>/payments/<paymentId>/cancel"
        },
        {
          "adapterId": "klarna_checkout_adapter",
          "type": "Capture",
          "url": "https://klarna-adapter.checkout.test.internal.norce.tech/api/order/v1/orders/<orderId>/payments/<paymentId>/capture"
        },
        {
          "adapterId": "klarna_checkout_adapter",
          "type": "Refresh",
          "url": "https://klarna-adapter.checkout.test.internal.norce.tech/api/order/v1/orders/<orderId>/payments/<paymentId>/refresh-kco"
        }
      ]
    }
  ],
  "customer": {
    "billing": {
      "type": "person",
      "givenName": "...",
      "familyName": "...",
      "streetAddress": "...",
      "streetAddress2": "",
      "postalCode": "...",
      "city": "...",
      "region": "",
      "country": "SE",
      "phone": "...",
      "email": "...",
      "attributes": {
        "dateOfBirth": "..."
      }
    },
    "shipping": {
      "type": "person",
      "givenName": "...",
      "familyName": "...",
      "streetAddress": "...",
      "streetAddress2": "",
      "postalCode": "...",
      "city": "...",
      "region": "",
      "country": "SE",
      "phone": "...",
      "email": "...",
      "attributes": {
        "dateOfBirth": "..."
      }
    },
    "type": "person"
  },
  "total": {
    "includingVat": 125,
    "excludingVat": 100
  }
}

Next Steps

In this tutorial, we've walked through configuring and using the Klarna Checkout Adapter, setting up payments, and leveraging the Klarna Shipping Assistant for managing shipping options. From creating a basket in Norce Commerce to configuring payment and delivery methods, we covered the full integration process. We also demonstrated how to render the Klarna Checkout snippet, handle shipping updates, and complete the purchase flow. The Klarna adapter effectively manages shipping and payment updates within Norce Checkout, with notifications and hooks ensuring seamless synchronization between the systems for order validation and completion.

Next, we'll look at how to add custom notifications to our checkout. Building on the previous tutorial, we'll explore how to configure a notification that triggers when an order is completed.

Copyright © Norce 2024. All right reserved.