External Payment Methods & Use Cases
These are examples of use cases that allow you to customize the buying experience with Klarna Checkout for your needs.
External Payment Methods & Use Cases
These are examples of use cases that allow you to customize the buying experience with Klarna Checkout for your needs. Klarna offers all payment methods in the Klarna Checkout smoothly and simply integrated. In addition to these, we support all major payment methods in Sweden such as Swish, Paypal & other external payment methods in Sweden.
External Payment Methods & Use Cases
These are examples of use cases that allow you to customize the buying experience with Klarna Checkout for your needs. Klarna offers all payment methods in the Klarna Checkout smoothly and simply integrated. In addition to these, we support major payment methods in Norway such as Vipps, Paypal & other external payment methods in Norway.
Additional payment methods in Klarna Checkout
Note: To use this feature, you will need an agreement that defines what payment methods that you will use.
This feature enables you to use Klarna Checkout for additional payment methods that are currently not offered by Klarna. This means that you will be able to offer one great checkout experience, regardless of how the consumer wants to pay.
How does it work?
When the Checkout is loaded, you have the option to load additional payment methods. “Wallets” are shown as buttons in the bottom of KCO and available from the moment KCO loads. Clicking the button will make the customer leave KCO and be redirected to an external payment window to complete the purchase, e.g. to PayPal.
In cases when the customer needs to choose payment method before completing the purchase, all payment methods including wallets will be shown in the payment selection list together with our standard offering. You can use all information the consumer has entered in KCO to complete the purchase with another payment method.
Please note that when a consumer is using a payment method not offered by default, no purchase order is created by Klarna. Klarna doesn’t know whether the consumer eventually finishes the purchase after leaving the checkout. Klarna doesn’t send any kind of confirmation emails or handle any money. All processing of the order is the merchant’s responsibility.
How to implement
The payment methods are classified as either External Payment Methods or External Checkouts. For External Payment Methods, you want to collect address data about the consumer via Klarna Checkout (e.g. Nachnahme). For External Checkouts, you don’t need Klarna Checkout to collect data about the consumer (e.g. PayPal)
Note: For Amazon Pay and PayPal you have both external_payment_method
or external_checkout
to make sure that they appear in all payment flows.
Code example
The payment methods are defined when calling the Klarna Checkout. The payment methods will be presented in the checkout in the order they are set in the API call, after the default options provided by Klarna.
Parameters
Additional payment methods in Klarna Checkout
This feature enables you to use Klarna Checkout for additional payment methods that are currently not offered by Klarna. This means that you will be able to offer one great checkout experience, regardless of how the consumer wants to pay.
Note: Integrating new payment methods requires additional integration work and since this payment method will be processed and finalized outside Klarna checkout you will also need to cater for some of the payment flows, both frontend and backend. See examples of additional integration steps below:
- To use this feature, you will need an agreement that defines what payment methods that you will use.
- Since external payments take place outside Klarna checkout, no user data will be shared for this purchase. You/the external payment method will need to cater for that so all relevant user data to finalize the purchase (e.g. address, name, etc.) is collected.
- You will need to host your own “thank you page” since this purchase will take place outside Klarna checkout.
- New backend integration towards the external payment method will be required.
- Given that this is an external payment, Klarna’s buyer protection will not apply for your consumers.
- The upside of using external payment methods in Klarna checkout is that you will be able to offer a smoother user experience regardless of payment alternative.
How does it work?
When the Checkout is loaded, you have the option to load additional payment methods. “Wallets” are shown as buttons in the bottom of KCO and available from the moment KCO loads. Clicking the button will make the customer leave KCO and be redirected to an external payment window to complete the purchase, e.g. to Swish.
All payment methods including wallets will be shown in the payment selection list together with our standard offering.
Please note that when a consumer is using a payment method not offered by default, no purchase order is created by Klarna. Klarna doesn’t know whether the consumer eventually finishes the purchase after leaving the checkout. Klarna doesn’t send any kind of confirmation emails or handle any money. All processing of the order is the merchant’s responsibility.
How to implement
The payment methods are classified as either External Payment Methods or External Checkouts. For External Payment Methods, the user will enter in their consumer data via Klarna Checkout (e.g.Swish) in order to checkout with an external payment method. For External Checkouts, you don’t need Klarna Checkout to collect data about the consumer (e.g. Swish or Paypal).
Note: For Swish and PayPal you have both external_payment_method
or external_checkout
to make sure that they appear in all payment flows. You are responsible for the completion of the purchase flow including the e.g. address collection and confirmation page.
Code example
The payment methods are defined when calling the Klarna Checkout. The payment methods will be presented in the checkout in the order they are set in the API call, after the default options provided by Klarna.
Parameters
Additional payment methods in Klarna Checkout
This feature enables you to use Klarna Checkout for additional payment methods that are currently not offered by Klarna. This means that you will be able to offer one great checkout experience, regardless of how the consumer wants to pay.
Note: Integrating new payment methods requires additional integration work and since this payment method will be processed and finalized outside Klarna checkout you will also need to cater for some of the payment flows, both frontend and backend. See examples of additional integration steps below:
- To use this feature, you will need an agreement that defines what payment methods that you will use.
- Since external payments take place outside Klarna checkout, no user data will be shared for this purchase. You/the external payment method will need to cater for that so all relevant user data to finalize the purchase (e.g. address, name, etc.) is collected.
- You will need to host your own “thank you page” since this purchase will take place outside Klarna checkout.
- New backend integration towards the external payment method will be required.
- Given that this is an external payment, Klarna’s buyer protection will not apply for your consumers.
- The upside of using external payment methods in Klarna checkout is that you will be able to offer a smoother user experience regardless of payment alternative.
How does it work?
When the Checkout is loaded, you have the option to load additional payment methods. “Wallets” are shown as buttons in the bottom of KCO and available from the moment KCO loads. Clicking the button will make the customer leave KCO and be redirected to an external payment window to complete the purchase, e.g. to Vipps.
All payment methods including wallets will be shown in the payment selection list together with our standard offering.
Please note that when a consumer is using a payment method not offered by default, no purchase order is created by Klarna. Klarna doesn’t know whether the consumer eventually finishes the purchase after leaving the checkout. Klarna doesn’t send any kind of confirmation emails or handle any money. All processing of the order is the merchant’s responsibility.
How to implement
The payment methods are classified as either External Payment Methods or External Checkouts. For External Payment Methods, the user will enter in their consumer data via Klarna Checkout (e.g. Vipps) in order to checkout with an external payment method. For External Checkouts, you don’t need Klarna Checkout to collect data about the consumer (e.g. Vipps or Paypal).
Note: For Swish and PayPal you have both external_payment_method
or external_checkout
to make sure that they appear in all payment flows. You are responsible for the completion of the purchase flow including the e.g. address collection and confirmation page.
Code example
The payment methods are defined when calling the Klarna Checkout. The payment methods will be presented in the checkout in the order they are set in the API call, after the default options provided by Klarna.
Parameters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
"external_payment_methods": [ { "name": "Cash on delivery", // Mandatory "redirect_uri": "https://…", // Mandatory. HTTPS. Page for completing the purchase. "image_uri": "https://…", // Optional. HTTPS. Exact size: 69x24px "fee": 1450 // Optional fee added to the order. "description": "Lorem.." // Optional. 500 character limit. Links can be set with the Markdown syntax [Text](URL) } ], "external_checkouts": [ { "name": "Non Klarna eWallet", // Mandatory "redirect_uri": "https://…", // Mandatory. HTTPS. Page for completing the purchase. "image_uri": "https://…", // Mandatory. HTTPS. Exact size: 276x48px "fee": 1450 // Optional fee added to the order. } ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
$create['external_payment_methods'][] = [ 'name' => 'Cash on delivery', 'redirect_uri' => 'https://example.com/payment', 'image_uri' => 'https://example.com/image', 'fee' => 1450, 'description' => 'Lorem..' ]; $create['external_checkouts'][] = [ 'name' => 'Non Klarna eWallet', 'redirect_uri' => 'https://example.com/checkout', 'image≈‹' => 'https://example.com/image', 'fee' => 1450 ];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
external_payment_methods = [ { 'name': 'Cash on delivery', 'redirect_uri': 'https://example.com/payment', 'image_uri': 'https://example.com/image', 'fee': 1450, 'description': 'Lorem...' } ] external_checkouts = [ { 'name': 'Non Klarna eWallet', 'redirect_uri': 'https://example.com/checkout', 'image_uri': 'https://example.com/image', 'fee': 1450 } ] create_data['external_payment_methods'] = external_payment_methods create_data['external_checkouts'] = external_checkouts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Dim externalPaymentMethod Set externalPaymentMethod = Server.CreateObject("Scripting.Dictionary") externalPaymentMethod.Add "name", "Cash on delivery" externalPaymentMethod.Add "redirect_uri", "https://example.com/payment" externalPaymentMethod.Add "image_uri", "https://example.com/image" externalPaymentMethod.Add "fee", 1450 externalPaymentMethod.Add "description", "Lorem.." Dim externalPaymentMethods(0) Set externalPaymentMethods(0) = externalPaymentMethod Dim externalCheckout Set externalCheckout = Server.CreateObject("Scripting.Dictionary") externalCheckout.Add "name", "Cash on delivery" externalCheckout.Add "redirect_uri", "https://example.com/checkout" externalCheckout.Add "image_uri", "https://example.com/image" externalCheckout.Add "fee", 1450 Dim externalCheckouts(0) Set externalCheckouts(0) = externalCheckout data.Add "external_payment_methods", externalPaymentMethods data.Add "external_checkouts", externalCheckouts
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
var externalPaymentMethods = new List<Dictionary<string, object>> { new Dictionary<string, object> { { "name", "Cash on delivery" }, { "redirect_uri", "https://example.com/payment" }, { "image_uri", "https://example.com/image" }, { "fee", 1450 }, { "description", "Lorem.." } } }; var externalCheckouts = new List<Dictionary<string, object>> { new Dictionary<string, object> { { "name", "Non Klarna eWallet" }, { "redirect_uri", "https://example.com/payment" }, { "image_uri", "https://example.com/image" }, { "fee", 1450 } } }; data.Add("external_payment_methods", externalPaymentMethods); data.Add("external_checkouts", externalCheckouts);
List of External Payment Methods supported in KCO
We support a wide range of external payment methods in Klarna Checkout. The following list displays the external payment methods we support:
- Achteraf betalen
- Amazon Pay
- Giropay
- Google Wallet
- iDeal
- Lastschrift
- PayPal
- Postförskott
- SOFORT Überweisung
- Swish
- Vipps
Legal Requirements
To be compliant, you have a contractual obligation to have an agreement between you and the external payment method providers (e.g. Swish and Paypal).
Reconciliation of Swish transactions
To simplify your bookkeeping, Klarna wants to provide a complete reporting offering.
However, as Swish has a slightly different setup compared to our other available payment methods you will need to do some changes in your reconciliation process.
What separates Swish from our other payment method is that the money from a Swish transaction will be paid out immediately and separately compared to Klarna’s aggregated payout.
New variables
Reconciliation of Swish transactions will require new variables to be included in your settlement reports.
Settled by:
Klarna - Paid out by Klarna
Swish as an External Payment Method - Paid out by Swish
External reference
The reference that will appear on your bank account, set and controlled by Swish.
Klarna reference
A reference number that Klarna sets and controls. This may may or may not appear on your bank account depending on which bank you are using.
New transaction types
Reconciliation of Swish transactions will require new transaction types to be included in your settlement reports.
External payout capture
Represents the transfer of money from consumer to merchant through Swish scheme upon purchase completion in the checkout
External payout refund
Represents the transfer of money from merchant to consumer through Swish scheme upon return/chargeback/refund
External payout retransfer
In the case where a consumer switches payment method after the order has been activated, External payout retransfer represents the shift of responsibility for the payout from Klarna to Swish. This transaction type will deduct money from the payout from Klarna, as money has already been transferred through the Swish schemes.
External payout reactivation
Since capture is only concerning money transfer, and External payout retransfer fully undoes the previous activation; External payout reactivation represents the activation (shipment) of the good whereas External payout capture only represents the transfer of funds.
Important - invoice number info
Please be advised that for transactions where Swish was selected as a payment method, Klarna can not guarantee that this transaction has an invoice number. As invoice numbers are created upon activation, some transactions that haven’t been activated yet will be included in the settlement report.
Best practice
We recommend matching the non-Swish transactions in the same way as you currently do it.
For Swish transactions, you can link the external reference to the order ID set by you in your ERP. You can use the invoice number in the cases you have that in the settlement report, but to keep things consistent Klarna recommends you to reconcile based on your order ID. When reconciling your bank statement, simply identify the paid orders using the external reference and reconcile these in your system.
Legal Requirements
To be compliant, you have a contractual obligation to have an agreement between you and the external payment method providers (e.g. Vipps and Paypal).
Reconciliation of Vipps transactions
To simplify your bookkeeping, Klarna wants to provide a complete reporting offering.
However, as Vipps has a slightly different setup compared to our other available payment methods you will need to do some changes in your reconciliation process.
What separates Swish from our other payment method is that the money from a Vipps transaction will be paid out immediately and separately compared to Klarna’s aggregated payout.
New variables
Reconciliation of Vipps transactions will require new variables to be included in your settlement reports.
Settled by:
Klarna - Paid out by Klarna
Vipps as an External Payment Method - Paid out by Vipps
External reference
The reference that will appear on your bank account, set and controlled by Vipps.
Klarna reference
A reference number that Klarna sets and controls. This may may or may not appear on your bank account depending on which bank you are using.
New transaction types
Reconciliation of Vipps transactions will require new transaction types to be included in your settlement reports.
External payout capture
Represents the transfer of money from consumer to merchant through Vipps scheme upon purchase completion in the checkout
External payout refund
Represents the transfer of money from merchant to consumer through Vipps scheme upon return/chargeback/refund
External payout retransfer
In the case where a consumer switches payment method after the order has been activated, External payout retransfer represents the shift of responsibility for the payout from Klarna to Vipps. This transaction type will deduct money from the payout from Klarna, as money has already been transferred through the Vipps schemes.
External payout reactivation
Since capture is only concerning money transfer, and External payout retransfer fully undoes the previous activation; External payout reactivation represents the activation (shipment) of the good whereas External payout capture only represents the transfer of funds.
Important - invoice number info
Please be advised that for transactions where Vipps was selected as a payment method, Klarna can not guarantee that this transaction has an invoice number. As invoice numbers are created upon activation, some transactions that haven’t been activated yet will be included in the settlement report.
Best practice
We recommend matching the non-Vipps transactions in the same way as you currently do it.
For Vipps transactions, you can link the external reference to the order ID set by you in your ERP. You can use the invoice number in the cases you have that in the settlement report, but to keep things consistent Klarna recommends you to reconcile based on your order ID. When reconciling your bank statement, simply identify the paid orders using the external reference and reconcile these in your system.
Extra merchant data
Providing Klarna with extra merchant data
In some cases, Klarna requires additional information regarding the customer and the purchase in order to make a correct risk assessment. In this tutorial you will learn what information Klarna requires, and how you can send it to Klarna.
Use cases
- Airline Tickets - when creating an order to sell an airline ticket, information about the passenger and itinerary to be booked should be provided to Klarna.
- Event sales merchant - when creating an order for selling a ticket to an event, information about the event should be provided to Klarna.
- Recurring orders - when creating an order for subscriptions or recurring payments, subscription and customer account information should be provided to Klarna.
1. Create the extra merchant data
Add the relevant data, based on the specification and your product vertical. To know which product vertical is right for you, please contact your integration sales representative.
The example below relates to recurring orders, which requires the subscription and customer_account_info details.
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
final Map<String, Object> subscription = new HashMap<String, Object>() { { put("subscription_name", "Test Testperson"); put("start_time", "2015-07-06T10:07:05Z"); put("end_time", "2016-07-06T10:07:05Z"); put("auto_renewal_of_subscription", false); } }; final Map<String, Object> customerInfo = new HashMap<String, Object>() { { put("unique_account_identifier", "user@example.com"); put("account_registration_date", "2015-07-06T10:07:05Z"); put("account_last_modified", "2015-07-06T10:07:05Z"); } }; final Map<String, Object> emd = new HashMap<String, Object>() { { put("subscription", new ArrayList<Map<String, Object>>() { { add(subscription); } }); put("customer_account_info", new ArrayList<Map<String, Object>>() { { add(customerInfo); } }); } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
const EMD_FORMAT = 'Y-m-d\TH:m:s\Z'; $now = new DateTime(); $end = new DateTime(); $emd = array( "subscription" => array( array( "subscription_name" => "Test Testperson", "start_time" => $now->format(EMD_FORMAT), "end_time" => $end->modify('+12 months')->format(EMD_FORMAT), "auto_renewal_of_subscription" => false ) ), "customer_account_info" => array( array( "unique_account_identifier" => "user@example.com", "account_registration_date" => $now->format(EMD_FORMAT), "account_last_modified" => $now->format(EMD_FORMAT) ) ) );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
from datetime import datetime, timedelta emd_format = '%Y-%m-%dT%H:%m:%SZ' start_time = datetime.now() end_time = datetime.now() + timedelta(days=365) emd = { 'subscription': [ { 'subscription_name': 'Test Testperson', 'start_time': start_time.strftime(emd_format), 'end_time': end_time.strftime(emd_format), 'auto_renewal_of_subscription': False } ], 'customer_account_info': [ { 'unique_account_identifier': 'user@example.com', 'account_registration_date': start_time.strftime(emd_format), 'account_last_modified': start_time.strftime(emd_format) } ] }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Dim subscription Set subscription = Server.CreateObject("Scripting.Dictionary") subscription.Add "subscription_name", "Test Testperson", subscription.Add "start_time", "2015-07-06T10:07:56Z", subscription.Add "end_time", "2016-07-06T10:07:56Z", subscription.Add "auto_renewal_of_subscription", False Dim subscriptions(0) Set subscriptions(0) = subscription Dim customerAccountInfo Set customerAccountInfo = Server.CreateObject("Scripting.Dictionary") customerAccountInfo.Add "unique_account_identifier", "user@example.com", customerAccountInfo.Add "account_registration_date", "2015-07-06T10:07:56Z", customerAccountInfo.Add "account_last_modified", "2015-07-06T10:07:56Z" Dim customerAccountInfos(0) Set customerAccountInfos = customerAccountInfo Dim emd Set emd = Server.CreateObject("Scripting.Dictionary") emd.Add "subscription", subscriptions emd.Add "customer_account_info", customerAccountInfos
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
var subscriptions = new List<Dictionary<string, object>> { new Dictionary<string, object> { { "subscription_name", "Test Testperson" }, { "start_time", DateTime.Now }, { "end_time", DateTime.Now.AddYears(1) }, { "auto_renewal_of_subscription", false } } }; var customerAccountInfos = new List<Dictionary<string, object>> { new Dictionary<string, object> { { "unique_account_identifier", "Test Testperson" }, { "account_registration_date", DateTime.Now }, { "account_last_modified", DateTime.Now } } }; var emd = new Dictionary<string, object> { { "subscription", subscriptions}, { "customer_account_info", customerAccountInfos} };
2. Attach the data to the order
Once the data is created, you would need to include it under the attachment
property. Once it is populated simply send the data as you learned in the Embed the checkout tutorial.
1 2 3 4 5 6
data.put("attachment", new HashMap<String, Object>() { { put("content_type", "application/vnd.klarna.internal.emd-v2+json"); put("body", JSONObject.toJSONString(emd)); } });
1 2 3 4
$create['attachment'] = array( 'content_type' => 'application/vnd.klarna.internal.emd-v2+json', 'body' => json_encode($emd) );
1 2 3 4 5 6
import json data['attachment'] = { 'content_type': 'application/vnd.klarna.internal.emd-v2+json', 'body': json.dumps(emd).encode('utf-8') }
1 2 3 4 5 6
Dim attachment Set attachment = Server.CreateObject("Scripting.Dictionary") attachment.Add "content_type", "application/vnd.klarna.internal.emd-v2+json" attachment.Add "boidy", JSON.stringify(emd) data.Add "attachment", attachment
1 2 3 4 5 6 7 8 9 10 11 12
const string EmdFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"; var converter = new IsoDateTimeConverter { DateTimeFormat = EmdFormat }; data.Add("attachment", new Dictionary<string, string> { { "content_type", "application/vnd.klarna.internal.emd-v2+json"}, { "body", JsonConvert.SerializeObject(emd, converter)} });
Note: Find out more about the different data fields by checking the attachments specification .
Validate a checkout order
This checkout function will allow you to validate the information provided by the consumer in the Klarna Checkout iframe before the purchase is completed.
Use cases
- Out of stock validation - for high turnaround businesses this functionality enables you to verify that an item added to a cart is indeed still in stock before the consumer completes the purchase.
- Delivery limitations - some products cannot be shipped to certain geographies. This functionality enables you to verify that the goods can be shipped to the address the consumer has provided.
- Order number generation - certain systems have flows that require the creation of an internal order ID when order has been created, such as for tracking purposes. This functionality allows you to create an order ID upon receiving the validation callback and displaying it on the confirmation page.
Tutorial requirements
- You should have already obtained your API credentials
- You have learned how to embed the checkout
1. Create a checkout order
Create a Checkout order exactly as you learned in the embed the checkout tutorial , and make sure to include the optional property merchant.validation_uri.
Note: All communication with the validation URI will be encrypted. For that reason you must use the HTTPS protocol for this URI.
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
Accept: application/vnd.klarna.checkout.aggregated-order-v2+json Authorization: Klarna pwhcueUff0MmwLShJiBE9JHA== Content-Type: application/vnd.klarna.checkout.aggregated-order-v2+json { "purchase_country": "se", "purchase_currency": "sek", "locale": "sv-se", "cart": { "items": [ { "reference": "123456789", "name": "Klarna t-shirt", "quantity": 2, "unit_price": 12300, "discount": 1000, "tax_rate": 2500 }, { "type": "shipping_fee", "reference": "SHIPPING", "name": "Shipping fee", "quantity": 1, "unit_price": 4900, "tax_rate": 2500 } ] }, "merchant": { "id": "0", "terms_uri": "http://example.com/terms.php", "checkout_uri": "https://example.com/checkout.php", "confirmation_uri": "https://example.com/thankyou.php?sid=123&klarna_order={checkout.order.uri}", "push_uri": "https://example.com/push.php?sid=123&klarna_order={checkout.order.uri}", "validation_uri": "https://example.com/klarna_validation.php" } }
2. Respond to Klarna’s POST request
When the consumer clicks “buy now” a POST request will be sent to the merchant.validation_uri. The body of the request will contain the current order information. The structure of the order information is identical to the result of fetching the order, as you saw in render the checkout.
Note: There is no need to fetch the order from Klarna since all the order information is included in the POST request body.
Once you receive the POST request, our system will expect a response within 5 seconds. If Klarna does not receive a response, we will approve the purchase. The response you provide Klarna will determine whether or not the purchase will be completed:
- To approve the purchase, reply with a HTTP status 200 OK. The consumer will then be redirected as normal to the checkout confirmation page.
- To deny the purchase, reply with a HTTP status 303 See Other. This needs to include a Location header pointing to a page which informs the consumer why the purchase was not completed. The consumer will be redirected to this page.
Note: The rejection page needs to be hosted by you, and we highly recommend that you give the consumer detailed information as to why you rejected the order.
Suspend and resume
In this tutorial, you will learn how to suspend and resume the checkout to reflect an updated order in the consumer’s iframe. You will do this by first suspending the Klarna Checkout while you do behind-the-scenes updates to the order. When you are done with these updates, you will resume the checkout.
Use case
A consumer increases the quantity of an item in their cart on the checkout page. You can have those changes reflected in the Klarna Checkout iframe without having to refresh the entire page.
Prerequisites
- You have embeded the checkout snippet
- You know how to update an ongoing order
Note: An order is valid for 48 hours and can be accessed only using the same API credentials used to create the order.
1. Suspend the checkout
Suspending the checkout puts it in a waiting state, preventing consumer input. A loading indicator is rendered on top of the iframe indicating to the consumer that the checkout is loading.
You will do this by issuing a Javascript command, as you can see in the code example below:
1 2 3
window._klarnaCheckout(function (api) { api.suspend(); });
2. Update a Checkout order
Update the order as you did in the update an ongoing order tutorial.
3. Resume the checkout
Resuming the checkout forces it to fetch the most recent order data from Klarna. The loading indicator will disappear and the consumer can continue to fill in the form. The amount presented in the checkout will now reflect the new order total.
1 2 3
window._klarnaCheckout(function (api) { api.resume(); });
Update an ongoing order
In this tutorial, you will learn how to update an order that the consumer changes before completing the order. If a checkout session already exists, do not create a new checkout order. Instead, use the ongoing order and update it with the new items in the cart as described in this tutorial.
Use case
A consumer goes to the checkout with one item in the cart. You have embedded the checkout snippet . While still on the checkout page, the consumer make changes to the order before completing the purchase.
Prerequisites
- A consumer has an ongoing Klarna Checkout order.
1. Retrieve the checkout order
Use the checkout order URI stored in the session to fetch the order from Klarna.
1 2 3 4 5 6 7 8 9
// Retrieve order id from session object. // String orderID = (String) session.get("klarna_order_id"); String orderID = "12345"; IConnector connector = Connector.create( "sharedSecret", IConnector.TEST_BASE_URL); Order order = new Order(connector, orderID); order.fetch();
1 2 3 4 5 6 7 8 9
$connector = Klarna_Checkout_Connector::create( 'sharedSecret', Klarna_Checkout_Connector::BASE_TEST_URL ); $orderID = $_SESSION['klarna_order_id']; $order = new Klarna_Checkout_Order($connector, $orderID); $order->fetch();
1 2 3 4 5 6 7 8 9 10
# Instance of the session library that is being used in the server session = {} connector = klarnacheckout.create_connector('shared_secret', klarnacheckout.BASE_TEST_URL) order_id = session['klarna_order_id'] order = klarnacheckout.Order(connector, order_id) order.fetch()
1 2 3 4 5 6 7 8 9 10
Dim connector : Set connector = CreateConnector("sharedSecret") connector.SetBaseUri KCO_TEST_BASE_URI ' Retrieve order id from session object. Dim orderID : orderID = Session("klarna_order_id") Dim order : Set order = CreateOrder(connector) order.ID orderID order.Fetch
1 2 3 4 5 6 7 8
var connector = Connector.Create("sharedSecret", Connector.TestBaseUri); // Retrieve order id from session object. // var orderId = session["klarna_order_id"] as string; var orderId = "12345"; var order = new Order(connector, orderId); order.Fetch();
2. Update the order
You should now update the checkout order to reflect the changes that the consumer has made to the cart.
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
final Map<String, Object> cart = new HashMap<String, Object>() { { put("items", new ArrayList<HashMap<String, Object>>() { { add(new HashMap<String, Object>() { { put("quantity", 2); put("reference", "123456789"); put("name", "Klarna t-shirt"); put("unit_price", 12300); put("discount_rate", 1000); put("tax_rate", 2500); } }); add(new HashMap<String, Object>() { { put("quantity", 1); put("type", "shipping_fee"); put("reference", "SHIPPING"); put("name", "Shipping Fee"); put("unit_price", 4900); put("tax_rate", 2500); } }); } }); } }; // Reset cart Map<String, Object> data = new HashMap<String, Object>() { { put("cart", cart); } }; order.update(data);
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
$cart = array( array( 'reference' => '123456789', 'name' => 'Klarna t-shirt', 'quantity' => 4, 'unit_price' => 12300, 'discount_rate' => 1000, 'tax_rate' => 2500 ), array( 'type' => 'shipping_fee', 'reference' => 'SHIPPING', 'name' => 'Shipping Fee', 'quantity' => 1, 'unit_price' => 4900, 'tax_rate' => 2500 ) ); // Reset cart $update = array(); $update['cart']['items'] = array(); foreach ($cart as $item) { $update['cart']['items'][] = $item; } $order->update($update);
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
cart = ( { 'quantity': 1, 'reference': '123456789', 'name': 'Klarna t-shirt', 'unit_price': 12300, 'discount_rate': 1000, 'tax_rate': 2500 }, { 'quantity': 1, 'type': 'shipping_fee', 'reference': 'SHIPPING', 'name': 'Shipping Fee', 'unit_price': 4900, 'tax_rate': 2500 } ) # Reset cart data = {'cart': []} data["cart"] = {"items": []} for item in cart: data["cart"]["items"].append(item) order.update(data)
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
' Cart Dim item1 Set item1 = Server.CreateObject("Scripting.Dictionary") item1.Add "reference", "123456789" item1.Add "name", "Klarna t-shirt" item1.Add "quantity", 2 item1.Add "unit_price", 12300 item1.Add "discount_rate", 1000 item1.Add "tax_rate", 2500 Dim item2 Set item2 = Server.CreateObject("Scripting.Dictionary") item2.Add "type", "shipping_fee" item2.Add "reference", "SHIPPING" item2.Add "name", "Shipping Fee" item2.Add "quantity", 1 item2.Add "unit_price", 4900 item2.Add "tax_rate", 2500 Dim cartItems(1) Set cartItems(0) = item1 Set cartItems(1) = item2 Dim cart Set cart = Server.CreateObject("Scripting.Dictionary") cart.Add "items", cartItems ' Reset cart Dim data Set data = Server.CreateObject("Scripting.Dictionary") data.Add "cart", cart order.Update data
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
var cartItems = new List<Dictionary<string, object>> { new Dictionary<string, object> { { "reference", "123456789" }, { "name", "Klarna t-shirt" }, { "quantity", 2 }, { "unit_price", 12300 }, { "discount_rate", 1000 }, { "tax_rate", 2500 } }, new Dictionary<string, object> { { "type", "shipping_fee" }, { "reference", "SHIPPING" }, { "name", "Shipping Fee" }, { "quantity", 1 }, { "unit_price", 4900 }, { "tax_rate", 2500 } } }; var cart = new Dictionary<string, object> { { "items", cartItems } }; // Reset cart var data = new Dictionary<string, object> { { "cart", cart } }; order.Update(data);
Recurring Orders
KCO Recurring reduces the effort for customers who want to start a subscription of any kind online. The functionality will enable you as a merchant to sell subscriptions and other recurring purchases through Klarna Checkout. It is as easy to set the subscription up as completing any purchase with Klarna Checkout. The function is based on a unique token that is created with the first purchase. This token which represents the customer and their purchase is then used to initiate an additional purchase.
Prerequisites
- Need to be enabled in your Klarna account
*Possible reasons to act upon: temporary_failure, limit_exceeded, card_expired, permanent_failure
1. Create a order ready for recurring
You must create a normal checkout order with the option “recurring” set to true. You can see the resource structure needed to create orders here .
1 2 3 4 5 6 7 8 9 10 11 12 13 14
IConnector connector = Connector.create( "sharedSecret", IConnector.TEST_BASE_URL); Order order = new Order(connector); // See regular order creation example for further options Map<String, Object> data = new HashMap<String, Object>() { { put("recurring", true); } }; order.create(data);
1 2 3 4 5 6 7 8 9 10 11
$connector = Klarna_Checkout_Connector::create( "sharedSecret", Klarna_Checkout_Connector::BASE_TEST_URL ); $order = new Klarna_Checkout_Order($connector); // See regular order creation example for further options $create['recurring'] = true; $order->create($create);
1 2 3 4 5 6 7 8 9 10 11 12
connector = klarnacheckout.create_connector('shared_secret', klarnacheckout.BASE_TEST_URL) order = klarnacheckout.Order(connector) # See regular order creation example for further options data = {'recurring': True} try: order.create(data) except klarnacheckout.HTTPResponseException as e: print(e.json.get('http_status_message')) print(e.json.get('internal_message'))
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Dim connector Set connector = CreateConnector("sharedSecret") connector.SetBaseUri KCO_TEST_BASE_URI Dim order Set order = CreateOrder(connector) ' See regular order creation example for further options Dim data Set data = Server.CreateObject("Scripting.Dictionary") data.Add "recurring", True order.Create data
1 2 3 4 5 6 7 8 9 10 11 12
var connector = Connector.Create("sharedSecret", Connector.TestBaseUri); Order order = new Order(connector); // See regular order creation example for further options var data = new Dictionary<string, object> { { "recurring", true } }; order.Create(data);
2. Consumer completes the purchase
After a consumer has completed the purchase the checkout order will have a “recurring_token” property needed to create recurring orders. This token must be stored for later use.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
String orderID = "12345"; IConnector connector = Connector.create( "sharedSecret", IConnector.TEST_BASE_URL); Order order = new Order(connector, orderID); try { order.fetch(); System.out.println(order.get("recurring_token")); } catch (ErrorResponseException e) { JSONObject json = e.getJson(); System.out.println(json.get("http_status_message")); System.out.println(json.get("internal_message")); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$orderID = 'ABC123'; $connector = Klarna_Checkout_Connector::create( 'sharedSecret', Klarna_Checkout_Connector::BASE_TEST_URL ); $order = new Klarna_Checkout_Order($connector, $orderID); try { $order->fetch(); var_dump($order['recurring_token']); } catch (Klarna_Checkout_ApiErrorException $e) { var_dump($e->getMessage()); var_dump($e->getPayload()); }
1 2 3 4 5 6 7 8 9 10 11 12 13
order_id = 'ABC123' connector = klarnacheckout.create_connector('shared_secret', klarnacheckout.BASE_TEST_URL) try: order = klarnacheckout.Order(connector, order_id) order.fetch() print(order['recurring_token']) except klarnacheckout.HTTPResponseException as e: print(e.json.get('http_status_message')) print(e.json.get('internal_message'))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Dim orderID : orderID = "ABC123" Dim connector : Set connector = CreateConnector("sharedSecret") connector.SetBaseUri KCO_TEST_BASE_URI Dim order : Set order = CreateOrder(connector) order.ID orderID order.Fetch If order.HasError = True Then Response.Write("Status: " & order.GetError().Marshal().http_status_message & "<br/>") Response.Write("Message: " & order.GetError().Marshal().internal_message & "<br/>") End If Dim resourceData : Set resourceData = order.Marshal() Response.Write("Token: " & resourceData.recurring_token)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var orderId = "ABC123"; var connector = Connector.Create("sharedSecret", Connector.TestBaseUri); Order order = new Order(connector, orderId); try { order.Fetch(); Console.WriteLine(order.GetValue("recurring_token")); } catch (ConnectorException ex) { Console.WriteLine(ex.Data["http_status_message"]); Console.WriteLine(ex.Data["internal_message"]); }
3. Create the recurring order
When creating a recurring order you will need to supply the recurring token along with the customer address and the cart.
In the event of a 402 Payment Required response, you should inspect the reason code and possibly let your customer know that he/she needs to redo the purchase flow again.
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
final String eid = "0"; final String secret = "sharedSecret"; final String recurringOrderToken = "ABC-123"; IConnector connector = Connector.create( secret, IConnector.TEST_BASE_URL); RecurringOrder recurringOrder = new RecurringOrder( connector, recurringOrderToken); final Map<String, Object> merchant = new HashMap<String, Object>() { { put("id", eid); } }; final Map<String, Object> merchantReference = new HashMap<String, Object>() { { put("orderid1", "Some unique id ..."); } }; final Map<String, String> address = new HashMap<String, String>() { { put("postal_code", "12345"); put("email", "checkout-se@testdrive.klarna.com"); put("country", "se"); put("city", "Ankeborg"); put("family_name", "Approved"); put("given_name", "Testperson-se"); put("street_address", "Stårgatan 1"); put("phone", "070 111 11 11"); } }; final Map<String, Object> cart = new HashMap<String, Object>() { { put("items", new ArrayList<HashMap<String, Object>>() { { add(new HashMap<String, Object>() { { put("quantity", 2); put("reference", "123456789"); put("name", "Klarna t-shirt"); put("unit_price", 12300); put("discount_rate", 1000); put("tax_rate", 2500); } }); add(new HashMap<String, Object>() { { put("quantity", 1); put("type", "shipping_fee"); put("reference", "SHIPPING"); put("name", "Shipping Fee"); put("unit_price", 4900); put("tax_rate", 2500); } }); } }); } }; // If the order should be activated automatically. final Boolean activate = false; Map<String, Object> data = new HashMap<String, Object>() { { put("purchase_country", "SE"); put("purchase_currency", "SEK"); put("locale", "sv-se"); put("merchant", merchant); put("merchant_reference", merchantReference); put("billing_address", address); put("shipping_address", address); put("cart", cart); put("activate", activate); } }; try { recurringOrder.create(data); System.out.println( recurringOrder.get(activate ? "invoice" : "reservation")); } catch (ErrorResponseException e) { JSONObject json = e.getJson(); if (e.getStatusCode() == 402) { System.out.println(json.get("reason")); } else { System.out.println(json.get("http_status_message")); System.out.println(json.get("internal_message")); } }
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
$eid = '0'; $sharedSecret = 'sharedSecret'; $recurringOrderToken = 'abc123'; $connector = Klarna_Checkout_Connector::create( $sharedSecret, Klarna_Checkout_Connector::BASE_TEST_URL ); $order = new Klarna_Checkout_RecurringOrder($connector, $recurringOrderToken); // If the order should be activated automatically. $activate = true; $create = array( 'purchase_currency' => 'SEK', 'purchase_country' => 'SE', 'locale' => 'sv-se', 'merchant' => array( 'id' => $eid ), 'merchant_reference' => array( 'orderid1' => 'someUniqueId...' ), 'activate' => $activate ); $address = array( 'postal_code' => '12345', 'email' => 'checkout-se@testdrive.klarna.com', 'country' => 'se', 'city' => 'Ankeborg', 'family_name' => 'Approved', 'given_name' => 'Testperson-se', 'street_address' => 'Stårgatan 1', 'phone' => '070 111 11 11' ); $create['billing_address'] = $address; $create['shipping_address'] = $address; $create['cart'] = array( 'items' => array( array( 'reference' => '123456789', 'name' => 'Klarna t-shirt', 'quantity' => 2, 'unit_price' => 12300, 'discount_rate' => 1000, 'tax_rate' => 2500 ), array( 'type' => 'shipping_fee', 'reference' => 'SHIPPING', 'name' => 'Shipping Fee', 'quantity' => 1, 'unit_price' => 4900, 'tax_rate' => 2500 ) ) ); try { $order->create($create); var_dump($activate ? $order['invoice'] : $order['reservation']); } catch (Klarna_Checkout_ApiErrorException $e) { var_dump($e->getMessage()); var_dump($e->getPayload()); }
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
eid = "0" shared_secret = 'shared_secret' recurring_order_token = 'abc123' connector = klarnacheckout.create_connector(shared_secret, klarnacheckout.BASE_TEST_URL) # If the order should be activated automatically. activate = True data = { 'purchase_country': 'SE', 'purchase_currency': 'SEK', 'locale': 'sv-se', 'merchant': { 'id': eid }, 'merchant_reference': { "orderid1": "someUniqueId" }, 'activate': activate, 'cart': {'items': []} } address = { 'postal_code': '12345', 'email': 'checkout-se@testdrive.klarna.com', 'country': 'se', 'city': 'Ankeborg', 'family_name': 'Approved', 'given_name': 'Testperson-se', 'street_address': 'Stårgatan 1', 'phone': '070 111 11 11' } data['billing_address'] = address data['shipping_address'] = address # Dictionary containing the cart items cart = ( { 'quantity': 1, 'reference': '123456789', 'name': 'Klarna t-shirt', 'unit_price': 12300, 'discount_rate': 1000, 'tax_rate': 2500 }, { 'quantity': 1, 'type': 'shipping_fee', 'reference': 'SHIPPING', 'name': 'Shipping Fee', 'unit_price': 4900, 'tax_rate': 2500 } ) for item in cart: data['cart']['items'].append(item) try: order = klarnacheckout.RecurringOrder(connector, recurring_order_token) order.create(data) print(order['invoice'] if activate else order['reservation']) except klarnacheckout.HTTPResponseException as e: if e.code == 402: print(e.json.get('reason')) else: print(e.json.get('http_status_message')) print(e.json.get('internal_message'))
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
On Error Resume Next Dim eid eid = "0" Dim sharedSecret sharedSecret = "sharedSecret" Dim recurringOrderToken recurringOrderToken = "ABC-123" Dim connector Set connector = CreateConnector(sharedSecret) connector.SetBaseUri KCO_TEST_BASE_URI Dim order Set order = CreateRecurringOrder(connector, recurringOrderToken) Dim merchant Set merchant = Server.CreateObject("Scripting.Dictionary") merchant.Add "id", eid Dim merchant_reference Set merchant_reference = Server.CreateObject("Scripting.Dictionary") merchant_reference.Add "orderid1", "someUniqueId" Dim address Set address = Server.CreateObject("Scripting.Dictionary") address.Add "postal_code", "12345" address.Add "email", "checkout-se@testdrive.klarna.com" address.Add "country", "se" address.Add "city", "Ankeborg" address.Add "family_name", "Approved" address.Add "given_name", "Testperson-se" address.Add "street_address", "Stårgatan 1" address.Add "phone", "070 111 11 11" Dim item1 Set item1 = Server.CreateObject("Scripting.Dictionary") item1.Add "reference", "123456789" item1.Add "name", "Klarna t-shirt" item1.Add "quantity", 2 item1.Add "unit_price", 12300 item1.Add "discount_rate", 1000 item1.Add "tax_rate", 2500 Dim item2 Set item2 = Server.CreateObject("Scripting.Dictionary") item2.Add "type", "shipping_fee" item2.Add "reference", "SHIPPING" item2.Add "name", "Shipping Fee" item2.Add "quantity", 1 item2.Add "unit_price", 4900 item2.Add "discount_rate", 2500 item2.Add "tax_rate", 2500 Dim cartItems(1) Set cartItems(0) = item1 Set cartItems(1) = item2 Dim cart Set cart = Server.CreateObject("Scripting.Dictionary") cart.Add "items", cartItems ' If the order should be activated automatically. Dim activate activate = False Dim data Set data = Server.CreateObject("Scripting.Dictionary") data.Add "purchase_country", "SE" data.Add "purchase_currency", "SEK" data.Add "locale", "sv-se" data.Add "merchant", merchant data.Add "merchant_reference", merchant_reference data.Add "billing_address", address data.Add "shipping_address", address data.Add "cart", cart data.Add "activate", activate order.Create data If order.HasError = True Then Dim errData Set errData = order.GetError().Marshal() If order.GetError().GetResponse().GetStatus() = 402 Then Response.Write("Message: " & errData.reason & "<br/>") Else Response.Write("Message: " & errData.internal_message & "<br/>") End If End If If Err.Number <> 0 Then Response.Write("An error occurred: " & Err.Description) Err.Clear ' Error occurred, stop execution Exit Sub End If Dim resourceData Set resourceData = order.Marshal() If activate = True Then Response.Write("Invoice number: " & resourceData.invoice) Else Response.Write("Reservation number: " & resourceData.reservation) End If
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
const string Eid = "0"; const string SharedSecret = "sharedSecret"; const string RecurringOrderToken = "ABC-123"; // Set optional merchant reference ids. Like internal order or customer id var merchant_reference = new Dictionary<string, object> { { "orderid1", "someUniqueId" } }; var merchant = new Dictionary<string, object> { { "id", Eid } }; var items = new List<Dictionary<string, object>> { new Dictionary<string, object> { { "reference", "123456789" }, { "name", "Klarna t-shirt" }, { "quantity", 2 }, { "unit_price", 12300 }, { "discount_rate", 1000 }, { "tax_rate", 2500 } }, new Dictionary<string, object> { { "type", "shipping_fee" }, { "reference", "SHIPPING" }, { "name", "Shipping Fee" }, { "quantity", 1 }, { "unit_price", 4900 }, { "tax_rate", 2500 } } }; var cart = new Dictionary<string, object> { { "items", items } }; var address = new Dictionary<string, object> { { "given_name", "Testperson-se" }, { "family_name", "Approved" }, { "street_address", "Stårgatan 1" }, { "postal_code", "12345" }, { "city", "Ankeborg" }, { "country", "se" }, { "email", "checkout-se@testdrive.klarna.com" }, { "phone", "070 111 11 11" } }; // If the order should be activated automatically. var activate = true; var data = new Dictionary<string, object> { { "purchase_country", "SE" }, { "purchase_currency", "SEK" }, { "locale", "sv-se" }, { "merchant", merchant }, { "merchant_reference", merchant_reference }, { "cart", cart }, { "activate", activate }, { "billing_address", address }, { "shipping_address", address } }; var connector = Connector.Create(SharedSecret, Connector.TestBaseUri); RecurringOrder order = new RecurringOrder(connector, RecurringOrderToken); try { order.Create(data); var result = order.Marshal(); if (activate) { Console.WriteLine(result["invoice"]; } else { Console.WriteLine(result["reservation"]; } } catch (ConnectorException ex) { if (exception.Data["HttpStatusCode"] == 402) { Console.WriteLine(ex.Data["reason"]); } else { Console.WriteLine(ex.Data["http_status_message"]); Console.WriteLine(ex.Data["internal_message"]); } }
Cross-sell on confirmation page
After the customer has completed the purchase and has been redirected to the confirmation page there is a possibility to add more items to the order. As you read the order on the confirmation page the order will contain the boolean field cart_update_allowed
which will indicate whether it is possible to use the cross-sell feature. You should not attempt to add items to the order if the cart_update_allowed
field is false.
To add items you show them on the confirmation page next to the Klarna iframe. When the user wants to add the item to the order you suspend the iframe, do an update to the order, resume the iframe and then show information that the item has been added to the same order. The update does not always succeed so make sure you handle the response.
Please note: The merchant_item_data
field is not available when updating the order through the XML-RPC API.
Implementation flow
When the customer reaches the confirmation page you check for the cart_update_allowed
field to see if it is possible to use the cross-sell feature. If the flag is true you can show items to the customer.
When the customer chooses to add an item to the order you suspend the iframe, try to update the order through the XML-RPC Order Management API (documentation ), and resume the iframe.
If the update was successful the new order amount will show on the confirmation page in the iframe and you should show the customer a confirmation text. Something similar to “Thanks! The product has been added to your order!” telling the user that the item has been added to the same order.
If the update fails you should handle this by giving the customer the opportunity to purchase the same item in a new order. We recommend you to handle this by showing a message that the order is already completed, and offer a button back to the checkout (which should already have this product in the basket and be loaded fully pre-filled).
If the user keeps the confirmation page open for more than 30 minutes and attempts to add an item to the order there iframe will be locked for updates. The order update migh succeed but the information in the iframe won’t be updated. There are two proposed ways to handle this scenario.
- Keep a timer and only allow the customer to add items for up to 30 minutes after order completion
- Accept the order update and hide the Klarna iframe and instead show your own confirmation and the new total price.
Legal requirements
To be compliant with credit rules you have to show information on the terms and conditions for the updated purchase. Our two proposals are
- Include an headline for the additional items containing info on the terms. Example “Add the following products to your purchase (same terms and conditions apply)”
- Include information about the terms close to each buy button. Example: Add “Same terms and conditions apply” below the buy button. Note that if you want to show the text next to the button in Germany and Austria you must show the text below the button.
Business to Business
Sometime an order is placed on behalf of an organization, not an individual. We refer to this as the Business to Business flow, or B2B flow, for Klarna Checkout. The B2B flow comes with some differences in the user experience and integration compared to the Business to Consumer flow (B2C).
Klarna Checkout can be configured to support B2B in Sweden, Norway and Finland.
Prerequisities
- You have implemented Klarna Checkout
- Your e-store ID has been enabled for B2B by Klarna (available in Sweden, Norway and Finland)
How it works
From an implementation point of view, B2B for Klarna Checkout is utilizing the same logic and API as the regular Klarna Checkout for B2C (Business to Consumer). This means you will re-use your existing Klarna Checkout integration and just make the changes described in the Implementation flow below.
When enabling support for B2B you introduce a new user flow, meaning there will visually be one option for business customers and a separate option for a regular consumer in the Klarna Checkout. The B2C flow is loaded as default, but you can optionally render the B2B flow by default to a known business customer.
- The customer can toggle between the B2C and B2B flows in the checkout.
- The B2B flow asks for details pertaining to an organization, such as Organization number.
- It is possible to configure the checkout for separate shipping and billing address in the B2B flow.
- The available payment methods in the B2B flow are Invoice and Card payments.
- Recurring orders are not supported in the B2B flow.
- It is possible to use a separate link for the terms presented in the B2B flow, which you pass along when creating the order. If such a link is not provided, the B2C terms will be presented by default.
The B2B flow for Klarna Checkout will be configured by Klarna on the same e-store ID as the regular B2C Klarna Checkout.
Implementation flow
Follow these steps to enable the B2B flow in your existing Klarna checkout integration.
Step 1 - Configure the checkout
Before loading the checkout, you will set the relevant options to indicate that B2B should be included.
1a. Enable the option to choose between the B2C or B2B flows
When configuring the checkout order , set the options for <span>allowed_customer_types</span>
to both person and organization.
“options”: { “allowed_customer_types”: [“person”, “organization"] }
1b. (Optional) - If desired, render the B2B flow instead of B2C
By default, the regular B2C user flow will be rendered when the checkout loads. If you instead want to render the B2B flow when it loads, you can optionally set the <span>customer.type</span>
field to organization.
“customer”: { “type”: “organization” }
1c. (Optional) - Prefill the organization number
If you have the organization number available for this business, you can optionally prefill it in the checkout by setting it in the <span>organization_registration_id</span>
field. That way the customer will not have to enter them again in the checkout, but still has the option to change it if it is incorrect.
“customer”: { “type”: “organization”, “organization_registration_id”: “556036-0793” }
1d. (Optional) - Set specific T&Cs to be presented in the B2B flow
In order for a merchant to display their b2b and b2c terms differently it is possible to have a separate links. The terms are displayed in the same place as the b2c terms. In addition to the existing field that can be used for adding legal terms for B2C (merchant.terms_uri), a separate field called merchant.organization_terms_uri
is also available. If set, the terms from that field will be presented when the customer is in the b2b flow. If not set then the terms from merchant_uri will be used.
“merchant.organization_terms_uri”: { “your URI string” }
Step 2 - Load the checkout
Create the order and render the checkout as usual . The customer should now be able to switch between the B2C and the B2B flows.
Step 3 (Optional) - Listen to customer interaction events from the checkout
The customer starts entering the required fields in the B2B flow. The additional fields will be the organization id and an optional “Reference” field where they may for example add their name or department.
If you need to know which flow the customer is in before the order is placed, in order to for example always show the correct shipping options on your page, you may do so using our JavaScript API.
Start by subscribing to the load signal.
_klarnaCheckout(function(api){ api.on({ load: function(data){ console.info (data) } }) }) You will now be notified about customer data including the flow type and partial shipping address before the order is placed. When the customer switches the flow, the checkout reloads and callback is triggered again.
Here is a sample of the notification from the callback
{ “customer”: { “type”: “person” }, “shipping_address”: { “country”: “SE”, “email”: “klara.joyce@klarna.com ”, “postal_code”: “12345” } } In order to listen shipping address change events before the order is placed, the relevant shipping_address_change signal must be used in the same way.
Step 4 - Parse the organization’s address details from the completed order
The B2B customer places the order when they press the buy button. When you retrieve the completed order placed in the B2B flow, the customer object contains a type which identifies if this was an organization or a consumer (person).
“customer”: {
“type”: “organization”, // optionally, this could be set to “person”
“organization_registration_id”: “556036-0793”
},
If the customer.type is organization, the <span>billing address</span>
includes potentially two additional fields called <span>organization_name</span>
and reference
. Note that empty fields are not returned, so if the reference was not entered by the customer, it will not be available in the response.
“billing_address”: { “country”: “{{<country}}”, “given_name”: “{{<given_name}}”, “family_name”: “{{<family_name}}”, “organization_name”: “{{<organization_name}}”, “street_address”: “{{<street_address}}”, “city”: “{{<city}}”, “phone”: “{{<phone}}”, “reference”: “{{<reference}}” }, This was the final step.
Please note: You need to contact Klarna to enable B2B for any applicable e-store ID before going live.