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 pricesCountryCode
controls the VAT or sales taxes used in price calculationsLanguageId
controls the language of the returned data, e.g. the name and description of products or name shipping methods
Other context related information
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 usedStockLocationId
when prices change depending on stock location or when creating carts with stock checks in the specified stock locationShopId
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 groupQueryName
to use a pre made query to return products (together withRepositoryName
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’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’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é 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