Webhooks

All event information can be automatically fed back into the shop systems using webhooks.

Getting Started

You need to provide parcelLab with a webhook URL that is secured with HTTPS.

Plain HTTP is not supported.

All webhook requests are sent from one of the following IP addresses (for firewall whitelists).

35.156.240.70
35.157.215.87
35.157.195.174

The following authentication mechanisms are supported:

  • HTTP Basic Authentication

  • Access Token Headers

  • OAuth2.0 Access Token

Webhooks are sent for individual consignments (that is: records in the parcelLab system). For split orders with multiple trackings, each individual tracking will receive an onDispatch event, even if they are sent at the same time.

If an error is received after sending a webhook, there will be 15 retries at 30 minute intervals before an error is logged and the event is deleted from the queue.

Events

The events described in the following table can be sent via webhook. There is no deduplication of events, which means multiple scans of the OutForDelivery type will trigger multiple webhooks.

All events contain the same data structure as specified in the Data Format section, with a set of the events having additional fields that are only present for a specific event type. For details on the structure of the data key, please refer to the Structure of data section.

Event
Description

onInternalDelay

The consignment was not shipped in time. This event describes a breach of the specified send_date on record creation, if not specified differently in the retailer’s logic.

onCreated

A new record has been created through data transfer from the retailer.

onUpdated

A record has been updated through data transfer from the retailer. This does not include the updated fields.

onDispatch

The consignment was scanned for the first time (that is: network inbound scan) and is now on its way.

This event is only triggered once.

onScheduled

The carrier has announced the delivery day, optionally including a time window.

This event is triggered for every change in scheduled delivery date (for example: if the delivery is scheduled for an earlier or later day or to a different time window).

onDelay

Any delay or delivery issue event. This event includes an additional key that specifies the reason code for the delay.

onOutForDelivery

The consignment is out for delivery. Depending on the carrier, a delivery time window may be provided.

onFailedAttempt

The carrier attempted a delivery to the recipient but did not meet someone or could not access the delivery location.

This event can include additional keys that specify details about the expected next action that will be performed by the carrier.

onPickupReady

The consignment is ready for collection by the recipient at a courier location (for example: an access point or parcel locker). A further event for delivery or no collection can be expected.

This event can include additional keys that specify the pickup location.

onDelivered

Final event: The consignment has been delivered. This event can include an additional key that provides unstructured information about the delivery (for example: signature name).

onReturn

Final event: The delivery failed and the consignment will be returned to the sender.

This event can include an additional key that specifies the reason code for the return.

Data Format

Each event is submitted as a POST request.

The request can include the following optional URL query parameters, which are keys in the references field:

  • courier

  • tracking_number

  • orderNo

  • client

  • warehouse

  • destination_country_iso3

  • language

For more information, please refer to the Structure of references section.

The actual data is transmitted in the JSON encoded body (where header Content-Type: 'application/json' is set).

{
  "event": "onDelivered",
  "eventid": "abc123-def456",
  "timestamp": "2000-12-16T16:12:00.000Z",
  "references": {
    "courier": "dhl-germany",
    "tracking_number": "00340000000001",
    "orderNo": "ORD0012345",
    "client": "parcelFashion",
    "warehouse": "EU",
    "destination_country_iso3": "DEU",
    "language": "de"
  },
  "data": {
    "tracking_link": "https://www.dhl.de/...?piececode=00340000000001",
    "reroute_link": "",
    "raw_scan": "DLVRD-ACCPT-ZU | parcelLab",
    "raw_scan_location": "Munich",
    "delivery_status": "Delivered",
    "delivery_status_locale_short": "Zugestellt",
    "delivery_status_locale_long": "Die Lieferung wurde der Empfängerin oder dem Empfänger (parcelLab) zugestellt.",
    "expected_delivery_date_raw": "",
    "expected_delivery_date_formatted": "",
    "delivery_location": "Doorstep",
    "delivery_information": "parcelLab"
  },
  "reporting": {
    "lead_time_door_to_door": 2,
    "lead_time_qualified_attempt": 2,
    "lead_time_end_to_end": 3
  }
}

Data Structure of Webhooks

On the top level, webhooks include the fields described in the following table.

Field
Description

event

The event type as specified in the Events section (for example: onCreated).

eventid

A unique ID for this specific event that can be used for deduplication. Event IDs are strings consisting of a-f, 0-9 and dash -.

timestamp

The timestamp of when the event happened (not when the webhook was triggered) in ISO 8601 format: Date and time in UTC YYYY-MM-DDTHH:mm:ssZ.

references

The reference numbers for the consignment as described in the Structure of references section. Can optionally be submitted as URL search query parameters as well.

reporting

Logistics lead times of the consignment as described in the Structure of reporting section.

data

The event data as described in the Structure of data section. The data key contains mandatory fields that are transferred for every event and optional fields that are only transferred for specific events.

JSON Schema

This section provides details on the JSON schema for webhooks.

JSON Schema for Webhook Payloads
{
  "$schema": "http://json-schema.org/draft-06/schema#",
  "$ref": "#/definitions/Root",
  "title": "parcelLab webhook JSON schema",
  "definitions": {
    "Root": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "event": {
          "type": "string",
          "description": "The event type as specified in the section for events below, for example onCreated"
        },
        "eventid": {
          "type": "string",
          "description": "A unique ID for this specific event that can be used for deduplication. Event IDs are string consisting of a-f, 0-9 and dash -"
        },
        "timestamp": {
          "type": "string",
          "format": "date-time",
          "description": "The timestamp of when the event happened (not the webhook was triggered) in ISO 8601 format"
        },
        "references": {
          "$ref": "#/definitions/References",
          "description": "Reference numbers for this consignment"
        },
        "data": {
          "$ref": "#/definitions/Data",
          "description": "Contains mandatory fields that are transferred for every event and optional fields that are only transferred for specific events"
        },
        "reporting": {
          "$ref": "#/definitions/Reporting",
          "description": "Logistics lead times of this consignment"
        }
      },
      "required": [
        "data",
        "event",
        "eventid",
        "references",
        "reporting",
        "timestamp"
      ],
      "title": "Root"
    },
    "Data": {
      "title": "Data",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "tracking_link": {
          "type": "string",
          "format": "uri",
          "description": "URL to the carrier tracking page"
        },
        "reroute_link": {
          "type": "string",
          "format": "uri",
          "description": "URL to the carrier tracking page with delivery services like rerouting, change of delivery date etc. (is empty if link is not yet or no longer available)"
        },
        "raw_scan": {
          "type": "string",
          "description": "The raw event data as provided by the carrier (there is no common data pattern as this data is provided depending on the carrier interface)"
        },
        "raw_scan_location": {
          "type": "string",
          "description": "The location as provided by the carrier as a string, does not include coordinates or any structured address or location data"
        },
        "delivery_status": {
          "type": "string",
          "enum": [
            "InternalStatus",
            "Pending",
            "WarehousePrepared",
            "WarehouseDelay",
            "Packed",
            "Loaded",
            "OrderProcessed",
            "ReturnRegistered",
            "PickUpScheduled",
            "PickUpPlanned",
            "Upgrade",
            "InboundScan",
            "InterimHaul",
            "InTransit",
            "ExportHub",
            "ImportHub",
            "CustomsIn",
            "CustomsReleased",
            "Scheduled",
            "DestinationDeliveryCenter",
            "DestinationDeliveryDepot",
            "OutForDelivery",
            "Rerouted",
            "FailedAttemptFirst",
            "FailedAttemptSecond",
            "FailedAttemptFinal",
            "PickupReadyToday",
            "PickupReadyNextDay",
            "PartiallyDelivered",
            "Delivered",
            "Stored",
            "Return",
            "ReturnWarning",
            "Exception",
            "ReturnInProcess",
            "ReturnProcessed",
            "ReturnRefunded",
            "None",
            "Ignore",
            "Cancelled"
          ],
          "description": "parcelLab status code as specified at https://how.parcellab.works/docs/reporting/status-model#status-codes"
        },
        "delivery_status_locale_short": {
          "type": "string",
          "description": "Short localized string representing the delivery status limited to a few words (based on language as per references.language)"
        },
        "delivery_status_locale_long": {
          "type": "string",
          "description": "Full localized string representing the delivery status including all details like delivery date, delivery location, and delivery information (based on language as per references.language)"
        },
        "expected_delivery_date_raw": {
          "type": "string"
        },
        "expected_delivery_date_formatted": {
          "type": "string",
          "description": "Localized representation of the delivery date (based on language as per references.language), or empty string if no reliable EDD available"
        },
        "delivery_location": {
          "type": "string",
          "description": "Planned or actual delivery location as per parcelLab's delivery location codes, will be non-empty as soon as carrier scan indicates a planned delivery location and is not only set on successful delivery (see https://how.parcellab.works/docs/reporting/status-model#delivery-location-codes)"
        },
        "exception_code": {
          "type": "string",
          "enum": [
            "Exception",
            "Damaged",
            "TimeIssue",
            "AddressIssue",
            "CustomerRefusal",
            "Return",
            "DeliveryPayment",
            "Customs",
            "IdentFailed",
            "Misrouted",
            "ItemMissing",
            "LackSpace",
            "Notified",
            "MissingUpdates"
          ],
          "description": "Reason for the delay specified as parcelLab Delivery Problem Code, this key also is used for delivery_status_locale_long (see https://how.parcellab.works/docs/reporting/basics-of-logistics-analysis#delivery-problems)"
        },
        "next_action": {
          "type": "string",
          "enum": [
            "NewAttemptToday",
            "NewAttemptNextDay",
            "PickUpReady"
          ],
          "description": "Planned next action for this delivery after a failed attempt"
        },
        "next_action_is_specified": {
          "type": "boolean",
          "description": "Whether or not the next_action is explicitly specified in the scan event for the failed attempt (then true), or is set by the default value for the courier (then false)"
        },
        "pickup_location_address": {
          "type": "string",
          "description": "Plain address of pickup location without any HTML formatting, typically includes location name, street, zip code and city, country (all comma separated)"
        },
        "pickup_location_opening_hours": {
          "type": "object",
          "description": "Opening hours of pickup location in the format as specified below, is not available for all pickup locations"
        },
        "pickup_location_coordinates": {
          "type": "object",
          "description": "Geo-coordinates of pickup location in the format { lat: Float, long: Float }, is not available for all locations"
        },
        "delivery_information": {
          "type": "string",
          "description": "Specifies any details about the delivery, for example name of recipient, name of neighbor, description of deposit location for signature release"
        },
        "return_reason": {
          "type": "string",
          "enum": [
            "Recall",
            "NotCollected",
            "CustomerRefusal",
            "DeliveryPayment",
            "Customs",
            "AddressIssue",
            "Damaged",
            "Exception",
            "FailedDelivery",
            "Unknown"
          ],
          "description": "parcelLab code for failed delivery reasons as specified at https://how.parcellab.works/docs/reporting/watchlist#reasons-for-failed-deliveries"
        }
      },
      "required": [
        "tracking_link",
        "reroute_link",
        "raw_scan",
        "raw_scan_location",
        "delivery_status",
        "delivery_status_locale_short",
        "delivery_status_locale_long",
        "expected_delivery_date_raw",
        "expected_delivery_date_formatted",
        "delivery_location"
      ]
    },
    "References": {
      "title": "References",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "courier": {
          "type": "string",
          "description": "parcelLab courier code"
        },
        "tracking_number": {
          "type": "string",
          "description": "Tracking number"
        },
        "orderNo": {
          "type": "string",
          "description": "Customer-facing order number"
        },
        "client": {
          "type": "string",
          "description": "Shop identifier"
        },
        "warehouse": {
          "type": "string",
          "description": "Warehouse identifier"
        },
        "destination_country_iso3": {
          "type": "string",
          "pattern": "^[A-Z]{3}$",
          "description": "Destination country as ISO 3166-1 alpha-3"
        },
        "language": {
          "type": "string",
          "pattern": "^[a-z]{2}$",
          "description": "Customer language as ISO 639-1 (two-letter code)"
        }
      },
      "required": [
        "client",
        "courier",
        "destination_country_iso3",
        "language",
        "orderNo",
        "tracking_number",
        "warehouse"
      ]
    },
    "Reporting": {
      "title": "Reporting",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "lead_time_door_to_door": {
          "type": "integer",
          "minimum": -1,
          "maximum": 90,
          "description": "Courier network lead time starting from the inbound scan (onDispatch) until the first qualified delivery attempt (the first occurrence of onFailedAttempt, onPickupReady, or onDelivered)"
        },
        "lead_time_qualified_attempt": {
          "type": "integer",
          "minimum": -1,
          "maximum": 90,
          "description": "Recipient-percevied lead time starting from the EDI label confirmation by the carrier (typically coincides with onCreated) until the first qualified delivery attempt (the first occurrence of onFailedAttempt, onPickupReady, or onDelivered)"
        },
        "lead_time_end_to_end": {
          "type": "integer",
          "minimum": -1,
          "maximum": 90,
          "description": "Complete delivery time from the EDI label confirmation by the carrier (typically coincides with onCreated) until final delivery to the recipient (onDelivered)"
        }
      },
      "required": [
        "lead_time_door_to_door",
        "lead_time_end_to_end",
        "lead_time_qualified_attempt"
      ]
    }
  }
}

Structure of references

The references key includes the most commonly used references for the consignment and forwards the data as received from the retailer. These fields are described in the following table.

Field
Description

courier

The parcelLab carrier code.

tracking_number

The tracking number.

orderNo

The customer-facing order number.

client

The shop identifier.

warehouse

The warehouse identifier.

destination_country_iso3

The country code (for example: USA, GBR, DEU).

language

The language code (for example: en, es, de).

For further details on the content and format of these fields, please refer to the data model description for sending data to parcelLab.

Data Model

Structure of reporting

Lead times that are not yet available because their ending scan has not happened yet are sent with a -1. The fields included in the reporting key are described in the following table.

Field
Description

lead_time_door_to_door

The carrier network lead time starting from the inbound scan (onDispatch) until the first qualified delivery attempt (the first occurrence of onFailedAttempt, onPickupReady, or onDelivered).

lead_time_qualified_attempt

The recipient-perceived lead time starting from the EDI label confirmation by the carrier (typically coincides with onCreated) until the first qualified delivery attempt.

lead_time_end_to_end

The complete delivery time from EDI label confirmation until final delivery to the recipient (onDelivered).

Structure of data

The fields included in the data key are described in the following table.

Field
Description

tracking_link

The URL to the carrier’s tracking page.

reroute_link

The URL to the carrier’s tracking page with delivery services such as rerouting, change of delivery date, and so on. This field will be empty if the link is not defined yet or no longer available.

raw_scan

The raw event data as provided by the carrier. There is no common data pattern as the data provided depends on the carrier interface.

raw_scan_location

The location as provided by the carrier as a string. This does not include coordinates or any structured address or location data.

delivery_status

The parcelLab status code as specified in our status code documentation.

delivery_status_locale_short

A short localized string representing the delivery status limited to a few words (based on language as per references.language).

delivery_status_locale_long

A full localized string representing the delivery status including all details such as delivery date, delivery location, and delivery information (based on language as per references.language).

expected_delivery_date_raw

JSON Object or an empty object if no reliable estimated delivery date is available, according to this format.

expected_delivery_date_formatted

A localized representation of the delivery date (based on language as per references.language) or an empty string if no reliable estimated delivery date is available.

delivery_location

The planned or actual delivery location according to parcelLab’s delivery location codes. This field will be non-empty as soon as the carrier scan indicates a planned delivery location and is not only set on successful delivery.

exception_code Only for onDelay

The reason for the delay according to parcelLab's delivery problem codes. This key is also used for delivery_status_locale_long.

next_action Only for onFailedAttempt

The planned next action for this delivery after a failed attempt. This can be one of the following: NewAttemptToday, NewAttemptNextDay or PickUpReady.

next_action_is_specified Only for onFailedAttempt

If the next_action is explicitly specified in the scan event for the failed attempt (then true) or is set by the default value for the carrier (then false).

pickup_location_address Only for onPickupReady

The plain address of pickup location without any HTML formatting. This typically includes location name, street, zip code and city, country (all comma separated).

pickup_location_opening_hours Only for onPickupReady

The opening hours of the pickup location. Note: This is not available for all pickup locations.

pickup_location_coordinates Only for onPickupReady

The geo-coordinates of the pickup location in the format { lat: Float, long: Float }. Note: This is not available for all pickup locations.

delivery_information Only for onDelivered

This specifies any details about the delivery (for example: name of recipient, name of neighbor, description of deposit location for signature release).

return_reason Only for onReturn

The return reason according to parcelLab’s code reasons for failed deliveries.

Format of expected_delivery_date_raw

If no expected delivery date is known, this field will be an empty string "".

If an expected delivery date is set, it can be in one of these formats, with all date/time format definitions in Unicode Technical Standard #35. No timezone is given, as all dates are in local time of the recipient.

{
    "startDate": "yyyy-MM-dd",
    "endDate": "yyyy-MM-dd",
    "startTime": "HH:mm:ss",
    "endTime": "HH:mm:ss"
}

There are two cases for known expected delivery dates:

  1. Date only: Can be a date range or a single date. In this case both startDate and endDate are set. The format is yyyy-MM-dd.

  2. Date and time: If the expected delivery date is a single day, it can optionally include a time window for delivery. In this case again startDate is equal to endDate, and both startTime and endTime are filled in format HH:mm:ss. In the case of the carrier announcing an approximate point in time for delivery (for example: "delivery approximately at 12:35h"), startTime and endTime will also contain the same value: 12:35:00.

Data in CloudEvent Format

parcelLab also supports transmitting data in the CloudEvent format. The data key is then dropped from the payload and directly listed as part of CloudEvent’s data key. The references and reporting keys are kept as a sub-object within the transmitted data.

{
  "specversion": "1.0",
  "id": "abc123-def456",
  "source": "https://parcellab.com/integration/cloudevents",
  "type": "com.parcellab.tracking.event.ondelivered",
  "time": "2000-12-16T16:12:00.000Z",
  "datacontenttype": "application/json",
  "data": {
    "references": {
      "courier": "dhl-germany",
      "tracking_number": "00340000000001",
      "orderNo": "ORD0012345",
      "client": "parcelFashion",
      "warehouse": "EU",
      "destination_country_iso3": "DEU",
      "language": "de"
    },
    "data": {
      "tracking_link": "https://www.dhl.de/...?piececode=00340000000001",
      "reroute_link": "",
      "raw_scan": "DLVRD-ACCPT-ZU | parcelLab",
      "raw_scan_location": "Munich",
      "delivery_status": "Delivered",
      "delivery_status_locale_short": "Zugestellt",
      "delivery_status_locale_long": "Die Lieferung wurde der Empfängerin oder dem Empfänger (parcelLab) zugestellt.",
      "expected_delivery_date_raw": "",
      "expected_delivery_date_formatted": "",
      "delivery_location": "Doorstep",
      "delivery_information": "parcelLab"
    },
    "reporting": {
      "lead_time_door_to_door": 2,
      "lead_time_qualified_attempt": 2,
      "lead_time_end_to_end": 3
    }
  }
}

Last updated

Was this helpful?