Temu Courier Integration with Voila
This document provides a step-by-step guide to integrating Temu with Voila.
Last updated About 4 hours ago

Temu Courier Integration Tutorial
Temu sellers tend to move at the speed of light; your labels should do their best to keep up. This guide walks you through plugging Temu Buy Shipping into the Voila API so you can fetch services and generate shipping labels automatically for your Temu marketplace orders.
By the end, you will be able to:
Authenticate Temu against a Voila API User.
Fetch available Temu services for an order.
Create shipping labels and download the PDF.

What this integration does
This tutorial shows you how to use Temu Buy Shipping via the Voila API to:
Ask Temu which shipping services are available for a given order.
Create labels using a recommended identifier (
service_identifier), or by specifying explicit IDs.Confirm shipped packages back to Temu (optional, but useful for tighter control).
Everything here is designed to be callable from your own system or integration, so you can automate away any temptation to click things manually.
Prerequisites
Before you start wiring things together, make sure you have:
An active Voila account with access to API Accounts.
An active Temu seller account.
Temu API credentials from the Temu Partner Platform:
app_key,app_secret,access_token.At least one Temu order with status “Pending Shipment” (status = 2).
Once you have these, you are ready to move from “thinking about labels” to “creating labels”.

Step 1: Set up or access your Voila API Account
Click here to log in to Voila ↗.
From the left sidebar, go to API Accounts.
Either:
Select an existing API User you want to use for Temu, or
Click Create API User and provide:
Name (for example
temu-production).
Click Create, then immediately note down:
API User Name (for example
temu-production).Account Key.
API Token (create one if none exists).
You will use API User Name and API Token in the request headers for all Temu calls.

Step 2: Register Temu as a courier for that API User
In the API Accounts page, locate your chosen API User.
In the Registered Auth column, click the + icon.
In the modal:
Type or choose Temu from the courier dropdown.
Fill in the Temu credentials:
Company Name: a friendly identifier, for example
MyTemuStore.app_key: your Temu application key.app_secret: your Temu application secret.access_token: your Temu OAuth access token.
Click Save.
To verify, click View in the Registered Auth column and confirm Temu appears in the list.
> The Company Name you enter here is critical. If you provide one, you must send it as auth_company in your API requests. If you did not specify a Company Name, you must omit auth_company entirely.

Step 3 (optional): Get available Temu shipping services
Before deciding which service to use, you can ask Temu which services are available for a specific order. This is useful when you want Voila to return a list of options instead of hard-coding a single service.
3.1 Endpoint: Get services only
Endpoint:
POST: https://app.heyvoila.io/api/couriers/v1/Temu/get-services
Headers:
api-user: your API User Name (for exampletemu-production).api-token: your API Token.Content-Type:application/json
Example request body:
{
"auth_company": "MyTemuStore",
"shipment": {
"order_id": "PO-210-00485674593911312",
"parcels": [
{
"dim_length": 30,
"dim_width": 20,
"dim_height": 10,
"dim_unit": "cm",
"items": [
{
"weight": 0.5,
"weight_unit": "kg"
}
]
}
]
}
}Notes:
collection_dateis not required forget-services.The
courierobject is optional here. Onlyorder_idand parcel dimensions are validated for the service calculation.If you need to influence behaviour, you may still send a
courierobject with fields such aswarehouse_id,send_typeormerge_order_ids(see the field reference later).
3.2 Response: Services list
You will receive something like:
{
"services": [
{
"service_courier": "Temu",
"service_identifier": "eyJzaGlwX2NvbXBhbnlfaWQiOjEwMDAxLCJjaGFubmVsX2lkIjoyMDAxfQ==",
"service_name": "DHL Express - Standard (Est. 3-5 days)",
"service_price": null
},
{
"service_courier": "Temu",
"service_identifier": "eyJzaGlwX2NvbXBhbnlfaWQiOjEwMDIyLCJzaGlwX2xvZ2lzdGljc190eXBlIjoyMDAyfQ==",
"service_name": "[Regional] DPD - 3",
"service_price": null
}
],
"warehouse_id": "WH123",
"unavailable_services": [],
"warehouse_note": "Using default warehouse (WH123). Specify warehouse_id in courier specifics to use a different warehouse."
}Key points:
The top-level key is
services, notavailable_services.Each service entry contains
service_courier,service_identifier,service_nameandservice_price.service_identifieris a base64-encoded JSON string that containsship_company_idplus eitherchannel_idorship_logistics_type.Regional, logistics-type services are prefixed with
[Regional]in theservice_name.warehouse_noteappears when a default warehouse has been auto-selected.
Record the service_identifier for any services you intend to use in production. You will usually pass this directly to the create-label endpoint. If you prefer, you can base64-decode it and extract ship_company_id and channel_id or ship_logistics_type, but that is optional.

Step 4 (optional but recommended): Create Temu service presets
Service presets let you save courier-specific settings and reuse them simply by sending a dc_service_id in your API calls. This keeps your integration cleaner and makes it easier to switch or add services later.
4.1 Create a Temu preset
In the Voila sidebar, go to Couriers → Service Presets.
Search for Temu and select it.
Choose the API Account you set up earlier.
Click Create Preset and fill in:
Name: for example
Temu DHL Express EUDC Service ID: a unique ID you will send from your system, for example
TEMU-DHL-EU.Optional notes (for your own reference).
In the courier-specific section, you can configure:
service_identifier: base64-encoded service fromget-services(recommended)warehouse_id: Temu warehouse ID (uses default if omitted)ship_company_id: shipping company ID (alternative toservice_identifier)channel_id: use withship_company_id(alternative toship_logistics_type)ship_logistics_type: use withship_company_id(alternative tochannel_id)retry_shipment: whether to auto retry failed shipmentssend_type:0single package (default),1multi package,2merge ordersmerge_order_ids: comma separated order IDs, required ifsend_type = 2
Configure Transit Times (required):
Choose countries for each zone.
Set minimum and maximum transit days per zone.
Save the preset when you are done.
4.2 Example preset patterns
Some useful presets you might configure:
Fixed carrier or channel (for example DHL Express EU)
Name:
Temu DHL Express EUdc_service_id:TEMU-DHL-EUEither:
service_identifier: value returned fromget-services, orship_company_id:1001channel_id:2001
Multi package or merged orders
Multi package:
send_type = 1Merge orders:
send_type = 2andmerge_order_idsset to a comma separated list of at least two Temu parent order IDs
There is no longer a “get services only” preset. Getting services is now handled entirely by the dedicated get-services endpoint.

Step 5: Create a Temu shipping label
Once your API User and Temu auth are set up, you can start generating labels.
Endpoint:
POST https://app.heyvoila.io/api/couriers/v1/Temu/create-label
Headers:
api-user: your API User Nameapi-token: your API TokenContent-Type:application/json
5.1 Request using service_identifier (recommended)
The simplest and most robust way to select a service is to pass the service_identifier you received from the get-services response.
{
"auth_company": "MyTemuStore",
"shipment": {
"order_id": "PO-210-00485674593911312",
"collection_date": "2026-01-15",
"parcels": [
{
"dim_length": 30,
"dim_width": 20,
"dim_height": 10,
"dim_unit": "cm",
"items": [
{
"weight": 0.5,
"weight_unit": "kg"
}
]
}
],
"courier": {
"service_identifier": "eyJzaGlwX2NvbXBhbnlfaWQiOjEwMDAxLCJjaGFubmVsX2lkIjoyMDAxfQ=="
}
}
}service_identifier is a base64-encoded JSON object returned by get-services. It encapsulates ship_company_id plus either channel_id or ship_logistics_type for you.
5.2 Request using explicit service IDs
If you do not want to use service_identifier, you can instead send ship_company_id with either channel_id or ship_logistics_type inline.
Using ship_company_id and channel_id:
{
"auth_company": "MyTemuStore",
"shipment": {
"order_id": "PO-210-00485674593911312",
"collection_date": "2026-01-15",
"parcels": [
{
"dim_length": 30,
"dim_width": 20,
"dim_height": 10,
"dim_unit": "cm",
"items": [
{
"weight": 0.5,
"weight_unit": "kg"
}
]
}
],
"courier": {
'ship_company_id": 1001,
"channel_id": 2001
}
}
}Using ship_company_id and ship_logistics_type:
{
"auth_company": "MyTemuStore",
"shipment": {
"order_id": "PO-210-00485674593911312",
"collection_date": "2026-01-15",
"parcels": [
{
"dim_length": 30,
"dim_width": 20,
"dim_height": 10,
"dim_unit": "cm",
"items": [
{
"weight": 0.5,
"weight_unit": "kg"
}
]
}
],
"courier": {
"ship_company_id": 1001,
"ship_logistics_type": 2001
}
}
}In Voila, when using Courier Presets, the preset should contain service_identifier or ship_company_id plus either channel_id or ship_logistics_type.
5.3 Request using a preset (`dc_service_id`)
If you have set up a preset, you can reference it directly instead of passing courier specifics.
The preset should contain service_identifier or ship_company_id plus either channel_id or ship_logistics_type.
{
"auth_company": "MyTemuStore",
"shipment": {
"order_id": "PO-210-00485674593911312",
"dc_service_id": "TEMU-DHL-EU",
"collection_date": "2026-01-15",
"parcels": [
{
"dim_length": 30,
"dim_width": 20,
"dim_height": 10,
"dim_unit": "cm",
"items": [
{
"weight": 0.5,
"weight_unit": "kg"
}
]
}
]
}
}Preset values are automatically applied, but you can still override them by including fields in the courier object.
5.4 Successful response
A successful label creation returns something similar to:
{
"type": "PDF",
"request_id": "12345",
"tracking_codes": ["TRACK123456789"],
"tracking_urls": [null],
"label_url": "https://s3.../label.pdf",
"uri": "https://s3.../label.pdf",
"courier_specifics": {
"package_sn_list": ["PKG001"],
"package_sn": "PKG001",
"tracking_map": {
"PKG001": "TRACK123456789"
}
}
}From here, you can store the tracking code and label URL in your system and surface them wherever your users expect to see tracking details.

Step 6: Download and print the Temu label
Take the
label_urlfrom the response.Open it in a browser, or download it programmatically.
The label is a 4 × 6 inch PDF.
Printing guidelines:
Paper size: 4 × 6 inches (or A6)
Orientation: Portrait
Scale: 100 percent (no scaling)
If the label URL has expired (it is valid for one hour), you can get a fresh link:
GET https://app.heyvoila.io/api/pdfs/renew?key={label_key}.
Use the key portion of the original URL.

Step 7 (optional): Confirm shipped packages
After a label is created and the package has physically left your premises, you can confirm the shipment back to Temu. If you do not confirm it manually, packages automatically move to “shipped” status after 48 hours.
Endpoint:
POST https://app.heyvoila.io/api/couriers/v1/Temu/confirm-shipped-package
Headers: same as other endpoints (api-user, api-token, Content-Type).
Request body:
{
"auth_company": "MyTemuStore",
"packageSendInfoList": [
{
"packageSn": "PKG001",
"trackingNumber": "TRACK123456789",
"packageDetail": [
{
"quantity": 1,
"orderSn": "ORDER001",
"parentOrderSn": "PO-210-00485674593911312"
}
]
}
]
}Validation rules:
packageSendInfoList: required, array, at least one itempackageSendInfoList.*.packageSn: required, stringpackageSendInfoList.*.trackingNumber: required, stringpackageSendInfoList.*.packageDetail: required, array, at least one itempackageSendInfoList.*.packageDetail.*.quantity: required, integer, minimum1packageSendInfoList.*.packageDetail.*.orderSn: required, stringpackageSendInfoList.*.packageDetail.*.parentOrderSn: required, string
Response:
{
"success": true,
"result": null,
"errorCode": null,
"errorMsg": null
}All required values (packageSn, trackingNumber, order numbers) are available in the create-label response under courier_specifics.
Request field reference (for implementers)
Top level fields
auth_company(string, conditional): Company Name used when registering Temu. Omit this field entirely if no Company Name was set in Temu auth.dc_service_id(string, optional): ID of the service preset to apply when creating a label.
shipment object
order_id(string): Temu parent order number, for examplePO-210-00485674593911312.Order ID resolution:
The system looks for a valid Temu order ID (patternPO-XXX-XXXXXXXXXXXXXXXXX) in this order:order_id, if it matches the Temu patternreference, if it matches the Temu patternreference_2, if it matches the Temu patternFallback: the first non empty value from
order_idthenreferencethenreference_2
This allows integrations where the Temu order ID passes through intermediary systems and ends up in
referenceorreference_2.collection_date(date):YYYY-MM-DD.parcels(array, required): at least one parcel:dim_length,dim_width,dim_height(numbers)dim_unit:cmormmitems(array, required, minimum 1):weight(number)weight_unit:kg,g,lb, oroz
Optional courier fields (either inline or via preset)
service_identifier(string, recommended): base64-encoded service identifier from theget-servicesendpoint. Containsship_company_idwith eitherchannel_idorship_logistics_type. This is the preferred way to select a shipping service.ship_company_id(integer): alternative toservice_identifier. Must be paired with eitherchannel_idorship_logistics_type.channel_id(integer): use withship_company_id. Alternative toship_logistics_type.ship_logistics_type(integer): use withship_company_id. Alternative tochannel_id.warehouse_id(string): Temu warehouse ID. If not provided, the default warehouse for the account will be used.retry_shipment(boolean): retry a failed shipment using the shipment update API. Requires an existingpackageSnfrom a previous failed attempt.send_type(integer:0,1or2):0: single package (default)1: multi package2: merge orders
merge_order_ids(string): comma separated list of Temu parent order IDs. Required whensend_type = 2and must contain at least two order IDs.

Common errors and how to fix them
API User not authenticatedCheck the
api-userheader uses the User Name, not the key or token.Confirm
api-tokenis valid and the API User is enabled.
No api-user set in headerAdd the
api-userheader to the request.
not authenticated for this courierTemu credentials might be missing, or
auth_companydoes not match the Company Name from the Temu auth.
Order has already been shippedTemu status is
4or5; you cannot create another label.
Order has been canceledTemu status is
3; label creation is blocked.
No shipping services availableCheck that weight and dimensions are valid for Temu constraints.
For authentication issues, run through:
api-useris the API User Name.api-tokenis a valid token from the Tokens table.Temu courier credentials are registered and active.
auth_companyexactly matches the Company Name (if used).
