Documentation

SIW API

Overview

Note

All of the examples below are HTTP requests that can be roughly translated to the generated client method calls. The main goal is to get the overall feeling of the API and the data flows.

SIW is responsible for maintaining life cycle of a session that has all the data needed by the shipping selector widget. When a user visits checkout page, makes any changes to cart contents, selects shipping options and completes a purchase, all the relevant data are stored in the session.

Every session contains result field which provides information about currently selected delivery option. It contains all important information like:

Result field should be used in integration to get final result of session. The example result looks as follows:

{
"session": {
"result": {
"shipping": {
"shipping_method": "pnl-mpc",
"delivery_type": "pickup",
"carrier": "PostNord",
"product": "MyPack Collect",
"location": {
"external_id": "586287",
"name": "Direkten Sveavägen",
"address": {
"name": "Direkten Sveavägen",
"address_lines": ["Sveavägen 137"],
"city": "Stockholm",
"postal_code": "11346",
"country": "SE",
"coordinates": {
"lat": 59.34909509999998,
"lng": 18.050284299999994
}
},
"distance": {
"walking": {
"value": 450,
"duration": 5
},
"driving": {
"value": 771,
"duration": 1
}
},
"operational_hours": {
"mon": "08:00-20:00",
"tue": "08:00-20:00",
"wed": "08:00-20:00",
"thu": "08:00-20:00",
"fri": "08:00-20:00",
"sat": "09:00-17:00",
"sun": "10:00-16:00"
}
},
"delivery_time": {
"id": "VMzp-Ei2Lx7PAbmQMbnbFg",
"expires": "2019-07-04T15:00:00+02:00",
"start": "2019-07-05T00:00:00+02:00",
"end": "2019-07-09T00:00:00+02:00"
},
"external_method_id": "pnl-mypack",
"supports": {}
},
"category": {
"id": "category-pickup",
"name": "Category Pickup"
},
"pricing": {
"currency": "SEK",
"price": 1900
}
}
}
}

Create Session

The session.create method is used to create a new session. It returns the newly created Session as well as a html_snippet that can be embedded in the checkout page. Session can be created with minimal set of properties - purchase_country, purchase_currency, locale and cart.

SIW also supports embedding multiple widgets on a single page, see Multiple widgets.

Generic Flow

The sequence diagram below describes the flow between the Customer, Merchant, Shipping Selector and SIW API when creating a new session and rendering shipping selector for that session onto the checkout page.

sequenceDiagram participant C as Customer participant M as Merchant participant A as SIW API C->>M: Load checkout page M->>A: Create new session A->>M: Return shipping selector html snippet and session state M->>C: Render shipping selector html snippet on the page
  1. Customer loads the checkout page
  2. Merchant calls the session.create method
  3. SIW returns a new Session and the html_snippet needed to render the shipping selector.
  4. Merchant renders html_snippet on the page.

A minimal set of fields required to create a session is purchase_country, purchase_currency, locale and cart. A new session is returned along with an identifier and a token for authorization.

Note

We support Canada and United States regions, such as states and army regions that can be passed in the address (and on which the filtering of configured shipping methods can be done).

Supported Languages

The following locales are supported:

Example Calls

Request

POST /v1/siw/session.create HTTP/1.1
Host: api.ingrid.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer base64-encoded-api-token

{
"purchase_country": "SE",
"purchase_currency": "SEK",
"locales": [
"sv-SE"
],
"search_address": {
"postal_code": "11239",
"country": "SE"
},
"cart": {
"cart_id": "unique_id",
"total_value": 129900,
"currency": "SEK",
"items": [
{
"sku": "SKU12345",
"name": "Saucony Shadow 6000",
"quantity": 1,
"attributes": [
"shoes",
"indigo",
"class_one"
]
}
]
}
}

Response

HTTP/1.1 200 OK
Date: Mon, 04 Apr 2022 12:48:49 GMT
Content-Type: application/json
Content-Length: 311
Connection: close
Vary: Accept-Encoding
x-trace-id: S2022040412484922DNWX9NWYYT7EX9

{
"session": {
"id": "9a06e396-ec3a-4828-adc8-48159f05f049",
"status": "ACTIVE",
"cart": {
"total_value": 129900,
"total_discount": 0,
"currency": "SEK",
"pre_order": false,
"items": [
{
"sku": "SKU12345",
"name": "Saucony Shadow 6000",
"attributes": [
"shoes",
"indigo",
"class_one"
],
"out_of_stock": false,
"quantity": 1,
"price": 0
}
],
"cart_id": "unique_id"
},
"selected_shipping_option": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"price": 2900,
"currency": "SEK",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
},
"location_type": "MANNED"
},
"time_slot": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX"
},
"shipping_price": 2900,
"expires_at": "2022-04-04T17:00:00+02:00",
"search_address": {
"postal_code": "11239",
"country": "SE",
"coordinates": {
"lat": 59.33122199302237,
"lng": 18.030565761645196
}
},
"result": {
"shipping": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
}
},
"delivery_time": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX",
"supports": {
"search": true
},
"warehouse": {
"address": {
"name": "Ingrid Swedish Warehouse",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.320672,
"lng": 18.035503
}
}
}
},
"category": {
"id": "to-store-32e78a504919437fa8e191adc389aaaa",
"name": "To Store",
"presented_category_name": "Delivery To Store"
},
"pricing": {
"currency": "SEK",
"price": 2900,
"price_components": [
{
"type": "PRICE_COMPONENT_TYPE_SHIPPING",
"value": 2900
}
]
},
"selection": "PRESELECTED_CHOICE",
"delivery_time": {
"pickup_from_merchant": {
"earliest": "2022-04-04T16:00:00+02:00",
"latest": "2022-04-04T16:00:00+02:00"
},
"customer_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
},
"carrier_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
}
}
}
},
"html_snippet": "<div id='ingrid'> ... </div>"
}

Update Session

The session.update method can be used to update the Cart or Customer of the session if needed. You can updated either Cart, Customer or both at the same time.

There are two flows that should be used when it comes to updating the session.

  1. When customer changes the shipping option
  2. When cart contents change

Generic flow when customer changes shipping option

The sequence diagram below describes the flow between the Customer, Merchant, Shipping Selector and SIW API when updating a session. In this scenario shipping selector is the master so there is no need to suspend it.

sequenceDiagram participant C as Customer participant SS as Shipping Selector participant CO as Checkout participant M as Merchant participant A as SIW API C->>SS: Change the shipping option SS->>CO: Fire option changed JS event CO->>M: Do Ajax call to backend M->>A: Call /session.get A->>M: Return Session state M->>M: Update order with new shipping cost M->>CO: Return new shipping cost CO->>CO: Update total cost CO->>C: Show new total
  1. Customer changes shipping option
  2. Merchant is notified via JS event subscription
  3. Merchant makes the Ajax call to its backend
  4. Merchant fetches Ingrid Session using session.get and extracts the shipping cost
  5. Merchant updates its order data in the backend
  6. Merchant completes Ajax call and returns updated shipping cost
  7. Merchant updates total cart cost with newly updated shipping cost

Generic flow when cart contents change

The sequence diagram below describes the flow between the Customer, Merchant, Shipping Selector and SIW API when updating a session and checkout page is master.

sequenceDiagram participant C as Customer participant SS as Shipping Selector participant CO as Checkout participant M as Merchant participant A as SIW API C->>CO: Update cart CO->>SS: Suspend CO->>M: Ajax call to backend M->>A: Call /session.update A->>M: Return updated session state M->>M: Update order with updated shipping cost M->>CO: Return Ajax call CO->>CO: Update cart and totals CO->>SS: Resume shipping selector SS->>M: Refresh state A->>SS: Return updated state SS->>C: Display fresh shipping options
  1. Put shipping selector in suspend mode using the Javascript API
  2. Call Merchant backend to make the change, for example remove item from the cart.
  3. Apply the update to the Session using the session.update call
  4. Updated session is returned
  5. Merchant update order with updated shipping cost
  6. Complete the Ajax call in the checkout
  7. Resume shipping selector using the Javascript API
  8. Shipping selector will then refresh its state

Example Calls

Request

POST /v1/siw/session.update HTTP/1.1
Host: api.ingrid.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer base64-encoded-api-token

{
"id": "9a06e396-ec3a-4828-adc8-48159f05f049",
"cart": {
"cart_id": "unique_id",
"total_value": 274800,
"currency": "SEK",
"items": [
{
"sku": "SKU12345",
"name": "Saucony Shadow 6000",
"quantity": 1,
"price": 129900,
"attributes": [
"shoes",
"indigo",
"class_one"
]
},
{
"sku": "SKU65432",
"name": "Michigan Coat XL",
"quantity": 1,
"price": 144900,
"attributes": [
"tops",
"spring_campaign"
]
}
]
}
}

Response

HTTP/1.1 200 OK
Date: Mon, 04 Apr 2022 12:48:50 GMT
Content-Type: application/json
Content-Length: 357
Connection: close
Vary: Accept-Encoding
x-trace-id: S20220404124849MMYXH9MYX0ZCFX2W

{
"session": {
"id": "9a06e396-ec3a-4828-adc8-48159f05f049",
"status": "ACTIVE",
"cart": {
"total_value": 274800,
"total_discount": 0,
"currency": "SEK",
"pre_order": false,
"items": [
{
"sku": "SKU12345",
"name": "Saucony Shadow 6000",
"attributes": [
"shoes",
"indigo",
"class_one"
],
"out_of_stock": false,
"quantity": 1,
"price": 129900
},
{
"sku": "SKU65432",
"name": "Michigan Coat XL",
"attributes": [
"tops",
"spring_campaign"
],
"out_of_stock": false,
"quantity": 1,
"price": 144900
}
],
"cart_id": "unique_id"
},
"selected_shipping_option": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"price": 2900,
"currency": "SEK",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
},
"location_type": "MANNED"
},
"time_slot": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX"
},
"shipping_price": 2900,
"expires_at": "2022-04-04T17:00:00+02:00",
"search_address": {
"postal_code": "11239",
"country": "SE",
"coordinates": {
"lat": 59.33122199302237,
"lng": 18.030565761645196
}
},
"result": {
"shipping": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
}
},
"delivery_time": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX",
"supports": {
"search": true
},
"warehouse": {
"address": {
"name": "Ingrid Swedish Warehouse",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.320672,
"lng": 18.035503
}
}
}
},
"category": {
"id": "to-store-32e78a504919437fa8e191adc389aaaa",
"name": "To Store",
"presented_category_name": "Delivery To Store"
},
"pricing": {
"currency": "SEK",
"price": 2900,
"price_components": [
{
"type": "PRICE_COMPONENT_TYPE_SHIPPING",
"value": 2900
}
]
},
"selection": "PRESELECTED_CHOICE",
"delivery_time": {
"pickup_from_merchant": {
"earliest": "2022-04-04T16:00:00+02:00",
"latest": "2022-04-04T16:00:00+02:00"
},
"customer_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
},
"carrier_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
}
}
}
},
"html_snippet": "<div id=\"shipwallet-container\" style=\"min-height:350px\"> <style> #ingrid-loader { min-height: 350px; padding: 32px 12px 12px 12px; border: 1px solid #e6e6e6; border-radius: 6px; background-color: white; } ._ingrid-skeleton { background-color: #ededed; position: relative; overflow: hidden; -webkit-mask-image: -webkit-radial-gradient(white, black); } ._ingrid-skeleton::before { content: ''; background-image: linear-gradient(90deg, #ededed 0px, #f8f8f8 80px, #ededed 160px); animation: transform 1.8s ease-out infinite; transform-origin: 0 0; width: 100vw; height: 100%; left: -160px; position: absolute; display: block; } ._ingrid-skeleton-text { height: 10px; } ._ingrid-skeleton-shipping-indicator { height: 45px; width: 100%; } ._ingrid-skeleton-shipping-indicator-label { margin-bottom: 20px; width: 100px; } ._ingrid-skeleton-delivery-categories-wrapper { display: flex; flex-direction: column; width: 100%; padding-bottom: 9px; } ._ingrid-skeleton-shipping-option-first-row { display: flex; align-items: center; width: 100%; } ._ingrid-skeleton-checkbox { width: 20px; height: 20px; border-radius: 10px; margin-right: 8px; } ._ingrid-skeleton-flex-1 { flex: 1; } ._ingrid-skeleton-shipping-option-name { width: 60%; } ._ingrid-skeleton-price { width: 30px; margin-right: 12px; } ._ingrid-skeleton-shipping-option-second-row { display: flex; width: 100%; } ._ingrid-skeleton-delivery-description { width: 35%; } ._ingrid-skeleton-delivery-logo { width: 32px; height: 32px; border-radius: 50%; } ._ingrid-skeleton-delivery-categories-label { width: 200px; } ._ingrid-skeleton-delivery-category-wrapper { padding-bottom: 16px; } @keyframes transform { to { transform: translateX(120%); } } ._ingrid-skeleton-zipcode-label { width: 70px; margin-bottom: 12px; } ._ingrid-skeleton-zipcode-input { height: 50px; width: 100%; margin-bottom: 28px; } </style> <div id=\"ingrid-loader\"> <div style=\"width: 100%\"> <div> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-zipcode-label\"></div> <div class=\"_ingrid-skeleton _ingrid-skeleton-zipcode-input\"></div> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-shipping-indicator-label\" ></div> <div class=\"_ingrid-skeleton-delivery-categories-wrapper\"> <div class=\"_ingrid-skeleton-delivery-category-wrapper\"> <div class=\"_ingrid-skeleton-shipping-option-first-row\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-shipping-option-name\" ></div> </div> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-price\"></div> <div class=\"_ingrid-skeleton _ingrid-skeleton-delivery-logo\"></div> </div> <div class=\"_ingrid-skeleton-shipping-option-second-row\"> <div class=\"_ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-delivery-description\" ></div> </div> </div> </div> <div class=\"_ingrid-skeleton-delivery-category-wrapper\"> <div class=\"_ingrid-skeleton-shipping-option-first-row\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-shipping-option-name\" ></div> </div> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-price\"></div> <div class=\"_ingrid-skeleton _ingrid-skeleton-delivery-logo\"></div> </div> <div class=\"_ingrid-skeleton-shipping-option-second-row\"> <div class=\"_ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-delivery-description\" ></div> </div> </div> </div> <div class=\"_ingrid-skeleton-delivery-category-wrapper\"> <div class=\"_ingrid-skeleton-shipping-option-first-row\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-shipping-option-name\" ></div> </div> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-price\"></div> <div class=\"_ingrid-skeleton _ingrid-skeleton-delivery-logo\"></div> </div> <div class=\"_ingrid-skeleton-shipping-option-second-row\"> <div class=\"_ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-delivery-description\" ></div> </div> </div> </div> <div class=\"_ingrid-skeleton-shipping-option-first-row\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-shipping-option-name\" ></div> </div> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-price\"></div> <div class=\"_ingrid-skeleton _ingrid-skeleton-delivery-logo\"></div> </div> <div class=\"_ingrid-skeleton-shipping-option-second-row\"> <div class=\"_ingrid-skeleton-checkbox\"></div> <div class=\"_ingrid-skeleton-flex-1\"> <div class=\"_ingrid-skeleton _ingrid-skeleton-text _ingrid-skeleton-delivery-description\" ></div> </div> </div> </div> </div> </div> </div> <script> (function(window, instanceId, containerId, document) { window[instanceId] = window[instanceId] || function() { (window[instanceId].q = window[instanceId].q || []).push(arguments) }; var bootstrapURL = \"https://cdn-stage.ingrid.com/checkout-widget/94809f6/bootstrap.js\"; var bootstrapFallbackURL = \"https://cdn-stage.ingrid.com/checkout-widget/516071d/bootstrap.js\"; if (/MSIE|Trident/.test(window.navigator.userAgent)) { bootstrapURL = bootstrapFallbackURL; } window[instanceId].config = { container: document.getElementById(containerId), bootstrapURL: bootstrapURL, bootstrapFallbackURL: bootstrapFallbackURL, features: {\"hide_toc\":false,\"show_shipping_price_on_service_points_view\":true,\"show_carrier_icons\":true,\"new_search_address\":true,\"door_code\":false,\"show_map\":true,\"hide_street_on_address_fields\":true,\"disable_address_form\":false,\"show_city_on_address_fields\":false,\"display_upfront_address\":false,\"autocomplete_street\":false,\"display_location_type\":false,\"dont_require_street_on_address_fields\":false,\"show_state_on_address_fields\":false,\"show_delivered_by\":false,\"show_street_on_address_module\":false,\"show_city_on_address_module\":false,\"require_street_on_address_module\":false,\"enable_ingrid_logo\":true,\"enable_widget_border\":true,\"enable_transparent_background\":false,\"show_shipping_categories_before_address\":true,\"enable_accent_color_for_widget_elements\":false,\"dark_color_enabled\":true,\"show_slogan\":false,\"show_carrier_logos_in_shipping_categories_placeholder\":true,\"enable_free_shipping_indicator\":true,\"enable_free_shipping_indicator_category_name_message\":true,\"enable_free_shipping_indicator_carrier_logo\":false,\"enable_delivery_address_form\":false,\"show_privacy_policy\":false,\"show_region\":false,\"require_region\":false,\"shipping_categories_visible_when_folded_count\":0,\"enable_multiple_home_delivery_in_category\":false,\"display_currency_iso_code\":false,\"enable_postal_code_in_location_address\":false,\"enable_analytics\":false,\"show_currency_before_price\":false,\"show_cancel_button_on_modal\":false}, instanceId: instanceId, locale: \"sv-SE\", logging: \"https://c7a68a2a3cfe4024bf719e6485aa8751@sentry.io/141995\", status: \"ACTIVE\", style: {}, session: \"9a06e396-ec3a-4828-adc8-48159f05f049\", token: \"Y2xpZW50dHdvOjFlMzZmMGI2ZjhjYjRhYzk4ZTg5NzcwYjQ5OTRkYjUx\", version: \"8f7ecbbf\", loaderId: \"ingrid-loader\" }; var container = document.getElementById(containerId); var bootstrapScript = document.createElement(\"script\"); bootstrapScript.async = true; bootstrapScript.src = bootstrapURL; bootstrapScript.className = \"ingrid-bootstrap-script\"; bootstrapScript.addEventListener(\"load\", function (e) { if (typeof _ingrid_initializeWidgetInstance === \"function\") { _ingrid_initializeWidgetInstance(instanceId); } }); container.appendChild(bootstrapScript); })(window, '_sw', 'shipwallet-container', document); </script> <noscript> Please <a href=\"https://enable-javascript.com\">enable JavaScript</a>. </noscript></div>"
}
Note

The difference between the search address and the customer address is that the first one simply points us to which area package should be delivered, but it doesn't need to be customer real address. The customer address must be provided by the merchant.

For example, if you want to have a package delivered close to your work, you can fill search address with your office address. The customer is a customer home address. It allows performing fraud detection if someone is ordering an expensive item and customer and search addresses are distant to each other. The merchant could compare both addresses and verify if the order is valid by contacting the customer before shipping goods.

Complete Session

The session.complete method is used to mark a session as complete. At this point, if the customer haven't made a choice we'll generate one for the customer based on the information in the Customer property provided in the request.

::: tip Search address and customer address are two different entities, that serve separate purposes during session lifetime. Search address is provided by the customer and the customer address is always provided by merchant. Search address is used to generate the shipping options that will be presented to the customer. Customer address is the address where the parcel will be sent and should be provided sometime during session lifetime (at the latest during session.complete).

Shipping options may be regenerated under some conditions when the customer address is provided and it differs from the search address. :::

The sequence diagram below describes the flow between the Customer, Merchant, Shipping Selector and SIW API when completing a session when the customer checkout.

sequenceDiagram participant C as Customer participant M as Merchant participant A as SIW API C->>M: Completes the order M->>A: Call /session.complete A->>M: Return completed session state M->>C: Redirects to confirmation page
  1. Customer completes the transaction
  2. Merchant completes the session using session.complete method
  3. SIW API returns session in a completed state. The SelectedShippingOption and tos_id are also returned.
  4. Merchant redirects the customer to the confirmation page

On session complete call a tos_id will be returned. This id is important if you need to re-open a session as a completed session is "frozen" and cannot be modified. You can use tos_id to clone a completed session.

Example Calls

Request

POST /v1/siw/session.complete HTTP/1.1
Host: api.ingrid.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer base64-encoded-api-token

{
"id": "9a06e396-ec3a-4828-adc8-48159f05f049",
"customer": {
"email": "erik@ingrid.com",
"phone": "0709997711",
"address": {
"name": "Erik Johansson",
"address_lines": [
"Industrigatan 5"
],
"city": "Stockholm",
"postal_code": "11239",
"country": "SE"
}
}
}

Response

HTTP/1.1 200 OK
Date: Mon, 04 Apr 2022 12:48:51 GMT
Content-Type: application/json
Content-Length: 233
Connection: close
Vary: Accept-Encoding
x-trace-id: S20220404124851BM4ZP8VGHFFCF98A

{
"session": {
"id": "9a06e396-ec3a-4828-adc8-48159f05f049",
"status": "COMPLETE",
"cart": {
"total_value": 274800,
"total_discount": 0,
"currency": "SEK",
"pre_order": false,
"items": [
{
"sku": "SKU12345",
"name": "Saucony Shadow 6000",
"attributes": [
"shoes",
"indigo",
"class_one"
],
"out_of_stock": false,
"quantity": 1,
"price": 129900
},
{
"sku": "SKU65432",
"name": "Michigan Coat XL",
"attributes": [
"tops",
"spring_campaign"
],
"out_of_stock": false,
"quantity": 1,
"price": 144900
}
],
"cart_id": "unique_id"
},
"selected_shipping_option": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"price": 2900,
"currency": "SEK",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
},
"location_type": "MANNED"
},
"time_slot": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX"
},
"shipping_price": 2900,
"expires_at": "2022-04-04T17:00:00+02:00",
"customer": {
"address": {
"name": "Erik Johansson",
"address_lines": [
"Industrigatan 5"
],
"city": "Stockholm",
"postal_code": "11239",
"country": "SE"
},
"phone": "0709997711",
"email": "erik@ingrid.com"
},
"search_address": {
"postal_code": "11239",
"country": "SE",
"coordinates": {
"lat": 59.33122199302237,
"lng": 18.030565761645196
}
},
"tos_id": "01FZT9XVY7R95VRE6BT3YS1MF2",
"result": {
"shipping": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
}
},
"delivery_time": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX",
"supports": {
"search": true
},
"warehouse": {
"address": {
"name": "Ingrid Swedish Warehouse",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.320672,
"lng": 18.035503
}
}
}
},
"category": {
"id": "to-store-32e78a504919437fa8e191adc389aaaa",
"name": "To Store",
"presented_category_name": "Delivery To Store"
},
"pricing": {
"currency": "SEK",
"price": 2900,
"price_components": [
{
"type": "PRICE_COMPONENT_TYPE_SHIPPING",
"value": 2900
}
]
},
"selection": "PRESELECTED_CHOICE",
"delivery_time": {
"pickup_from_merchant": {
"earliest": "2022-04-04T16:00:00+02:00",
"latest": "2022-04-04T16:00:00+02:00"
},
"customer_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
},
"carrier_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
}
}
}
},
"tos_id": "01FZT9XVY7R95VRE6BT3YS1MF2"
}
  1. Customer loads the checkout page
  2. Merchant calls the session.get method
  3. SIW API returns a new Session and the html_snippet to render shipping selector
  4. Merchant renders html_snippet in the checkout page

Example Calls

Request

GET /v1/siw/session.get?id=9a06e396-ec3a-4828-adc8-48159f05f049 HTTP/1.1
Host: api.ingrid.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer base64-encoded-api-token


Response

HTTP/1.1 200 OK
Date: Mon, 04 Apr 2022 12:48:51 GMT
Content-Type: application/json

Connection: close
Vary: Accept-Encoding
x-trace-id: S20220404124851TQFJ979G26X0E9GC

{
"session": {
"id": "9a06e396-ec3a-4828-adc8-48159f05f049",
"status": "COMPLETE",
"cart": {
"total_value": 274800,
"total_discount": 0,
"currency": "SEK",
"pre_order": false,
"items": [
{
"sku": "SKU12345",
"name": "Saucony Shadow 6000",
"attributes": [
"shoes",
"indigo",
"class_one"
],
"out_of_stock": false,
"quantity": 1,
"price": 129900
},
{
"sku": "SKU65432",
"name": "Michigan Coat XL",
"attributes": [
"tops",
"spring_campaign"
],
"out_of_stock": false,
"quantity": 1,
"price": 144900
}
],
"cart_id": "unique_id"
},
"selected_shipping_option": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"price": 2900,
"currency": "SEK",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
},
"location_type": "MANNED"
},
"time_slot": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX"
},
"shipping_price": 2900,
"expires_at": "2022-04-04T17:00:00+02:00",
"customer": {
"address": {
"name": "Erik Johansson",
"address_lines": [
"Industrigatan 5"
],
"city": "Stockholm",
"postal_code": "11239",
"country": "SE"
},
"phone": "0709997711",
"email": "erik@ingrid.com"
},
"search_address": {
"postal_code": "11239",
"country": "SE",
"coordinates": {
"lat": 59.33122199302237,
"lng": 18.030565761645196
}
},
"tos_id": "01FZT9XVY7R95VRE6BT3YS1MF2",
"result": {
"shipping": {
"shipping_method": "ics-ingrid",
"delivery_type": "instore",
"carrier": "Ingrid",
"product": "Pickup in Store",
"location": {
"external_id": "I1",
"name": "Ingrid HQ",
"address": {
"name": "Ingrid HQ",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.3207318,
"lng": 18.0335876
}
},
"distance": {
"walking": {
"value": 1780,
"duration": 21
},
"driving": {
"value": 3097,
"duration": 6
}
}
},
"delivery_time": {
"id": "JX-j3oY97EGJjuCfx7MF2g",
"expires": "2022-04-04T17:00:00+02:00",
"start": "2022-04-04T00:00:00+02:00",
"end": "2022-04-04T00:00:00+02:00"
},
"external_method_id": "ProffsmagasinetBOX",
"supports": {
"search": true
},
"warehouse": {
"address": {
"name": "Ingrid Swedish Warehouse",
"address_lines": [
"Mälarvarvsbacken 8"
],
"city": "Stockholm",
"postal_code": "11733",
"country": "SE",
"coordinates": {
"lat": 59.320672,
"lng": 18.035503
}
}
}
},
"category": {
"id": "to-store-32e78a504919437fa8e191adc389aaaa",
"name": "To Store",
"presented_category_name": "Delivery To Store"
},
"pricing": {
"currency": "SEK",
"price": 2900,
"price_components": [
{
"type": "PRICE_COMPONENT_TYPE_SHIPPING",
"value": 2900
}
]
},
"selection": "PRESELECTED_CHOICE",
"delivery_time": {
"pickup_from_merchant": {
"earliest": "2022-04-04T16:00:00+02:00",
"latest": "2022-04-04T16:00:00+02:00"
},
"customer_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
},
"carrier_delivery_promise": {
"earliest": "2022-04-04T00:00:00+02:00",
"latest": "2022-04-04T00:00:00+02:00"
}
}
}
},
"html_snippet": "<div id='ingrid'> ... </div>"
}

Errors

Concurrent updates

Session get, update and complete calls can fail when another concurrent call is made, that updates the session resource. In that case, the response to this call would be a message with HTTP 409 Conflict code, and the call would have to be made again.

Last updated: Thu, Jun 30, 06:15 AM