Merchant API: best practices
About this article
This article contains guidelines to improve the quality and resiliency of implementations of ChannelEngine's Merchant API.
Table of contents
Check and log the response code, and retry if needed
Use incremental updates, but add an option to (re-)export all
Submitting product data is purge and replace
Log your order validation for users (show why an order is not acknowledged)
Build support for paginated responses
Do bulk calls when possible, limit the total number of calls
Submit valid shipment information, no placeholders
Introduction
When you build an implementation of the ChannelEngine REST API (either for merchants or for a channel), it is crucial that you or your developer implement all calls properly – including fallbacks in case of incorrect calls or unavailable services.
This article describes best practices to develop an integration with ChannelEngine's Merchant API. Following these guidelines, the testing flow, and the dataflow increases the chance of your integration working flawlessly.
Test your integration
ChannelEngine's teams have seen many integrations that were not fully tested – and issues came to light when the integration was already in production. Therefore, it is crucial to check your testing flow and compare it with ChannelEngine's standard test flow to see if you missed any specific parts of the integration. If you do not already have a dev environment (usually account-name-dev.channelengine.net), make sure to request one.
Check and log the response code
If you perform a valid API call with valid content and ChannelEngine's services are fully online, you receive a 2xx status code – and whatever data was submitted is processed correctly. This is the case for 99.9% of the calls handled by ChannelEngine's API.
For the remaining 0.1%, it is critical to build checks and retries in case of a 4xx or 5xx status code. Make sure to also check the validation message on statuses 200 when using the product and offer endpoints to see if you submitted items in bulk (which you should) and if there were validation errors on some of these items.
Example A - 500
- You make a
POST /v2/offer
call to change the stock of an item from 5 to 0. - ChannelEngine is under maintenance, so it returns an error 500 because the update cannot be processed.
- If this response is ignored, the stock exported to marketplaces is still 5.
- This can cause placed orders that need to be canceled, resulting in bad metrics on the marketplace.
Example B - 400
- You make a
POST /v2/shipments
call to create a shipment. This shipment has a single order line with a quantity of 4 products. However, you only ship 2 products – and the channel does not allow for the splitting of order lines. - ChannelEngine's API returns a response 4xx because the number of shipped products submitted is lower than the expected (and accepted) number of products in the order.
- If this is ignored, no shipment is created and exported to marketplaces – resulting in an open order.
- That results in bad metrics on the marketplace, as well as customer complaints.
Example C - 200, with validation errors
- You make a
POST /v2/offer
call to update a batch of products. - 50 of the 100 submitted products contain a Merchant product number for which no known products are in the ChannelEngine database.
- That results in the task itself succeeding, updating 50 products – and returning status code 200. However, 50 products in the update are unknown.
- If that is ignored, the user of the integration might erroneously expect those products to be on ChannelEngine – and available for sale on marketplaces.
Scenarios
- If you encounter an error 500, log it and mark all affected data as not exported. If you use a scheduled solution (e.g.: cronjobs) or a real-time solution, include all data from the failed export in the next export.
- If you encounter an error 400, log it and make it visible to the user of the integrated system. Errors 400 are most likely caused by invalid input, and tend to require some manual correction to prevent them from reoccurring. Marking them for re-export with every export is not a proper solution. The exception to this is an error 429, which means you are making too many API calls to ChannelEngine in short succession. If that is the case, implement rate-limiting on your end.
- If you encounter a code 200 for a
/v2/product
or/v2/offer
endpoint, check and log the validation message (if any) and make it visible to the user of the integrated system. These validation errors are most likely caused by invalid input, and tend to require some manual correction to prevent them from re-occurring. Marking them for re-export with every export is not a proper solution.
Check ChannelOrderSupport for partial shipment possibilities
One of the most common reasons for errors 4xx is shipments or cancelations with submitted lines containing an invalid quantity. This results in errors such as:
{"StatusCode":400,"LogId":null,"Success":false,"Message":"Channel requires one shipment line per order line. Incomplete shipment line for order line id 2: expected quantity 3, received 1","ValidationErrors":{}}
Whether an order or order line can be split up or not can be checked when fetching an order on the ChannelOrderSupport attribute.
{ "Content": [ { "Id": 86351, "ChannelName": "bol.com Plaza NL (v3)", "ChannelId": 6, "GlobalChannelName": "bol.com Plaza NL (v3)", "GlobalChannelId": 76, "ChannelOrderSupport": "SPLIT_ORDERS", "ChannelOrderNo": "1107022893"
The example above shows an order from bol.com, which only allows SPLIT_ORDERS. The order itself can be split up in individual order lines, but the order lines themselves can not be split up. All possible options are listed below:
- 0 (NONE) - the channel does not support any orders or order follow-up actions. E.g.: Beslist does not support automated shipments or returns, therefore it is not possible to perform any partial order actions.
- 1 (NO_SPLIT/ORDERS) - the channel supports orders and follow-up actions, but these cannot be split. If an order has two order lines, both must be included in a single shipment.
- 2 (SPLIT_ORDERS) - the channel supports orders and follow-up actions, but they can only be split into individual order lines. An order containing two separate products can be shipped in two shipments, with each shipment containing one product. However, an order line cannot be split. If there is a quantity of three for an ordered product, only the total number of three items can be either shipped or canceled, for instance.
- 3 (SPLIT_ORDER_LINES) - the channel supports orders and follow-up actions, and can be split per each individual product. If there is a quantity of three ordered for a product, it is possible to ship two items and cancel one item, for instance.
While the above order support also applies to returns, in some specific cases it can differ. Consult the individual marketplace guides to verify or contact ChannelEngine's Support team.
Use incremental updates, but add an option to (re-)export all
It is highly recommended to submit incremental updates of product or offer data to ChannelEngine, however, make sure to include an option on your end to trigger an export for everything.
Offers
PUT /v2/offer
A good setup exports all incremental changes since the last export every five, ten, or 15 minutes.
Bear in mind that the offer endpoint can only be used for updating price and stock. Some integrations depend on the purchase price or other (custom) price attribute to determine sales prices, in which case you need to use the /v2/products
endpoint to update that information.
Data
A good setup exports all incremental changes since the last export every 30 or 60 minutes. If you have few product data changes during the day, you can also limit this to once or twice a day.
PATCH /v2/products
This endpoint is used to update fields on a single product. Using this endpoint you only have to provide the value for the field you wish to update or clear. This endpoint uses a JsonPatchDocument. More information on this can be found on What is JSON Patch?. Using the operation 'replace', a value can be updated. Using the operation 'remove', a value can be cleared. One of the advantages of the PATCH endpoint over the POST endpoint is that there is no need to provide all product information, just the field that has to be updated.
POST /v2/products
Bear in mind that this endpoint is purge and replace (which is covered in the next section), so even incremental updates should contain all product data for the product you want to update.
Regardless of the type of update, make sure to build in a manual option to export everything or at least the stock. Combined with building retries based on error codes, this prevents data from not being synchronized for whatever reason (e.g.: disruptions, failed API calls, invalid data, etc.) – resulting in lost data, and no possibility to update again. When connecting to marketplaces or merchant integrations, ChannelEngine uses a similar method to ensure that incremental updates are exported and retried in case of failure, but with an option on its end to re-export all data if needed.
Submitting product data is purge and replace
Note that the /v2/products
endpoint is purge and replace, which means that it expects all data even if you are only updating one attribute. This includes the stock value.
If you do leave out a value from the upsert, it results in it becoming an empty attribute on ChannelEngine. The value is cleared, numeric values are changed to zero. This behavior is intended, as otherwise there would be no easy option to clear existing attribute data via the API.
ChannelEngine is looking into the option to add an product endpoint where it is possible to only upsert attributes that are actually changed, similar to how an additional product feed works. However, currently this means you need to include all product data when updating a specific attribute value. Note that if you want to update only the price or stock, you can use the /v2/offer
endpoint.
Acknowledge orders
Some endpoints require an acknowledgement for the status of the order to be changed and to make follow-up actions possible. The most important endpoint is GET /v2/orders/new
. If an order is not acknowledged, it remains on status New and is returned indefinitely as a new order.
Make sure that after you fetch new orders you acknowledge them via POST /v2/orders/acknowledge
. If you cannot process the order, there are two options:
-
It is an error with the input not validated correctly (e.g.: an address field your system can not handle or an SKU that is unknown)
It is advised that you do not acknowledge the order, but correct the input that is causing the error. In case of addresses/user information, this can be done in the ChannelEngine web interface, or you can contact ChannelEngine's Support. If it is an incorrect SKU (usually an old listing remaining on a marketplace) of a known product, contact ChannelEngine's Support as this can only be corrected in the database. -
It is an error with the product not available/out of stock (e.g.: the SKU sold has no stock anymore, so the order cannot be fulfilled)
This is tricky, and can depend fully on your logical situation and how fast backorders can be delivered. Some clients auto-cancel orders in this case.
To do so, you need to acknowledge the order with a unique Merchant order number. This can also be a unique placeholder, if the underlying system can only provide IDs for accepted orders. Then, submit a cancelation for it via aPOST /v2/cancellations
call, which needs a Merchant order number, so you need to acknowledge the order first.
In both scenarios, it is crucial to log your order validation so it is visible for users. More on this in the next section.
Acknowledge returns
Returns can be created, fetched, and acknowledged via the API. To retrieve only the latest returns from the marketplaces you can use the GET
v2/returns/merchant/
and POST /v2/returns/merchant/acknowledge
endpoints. With the isAcknowledged
parameter you can identify the returns that are already registered to fetch only unknown returns.
To acknowledge returns if you just started working with ChannelEngine:
- Use the
GET /v2/returns/merchant
endpoint. - Use the following parameters:
- statuses - in_progress
- isAcknowledged - false
- Use
POST /v2/returns/merchant/acknowledge
to acknowledge the new returns.
To acknowledge returns if you have been working with ChannelEngine for some time:
- Use the
GET /v2/returns/merchant
endpoint. - Use the following parameters:
- statuses - in_progress
- isAcknowledged - false
- fromDate - enter the date from which you want to start acknowledging returns.
- Use
POST /v2/returns/merchant/acknowledge
to acknowledge the new returns.
To retrieve and acknowledge marketplace fulfilled returns:
- Use the
GET /v2/returns/merchant
endpoint. - Use the following parameters:
- fulfillmentType - ONLY_CHANNEL
- isAcknowledged - false
- Use
POST /v2/returns/merchant/acknowledge
to acknowledge the new returns.
Log your order validation for users (show why an order is not acknowledged)
One of the most common questions ChannelEngine receives is: Why is my order not fetched/stuck as New? This is, unfortunately, a question that ChannelEngine is unable to answer precisely.
With the exception of the API not being available and/or the state of the order changed to something else, the API returns all available information on orders. If your system/integration cannot process the order for whatever reason (e.g.: invalid address, out of stock, unknown product, etc.), it is highly recommended to make this visible to those using your system. As ChannelEngine has no insight into the reason why an order is not accepted or acknowledged, it has to refer users back to someone who does have technical insight into the integration for further investigation.
By adding logging visible to users during the development, orders that remain open for a long period and complex investigations can be avoided.
Build support for paginated responses
Several endpoints can return a paginated response. These endpoints include (GET):
/v2/notifications
/v2/orders
/v2/returns/merchant
/v2/products
If there are more than 100 results for any of those endpoints, there are multiple pages returned. Make sure to build support for fetching additional pages. You can use the following attributes on responses to check the number of results and available pages:
"Count": 0, "TotalCount": 0, "ItemsPerPage": 0,
- ItemsPerPage is currently set to 100 for all responses, but as this might change in future it is not recommended to build any solutions based on this number.
- The TotalCount returns the total number of results available, so if you divide this by the ItemsPerPage and round up to the nearest whole number you get the total number of pages you can fetch.
- The Count gives an indication of how many results the last page contains.
Do bulk calls when possible, limit the total number of calls
Many endpoints of the ChannelEngine Merchant API are bulk endpoints, and are meant as such. The two most important endpoints are:
PUT /v2/offer
POST /v2/products
While it is not a problem to include only one product in an incremental /v2/products
call if, for that period, this is the only update, it is a problem if you want to update 10,000 products and do so in 10,000 separate calls at the same time.
When developing a connection with the Merchant API, use the following guidelines:
-
Make calls in batches
If you want to update 500 products, do one call with 500 products in it. If you want to upsert 100,0000 products, split this up in ten batches of 10,000 products.
-
Do not send multiple batches simultaneously, especially if there is overlapping content
-
Scenario A - if you submit several separate shipments for one order with multiple order lines simultaneously, the order status does not change to Shipped – it remains on In progress. This is due to the fact that the shipments are processed at the same time, and during processing the various threads are not aware of the results of the others.
When processing one shipment and checking the remaining open order lines, all other order lines are considered open so the status of the order does not have to be updated yet. You can prevent this by submitting the shipments with an interval of 2-3 seconds.
-
Scenario B - if you submit an offer update containing 50,000 products (be it batched or not) and submit another offer update 30 seconds later containing several of the same products from the first update, you are likely to get errors from the API. The database is still 'locked' while processing the updates from the first 50,000 products.
Although it is possible to send frequent offer updates (e.g.: every 5-10 minutes), bear in mind that, based on the total number of updates, there are limits on how often certain data can be updated.
-
-
If you receive an error 429, you have made too many requests
You are limited to a set number of requests per endpoint. The status of the rate limiting is communicated in the response headers, as seen in the Rate limiting section of this article. If you batch and schedule your bulk calls, this limit should never be reached. For the sake of comparison, Amazon has a limit of 30 calls per hour, shared across all EU countries, on their Feeds API.
Rate limiting
To ensure that ChannelEngine can continue serving its customers and partners efficiently and reliably, it is necessary to make use of rate limiting in the Merchant, Channel, and Channel Management APIs. The rate limits defined allow ChannelEngine's customers and partners to perform all calls required to conduct their business in a timely manner.
It is recommended that you make use of dynamic throttling, taking into account the limits and intervals communicated in the response headers.
To request the rate limit for each endpoint you use:
- Go to ChannelEngine's OpenAPI/Swagger page for your environment. If you do not know its URL, replace the term 'example' in the URL https://example.channelengine.net/api/swagger/index.html with the first part of the URL of your ChannelEngine environment. E.g.: if your ChannelEngine environment is Sustainable Suits, its URL should be https://sustainable-suits.channelengine.net/ and its OpenAPI/Swagger URL should be https://sustainable-suits.channelengine.net/api/swagger/index.html.
- Click Authorize and, in the Value field, enter your Merchant API key. To find your Merchant API key, log into ChannelEngine and click Settings, Merchant API keys.
- Click Close and select the endpoint for which you would like to know the limit.
- Click Try it out. If the endpoint selected requires parameters, make sure to provide them before clicking Execute. Otherwise, click Execute.
- In the Response headers section, check the values provided by the headers:
- x-rate-limit-limit - provides you with an interval in minutes.
- x-rate-limit-remaining - provides you with the number of calls remaining in that interval.
Submit valid shipment information, no placeholders
Another of the most common questions ChannelEngine receives is: why is my shipment not processed correctly on the marketplace? The main reason for this is that the provided shipment information is missing or incorrect.
If you are implementing an integration with ChannelEngine, take note of the following scenarios and what is valid to submit:
Create a shipment, update track-and-trace information later
- Create a shipment via
POST /v2/shipments
. - Make sure it contain the Merchant shipment number, the Merchant order number, and at least one order line.
- Do not include a placeholder Method or track-and-trace code, leave them null.
- If you do submit data in those fields (even if it is a placeholder), the status of the shipment changes to Closed instead of Pending, and ChannelEngine tries to export the shipment to the marketplace. This almost certainly leads to errors on the marketplace, as it considers the track-and-trace information invalid.
- Once the track-and-trace information becomes available in the seller's system, you can update the shipment via the
PUT /v2/shipments/{merchantShipmentNo}
call. This call has to contain the Method (carrier) and the track-and-trace code. The TrackTraceUrl can be left empty, as most marketplaces generate their own link – which is also why the correct carrier and track-and-trace code are important. - It is sometimes necessary to use carrier mapping to select the correct carrier for a marketplace. Bear in mind that your output (i.e.: the Method provided in the shipment), is the input for the carrier mapping. These must match 100%.
Create a shipment, add track-and-trace information right away
- Create a shipment via
POST /v2/shipments
. - Make sure it contains the Merchant shipment number, the Merchant order number, at least one order line, the Method and the track-and-trace code. No empty or null values, and no placeholders.
- It is sometimes necessary to use carrier mapping to select the correct carrier for a marketplace. Bear in mind that your output (i.e.: the Method provided in the shipment), is the input for the carrier mapping. These must match 100%.
Scenarios
Prevent superfluous API calls
Use case | Fetch all returns from the past three months, keeping them up-to-date every ten minutes. |
Endpoint | GET /v2/returns/merchant |
Best practices |
Use the fromDate field to filter on the creation date.
|
First API call: https://YourTenant.channelengine.net/api/v2/returns/merchant?fromDate=2022-09-01 00:00:00.000&page=1 |
|
Then loop over the pages using the following:
and so on. |
|
If the newest return in this list has the property createdAt: "2022-09-15T09:45:10.692Z", for instance, use the following request in the next call to fetch returns:
|
Plan the API calls based on the rate limit response headers received
Use case | Fetch all shipments to cross-check if everything has been created correctly. |
Endpoint | GET /v2/shipments/merchant |
Best practices | Use the fromCreateDate field to specify a start date for your report and iterate through the pages of shipments by increasing the Page field on every call. Make sure to check the X-rate-limit-remaining header on every call, so you are aware of the remaining number of API calls available. Once this limit is one, stop making calls after your next call and wait until the limit is restored. |
Fetch new order information efficiently
Use case | Fetch new orders. |
Endpoint | GET /v2/orders/new |
Best practices | Use the API endpoint on a fixed timeframe (e.g.: every ten minutes to fetch all the new orders) by calling the endpoint, importing the orders, and then acknowledging each one. If the TotalCount in the response is higher than the Count, fetch the next page and import and acknowledge every order. |
Comments
0 comments
Article is closed for comments.