How to integrate Instant Shopping into an Upsell Page

During the next steps you will learn how to integrate Instant Shopping into any page where you want to promote a specific product.

1. Obtain an Instant Shopping Key (server-side)

You complete this step leveraging the Instant Shopping Button Keys API from your server-side

As a first step you need to obtain a Button key which you can reuse for displaying the Instant Shopping button. This key is used to identify you as a merchant and also to link to some necessary configuration options.

To obtain a key you can use the Instant Shopping Button Keys Service. An example of a request to this service is given below. Note that you need to use your API credentials to authenticate.

The minimum information needed to setup a Key is the URL of an endpoint where the Instant Shopping Button’s server-side will ping you when an Order is authorized.

Read about Klarna’s API URLs to know the base URL, and about Authentication to know how to authenticate when calling our REST API. More detailed documentation on the Instant Shopping orders API is available in the API documentation .

Request to generate a Button key

1
2
3
4
5
6
7
8
POST /instantshopping/v1/buttons
Authorization: Basic pwhcueUff0MmwLShJiBE9JHA==
Content-Type: application/json
{
  "merchant_urls": {
    "place_order": "< mandatory, URL of an endpoint at the merchant side, which will receive a ping to place an order. (must be https, max 2000 characters) >"
  }
}

Upon success the response of this service will provide you the button key.

Response for created Button key

1
2
3
4
5
6
7
HTTP 201 Created
Content-Type: application/json
Location: /instantshopping/v1/buttons/123e4567-e89b-12d3-a456-426655440000
{
  "button_key": "123e4567-e89b-12d3-a456-426655440000",
  "merchant_urls": { /* ... */ }
}

2. Setup and Display Instant Shopping Button (client-side)

You complete this step from your client-side

After successfully completing this part you should see the Instant Shopping Button.

2.a. Add the Javascript SDK to the page

You will need to make sure that the Instant Shopping Button Javascript SDK is available on the page you want to display the Instant Shopping Button.

To do this add the following script tag as soon as possible in the page (e.g. <head>).

1
2
3
4
5
6
7
8
9
10
<script>
  window.klarnaAsyncCallback = function () {

    // This is where you start calling Instant Shopping JS SDK functions
    //
    // Klarna.InstantShopping.load({....})

  };
</script>
<script src="https://x.klarnacdn.net/instantshopping/lib/v1/lib.js" async></script>

2.b. Add a container for the Instant Shopping Button to the page

At this step you decide where you want to place the Instant Shopping button within the page by positioning the HTML container element.

It is important to add a data attribute named data-instance-id to this element, which will uniquely identify this button. Note that you will refer to the value of this attribute when you use the JavaScript API and need to provide the setup.instance_id option. This is particularly necessary if you want to show multiple buttons on the same page. In that case each data-instance-id should be different and unique for this page.

1
  <klarna-instant-shopping data-instance-id="button-123abc456" />

2.c. Configure and display the Instant Shopping Button

You will now need to provide all the information necessary to support the purchase flow. This information refers to the product being promoted, relevant shipping options, locale, currency, etc.

Note that you will use the button key created from the previous step.

Below you see an example of the configuration options that are necessary for the consumer flow. Please note that the order_amount and order_tax_amount will be calculated by the service.

Consult our Javascript Docs for more information.

2.c.1 Load the Instant Shopping

The klarnaAsyncCallback is executed as soon as the Instant Shopping Javascript SDK is ready.

You should define this function before the script tag for fetching lib.js (see 2.a) and as early as possible in the page, e.g. head.

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
<head>
  <script>
    window.klarnaAsyncCallback = function () {
      Klarna.InstantShopping.load({
        "setup": {
          "instance_id": "button-123abc456",
          "key": "123e4567-e89b-12d3-a456-426655440000 >",
          "environment": "production",
          "region": "eu"
        },
        "purchase_country": "SE",
        "purchase_currency": "SEK",
        "locale": "sv-SE",
        "merchant_urls": {
          "terms": "https://www.example.com/terms.php", // mandatory
        },
        "order_lines": [{
          "type": "physical",
          "reference": "CLW-52m-5discount",
          "name": "Classic Low Bridge Sunglasses 5% Off Today!",
          "quantity": 1,
          "unit_price": 500000,
          "tax_rate": 0,
          "total_amount": 400000,
          "total_discount_amount": 100000,
          "total_tax_amount": 0,
          "product_url": "https://www.example.com/products/f2a8d7e34",
          "image_url": "https://www.example.com/products/f2a8d7e34"
        }],
        "merchant_reference1": "45aa52f387871e3a210645d4", // optional
        "shipping_options": [{ // add multiple if necessary
          "id": "express_priority",
          "name": "Express 1-2 days",
          "description": "Delivery by 4:30pm",
          "price": 5000,
          "tax_amount": 0,
          "tax_rate": 0,
          "shipping_method": "PickUpStore"
        }]
      }, function (response) {
        console.log('Klarna.InstantShopping.load callback with data:' + JSON.stringify(response))
      })
    };
  </script>
  <script src="https://x.klarnacdn.net/instantshopping/lib/v1/lib.js" async></script>
</head>
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
<head>
  <script>
    window.klarnaAsyncCallback = function () {
      Klarna.InstantShopping.load({
        "setup": {
          "instance_id": "button-123abc456",
          "key": "123e4567-e89b-12d3-a456-426655440000 >",
          "environment": "production",
          "region": "na"
        },
        "purchase_country": "US",
        "purchase_currency": "USD",
        "locale": "en-US",
        "merchant_urls": {
          "terms": "https://www.example.com/terms.php", // mandatory
        },
        "order_lines": [{
          "type": "physical",
          "reference": "CLW-52m-5discount",
          "name": "Classic Low Bridge Sunglasses 5% Off Today!",
          "quantity": 1,
          "unit_price": 50000,
          "tax_rate": 0,
          "total_amount": 40000,
          "total_discount_amount": 10000,
          "total_tax_amount": 0,
          "product_url": "https://www.example.com/products/f2a8d7e34",
          "image_url": "https://www.example.com/products/f2a8d7e34"
        }],
        "merchant_reference1": "45aa52f387871e3a210645d4", // optional
        "shipping_options": [{ // add multiple if necessary
          "id": "express_priority",
          "name": "Express 1-2 days",
          "description": "Delivery by 4:30pm",
          "price": 500,
          "tax_amount": 0,
          "tax_rate": 0,
          "shipping_method": "PickUpStore"
        }]
      }, function (response) {
        console.log('Klarna.InstantShopping.load callback with data:' + JSON.stringify(response))
      })
    };
  </script>
  <script src="https://x.klarnacdn.net/instantshopping/lib/v1/lib.js" async></script>
</head>

If you would like for a user to be presented with product specification options (examples include options for size, color, etc.), use the items object array instead of the order_lines object array. If you use both, Instant Shopping will default to using the order_lines object array.

3. Place the order (server-side)

You complete this step leveraging the Instant Shopping Button Keys API from your server-side

When the consumer has chosen to finalize the purchase, our server-side will ping you at the merchant_urls.place_order, and prompt you to place the order for a specific authorization_token. Remember that the URL for this endpoint was defined in the first step when you created this button key.

You will place the order through our REST API, and will be notified immediately about the successful or failed order placement. So you are able at this point already to create the order within your system.

You can choose to deny the purchase and in this case provide a deny reason and/or a URL to redirect the consumer to.

Read about Klarna’s API URLs to know the base URL, and about Authentication to know how to authenticate when calling our REST API. More detailed documentation on the Instant Shopping orders API is available in the API documentation.

Request prompt for placing Order

During this request we make available to you both the authorization_token to use next for placing the order, but also the details of the authorized order. Below you see an example of how the Request Body looks.

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
POST https://example.com/placeOrder.php
Content-Type: application/json
{
    "authorization_token": "a2be5f86-e505-4c6b-8d2c-bebdda7f5956",
    "order" : {
      "integrator_url": "https://example.com/cart.php",
      "purchase_country": "SE",
      "purchase_currency": "SEK",
      "locale": "sv-SE",
      "merchant_urls": {
        "terms": "https://www.example.com/terms.php",
      },
      "billing_address": {
        "given_name": "John",
        "family_name": "Doe",
        "email": "john.doe@example.com",
        "street_address": "Sveavägen 46",
        "postal_code": "11134",
        "city": "Stockholm",
        "phone": "+460700020020",
        "country": "SE"
      },
      "shipping_address": {
        "given_name": "John",
        "family_name": "Doe",
        "email": "john.doe@example.com",
        "street_address": "Sveavägen 46",
        "postal_code": "11134",
        "city": "Stockholm",
        "phone": "+460700020020",
        "country": "SE"
      },
      "customer": {
        "date_of_birth": "1985-10-20",
        "gender": "male"
      },
      "order_amount": 405000,
      "order_tax_amount": 0,
      "order_lines": [{
        "type": "physical",
        "reference": "CLW-52m-5discount",
        "name": "Classic Low Bridge Sunglasses 5% Off Today!",
        "quantity": 1,
        "unit_price": 500000,
        "tax_rate": 0,
        "total_amount": 500000,
        "total_discount_amount": 100000,
        "total_tax_amount": 0,
        "product_url": "https://www.example.com/products/f2a8d7e34",
        "image_url": "https://www.example.com/products/f2a8d7e34"
      }, {
        "type": "shipping_fee",
        "name": "express_priority",
        "quantity": 1,
        "tax_rate": 0,
        "total_tax_amount": 0,
        "unit_price": 5000,
        "total_amount": 5000
      }],
      "merchant_reference1": "45aa52f387871e3a210645d4",
      "selected_shipping_option": {
        "id": "express_priority",
        "name": "Express 1-2 days",
        "description": "Delivery by 4:30pm",
        "price": 5000,
        "tax_amount": 0,
        "tax_rate": 0,
        "shipping_method": "PickUpStore"
      }
    }
}
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
POST https://example.com/placeOrder.php
Content-Type: application/json
{
    "authorization_token": "a2be5f86-e505-4c6b-8d2c-bebdda7f5956",
    "order" : {
      "integrator_url": "https://example.com/cart.php",
      "purchase_country": "US",
      "purchase_currency": "USD",
      "locale": "en-US",
      "merchant_urls": {
        "terms": "https://www.example.com/terms.php",
      },
      "billing_address": {
        "given_name": "John",
        "family_name": "Doe",
        "email": "john.doe@example.com",
        "street_address": "8478 Hillside Street",
        "postal_code": "60102",
        "city": "Algonquin",
        "region": "IL",
        "phone": "630-342-7187",
        "country": "US"
      },
      "shipping_address": {
        "given_name": "John",
        "family_name": "Doe",
        "email": "john.doe@example.com",
        "street_address": "8478 Hillside Street",
        "postal_code": "60102",
        "city": "Algonquin",
        "region": "IL",
        "phone": "630-342-7187",
        "country": "US"
      },
      "customer": {
        "date_of_birth": "1985-10-20",
        "gender": "male"
      },
      "order_amount": 40500,
      "order_tax_amount": 0,
      "order_lines": [{
        "type": "physical",
        "reference": "CLW-52m-5discount",
        "name": "Classic Low Bridge Sunglasses 5% Off Today!",
        "quantity": 1,
        "unit_price": 50000,
        "tax_rate": 2500,
        "total_amount": 50000,
        "total_discount_amount": 0,
        "total_tax_amount": 10000,
        "product_url": "https://www.example.com/products/f2a8d7e34",
        "image_url": "https://www.example.com/products/f2a8d7e34"
      }, {
        "type": "discount",
        "name": "5% Discount",
        "quantity": 1,
        "tax_rate": 0,
        "total_tax_amount": 0,
        "unit_price": -10000,
        "total_amount": -10000
      }, {
        "type": "shipping_fee",
        "name": "express_priority",
        "quantity": 1,
        "tax_rate": 2500,
        "total_tax_amount": 100,
        "unit_price": 500,
        "total_amount": 500
      }],
      "merchant_reference1": "45aa52f387871e3a210645d4",
      "selected_shipping_option": {
        "id": "express_priority",
        "name": "Express 1-2 days",
        "description": "Delivery by 4:30pm",
        "price": 500,
        "tax_amount": 100,
        "tax_rate": 2500,
        "shipping_method": "PickUpStore"
      }
    }
}

The response from the place order request is not important for Klarna Instant Shopping to progress the purchase flow.

Instead you should proceed with all validations (stock, shipping capabilities, prices, etc.) on your side. Once those are done, approve or deny the order following the request guidelines below.

Deny the order

If you need to deny the purchase you need to perform a DELETE call though our API and provide some information in the request body. Note that you need to use your API credentials to authenticate.

Below you may find an example of how a deny requests may look:

1
2
3
4
5
6
7
DELETE /instantshopping/v1/authorizations/{authorization_token}
Authorization: Basic pwhcueUff0MmwLShJiBE9JHA==
Content-Type: application/json
{
  "deny_code": "address_error",
  "deny_message": "We cannot ship at this address."
}

Place the order

If you accept the order, then you need to place the order with our REST API. You do so by performing an HTTP POST in our API for the specific authorization_token and passing to the request body the complete Order. Note that you need to use your API credentials to authenticate.

Place order request

This is an example of how the Request could look like. Note that potential shipping fees are included in the order_lines object.

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
POST /instantshopping/v1/authorizations/{authorization_token}/orders
Authorization: Basic pwhcueUff0MmwLShJiBE9JHA==
Content-Type: application/json
  {
    "purchase_country": "SE",
    "purchase_currency": "SEK",
    "locale": "sv-SE",
    "merchant_urls": {
      "confirmation": "https://www.example.com/upsell.php", // mandatory if not given at step #3, this value will ovewrite the one set through button generation
      "push": "https://www.example.com/klarna-completed-orders", // optional, will overwrite the existing value if already set through button generation
      "notification": "https://www.example.com/klarna-pending-orders" // optional, will overwrite the existing value if already set through button generation
    },
    "billing_address": {
      "given_name": "John",
      "family_name": "Doe",
      "email": "john.doe@example.com",
      "street_address": "Sveavägen 46",
      "postal_code": "11134",
      "city": "Stockholm",
      "phone": "+460700020020",
      "country": "SE"
    },
    "shipping_address": {
      "given_name": "John",
      "family_name": "Doe",
      "email": "john.doe@example.com",
      "street_address": "Sveavägen 46",
      "postal_code": "11134",
      "city": "Stockholm",
      "phone": "+460700020020",
      "country": "SE"
    },
    "customer": {
      "date_of_birth": "1985-10-20",
      "gender": "male"
    },
    "order_amount": 405000,
    "order_tax_amount": 0,
    "order_lines": [{
      "type": "physical",
      "reference": "CLW-52m-5discount",
      "name": "Classic Low Bridge Sunglasses 5% Off Today!",
      "quantity": 1,
      "unit_price": 500000,
      "tax_rate": 2500,
      "total_amount": 500000,
      "total_discount_amount": 0,
      "total_tax_amount": 100000,
      "product_url": "https://www.example.com/products/f2a8d7e34",
      "image_url": "https://www.example.com/products/f2a8d7e34"
    }, {
      "type": "discount",
      "name": "5% Discount",
      "quantity": 1,
      "tax_rate": 0,
      "total_tax_amount": 0,
      "unit_price": -100000,
      "total_amount": -100000
    }, {
      "type": "shipping_fee",
      "name": "express_priority",
      "quantity": 1,
      "tax_rate": 2500,
      "total_tax_amount": 1000,
      "unit_price": 5000,
      "total_amount": 5000
    }],
    "merchant_reference1": "45aa52f387871e3a210645d4"
  }
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
POST /instantshopping/v1/authorizations/{authorization_token}/orders
Authorization: Basic pwhcueUff0MmwLShJiBE9JHA==
Content-Type: application/json
  {
    "purchase_country": "US",
    "purchase_currency": "USD",
    "locale": "en-US",
    "merchant_urls": {
      "confirmation": "https://www.example.com/upsell.php", // mandatory if not given at step #3, this value will ovewrite the one set through button generation
      "push": "https://www.example.com/klarna-completed-orders", // optional, will overwrite the existing value if already set through button generation
      "notification": "https://www.example.com/klarna-pending-orders" // optional, will overwrite the existing value if already set through button generation
    },
    "billing_address": {
      "given_name": "John",
      "family_name": "Doe",
      "email": "john.doe@example.com",
      "street_address": "8478 Hillside Street",
      "postal_code": "60102",
      "city": "Algonquin",
      "region": "IL",
      "phone": "630-342-7187",
      "country": "US"
    },
    "shipping_address": {
      "given_name": "John",
      "family_name": "Doe",
      "email": "john.doe@example.com",
      "street_address": "8478 Hillside Street",
      "postal_code": "60102",
      "city": "Algonquin",
      "region": "IL",
      "phone": "630-342-7187",
      "country": "US"
    },
    "customer": {
      "date_of_birth": "1985-10-20",
      "gender": "male"
    },
    "order_amount": 40500,
    "order_tax_amount": 0,
    "order_lines": [{
      "type": "physical",
      "reference": "CLW-52m-5discount",
      "name": "Classic Low Bridge Sunglasses 5% Off Today!",
      "quantity": 1,
      "unit_price": 50000,
      "tax_rate": 2500,
      "total_amount": 50000,
      "total_discount_amount": 0,
      "total_tax_amount": 10000,
      "product_url": "https://www.example.com/products/f2a8d7e34",
      "image_url": "https://www.example.com/products/f2a8d7e34"
    }, {
      "type": "discount",
      "name": "5% Discount",
      "quantity": 1,
      "tax_rate": 0,
      "total_tax_amount": 0,
      "unit_price": -10000,
      "total_amount": -10000
    }, {
      "type": "shipping_fee",
      "name": "express_priority",
      "quantity": 1,
      "tax_rate": 2500,
      "total_tax_amount": 100,
      "unit_price": 500,
      "total_amount": 500
    }],
    "merchant_reference1": "45aa52f387871e3a210645d4"
  }

The response of the order placement endpoint may be success or failure.

Success response when placing order

1
2
3
4
5
6
HTTP 200 Success
Content-Type: application/json
{
  "order_id": "41475c53-b38e-427e-ade1-db78e3018e19",
  "fraud_status": "ACCEPTED"
}

Failure response when placing order

1
2
3
4
5
6
HTTP 400 Bad Request
Content-Type: application/json
{
  "error_code": "bad_value",
  "error_message": "bad_value:locale"
}

4. Show post-purchase page

When the purchase is completed the consumer is notified via suitable messaging within the Instant Shopping. There, we show a call-to-action button for directing the consumer to a new location. This location is the post-purchase page you have supplied through the merchant_urls.confirmation when setting up the Instant Shopping Button.

The URL of this page has already been defined either in the first step when you created this button key or in the step when you approved the order. If you choose to do this when you approve the order, then you can customize and personalize what this page will be for the specific consumer and purchase.

For instance with these merchant urls:

1
2
3
"merchant_urls": {
  "confirmation": "http://example.com/upsell-similar-product.php"
}

the consumer after closing our dialog will land to: http://example.com/upsell-similar-product.php

Order Management

After the order is created, you can manage the order either manually via our Merchant Portal or through our Order Management API .