Returns integration

This guide takes you through the basic setup and steps to integrate a return flow with Helthjem.

Steps:

  1. Authorize
  2. Check address for coverage
  3. Fetch available pickup dates
  4. Book return
  5. Provide label or return code
  6. Track return

Choose a transport solution

See our page with descriptions on Delivery Methods to find an appropriate Transport Solution. A return transport solution determines which return products the customer can be offered, and the order Helthjem falls back through if the first one is not available for the address.

transportSolutionId Name Falls back through Use when
21 Helthjem retur 4 Home pickup only
33 Helthjem retur m/retur via butikk 4 → 56 → 20 Home pickup, labeled PUDO as backup
63 Helthjem retur butikk 56 → 20 Labeled PUDO only
116 Etikettløs retur via butikk 95 Labelless PUDO only
118 Helthjem Returpakke 56 Labeled Helthjem PUDO only
119 Pure Helthjem Retur 4 → 56 Home pickup, Helthjem PUDO as backup
121 100% Etikettløs Retur 4 → 95 Labelless throughout
122 Helthjem retur m/etikettløs PUDO 4 → 95 → 56 Labelless first, labeled as last resort
135 Etikettløs retur via butikk eller PN 95 → 20 Labelless PUDO, PostNord as backup

The freight products these resolve to:

freightProductId productName Return type Label
4 HELTHJEM_RETUR Home Label or code
56 HELTHJEM_SHOP_RETURN PUDO Label
95 HELTHJEM_C2B_PUDO_RETURN PUDO Label or code
20 PN_MYPACK_RETUR PUDO Label

Tip: Use a transport solution with fallbacks (33, 122, 135) in rural or low-coverage areas to raise the share of returns you can accept.

In this guide we will be using transport solution 21 for home pickup and transport solution 116 for labelless drop-off at a service point, in collaboration with the Single Address Check to confirm coverage before booking.

Lets begin

1. Authorize

Use the Authorization endpoint with your client_id and client_secret to obtain a JWT. This token expires in 24hrs, if you store it and refresh it every 12 hours, you will not need to authorize for every request.

Request

{
    "client_id": "your-client-id",
    "client_secret": "your-secret",
    "grant_type": "client_credentials"
}

Response

{
  "token": "xxx",
  "expires_in": 86400,
  "token_type": "Bearer"
}
Authorization: Bearer <token>
Content-Type: application/json

2. Check address for coverage

2.1 Single Address Check

Check coverage of an address with the Single Address Check endpoint for a given address to confirm that we have coverage for a return Transport Solution.

Run the check once per return method you intend to display, so the customer only sees options that are available at their address.

Checkout example

In this example, we want to check that we can collect a return from the doorstep of “Ola Nordman”, who lives at Kongsberggata 18, Oslo 0468. Ola has also sent us his apartment number H0201.

Request

{
    "shopId": 1,
    "transportSolutionId": 21,
    "customerName": "Ola Nordmann",
    "address": "Kongsberggata 18 H0201",
    "zipCode": "0468",
    "postalName": "Oslo",
    "countryCode": "NO",
    "weight": 1000,
    "volume": null
}

Success (200)

{
  "productName": "HELTHJEM_RETUR",
  "routeName": "21516",
  "routing": "1-31/114-43-x21516x385",
  "routeAddress": "TÅSENVEIEN 26",
  "handoverCity": "OSLO",
  "plannedDeparture": "1600"
}

We get the response "productName": "HELTHJEM_RETUR", which confirms that we can collect a return from this address.

Now that the coverage has been confirmed, the Transport solution can confidently be exposed as a return option.

A 400 with "no.carrier.support" means we cannot collect from that address with the chosen transport solution — hide that option in the checkout.

2.2 Nearby Service points

If you wish to offer Service Point drop-off, use the Nearby Service Points endpoint to retrieve the 3 closest locations to an address.

In this example, we will use transportSolutionId: 62, which includes both Helthjem and Postnord service points.

Request

{
    "shopId": 1,
    "transportSolutionId": 62,
    "streetAddress": "Kongsberggata 18",
    "zipCode": "0468",
    "postalName": "Oslo",
    "countryCode": "NO"
}

Response (trimmed)

{
  "freightProducts": [
    {
      "freightName": "Helthjem Hentepakke",
      "servicePoints": [
        {
          "servicePointExternalId": "30694",
          "servicePointName": "Joker Toftes Gate",
          "openingHours": [
            {"day":"MONDAY","from1":"07:00","to1":"00:00"}
          ],
          "visitingAddress": {
            "streetName": "TOFTES GATE",
            "streetNumber": "12",
            "postalCode": "0556",
            "postalName": "OSLO",
            "countryCode": "NO"
          }
        }
      ]
    }
  ]
}

For a return the customer can hand the parcel in at any eligible location, so this is for display only — the service point is not included as a party when booking.

3. Fetch available pickup dates

If the customer chooses Home pickup (TS 21), show available pickup dates. This date is needed in the booking to order a Helthjem driver to pickup the parcel and receive a returnCode.

Skip this step for PUDO returns — there is no date to select.

Note: You need to use "freightProductId": 4, not a transportSolutionId.

Path: /parcels/v1/addresses/find/single/dates

Request

{
    "shopId": 16,
    "freightProductId": 4,
    "zipCode": "0561",
    "customerName": "Test customer",
    "countryCode": "NO",
    "postalName": "Oslo",
    "address": "Herslebs gate 2F",
    "co": ""
}

Response

{
    "dates": [
        "2026-06-17",
        "2026-06-18",
        "2026-06-19",
        "2026-06-20",
        "2026-06-22",
        "2026-06-23",
        "2026-06-24",
        "2026-06-25",
        "2026-06-26",
        "2026-06-27",
        "2026-06-29",
        "2026-06-30"
    ]
}

Dates we cannot collect on are absent from the list, so present the array as-is.

4. Book the return

Now that we have successfully confirmed that the transport solution is available for an address, book the return using the Booking endpoint.

A return uses the same endpoint and payload shape as an outgoing booking, with the parties swapped. For a C2B return, the customer = consignor and the shop = consignee.

For home pickup, include the date the customer selected as "desiredDeliveryDate".

**Request **(transportSolutionId: 121)

{
    "shopId": 1,
    "transportSolutionId": 4,
    "shipmentId": "",
    "desiredDeliveryDate": 20260617,
    "parties": [
        {
            "type": "consignee",
            "name": "Demo Shop",
            "countryCode": "NO",
            "zipCode": "0484",
            "address": "Sandakerveien 88",
            "phone1": "12345678"
        },
        {
            "type": "consignor",
            "name": "Ola Nordmann",
            "countryCode": "NO",
            "postalName": "Oslo",
            "zipCode": "0468",
            "address": "Kongsberggata 18",
            "phone1": "12345678",
            "email": "ola@example.com"
        }
    ],
    "items": [
        {
            "itemNumber": 1,
            "weight": 1000,
            "width": 12,
            "height": 12,
            "length": 12,
            "contents": "Shoes"
        }
    ]
}

Response

{
  "shipmentId": "70724762400784060",
  "freightProductId": 4,
  "parties":[...]
  "items":[
    {
      "trackingReference": "...",
      "returnCode": "H987654"
    }
  ],
  "properties":{...},
  "orderId": 133370472
}

In this response, you receive the shipmentId and trackingReference as identifiers, and the returnCode where the booking resolved to a labelless product.

For a PUDO return, use a PUDO transport solution (116, 63, 118 or 135) and omit "desiredDeliveryDate".

Tip: Make sure phone1 and email are populated on the consignor. We use them to send the customer the return code and instructions.

5. Provide label or return code

What you give the customer depends on which freight product the booking resolved to. Check "freightProductId" in the response.

Labelled products (4 with label, 56, 20) — fetch a printable label after a successful booking. Use either shipmentId or trackingReference as the identifier. A standard label is 102×192 mm PDF.

Read our label guide for more details and to configure other options.

Request

curl -X GET "https://api.pre.helthjem.no/parcels/v1/labels/{identifier}/unified-large" \
  -H "Authorization: Bearer <token>" \
  -H "Accept: application/pdf,application/json"

Labelless products (95, and 4 when used without a label) — there is no label. The booking response contains a return code instead:

{
  "returnCode": "H987654"
}

Display the return code in your own flow if you want to, and instruct the customer accordingly:

Home pickup: write the code on the parcel and leave it outside by 07:00 on the selected date.

PUDO: write the code on the parcel and drop it at the nearest Helthjem return point

We also send the customer an SMS and an email with the code and instructions, so this step is optional on your side.

6. Track the return

Track return progress via events from booking to arrival.

curl -X GET "https://api.pre.helthjem.no/parcels/v1/tracking/fetch/{identifier}/NO/false" \
  -H "Authorization: Bearer <token>" \
  -H "Accept: application/pdf,application/json"

Response

[
    {
        "shipmentNumber": "70724763243779244",
        "shopName": "Testbutikken",
        "shopId": 1,
        "consigneeReference": "shop_ref",
        "consignorReference": "cust_ref",
        "properties": {},
        "items": [
            {
                "trackingNumber": "370724763243779252",
                "returnCode": "H987654",
                "freightProductId": 4,
                "freightProductName": "HELTHJEM_RETUR",
                "parcelStatus": "WAITING_FOR_PACKAGE",
                "linkedParcelNumbers": [],
                "events": [
                    {
                        "eventTime": "2025-10-13 13:46:07",
                        "eventTimeUtc": "2025-10-13T11:46:07.028470Z",
                        "lat": null,
                        "lon": null,
                        "locationContext": "Testbutikken",
                        "locationContextId": null,
                        "eventType": {
                            "apiKey": "001",
                            "description": "Meldt ankomst av pakke",
                            "i18nKey": "event.type.distr.import.edi.information.received"
                        },
                        "additionalInfo": null,
                        "eventGroup": {
                            "id": 1,
                            "name": "event.type.group.import"
                        },
                        "comChannelType": null,
                        "changeUserId": null,
                        "changeUsername": null,
                        "regSystem": {
                            "id": 1,
                            "name": "Beh. Engangslev."
                        },
                        "message": null,
                        "eventData": null
                    }
                ]
            }
        ]
    }
]

For a PUDO return nothing moves until the customer drops the parcel off, so expect a gap between booking and the first scan.