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.


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: 

  1. To use this feature, you will need an agreement that defines what payment methods that you will use. 
  2. 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.
  3. You will need to host your own “thank you page” since this purchase will take place outside Klarna checkout.
  4. New backend integration towards the external payment method will be required. 
  5. Given that this is an external payment, Klarna's buyer protection will not apply for your consumers.
  6. 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

"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.
    }
]
$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
];
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
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);
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

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 Payments
  • 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.


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.

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)
        )
    )
);
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);
            }
        });
    }
};
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)
        }
    ]
}
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}
};
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

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.

$create['attachment'] = array(
    'content_type' => 'application/vnd.klarna.internal.emd-v2+json',
    'body' => json_encode($emd)
);
data.put("attachment", new HashMap<String, Object>() {
    {
        put("content_type", "application/vnd.klarna.internal.emd-v2+json");
        put("body", JSONObject.toJSONString(emd));
    }
});
import json

data['attachment'] = {
    'content_type': 'application/vnd.klarna.internal.emd-v2+json',
    'body': json.dumps(emd).encode('utf-8')
}
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)}
});
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

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

 

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.

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

 


Remarketing with Klarna Checkout


Using remarketing on abandoned carts is a good way to get more customers to complete their purchases. If customers have started to enter their contact details but then decide to cancel their purchase, the merchant can email the customer, prompting them to return to the abandoned cart.

Klarna Checkout together with abandoned cart software is an effective way of increasing sales. It allows you to pre-fill email addresses and postcodes when customers return. Klarna uses the pre-filled information to identify customers and provide a one-click buying experience.

 

1. Obtain customer details


With Klarna Checkout Javascript API, merchants receive notifications when a customer enters data in the Checkout form. This is done by registering a callback function that receives the customer's email address, postcode, given name, and family name. 

It’s important that the callback function is registered after Klarna Checkout in the HTML code, or after Klarna Checkout has been rendered. 

This is how the callback function is registered

window._klarnaCheckout(function(api) {
     api.on({
         'change': function(data) {
             // Do something
         }
     });
});


The data object contains the consumer’s email address, postcode, given name, and last name. Fields that have not been filled are sent as empty strings.

An example of a data object:

{
     email: 'checkout-se@testdrive.klarna.com',
     postal_code: '12345',
     given_name: 'Testperson-se',
     family_name: 'Approved'
}

2. Filter out completed purchases


To ensure abandoned cart emails are only sent to customers that have not completed purchases, the merchant must filter out orders that have been completed. This is done by removing matching email addresses from the remarketing email list. The best place to do this is on the order confirmation page where purchases are completed.

3. Send abandoned cart email


If a customer has abandoned a cart, an email should be sent, prompting them to return to it. This is a great opportunity to offer the consumer something extra if they complete their purchase. Merchants can, for example, offer customers a discount or free shipping to encourage them to complete their purchase. A popular way of doing this is to send emails in three stages: an email to remind customers about their cart; a second email asking them to complete their purchase; and finally an email offering a discount to complete the purchase.

The link in the email that takes customers back to the web store should at least contain an identifier for the abandoned cart, as well as the customer’s email address and postcode. This is needed to load the abandoned cart and to pre-fill the Checkout with its parameters.

An example of a link:
https://www.store.com/checkout?cartid=1a2b3c4d&email=fornamn.efternamn@klarna.com&postal_code=12345

4. Pre-fill Klarna Checkout


When the customer returns to the checkout, the merchant should load the previously abandoned cart. This can for example be done by using the cartid which was included in the link in the e-mail. The merchant should then pre-fill Klarna Checkout with the email address and the postcode provided in the link from the email. Klarna will then take care of the rest: identify the customer and pre-fill the remaining fields.

This is how Klarna Checkout can be pre-filled:

$create['shipping_address']['email'] = 'checkout-se@testdrive.klarna.com';
$create['shipping_address']['postal_code'] = '12345';
order.put("shipping_address", new HashMap<String, Object>() {
    {
        put("email", "checkout-se@testdrive.klarna.com");
        put("postal_code", "12345");
    }
});
create['shipping_address'] = {
    'email': 'checkout-se@testdrive.klarna.com',
    'postal_code': '12345'
}
order["shipping_address"] = new Dictionary<string, object>()
    {
        { "email", "checkout-se@testdrive.klarna.com" },
        { "postal_code", "12345" }
    }
);

The customer is then just one click away from converting to a completed transaction.


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

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:

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.

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.

$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();
// 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();
# 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()
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();
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

2. Update the order

You should now update the checkout order to reflect the changes that the consumer has made to the cart.

$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);
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);
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)
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);
' 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

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.

$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);
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);
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'))
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);
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

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.

$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());
}
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"));
}
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'))
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"]);
}
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)

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.

$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());
}
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"));
    }
}
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'))
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"]);
    }
}
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

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. 

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 allowed_customer_types 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 customer.typefield 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 organization_registration_id 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 billing address includes potentially two additional fields called organization_name 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.