Migration from 2024-10 API to 2025-01

This migration guide outlines the essential changes required to implement new functionalities when transitioning from the API and webhook version 2024-10 to 2025-01.

ChangeBeforeAfter
Base URLhttps://api.aftership.com/tracking/2024-10https://api.aftership.com/tracking/2025-01
as-api-version header’s value2024-102025-01
as-webhook-version header’s value2024-102025-01

Make the following updates to your application's code:

  1. Replace the base URL from https://api.aftership.com/tracking/2024-10 to https://api.aftership.com/tracking/2025-01.
  2. Select the Webhook version when editing existing URLs or adding new ones. Please review your webhook settings for verification.
  3. Parse the header to distinguish between different versions. Otherwise, no further action is required.

If a user inputs an invalid query time parameter, we will no longer set it to the default time value. We will return a 400 error code to indicate the invalid query time parameter, preventing any hidden behavior.

ChangeBeforeAfter
Add validation for created_at_maxSet the value to the current time when a user inputs an invalid time valueReturn a 400 error when a user inputs an invalid time value
Add validation for created_at_minSet the value to 120 days ago when a user inputs an invalid time valueReturn a 400 error when a user inputs an invalid time value
Add validation for updated_at_maxSet the value to the current time when a user inputs an invalid time valueReturn a 400 error when a user inputs an invalid time value
Add validation for updated_at_minSet the value to 120 days ago when a user inputs an invalid time valueReturn a 400 error when a user inputs an invalid time value

A common mistake when providing datetime values for the above keys is improper character escaping of the + sign. For example, when sending a timestamp via a GET request, such as 2024-12-01T16:42:00+00:00, the plus sign (+) must be correctly escaped as %2B. Thus, the correct value should be 2024-12-01T16:42:00%2B00:00. If this character is not properly escaped, a 400 error will occur in the API response.

Make the following updates to your application's code:

  1. Implement error handling mechanisms in your application’s code to capture and handle 400 Bad Request errors.
  2. Ensure that the data types of all fields match the types specified in the document.

A new prediction endpoint has been added to get the estimated delivery date.

  1. If you want to learn more about this endpoint, please refer to the detailed documentation. Otherwise, no further action is required.
UpdateAffected Endpoints
Tracking modal new fields:
first_mile.tracking_number
first_mile.slug
first_mile.transit_time
first_mile.courier_tracking_link
first_mile.courier_redirect_link
last_mile.transit_time
customers[x].role
customers[x].language
checkpoints[x].source
API endpoint:
- GET /trackings
- GET /trackings/:id
- DELETE /trackings/:id
- POST /trackings
- PUT /trackings/:id
- POST /trackings/:id/mark-as-completed
- POST /trackings/:id/retrack

Tracking Webhook
- The existing fields tracking.next_couriers will be replaced with tracking.last_mile
- The existing field tracking.customer_name will be replaced with tracking.customers[x].name
- The existing field tracking.smses will be replaced with tracking.customers[x].phone_number
- The existing field tracking.emails will be replaced with tracking.customers[x].email
API endpoint:
- GET /trackings
- GET /trackings/:id
- DELETE /trackings/:id
- POST /trackings
- PUT /trackings/:id
- POST /trackings/:id/mark-as-completed
- POST /trackings/:id/retrack

Tracking Webhook
The existing field tracking.last_updated_at will be deprecated.API endpoint:
- GET /trackings
- GET /trackings/:id
- DELETE /trackings/:id
- POST /trackings
- PUT /trackings/:id
- POST /trackings/:id/mark-as-completed
- POST /trackings/:id/retrack

Tracking Webhook
tracking.tracking_ship_date supports new value formats:
- YYYY-MM-DD
- YYYY-MM-DDTHH:mm:ss
- YYYY-MM-DDTHH:mm:ssZ
API endpoint:
- GET /trackings
- GET /trackings/:id
- DELETE /trackings/:id
- POST /trackings
- PUT /trackings/:id
- POST /trackings/:id/mark-as-completed
- POST /trackings/:id/retrack

Tracking Webhook
A new checkpoint will be created when the user marks a tracking as completed.API endpoint:
- GET /trackings
- GET /trackings/:id
- DELETE /trackings/:id
- POST /trackings
- PUT /trackings/:id
- POST /trackings/:id/mark-as-completed
- POST /trackings/:id/retrack

Tracking Webhook
- Rename tracking.courier_destination_country_iso3 to tracking.courier_destination_country_region
- Rename tracking.origin_country_iso3 to tracking.origin_country_region
- Rename tracking.destination_country_iso3 to tracking.destination_country_region
- Rename tracking.checkpoints[x].country_iso3 to tracking.checkpoints[x].country_region
- Rename tracking.checkpoints[x].country_name to tracking.checkpoints[x].country_region_name
- Rename tracking.tracking_origin_country to tracking.tracking_origin_country_region
- Rename tracking.tracking_destination_country to tracking.tracking_destination_country_region
- Rename courier.service_from_country_iso3 to courier.service_from_country_regions
- Rename estimated_delivery_date.origin_address.country to estimated_delivery_date.origin_address.country_region
- Rename estimated_delivery_date.destination_address.country to estimated_delivery_date.destination_address.country_region
API endpoint:
- GET /trackings
- GET /trackings/:id
- DELETE /trackings/:id
- POST /trackings
- PUT /trackings/:id
- POST /trackings/:id/mark-as-completed
- POST /trackings/:id/retrack
- GET /couriers
- GET /couriers/all
- POST /couriers/detect
- POST /estimated-delivery-date/predict-batch
- POST /estimated-delivery-date/predict

Tracking Webhook
Tracking marked as completed endpoint supportsevent_datetime fieldAPI endpoint:
- POST /trackings/:id/mark-as-completed

The tracking number of the first-mile carrier.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The Unique code of the carrier responsible for the first mile of the shipping of the package.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The transit time for the first-mile of a shipment in days. This field is calculated based on whether the handed_over_to_last_mile_carrier or received_by_last_mile_carrier event is detected by AfterShip. The handover event date is used to calculate the first-mile transit time.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The field contains the official tracking URL of the first-mile carrier, if available. The language parameter of this link is determined by the destination country/region and the language associated with the shipment. If the destination country/region and language data is unavailable, AfterShip will default the language parameter to "US".

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The field provides the link for modifying delivery instructions (such as delivery date and shipping address), if supported by the first-mile carrier. The language parameter of this link is determined by the destination country/region and the language associated with the shipment. If the destination country/region and language data is unavailable, AfterShip will default the language parameter to "US".

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The transit time for the last-mile of a shipment in days. This field is calculated based on whether the handed_over_to_last_mile_carrier or the received_by_last_mile_carrier event is detected by AfterShip. The handover event date is used to calculate the last-mile transit time.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The role of the customer, indicating whether the customer is an individual or a company.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The customer’s preferred language. If you have set up AfterShip notifications in different languages, this field is used to send the tracking updates to the customer in their preferred language.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The source of the checkpoint, which can either be from the carrier or when the user marks the tracking as completed.

What do I need to do?

Parse the new field in the API response and the webhook body if you want to fetch data from it. Otherwise, no further action is required.

The tracking.next_couriers field will be replaced with tracking.last_mile.

What's the difference?

ChangeBeforeAfter
The field name has been changed and contains the last mile transit time in days.{"meta":{"code":201},"data":{"tracking":{"id":xxxx,"created_at":xxxx,"updated_at":xxxx,"next_couriers":[{"slug":xxxx,"tracking_number":xxxx,"source":xxxx,"tracking_courier_link":xxxx,"tracking_redirect_link":xxxx,}],…}}}{"meta":{"code":201},"data":{"tracking":{"id":xxxx,"created_at":xxxx,"updated_at":xxxx,"last_mile":{"slug":xxxx,"tracking_number":xxxx,"source":xxxx,"transit_time":xxxx,"tracking_courier_link":xxxx,"tracking_redirect_link":xxxx},…}}}

What do I need to do?

  1. Add the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.next_couriers field.
  3. Parse the new field tracking.last_mile in the API response and the webhook body if you want to retrieve data from this field. Otherwise, no further action is required.

The tracking.customer_name field will be replaced with tracking.customers[x].name customers.

What's the difference?

ChangeBeforeAfter
The field type has been changed to object.{"meta": {"code": 201},"data": {"tracking": {"id": xxxx,"created_at": xxxx,"updated_at": xxxx,"customer_name": xxxx,…}}}{"meta":{"code":201},"data":{"tracking":{"id":xxxx,"created_at":xxxx,"updated_at":xxxx,"customers":[{"role":xxxx,"name":xxxx,"email":xxxx,...},{"role":null,"name":xxxx,"email":xxxx,...}],...}}}

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.customer_name field.
  3. Parse the new field tracking.customers[x].name in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.emails field will be replaced with tracking.customers[x].email customers.

What's the difference?

ChangeBeforeAfter
The field type has been changed from an array to an object.{"meta":{"code":201},"data":{"tracking":{"id":xxxx,"created_at":xxxx,"updated_at":xxxx,"emails":[xxxx,xxxx],…}}}{"meta":{"code":201},"data":{"tracking":{"id":xxxx,"created_at":xxxx,"updated_at":xxxx,"customers":[{"role":xxxx,"name":xxxx,"email":xxxx,…},{"role":xxxx,"name":xxxx,"email":xxxx,…}],…}}}

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.emails field.
  3. Parse the new field tracking.customers[x].email in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.smses field will be replaced with tracking.customers[x].phone_number customers.

What's the difference?

ChangeBeforeAfter
The field type has been changed from an array to an object.{"meta": {"code": 201},"data": {"tracking": {"id": xxxx,"created_at": xxxx,"updated_at": xxxx,"smses": [xxxx, xxxx],…}}}{"meta":{"code":201},"data":{"tracking":{"id":xxxx,"created_at":xxxx,"updated_at":xxxx,"customers":[{"role":xxxx,"name":xxxx,"phone_number":xxxx,…},{"role":xxxx,"name":xxxx,"phone_number":xxxx,…}],…}}}

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.smses field.
  3. Parse the new field tracking.customers[x].phone_number in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.tracking_ship_date field date format has been updated and will support more date-time formats.

What's the difference?

ChangeBeforeAfter
Removed the YYYYMMDD format, and introduced support for the new formats:
- YYYY-MM-DD
- YYYY-MM-DDTHH:mm:ss
- YYYY-MM-DDTHH:mm:ssZ
{"meta": {"code": 201},"data": {"tracking": {"id": xxxx,"created_at": xxxx,"updated_at": xxxx,"tracking_ship_date": "20250102",…}}}{"meta": {"code": 201},"data": {"tracking": {"id": xxxx,"created_at": xxxx,"updated_at": xxxx,"tracking_ship_date": "2025-01-02T10:00:00+01:00",…}}}

What do I need to do?

  1. Ensure that valid values are provided for tracking_ship_date in your API request. Otherwise, the API will return a 400 error.
  2. Parse the field tracking.tracking_ship_date in the API response and the webhook body using the new formats if you want to retrieve data. Otherwise, no further action is required.

A new checkpoint will be created when the users marks the tracking as completed.

What's the difference?

ChangeBeforeAfter
A new checkpoint will be created when the user marks the tracking as completed.{"meta": {"code": 201},"data": {"tracking": {"id": xxxx,"created_at": xxxx,"updated_at": xxxx,"checkpoints": [],…}}}{"meta": {"code": 201},"data": {"tracking": {"id": xxxx,"created_at": xxxx,"updated_at": xxxx,"checkpoints": [{"checkpoint_time": "xxxx","source": "user","subtag": "Delivered_001", "subtag_message": "Delivered", "tag": "Delivered", …}],…}}}

What do I need to do?

  1. Parse the new checkpoint in the API response and the webhook body if you want to retrieve data. Otherwise, no further action is required.

The tracking.courier_destination_country_iso3 field will be renamed to tracking.courier_destination_country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.courier_destination_country_iso3 field.
  3. Parse the new field tracking.courier_destination_country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.origin_country_iso3 field will be renamed to tracking.origin_country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.origin_country_iso3 field.
  3. Parse the new field tracking.origin_country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.destination_country_iso3 field will be renamed to tracking.destination_country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.destination_country_iso3 field.
  3. Parse the new field tracking.destination_country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.tracking_origin_country field will be renamed to tracking.tracking_origin_country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.tracking_origin_country field.
  3. Parse the new field tracking.tracking_origin_country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.tracking_destination_country field will be renamed to tracking.tracking_destination_country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.tracking_destination_country field.
  3. Parse the new field tracking.tracking_destination_country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.checkpoints[x].country field will be renamed to tracking.checkpoints[x].country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.checkpoints[x].country field.
  3. Parse the new field tracking.checkpoints[x].country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking.checkpoints[x].country_name field will be renamed to tracking.checkpoints[x].country_region_name.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the tracking.checkpoints[x].country_name field.
  3. Parse the new field tracking.checkpoints[x].country_region_name in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The courier.service_from_country_iso3 field will be renamed to courier.service_from_country_regions.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the courier.service_from_country_iso3 field.
  3. Parse the new field courier.service_from_country_regions in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The estimated_delivery_date.origin_address.country field will be renamed to estimated_delivery_date.origin_address.country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the estimated_delivery_date.origin_address.country field.
  3. Parse the new field estimated_delivery_date.origin_address.country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The estimated_delivery_date.destination_address.country field will be renamed to estimated_delivery_date.destination_address.country_region.

What do I need to do?

  1. Put the new field in the API request body if you want to use the field.
  2. Remove the parsing for the estimated_delivery_date.destination_address.country field.
  3. Parse the new field estimated_delivery_date.destination_address.country_region in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.

The tracking_destination_country enum and the tracking_origin_country enum will be renamed to tracking_destination_country_region and tracking_origin_country_region.

What's the difference?

ChangeBeforeAfter
courier.required_fields enums renamedThe enums of the courier.required_fields:
- tracking_account_number
- tracking_postal_code
- tracking_ship_date
- tracking_key
- tracking_origin_country
- tracking_destionation_country
- tracking_state
The enums of the courier.required_fields:
- tracking_account_number
- tracking_postal_code
- tracking_ship_date
- tracking_key
- tracking_origin_country_region
- tracking_destionation_country_region
- tracking_state

What do I need to do?

  1. Parse the new enums tracking_destination_country_region and tracking_origin_country_region in the API response if you want to retrieve data. Otherwise, no further action is required.

What's the difference?

ChangeBeforeAfter
tracking_origin_country in the request body renamed to tracking_origin_country_regiontracking_origin_countrytracking_origin_country_region
tracking_destination_country in the request body renamed to tracking_destination_country_regiontracking_destination_countrytracking_destination_country_region
origin_country_iso3 in the request body renamed to origin_country_regionorigin_country_iso3origin_country_region
destination_country_iso3 in the request body renamed to destination_country_regiondestination_country_iso3destination_country_region

What do I need to do?

  1. Remove the tracking_origin_country, tracking_destination_country, origin_country_iso3, and destination_country_iso3 fields in the request body.
  2. Aadd the new fields tracking_origin_country_region, tracking_destination_country_region, origin_country_region, and destination_country_region in the API request body if you want to retrieveinput these data from these fields. Otherwise, no further action is required.

What's the difference?

ChangeBeforeAfter
The request body of tracking mark as completed endpoint now supports event_datetime fieldThe request body:
{
"reason": "DELIVERED"
}
The request body:
{
"reason": "DELIVERED",
"event_datetime": "2024-12-10T01:22:19+01:00"
}

What do I need to do?

  1. Add the new field event_datetime to the API request body if you want to retrieve corresponding data. Otherwise, no further action is required.

If you choose not to migrate, the 2024-10 API will continue to be supported for at least 18 months. However, API traffic will eventually be redirected to the 2025-01 version following the deprecation of the versioned API. For further details on API versioning, please refer to our documentation.