Table of Contents

Commerce

How to use our commerce endpoints

When using the Commerce endpoints there are some context related information to consider.

Most of the endpoints can return the same data in different contexts that control e.g. prices and languages why most of the endpoints accepts additional parameters - the most important ones being the following:

  • CurrencyCode
  • CountryCode
  • LanguageId

E.g.

GET /dwapi/ecommerce/products/search?GroupId=group5&CurrencyCode=DKK&CountryCode=DK&LanguageId=LANG1

  • CurrencyCode parameter controls the currency of returned prices
  • CountryCode controls the VAT or sales taxes used in price calculations
  • LanguageId controls the language of the returned data, e.g. the name and description of products or name shipping methods

There are other parameters that can affect the price of a product and the calculation of order line sub totals.

Depending on the setup and prices in the price matrix, prices can differ on the following additional parameters:

  • OrderDate if prices change in periods in time, this parameter can be used
  • StockLocationId when prices change depending on stock location or when creating carts with stock checks in the specified stock location
  • ShopId when prices differs in different channels

User and personalised prices

The logged in user can also affect the prices and discounts applied to products and orders and can affect which products are returned if assortments are used.

Use a valid JWT in a bearer token.

Products

The POST /dwapi/ecommerce/products and GET /dwapi/ecommerce/products/search are essentially the same except one is POST and the other is a GET.

The endpoint has the following search methods:

  • GroupID to return products from a specific product group
  • QueryName to use a pre made query to return products (together with RepositoryName parameter)
  • ProductIds to find a range of products from the specific product ids

Get products by group id

To return products from a group, specify the group id parameter and use a valid group id as the value:

GET /dwapi/ecommerce/products/search?GroupId=group5&CurrencyCode=DKK&CountryCode=DK&LanguageId=LANG1

Get products using a query

To return products using a query, specify the QueryName parameter and use a valid name of a query and also specify the RepositoryName parameter and use the name of the repository of the query:

GET /dwapi/ecommerce/products/search?RepositoryName=Products&QueryName=Products&CurrencyCode=DKK&CountryCode=DK&LanguageId=LANG1

The query is defined in the admin under Settings > System > Repositories. The parameters defined in the query can be used as additional parameters on the endpoint for searching as well.

Say the query has a parameter called ShowActive that is used in an expression on the query:

GET /dwapi/ecommerce/products/search?RepositoryName=Products&QueryName=Products&CurrencyCode=DKK&CountryCode=DK&LanguageId=LANG1&ShowActive=True

Important

Please note that in a headless setup, macros are not available as they depend on a frontend context to run. Instead set a parameter (e.g. ShopId) and call it as a custom parameter through the /dwapi/query parameter.

Get products using product ids

The product ids is sent in as a list, so the request can look like the following:

GET /dwapi/ecommerce/products/search?ProductIds=10003&ProductIds=10004&CurrencyCode=DKK&CountryCode=DK&LanguageId=LANG1

Result from products endpoint

The return of this endpoint is a product list viewmodel. The list viewmodel contains information about the group, number of products and pages and the product items themselves.

{
  "group": {
    "id": "GROUP5",
    "name": "Road bikes",
    "title": "Road bikes",
    "number": "",
    "description": "",
    "metaDescription": "",
    "sorting": null,
  },
  "subGroups": [],
  "products": [
    {
      "id": "10003",
      "languageId": "LANG1",
      "name": "Scattante CFR Elite",
      ...
    },
    {
      "id": "10004",
      "languageId": "LANG1",
      "name": "Scattante CFR Max",
      ...
    }
    ...
   ],
  "pageSize": 10,
  "pageCount": 2,
  "currentPage": 1,
  "totalProductsCount": 16,
  "sortBy": null,
  "sortOrder": null,
  "spellCheckerSuggestions": null,
  "facetGroups": null
}

These 2 endpoints can take a lot of parameters to control which products to return, which properties of the product view model to return.

Refer to the Swagger docs on /dwapi/docs for options.

Get a single product

To retrieve a single product, add the product id as part of the URL and also specify currency code, country code and language id to get it in the right context:

GET /dwapi/ecommerce/products/10003?CurrencyCode=DKK&CountryCode=DK

Getting a variant of a product also add the variant id as part of the URL:

GET /dwapi/ecommerce/products/10003/VO1.VO2?CurrencyCode=DKK&CountryCode=DK

The product returned:

{
  "id": "10003",
  "variantId": "",
  "languageId": "LANG1",
  "name": "Scattante CFR Elite ",
  "title": "Scattante CFR Elite ",
  "shortDescription": "<p>Representing the upper crust of cycling society, the CFR Elite flaunts a beautiful carbon frame and sophisticated components that&rsquo;ll have you accelerating with speed, power and agility.</p>",
  "longDescription": "<ul>\n<li>Representing the upper crust of cycling society, the CFR Elite flaunts a beautiful carbon frame and sophisticated components that&rsquo;ll have you accelerating with speed, power and agility. Lightweight carbon monocoque frame with carbon/aluminum fork offers a stiff and efficient ride with less vibration</li>\n<li>Shimano Ultegra drivetrain blends race-proven technology with ergonomic perfection to give you a new level of shifting performance</li>\n<li>FSA SLK Light Carbon cranks with MegaExo bottom bracket deliver super-stiff, no-flex pedaling power for the road ahead</li>\n<li>Fort&eacute; Precision handlebar and stem with carbon seatpost supply core-level strength, style and vibration damping performance</li>\n<li>Tektro R740 dual pivot calipers deliver strong, progressive stopping power and good modulation</li>\n<li>Continental Ultra Sport tires provide comfort and exceptional handling, especially on rough road surfaces</li>\n<li>Mavic Aksium wheels are lightweight, responsive and ensure a stable, reliable ride</li>\n</ul>",
  "metaDescription": "",
  "metaTitle": "",
  "metaKeywords": "",
  "number": "10003",
  "created": "2021-05-11T11:07:39",
  "updated": "2024-03-06T13:57:27.773",
  "keywords": "",
  "stockLevel": -2,
  "stockStatus": null,
  "stockDeliveryText": null,
  "stockDeliveryValue": null,
  "weight": 2,
  "productType": "stock",
  "width": 2,
  "height": 2,
  "depth": 2,
  "purchaseMinimumQuantity": 0,
  "purchaseQuantityStep": 0,
  "cost": 1254,
  "ean": "9998877652764353674",
  "expectedDelivery": null,
  "discontinued": false,
  "discontinuedAction": 0,
  "pointPrice": 0,
  "defaultVariantId": "",
  "defaultUnitId": "",
  "variantName": "",
  "active": true,
  "rating": 0,
  "replacementProduct": {
    "productId": "",
    "variantId": ""
  },
  "price": {
    "showPricesWithVat": false,
    "price": 11993.33,
    "priceFormatted": "11.993,33 kr.",
    "priceWithoutVat": 11993.33,
    "priceWithoutVatFormatted": "11.993,33 kr.",
    "priceWithVat": 14991.67,
    "priceWithVatFormatted": "14.991,67 kr.",
    "vat": 2998.34,
    "vatFormatted": "2.998,34 kr.",
    "vatPercent": 25,
    "vatPercentFormatted": "25%",
    "currencyCode": "DKK"
  },
  "priceInformative": {
    "showPricesWithVat": false,
    "price": 0,
    "priceFormatted": null,
    "priceWithoutVat": 0,
    "priceWithoutVatFormatted": null,
    "priceWithVat": 0,
    "priceWithVatFormatted": null,
    "vat": 0,
    "vatFormatted": null,
    "vatPercent": 0,
    "vatPercentFormatted": null,
    "currencyCode": null
  },
  "priceBeforeDiscount": {
    "showPricesWithVat": false,
    "price": 11993.33,
    "priceFormatted": "11.993,33 kr.",
    "priceWithoutVat": 11993.33,
    "priceWithoutVatFormatted": "11.993,33 kr.",
    "priceWithVat": 14991.67,
    "priceWithVatFormatted": "14.991,67 kr.",
    "vat": 2998.34,
    "vatFormatted": "2.998,34 kr.",
    "vatPercent": 25,
    "vatPercentFormatted": "25%",
    "currencyCode": "DKK"
  },
  "discount": {
    "showPricesWithVat": false,
    "price": 0,
    "priceFormatted": "0,00 kr.",
    "priceWithoutVat": 0,
    "priceWithoutVatFormatted": "0,00 kr.",
    "priceWithVat": 0,
    "priceWithVatFormatted": "0,00 kr.",
    "vat": 0,
    "vatFormatted": "0,00 kr.",
    "vatPercent": 0,
    "vatPercentFormatted": "0%",
    "currencyCode": "DKK"
  },
  "productDiscounts": [],
  "prices": [],
  "productFields": {
    "Total_height": {
      "systemName": "Total_height",
      "name": "Total height",
      "type": "Double",
      "value": 0,
      "listType": 0
    }
  },
  "productCategories": {
    "brand_information": {
      "id": "brand_information",
      "name": "Brand information",
      "fields": {
        "Brand_name": {
          "systemName": "Brand_name",
          "name": "Brand name",
          "type": "Text",
          "value": "Scattante",
          "listType": 0
        },
        "Gear_no_of": {
          "systemName": "Gear_no_of",
          "name": "Gear (# of)",
          "type": "Integer",
          "value": 21,
          "listType": 0
        }
      }
    }
  }}
  "groups": [],
  "primaryOrDefaultGroup": {
    "id": "GROUP155",
    "name": "All bikes",
    "sorting": null,
    "primaryPageId": 0
  },
  "variantInfo": {
    "productID": "10003",
    "variantID": "",
    "optionID": null,
    "optionName": null,
    "optionColor": null,
    "optionSort": 0,
    "productName": "Scattante CFR Elite ",
    "productNumber": "10003",
    "productStock": -2,
    "variantInfoGroupId": null,
    "variantInfoGroupName": null,
    "variantInfoGroupDescription": null,
    "variantGroupDisplayType": "nothingSelected",
    "optionImage": null,
    "image": {
      "value": "/Files/Images/missing_image.jpg",
      "name": "Default",
      "keywords": null,
      "displayName": null
    },
    "price": {
      "showPricesWithVat": false,
      "price": 11993.33,
      "priceFormatted": "11.993,33 kr.",
      "priceWithoutVat": 11993.33,
      "priceWithoutVatFormatted": "11.993,33 kr.",
      "priceWithVat": 14991.67,
      "priceWithVatFormatted": "14.991,67 kr.",
      "vat": 2998.34,
      "vatFormatted": "2.998,34 kr.",
      "vatPercent": 25,
      "vatPercentFormatted": "25%",
      "currencyCode": "DKK"
    },
    "priceMin": {
      "showPricesWithVat": false,
      "price": 11993.33,
      "priceFormatted": "11.993,33 kr.",
      "priceWithoutVat": 11993.33,
      "priceWithoutVatFormatted": "11.993,33 kr.",
      "priceWithVat": 14991.67,
      "priceWithVatFormatted": "14.991,67 kr.",
      "vat": 2998.34,
      "vatFormatted": "2.998,34 kr.",
      "vatPercent": 25,
      "vatPercentFormatted": "25%",
      "currencyCode": "DKK"
    },
    "priceMax": {
      "showPricesWithVat": false,
      "price": 11993.33,
      "priceFormatted": "11.993,33 kr.",
      "priceWithoutVat": 11993.33,
      "priceWithoutVatFormatted": "11.993,33 kr.",
      "priceWithVat": 14991.67,
      "priceWithVatFormatted": "14.991,67 kr.",
      "vat": 2998.34,
      "vatFormatted": "2.998,34 kr.",
      "vatPercent": 25,
      "vatPercentFormatted": "25%",
      "currencyCode": "DKK"
    },
    "stock": -2,
    "variantInfo": null
  },
  "defaultImage": {
    "value": "/Files/Images/missing_image.jpg",
    "name": "Default",
    "keywords": null,
    "displayName": null
  },
  "groupPaths": [],
  "imagePatternImages": [],
  "manufacturer": {
    "id": null,
    "name": null,
    "address": null,
    "zipCode": null,
    "city": null,
    "country": null,
    "phone": null,
    "fax": null,
    "email": null,
    "web": null,
    "logo": null,
    "description": null
  },
  "assetCategories": [],
  "neverOutOfstock": false,
  "stockUnits": [],
  "unitOptions": [],
  "relatedGroups": []
}

The amount of fields can be limited by using the FilledProperties option`:

GET /dwapi/ecommerce/products/10003?CurrencyCode=DKK&CountryCode=DK&FilledProperties=Id,Name,Price

Which will make the returned document smaller:

{
  "id": "10003",
  "name": "Scattante CFR Elite ",
  "price": {
    "showPricesWithVat": false,
    "price": 11993.33,
    "priceFormatted": "11.993,33 kr.",
    "priceWithoutVat": 11993.33,
    "priceWithoutVatFormatted": "11.993,33 kr.",
    "priceWithVat": 14991.67,
    "priceWithVatFormatted": "14.991,67 kr.",
    "vat": 2998.34,
    "vatFormatted": "2.998,34 kr.",
    "vatPercent": 25,
    "vatPercentFormatted": "25%",
    "currencyCode": "DKK"
  }
}

One of the returned properties is Price, which is a view model it self with a number of properties. The return of those properties can also be limited by adding an additional parameter.

The amount of fields on the price viewmodel can be limited by using the PriceSettings.FilledProperties option:

GET /dwapi/ecommerce/products/10003?CurrencyCode=DKK&CountryCode=DK&FilledProperties=Id,Name,Price&PriceSettings.FilledProperties=priceWithVatFormatted,priceWithoutVatFormatted

Which will make the returned document even smaller:

{
  "id": "10003",
  "name": "Scattante CFR Elite ",
  "price": {
    "priceWithoutVatFormatted": "11.993,33 kr.",
    "priceWithVatFormatted": "14.991,67 kr.",
  }
}

Carts

Carts are created by using POST /dwapi/ecommerce/carts/create endpoint. The endpoint takes parameters to control currency, VAT and language as described in the introduction to this article.

  • CurrencyCode
  • CountryCode
  • LanguageId

A body is required in the POST of the create endpoint, but can be an empty document.

The cart can be created in the following contexts:

  • For anonymous user
  • For the current user
  • For users that the current user can impersonate

For anonymous users, make an anonymous post.

POST /dwapi/ecommerce/carts/create?CurrencyCode=DKK&=DK&LanguageId=LANG1
{
  "customerName": "John Doe"
}

For the current user, pass the JWT as a bearer token to create the cart in the context of the user to respect user specific prices and relate the cart to the user for later retrieval of stored carts. The id of the current user will be set on the cart automatically.

Authorization: Bearer <token>
POST /dwapi/ecommerce/carts/create?CurrencyCode=DKK&=DK&LanguageId=LANG1
{
}

For users that the current user can impersonate, pass the current user JWT as bearer and in the POST body document add the CustomerUserId with the id of user the cart should belong to. The CustomerUserId has to be a user that the current user can impersonate or a 403 will be returned.

Authorization: Bearer <token>
POST /dwapi/ecommerce/carts/create?CurrencyCode=DKK&=DK&LanguageId=LANG1
{
  "CustomerUserId" : 123
}

In the above example the user id that is connected to the JWT is e.g. 100 and that user can impersonate user with id 123 and will create a cart on behalf of user 123.

The return of the POST is an order ViewModel of the newly created cart with its id and its secret which has to be stored in your JS app and used in subsequent requests to the cart endpoints where {secret} is used as identifier.

{
  "id": "CART123",
  "secret": "a480a17e0d9e40a9bd3499be74db1b8f",
  "customerUserId" : 123,
  "deliveryCountryCode": "DK",
  "createdAt": "2024-04-23T18:26:03.2794348+02:00",
  "modified": "2024-04-23T18:26:03.286099+02:00",
  ...
}

To retrieve the cart at any point in time, use the secret in the get:

GET /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f

Adding products to cart

To add a product to the cart, a new order line has to be created using the POST /dwapi/ecommerce/carts/{secret}/items endpoint.

POST /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f/items
{
  "ProductId": "10100",
  "ProductVariantId": "",
  "Quantity": 2
}

The endpoint returns 200 when the product is added. To get an updated cart with the new prices, call the GET /dwapi/ecommerce/carts/{secret} endpoint to get the updated instance of the cart.

Update quantity on orderline

To update an order line and change i.e. the quantity, use the PATCH /dwapi/ecommerce/carts/{secret}/items/{itemId} endpoint:

PATCH /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f/items/OL12
{
  "quantity": 12
}

The endpoint returns 200 when the product is added. To get an updated cart with the new prices, call the GET /dwapi/ecommerce/carts/{secret} endpoint to get the updated instance of the cart.

Set shipping method

To set the shipping method of the order, call the PATCH /dwapi/ecommerce/carts/{secret}/shipping/{shippingId} endpoint with a valid cart secret and a valid shipping id. The list of available shipping methods can be retrieved on the /shippings endpoint.

PATCH /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f/shipping/SHIP1

When the shipping method is applied, the price of the cart is updated to reflect the shipping fee.

Set payment method

To set the payment method of the order, call the PATCH /dwapi/ecommerce/carts/{secret}/payment/{paymentId} endpoint with a valid cart secret and a valid payment id. The list of available payments can be retrieved on the /payments endpoint.

PATCH /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f/payment/PAY1

When the payment method is applied, the price of the cart is updated to reflect the payment fee.

Complete order

To convert a cart to an order there are the following options:

  • Complete an order after handling payment gateway in your app or if the user pays by invoice
  • Start checkout flow to collect payment from payment gateway

To convert a cart to an order without starting a payment flow make a POST to the createorder endpoint using the cart secret.

POST /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f/createorder

After this post, the cart is converted to an order with an order id instead of cart id and complete is set to true - the cart secret remains the same. The cart can no longer be modified and retrieved on the other cart endpoints. The order can now be retrieved on the orders endpoints instead for authenticated users.

To start a checkout flow using a payment gateway, call the checkout endpoint using the cart secret.

The cart has to have a payment method set that has a checkouthandler defined and setup. The checkout handler also has to support headless checkouts.

GET /dwapi/ecommerce/carts/a480a17e0d9e40a9bd3499be74db1b8f/checkout

When this endpoint is called, the cart is converted to an order with an order id (and no longer a cart id), but its complete state is still false. The return of this call is not a regular JSON document. It is the result of passing the order to the checkout handler which will create a payment and return some markup that needs to be injected in your app to start the payment window.

<!--/checkout response-->
<div>
....
<script>//logic to start payment gateway</script>
....
</div>

When the payment flow in the payment window is successfully completed, the payment gateway will make server-to-server callback to the /callback endpoint (you do not have to do this) which will set the order as complete.

Receipts

TBD: When and how to show receipt

To top