Temu Ship Orders
Version | Date | Created / Updated | Notes |
---|---|---|---|
v1.0 | Hristiyan | First publish |
Temu are supporting two models of shipping : Self-shipment by Merchant and Logistics Online Shipment. The second method is basically orders being shipped from Temu’s own warehouses.
For the moment we will only cover the first model which is the Self-shipment by Merchant.
Temu supports partial shipments so we need to be able to handle this as well. We need to create some additional logic when doing partial shipment and this will be explained below.
UML diagram of a successfull shipping logic :
All validations, triggers etc. which are not mentioned in this document will be as per the abstraction - Order Shipment Functional Details and Ship
Get Couriers
API Call : POST https://openapi-b-eu.temu.com/openapi/router
API Name: bg.logistics.companies.get
Please don’t forget that the call itself is to be used based on the value of Channel > Country
as described here: ‼ Please note that the above is true for all calls. In each call we will give the endpoint with an example host but we need to use the correct domain pointer based on the Channel > Country
value ‼
Temu are providing different couriers per different regions so we need to make a call for each different region that we have an account created for. In Hemi we keep the names but we always communicate via the ids with the marketplace.
Just to confirm for the time being we are to execute this ONLY for the countries of connected accounts as per this scope, further improvements with downloading all regions might be added with future versions
Example request :
{
"type": "bg.logistics.companies.get",
"timestamp": timestamp,
"app_key": app_key,
"data_type": "JSON",
"access_token": access_token,
"regionId": "69"
}
Request mapping :
Temu field | Field type | Notes/Mapping |
---|---|---|
regionId |
STRING | We want to create a mapping based on a table which is attached below (Temu Regions). We want to send the regionId based on the selected country in Account > Country |
Example response :
{
"result": [
{
"logisticsServiceProviderId": 141252268,
"logisticsServiceProviderName": "DHL",
"logisticsBrandName": "DHL"
},
{
"logisticsServiceProviderId": 193644895,
"logisticsServiceProviderName": "云途",
"logisticsBrandName": "YunExpress"
},
{
"logisticsServiceProviderId": 193647644,
"logisticsServiceProviderName": "Chronopost",
"logisticsBrandName": "Chronopost"
},
{
"logisticsServiceProviderId": 193667895,
"logisticsServiceProviderName": "DB SCHENKER",
"logisticsBrandName": "DB SCHENKER"
},
{
"logisticsServiceProviderId": 198247895,
"logisticsServiceProviderName": "colissimo",
"logisticsBrandName": "colissimo"
},
{
"logisticsServiceProviderId": 202302933,
"logisticsServiceProviderName": "Mondial Relay",
"logisticsBrandName": "Mondial Relay"
},
{
"logisticsServiceProviderId": 209234439,
"logisticsServiceProviderName": "Colicoli",
"logisticsBrandName": "Colicoli"
},
{
"logisticsServiceProviderId": 209334439,
"logisticsServiceProviderName": "PPL",
"logisticsBrandName": "PPL"
},
{
"logisticsServiceProviderId": 217968721,
"logisticsServiceProviderName": "Hermes",
"logisticsBrandName": "Hermes"
},
{
"logisticsServiceProviderId": 234789547,
"logisticsServiceProviderName": "Correos",
"logisticsBrandName": "Correos"
},
{
"logisticsServiceProviderId": 314439762,
"logisticsServiceProviderName": "優比速",
"logisticsBrandName": "UPS"
},
{
"logisticsServiceProviderId": 379877347,
"logisticsServiceProviderName": "Colis Prive",
"logisticsBrandName": "Colis Prive"
},
{
"logisticsServiceProviderId": 547987123,
"logisticsServiceProviderName": "GLS",
"logisticsBrandName": "GLS"
},
{
"logisticsServiceProviderId": 571132179,
"logisticsServiceProviderName": "法国邮政",
"logisticsBrandName": "La Poste"
},
{
"logisticsServiceProviderId": 578947137,
"logisticsServiceProviderName": "DHL Paket",
"logisticsBrandName": "DHL Paket"
},
{
"logisticsServiceProviderId": 653578654,
"logisticsServiceProviderName": "Paack",
"logisticsBrandName": "Paack"
},
{
"logisticsServiceProviderId": 699272611,
"logisticsServiceProviderName": "联邦快递",
"logisticsBrandName": "FedEx"
},
{
"logisticsServiceProviderId": 784213879,
"logisticsServiceProviderName": "Poste Italiane",
"logisticsBrandName": "Poste Italiane"
},
{
"logisticsServiceProviderId": 998264724,
"logisticsServiceProviderName": "Packeta",
"logisticsBrandName": "Packeta"
},
{
"logisticsServiceProviderId": 998264844,
"logisticsServiceProviderName": "TNT",
"logisticsBrandName": "TNT"
},
{
"logisticsServiceProviderId": 998264849,
"logisticsServiceProviderName": "DPD (FR)",
"logisticsBrandName": "DPD (FR)"
},
{
"logisticsServiceProviderId": 998264853,
"logisticsServiceProviderName": "DPD (DE)",
"logisticsBrandName": "DPD (DE)"
},
{
"logisticsServiceProviderId": 998264856,
"logisticsServiceProviderName": "Hermes(DE)",
"logisticsBrandName": "Hermes(DE)"
},
{
"logisticsServiceProviderId": 998264867,
"logisticsServiceProviderName": "菜鸟",
"logisticsBrandName": "CAINIAO"
},
{
"logisticsServiceProviderId": 998264874,
"logisticsServiceProviderName": "GLS(IT)",
"logisticsBrandName": "GLS(IT)"
},
{
"logisticsServiceProviderId": 998264957,
"logisticsServiceProviderName": "swiship(DE)",
"logisticsBrandName": "swiship(DE)"
},
{
"logisticsServiceProviderId": 998264958,
"logisticsServiceProviderName": "CIRRO PARCEL",
"logisticsBrandName": "CIRRO PARCEL"
},
{
"logisticsServiceProviderId": 998264960,
"logisticsServiceProviderName": "Amazon shiping(IT)",
"logisticsBrandName": "Amazon shiping(IT)"
},
{
"logisticsServiceProviderId": 998264966,
"logisticsServiceProviderName": "swiship(FR)",
"logisticsBrandName": "swiship(FR)"
},
{
"logisticsServiceProviderId": 998264967,
"logisticsServiceProviderName": "Amazon shiping(FR)",
"logisticsBrandName": "Amazon shiping(FR)"
},
{
"logisticsServiceProviderId": 998264972,
"logisticsServiceProviderName": "GEODIS",
"logisticsBrandName": "GEODIS"
},
{
"logisticsServiceProviderId": 998264994,
"logisticsServiceProviderName": "BRT Bartolini(DPD)",
"logisticsBrandName": "BRT Bartolini(DPD)"
},
{
"logisticsServiceProviderId": 998265042,
"logisticsServiceProviderName": "DSV",
"logisticsBrandName": "DSV"
},
{
"logisticsServiceProviderId": 998265070,
"logisticsServiceProviderName": "GEL Express",
"logisticsBrandName": "GEL Express"
},
{
"logisticsServiceProviderId": 998265081,
"logisticsServiceProviderName": "Dachser",
"logisticsBrandName": "Dachser"
},
{
"logisticsServiceProviderId": 998265084,
"logisticsServiceProviderName": "SDA",
"logisticsBrandName": "SDA"
},
{
"logisticsServiceProviderId": 998265089,
"logisticsServiceProviderName": "PostNL International Mail",
"logisticsBrandName": "PostNL International Mail"
},
{
"logisticsServiceProviderId": 998265110,
"logisticsServiceProviderName": "DPD (PL)",
"logisticsBrandName": "DPD (PL)"
},
{
"logisticsServiceProviderId": 998265113,
"logisticsServiceProviderName": "GLS Spain (National)",
"logisticsBrandName": "GLS Spain (National)"
},
{
"logisticsServiceProviderId": 998265120,
"logisticsServiceProviderName": "DPD (CZ)",
"logisticsBrandName": "DPD (CZ)"
},
{
"logisticsServiceProviderId": 998265122,
"logisticsServiceProviderName": "Rhenus Logistics (IT)",
"logisticsBrandName": "Rhenus Logistics (IT)"
},
{
"logisticsServiceProviderId": 998265182,
"logisticsServiceProviderName": "Raben Group",
"logisticsBrandName": "Raben Group"
},
{
"logisticsServiceProviderId": 998265189,
"logisticsServiceProviderName": "DPD (IE)",
"logisticsBrandName": "DPD (IE)"
},
{
"logisticsServiceProviderId": 998265211,
"logisticsServiceProviderName": "DPD (NL)",
"logisticsBrandName": "DPD (NL)"
},
{
"logisticsServiceProviderId": 998265212,
"logisticsServiceProviderName": "Hellmann",
"logisticsBrandName": "Hellmann"
},
{
"logisticsServiceProviderId": 998265262,
"logisticsServiceProviderName": "KUEHNE+NAGEL",
"logisticsBrandName": "KUEHNE+NAGEL"
}
],
"success": true,
"requestId": "eu-c8515bab-59de-4f3e-9df6-24f34015ac22",
"errorCode": 1000000,
"errorMsg": ""
}
Response mapping :
Temu field | Hemi Field | Notes | |
---|---|---|---|
result |
|||
logisticsServiceProviderId |
We want to store the id in the back end so we push the id when sending to Temu. | ||
logisticsServiceProviderName |
N/A | ||
logisticsBrandName |
Temu Courier Mapping > Temu Courier |
Should be an enum table wher we show the name of the courier, but in all the communication with Temu we must use the logisticsServiceProviderId |
|
success |
N/A | ||
requestId |
N/A | ||
errorCode |
N/A | ||
errorMsg |
N/A |
We want to introduce Courier mapping so we need to create a dependent table under Courier
called Temu Courier Mapping
. The specific here is that Temu have different couriers per different regions so we need to be able to handle this too. In order to handle this, we will have a dropdown field with all the carriers and also a dropdown field named Account ID
which will be an enum table of Accounts
.This way we should be able to create a record for each different Channel (previously account) which would essentially be different region id. We want to store the courier in the format of logisticsBrandName - country
. We always keep the name, but send the id. If Temu add or remove some couriers, we want to respectively add/remove them from the Courier
table. We don’t want to truncate the table with each run.
All the regions IDs can be found in this table -
We want to introduce a default courier field which will be in the Account Temu
. The field will be an enum dropdown menu where the user can select the desired default courier. The field should not be required. Even if there is a selected default courier, we should first check if we have mapping from the courier in Order Shipment
> Courier
with a record in table Courier
and pick this with priority. We should only pick the default courier if there is no mapping for the selected courier. We should not be able to send a shipping update if we don’t have mapped courier and if we don’t have default courier set. If we have such case, we want to store an error in Order Errors
with Type
> Shipping stating there is no courier mapping or default courier set.
Ship orders
API Call : POST https://openapi-b-eu.temu.com/openapi/router
API Name: bg.logistics.shipment.confirm
Request body :
{
"sendType": 1,
"sendRequestList": [
{
"orderSendInfoList": [
{
"quantity": 1,
"orderSn": "076-13925366551591879",
"parentOrderSn": "PO-076-13925408494631879",
"goodsId": 603617570475412,
"skuId": 67055176970656
}
],
"carrierId": 141252268,
"trackingNumber": "123456abcdWOW"
}
]
}
Request Mapping :
Shein Field | Hemi Field | Notes | ||
---|---|---|---|---|
sendType |
SendType,enumerated as follows: |
0 - All the products in one parent order are shipped in one package with one tracking number 1 - Partical products in one parent order are shipped in multiple packages with multiple tracking numbers and all the products in one order should be shipped in one API call. 2 - All the products in multiple parent orders are shipped in one package with one tracking number.
We need to create a logic - if we are doing full shipment on all products on order with the same tracking, we use 0. If we are doing partial shipment we use 1. We should not use 2 at all. |
| sendRequestList
| | | | |
| | orderSendInfoList
| | | |
| | | quantity
| Order Shipment Row
> Quantity
| |
| | | orderSn
| Order Item Line
> Marketplace Order Item ID
| |
| | | parentOrderSn
| Orders
> Marketplace Order ID
| |
| | | goodsId
| Product In Order
> Channel Item ID
| |
| | | skuId
| Product In Order
> Item Transaction ID
| |
| | carrierId
| | Order Shipment
> Carrier
| Carrier ID obtained from the courier mapping |
| | trackingNumber
| | Order Shipment
> Tracking Number
| |
Example success response :
{
"result": {
"result": {
"assistantAgreementText": null,
"warningMessage": []
},
"success": true,
"errorCode": 1000000,
"errorMsg": null
},
"success": true,
"requestId": "eu-ebe0f4d1-9bf9-42cc-a154-69d1d7e93689",
"errorCode": 1000000,
"errorMsg": ""
}
Example error response 200 OK:
{
"result": {
"result": null,
"success": false,
"errorCode": 20004,
"errorMsg": "Order shipped"
},
"success": true,
"requestId": "eu-ca3810a7-217d-4305-9000-55a1dc9ea630",
"errorCode": 1000000,
"errorMsg": ""
}
Incase we receive any error in the response, we will have a success
= false. In this case we want to store the errorMsg
in the Order Errors
table with Type
= Shipping. If we have both success
messages as false, we want to combine both errorMsg
when storing the error.