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.
API Version Changes
What's the difference?
Change | Before | After |
---|---|---|
Base URL | https://api.aftership.com/tracking/2024-10 | https://api.aftership.com/tracking/2025-01 |
as-api-version header’s value | 2024-10 | 2025-01 |
as-webhook-version header’s value | 2024-10 | 2025-01 |
What do I need to do?
Make the following updates to your application's code:
- Replace the base URL from
https://api.aftership.com/tracking/2024-10
tohttps://api.aftership.com/tracking/2025-01
. - Select the Webhook version when editing existing URLs or adding new ones. Please review your webhook settings for verification.
- Parse the header to distinguish between different versions. Otherwise, no further action is required.
API Endpoints Changes
Searching for tracking parameters validation
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.
What's the difference?
Change | Before | After |
---|---|---|
Add validation for created_at_max | Set the value to the current time when a user inputs an invalid time value | Return a 400 error when a user inputs an invalid time value |
Add validation for created_at_min | Set the value to 120 days ago when a user inputs an invalid time value | Return a 400 error when a user inputs an invalid time value |
Add validation for updated_at_max | Set the value to the current time when a user inputs an invalid time value | Return a 400 error when a user inputs an invalid time value |
Add validation for updated_at_min | Set the value to 120 days ago when a user inputs an invalid time value | Return a 400 error when a user inputs an invalid time value |
Common mistake
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.
What do I need to do?
Make the following updates to your application's code:
- Implement error handling mechanisms in your application’s code to capture and handle 400 Bad Request errors.
- Ensure that the data types of all fields match the types specified in the document.
New endpoint for estimated delivery date prediction
A new prediction endpoint has been added to get the estimated delivery date.
What do I need to do?
- If you want to learn more about this endpoint, please refer to the detailed documentation. Otherwise, no further action is required.
Business logic changes
Overview
Update | Affected 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 field | API endpoint: - POST /trackings/:id/mark-as-completed |
Key Updates - New fields
first_mile.tracking_number
first_mile.tracking_number
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.
first_mile.slug
first_mile.slug
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.
first_mile.transit_time
first_mile.transit_time
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.
first_mile.courier_tracking_link
first_mile.courier_tracking_link
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.
first_mile.courier_redirect_link
first_mile.courier_redirect_link
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.
last_mile.transit_time
last_mile.transit_time
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.
customers[x].role
customers[x].role
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.
customers[x].language
customers[x].language
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.
checkpoints[x].source
checkpoints[x].source
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.
Key Updates - Updated fields
tracking.next_couriers
rename
tracking.next_couriers
renameThe tracking.next_couriers
field will be replaced with tracking.last_mile
.
What's the difference?
Change | Before | After |
---|---|---|
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?
- Add the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.next_couriers
field. - 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.
tracking.customer_name
replaced
tracking.customer_name
replacedThe tracking.customer_name
field will be replaced with tracking.customers[x].name
customers.
What's the difference?
Change | Before | After |
---|---|---|
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?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.customer_name
field. - 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.
tracking.emails
replaced
tracking.emails
replacedThe tracking.emails
field will be replaced with tracking.customers[x].email
customers.
What's the difference?
Change | Before | After |
---|---|---|
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?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.emails
field. - 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.
tracking.smses
replaced
tracking.smses
replacedThe tracking.smses
field will be replaced with tracking.customers[x].phone_number
customers.
What's the difference?
Change | Before | After |
---|---|---|
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?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.smses
field. - 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.
tracking.tracking_ship_date
format updated
tracking.tracking_ship_date
format updatedThe tracking.tracking_ship_date
field date format has been updated and will support more date-time formats.
What's the difference?
Change | Before | After |
---|---|---|
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?
- Ensure that valid values are provided for
tracking_ship_date
in your API request. Otherwise, the API will return a 400 error. - 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.
Create new checkpoint when tracking is marked as completed
A new checkpoint will be created when the users marks the tracking as completed.
What's the difference?
Change | Before | After |
---|---|---|
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?
- Parse the new checkpoint in the API response and the webhook body if you want to retrieve data. Otherwise, no further action is required.
tracking.courier_destination_country_iso3
renamed
tracking.courier_destination_country_iso3
renamedThe tracking.courier_destination_country_iso3
field will be renamed to tracking.courier_destination_country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.courier_destination_country_iso3
field. - 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.
tracking.origin_country_iso3
renamed
tracking.origin_country_iso3
renamedThe tracking.origin_country_iso3
field will be renamed to tracking.origin_country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.origin_country_iso3
field. - 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.
tracking.destination_country_iso3
renamed
tracking.destination_country_iso3
renamedThe tracking.destination_country_iso3
field will be renamed to tracking.destination_country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.destination_country_iso3
field. - 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.
tracking.tracking_origin_country
renamed
tracking.tracking_origin_country
renamedThe tracking.tracking_origin_country
field will be renamed to tracking.tracking_origin_country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.tracking_origin_country
field. - 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.
tracking.tracking_destination_country
renamed
tracking.tracking_destination_country
renamedThe tracking.tracking_destination_country
field will be renamed to tracking.tracking_destination_country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.tracking_destination_country
field. - 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.
tracking.checkpoints[x].country
renamed
tracking.checkpoints[x].country
renamedThe tracking.checkpoints[x].country
field will be renamed to tracking.checkpoints[x].country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.checkpoints[x].country
field. - 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.
tracking.checkpoints[x].country_name
renamed
tracking.checkpoints[x].country_name
renamedThe tracking.checkpoints[x].country_name
field will be renamed to tracking.checkpoints[x].country_region_name
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
tracking.checkpoints[x].country_name
field. - 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.
courier.service_from_country_iso3
renamed
courier.service_from_country_iso3
renamedThe courier.service_from_country_iso3
field will be renamed to courier.service_from_country_regions
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
courier.service_from_country_iso3
field. - 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.
estimated_delivery_date.origin_address.country
renamed
estimated_delivery_date.origin_address.country
renamedThe estimated_delivery_date.origin_address.country
field will be renamed to estimated_delivery_date.origin_address.country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
estimated_delivery_date.origin_address.country
field. - 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.
estimated_delivery_date.destination_address.country
renamed
estimated_delivery_date.destination_address.country
renamedThe estimated_delivery_date.destination_address.country
field will be renamed to estimated_delivery_date.destination_address.country_region
.
What do I need to do?
- Put the new field in the API request body if you want to use the field.
- Remove the parsing for the
estimated_delivery_date.destination_address.country
field. - 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.
Additional courier fields enums renamed
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?
Change | Before | After |
---|---|---|
courier.required_fields enums renamed | The 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?
- Parse the new enums
tracking_destination_country_region
andtracking_origin_country_region
in the API response if you want to retrieve data. Otherwise, no further action is required.
Detect courier endpoint request body updated
What's the difference?
Change | Before | After |
---|---|---|
tracking_origin_country in the request body renamed to tracking_origin_country_region | tracking_origin_country | tracking_origin_country_region |
tracking_destination_country in the request body renamed to tracking_destination_country_region | tracking_destination_country | tracking_destination_country_region |
origin_country_iso3 in the request body renamed to origin_country_region | origin_country_iso3 | origin_country_region |
destination_country_iso3 in the request body renamed to destination_country_region | destination_country_iso3 | destination_country_region |
What do I need to do?
- Remove the
tracking_origin_country
,tracking_destination_country
,origin_country_iso3
, anddestination_country_iso3
fields in the request body. - Aadd the new fields
tracking_origin_country_region
,tracking_destination_country_region
,origin_country_region
, anddestination_country_region
in the API request body if you want to retrieveinput these data from these fields. Otherwise, no further action is required.
Tracking mark as completed endpoint supports event_datetime
What's the difference?
Change | Before | After |
---|---|---|
The request body of tracking mark as completed endpoint now supports event_datetime field | The request body: { "reason": "DELIVERED" } | The request body: { "reason": "DELIVERED", "event_datetime": "2024-12-10T01:22:19+01:00" } |
What do I need to do?
- Add the new field
event_datetime
to the API request body if you want to retrieve corresponding data. Otherwise, no further action is required.
What if I don’t migrate?
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.