Klarna Payments

Last updated

Klarna Payments is a PSP solution designed to incorporate Klarna's payment methods to existing checkout. By integrating with Klarna Payments, merchants retain control over the checkout experience, while also offering customers the convenience of Klarna's payment options to finalize their purchases.

Klarna Payments vs Klarna Checkout - ownership of the integration components#

Klarna Payments is an addition of payment methods to the existing merchant checkout, while Klarna Checkout is a complete checkout solution provided by Klarna including address collection. While the same payment methods are available in both solutions, there are differences in ownership of the components of the integration.

Integration ComponentOwnership in Klarna CheckoutOwnership in Klarna PaymentsComments
Address CollectionKlarnaFrontend
B2B customer information collectionKlarnaFrontend
Customer national identification number collectionKlarnaKlarnaRequired for certain payment methods e.g. credit
Payment MethodsKlarnaKlarna
Payment widget handling (display/lock/unlock)Frontend via CentraCheckoutScriptFrontend
Klarna session API IntegrationCentraCentra
Klarna order API IntegrationCentraCentra
Klarna server side callback handlingCentraCentra

Klarna Payments vs Klarna Checkout - supported use cases#

Use CaseKlarna PaymentsKlarna CheckoutComments
Age verificationNoYes
SubscriptionsNoYes
B2B CheckoutYesYes
Paypal in Klarna as external payment methodNoYes
Post-purchase cross-sellNoYes
Customer gender and birthdate collectionNoYes
Sending product imagesYesYes
Sending product sizesYesYes
Payment method costYesYes
US Tax calculation in the checkoutOnly in multistep checkout implementationMultistep checkout implementation or through address update callback
Validation callbackNoYesAllows for additional validations in late stage of the checkout when payment is submitted by customer e.g. additional stock check

Store plugin configuration#

//a.storyblok.com/f/233206/f4a152b3d2/store_plugin.png

Required configuration#

To ensure that Klarna Payments plugin is properly set up for testing fill in following configuration options:

  • Status - set status to Active
  • Plugin name - Name of the plugin
  • Name in frontend - Name of the plugin returned by the API
  • URI - Plugin identifier. Make sure that you're assigning a unique URI to the store plugin, especially if you're using multiple Klarna Payments plugins with plugin restrictions.
  • Secret - Set up to your MID configuration
  • E-Store ID - Linked to your MID
  • Klarna endpoint - Should point towards proper region as per your MID configuration

Testing#

For testing, set Test mode to Yes

//a.storyblok.com/f/233206/e19e70779c/test_mode.png

Available configuration options#

  • Default locale - Default locale sent to Klarna when payment session is initiated when Centra cannot match any locale on customer/basket level.
  • Send product images to Klarna
  • Product image size
  • Send product URLs to Klarna
  • Frontend prefix for product URLs
  • Send product sizes to Klarna

APIs used in the integration#

//a.storyblok.com/f/233206/1a046947e7/integration_apis.png

API references:

Authorization flow#

Checkout initialization#

Checkout initialization starts with POST /payment call which returns all data required to make a payment with Klarna Payments.

//a.storyblok.com/f/233206/ed0acdcc43/checkout_init.png

  1. POST /payment Shop API/Checkout API request
  2. Centra creates session with Klarna and responds to Frontend with client_token
  3. Frontend calls SDK.init() with client_token obtained from POST /payment response
  4. Frontend calls SDK.load() and Klarna Payments widget is presented to the shopper in the proper container
  5. Klarna Payments widget is displayed on the checkout page

Example POST /payment response:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 { "action": "form", "formType": "klarna-payments", "formFields": { "client_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJzZXNzaW9uX2lkIiA6ICIw", "authorizePayload": { "purchase_country": "SE", "purchase_currency": "SEK", "locale": "sv-SE", "order_amount": 20000, "order_tax_amount": 4000, "order_lines": [ { "type": "physical", "reference": "123_1", "name": "Brand Test Product Red", "quantity": 2, "unit_price": 10000, "tax_rate": 2500, "total_amount": 20000, "total_discount_amount": 0, "total_tax_amount": 4000 } ], "billing_address": { "given_name": "Test Billing", "family_name": "Testson Billing", "email": "abc123@example.com", "street_address": "Address One", "street_address2": "Address Two", "postal_code": "12345", "city": "Malmo", "region": "", "phone": "123456789", "country": "SE" }, "shipping_address": { "given_name": "Test Billing", "family_name": "Testson Billing", "email": "abc123@example.com", "street_address": "Address One", "street_address2": "Address Two", "postal_code": "12345", "city": "Malmo", "region": "", "phone": "123456789", "country": "SE" }, "customer": { "type": "person" } } } }

Authorization and order placement#

Authorization starts when customer decides to proceed to payment with Klarna Payments as a payment method. At this point frontend calls authorize() function from Klarna Payments SDK with the payload received from Centra. Payload required for that call is available on POST /payment response under response.formFields.authorizePayload. If any updates happen to selection state after POST /payment call, authorizePayload will be updated and available on every selection response while Klarna Payments is set as a paymentMethod on the selection. For the payment to succeed it is crucial to ensure that the authorizePayload used for authorize() call is up-to-date with the latest selection state.

//a.storyblok.com/f/233206/81355deaad/authorisation.png

  1. Customer proceeds to payment with Klarna Payments.
  2. Frontend calls SDK.authorize(authorizePayload).
  3. SDK.authorize() callback is fired with authorization_token as a parameter.
  4. Klarna Payments pop-up window is opened.
  5. Shopper signs in to Klarna, provides payment details and confirms the payment in pop-up window..
  6. Shopper is redirected to paymentSuccessPage.
  7. Frontend calls POST /payment-result Centra endpoint with authorization_token to finalize authorization and place an order in Centra. POST payment-result
1 2 3 4 5 { "paymentMethodFields": { "authorization_token": "abcde2d-1234-567d-bfc9-27a3d0dc396c" } }
  1. Centra creates order in Klarna using authorization_token received from the Frontend - customer is charged at this moment.
  2. Centra responds to Frontend with order response and parameters from Klarna including redirect_url.
  3. Frontend uses response.order.paymentMethodData.redirect_url to redirect Shopper to payment success page.

Error handling

To properly handle user interaction with the widget on the Frontend side and error handling, refer to following Klarna guides:

Handling updates in the checkout#

This section refers to any kind of update that happens in the checkout, which means that session has been already initiated with Klarna Payments via POST /payment endpoint. This includes:

  • Item quantity updates
  • Selection line updates
  • Address updates
  • Applying/removing voucher
  • Selection country update

//a.storyblok.com/f/233206/b62f77da78/updates_in_the_checkout.png

After choosing Klarna Payments as the selection's payment method and initializing the payment, Klarna Payments session will be created. Each selection response will now contain an object at path selection.pluginFields.klarnaPayments. This means there is no need for additional API calls to fetch the required payment data when the checkout is updated.

The object will include all the fields that are required to display or reload the payment widget and start the authorization process:

  • client_token - Required to call SDK.init(client_token) that initiates SDK library
  • replaceSnippet - Indicates whether SDK needs to be reinitialized by calling SDK.init(client_token) again
  • authorizePayload - Payload required for the authorization call SDK.authorize(authorizePayload). Authorization process will be described in detail in the next section.

Here's an example of klarnaPayments object on the selection response:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 { "selection": { "pluginFields": { "klarnaPayments": { "client_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjgyMzA1ZWJjLWI4MTasasEtMzYzNy1..CbYhjSt---1dzmTgvo3vDRA", "replaceSnippet": false, "authorizePayload": { "purchase_country": "se", "purchase_currency": "sek", "locale": "sv-SE", "order_amount": 20000, "order_tax_amount": 4000, "order_lines": [ { "name": "Brand Test Product Red", "quantity": 2, "reference": "123_1", "tax_rate": 2500, "total_amount": 20000, "total_discount_amount": 0, "total_tax_amount": 4000, "type": "physical", "unit_price": 10000 } ], "billing_address": { "given_name": "Test Billing", "family_name": "Testson Billing", "email": "abc123@example.com", "street_address": "Address One", "street_address2": "Address Two", "postal_code": "12345", "city": "Malmo", "region": "", "phone": "123456789", "country": "SE" }, "shipping_address": { "given_name": "Test Billing", "family_name": "Testson Billing", "email": "abc123@example.com", "street_address": "Address One", "street_address2": "Address Two", "postal_code": "12345", "city": "Malmo", "region": "", "phone": "123456789", "country": "SE" } } } } } }

Reinitialization of the payment widget

Once a Klarna Payments widget has been displayed on the checkout page, on every update to selection listen to klarnaReplaceSnippet field indicating whether the SDK needs to be reinitialized. Following code snippet is an example of how to properly handle klarnaReplaceSnippet flag on the selection response.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 function handleKlarnaReplaceSnippet(response) { const klarnaReplaceSnippet = response.selection.pluginFields.klarnaPayments.replaceSnippet; if (klarnaReplaceSnippet === false) { Klarna.Payments.load( { container: '#payment-container', payment_method_category: 'klarna' }, function (res) { console.log('Klarna Payments widget loaded without re-initialization'); } ); } else { document.getElementById('payment-container').innerHTML = ''; //clear old one entirely Klarna.Payments.init( { client_token: response.selection.pluginFields.klarnaPayments.client_token } ); Klarna.Payments.load( { container: '#payment-container', payment_method_category: 'klarna' }, function () { console.log('Klarna Payments widget loaded with re-initialization after client_token update'); } ); } }

Best practices#

Locking the payment widget during selection updates in the Checkout#

As shown on the below diagram, once session with Klarna has been initialized, whenever selection is updated in the checkout using Shop API/Checkout API endpoints, Centra sends session updates to Klarna. It's important to prevent customer from finalizing the payment during the time in which the update is being processed by Centra and Klarna. In case of Klarna Payments integration this kind of locking needs to be implemented on the Frontend side by making the widget non-interactive during the processing of the update.

This ensures that there is no inconsistencies between what customer has paid for and the order is placed in Centra.

//a.storyblok.com/f/233206/7e2550e3c6/locking_checkout_for_updates.png

Collecting customer address data#

Klarna Payments uses customer address data for fraud prevention and to determine available payment options. This data must be included in the SDK.authorize() call. The formatted payload for this call comes from selection.pluginFields.klarnaPayments.authorizePayload in the selection response. It's crucial to ensure that all customer data is correctly filled in and sent to Centra before the customer proceeds to payment. This ensures that the authorizePayload on the selection matches the checkout state.

There are two possible implementation scenarios:

  • Multistep checkout: In this case, customers must provide all their address data before they can view available payment methods or proceed to payment.
  • Single step checkout: Here, customers are shown available payment methods, including the Klarna Payments widget, as soon as the checkout page loads. However, the widget remains locked until all address data is correctly filled in.

Handling multiple tabs scenario#

After proceeding to checkout page, the customer might open a 2nd browser tab, modify the selection and proceed to the checkout. This would cause a new payment session to be created with a different client_token and authorizePayload than the one from the original tab.

Here are potential steps that customer may take:

  1. Customer opens the checkout page in the first tab and proceeds to payment with Klarna Payments.
  2. Customer opens the 2nd tab and modifies the selection.
  3. Customer proceeds to checkout page in the 2nd tab.
  4. New payment session is created with new client_token and authorizePayload.
  5. Customer goes back to the first tab and proceeds to payment with Klarna Payments.

To ensure that the customer proceeds to payment with the up-to-date client_token and authorizePayload and there's no errors during payment, keep track of the Klarna Payments session state between tabs.

When customer reopens previously initialized checkout with Klarna Payments, you have to make sure state between tabs is synchronized. Fetch selection and up-to-date Klarna Payments pluginFields and if client_token has changed, reinitialize SDK and reload the widget using new client_token as described in: Reinitialization of the payment widget.

Onsite messaging#

Onsite messaging is a way to inform customers about Klarna's payment methods availability before they reach the checkout. Integration of onsite messaging is outside of Centra's integration scope, however it can be integrated from the client side.

This guide provides step-by-step integration instructions.