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

  1. Click here to log in to Voila ↗.

  2. From the left sidebar, go to API Accounts.

  3. Either:

    • Select an existing API User you want to use for Temu, or

    • Click Create API User and provide:

      • Name (for example temu-production).

  4. 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

  1. In the API Accounts page, locate your chosen API User.

  2. In the Registered Auth column, click the + icon.

  3. 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.

  4. Click Save.

  5. 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 example temu-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_date is not required for get-services.

  • The courier object is optional here. Only order_id and parcel dimensions are validated for the service calculation.

  • If you need to influence behaviour, you may still send a courier object with fields such as warehouse_id, send_type or merge_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, not available_services.

  • Each service entry contains service_courier, service_identifier, service_name and service_price.

  • service_identifier is a base64-encoded JSON string that contains ship_company_id plus either channel_id or ship_logistics_type.

  • Regional, logistics-type services are prefixed with [Regional] in the service_name.

  • warehouse_note appears 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

  1. In the Voila sidebar, go to Couriers → Service Presets.

  2. Search for Temu and select it.

  3. Choose the API Account you set up earlier.

  4. Click Create Preset and fill in:

    • Name: for example Temu DHL Express EU

    • DC Service ID: a unique ID you will send from your system, for example TEMU-DHL-EU.

    • Optional notes (for your own reference).

  5. In the courier-specific section, you can configure:

    • service_identifier: base64-encoded service from get-services (recommended)

    • warehouse_id: Temu warehouse ID (uses default if omitted)

    • ship_company_id: shipping company ID (alternative to service_identifier)

    • channel_id: use with ship_company_id (alternative to ship_logistics_type)

    • ship_logistics_type: use with ship_company_id (alternative to channel_id)

    • retry_shipment: whether to auto retry failed shipments

    • send_type: 0 single package (default), 1 multi package, 2 merge orders

    • merge_order_ids: comma separated order IDs, required if send_type = 2

  6. 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 EU

    • dc_service_id: TEMU-DHL-EU

    • Either:

      • service_identifier: value returned from get-services, or

      • ship_company_id: 1001
        channel_id: 2001

  • Multi package or merged orders

    • Multi package: send_type = 1

    • Merge orders: send_type = 2 and merge_order_ids set 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 Name

  • api-token: your API Token

  • Content-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

  1. Take the label_url from the response.

  2. Open it in a browser, or download it programmatically.

  3. 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 item

  • packageSendInfoList.*.packageSn: required, string

  • packageSendInfoList.*.trackingNumber: required, string

  • packageSendInfoList.*.packageDetail: required, array, at least one item

  • packageSendInfoList.*.packageDetail.*.quantity: required, integer, minimum 1

  • packageSendInfoList.*.packageDetail.*.orderSn: required, string

  • packageSendInfoList.*.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 example PO-210-00485674593911312.

    Order ID resolution:
    The system looks for a valid Temu order ID (pattern PO-XXX-XXXXXXXXXXXXXXXXX) in this order:

    1. order_id, if it matches the Temu pattern

    2. reference, if it matches the Temu pattern

    3. reference_2, if it matches the Temu pattern

    4. Fallback: the first non empty value from order_id then reference then reference_2

    This allows integrations where the Temu order ID passes through intermediary systems and ends up in reference or reference_2.

  • collection_date (date): YYYY-MM-DD.

  • parcels (array, required): at least one parcel:

    • dim_length, dim_width, dim_height (numbers)

    • dim_unit: cm or mm

    • items (array, required, minimum 1):

      • weight (number)

      • weight_unit: kg, g, lb, or oz

Optional courier fields (either inline or via preset)

  • service_identifier (string, recommended): base64-encoded service identifier from the get-services endpoint. Contains ship_company_id with either channel_id or ship_logistics_type. This is the preferred way to select a shipping service.

  • ship_company_id (integer): alternative to service_identifier. Must be paired with either channel_id or ship_logistics_type.

  • channel_id (integer): use with ship_company_id. Alternative to ship_logistics_type.

  • ship_logistics_type (integer): use with ship_company_id. Alternative to channel_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 existing packageSn from a previous failed attempt.

  • send_type (integer: 0, 1 or 2):

    • 0: single package (default)

    • 1: multi package

    • 2: merge orders

  • merge_order_ids (string): comma separated list of Temu parent order IDs. Required when send_type = 2 and must contain at least two order IDs.

Common errors and how to fix them

  • API User not authenticated

    • Check the api-user header uses the User Name, not the key or token.

    • Confirm api-token is valid and the API User is enabled.

  • No api-user set in header

    • Add the api-user header to the request.

  • not authenticated for this courier

    • Temu credentials might be missing, or auth_company does not match the Company Name from the Temu auth.

  • Order has already been shipped

    • Temu status is 4 or 5; you cannot create another label.

  • Order has been canceled

    • Temu status is 3; label creation is blocked.

  • No shipping services available

    • Check that weight and dimensions are valid for Temu constraints.

For authentication issues, run through:

  • api-user is the API User Name.

  • api-token is a valid token from the Tokens table.

  • Temu courier credentials are registered and active.

  • auth_company exactly matches the Company Name (if used).