Migration from legacy API & Webhook to 2025-01
The following guide will help you migrate the API and webhook from the legacy version to the 2025-01 version.
1. General API Changes
1.1 Endpoint Change
What's the difference?
Change | Before | After |
---|---|---|
Base URL | https://api.aftership.com/v4 | https://api.aftership.com/tracking/2025-01 |
as-api-version response header value | - | 2025-01 |
API Key header's key | - as-api-key - aftership-api-key | - as-api-key |
API Key header's value | The API keys that are marked as Legacy Tracking API access only are supported within the legacy API. | The API keys that are marked as Legacy Tracking API access only are no longer supported in the versioned API. |
as-webhook-version request header value | - | 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/v4 to https://api.aftership.com/tracking/2025-01.
- The request header
aftership-api-key
is no longer supported in the versioned API. Please useas-api-key
instead. - The API keys that are marked as Legacy Tracking API access only are no longer supported in the versioned API. Create a new API key and update your application's code if required. Check your API keys here.
- 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.
1.2 Rate Limit Policy
We have updated the rate limit for all endpoints from sharing one rate limit to each endpoint now having its dedicated rate limit to reduce the mutual impact across endpoints. Find the specific rate limit for each endpoint in the table below.
Endpoint | Rate Limit(request / sec) |
---|---|
GET /trackings | 6 |
POST /trackings | 20 |
GET /trackings/:slug/:tracking_number | 5 |
GET /trackings/:id | 5 |
POST /couriers/detect | 3 |
POST /estimated-delivery-date/predict-batch | 20 |
Other endpoints | 5 |
What do I need to do?
Please refer to the updated rate limit table above to manage your requests and prevent encountering frequent 429 errors. If your request volume exceeds the maximum rate limit allocated for a specific endpoint, adjust the frequency of your requests accordingly. If your current request volume falls within the defined rate limits, no additional action is required.
1.3 Enhanced field type verification
For all POST / PUT / PATCH endpoints (the request with a body), a 400 Bad Request error will be returned if any field in the request body has an incorrect data type.
Before | After |
---|---|
The invalid field in the request body will be ignored. For example,
The |
A 400 bad request error will be returned if invalid fields in the request body exist. example:
A 400 bad request error will be returned as the |
What do I need to do?
Make the following updates to your application's code:
- Implement error handling mechanisms in your application to capture and handle the 400 Bad Request error.
- Ensure that the types of all fields are consistent with the types described in the document.
2. API Endpoints Deprecation
What's the difference?
Change | Before | After |
---|---|---|
Deprecating endpoints | - POST /notifications/{tracking_id}/add - POST /notifications/{tracking_id}/remove - POST /notifications/{slug}/{tracking_number}/add - POST /notifications/{slug}/{tracking_number}/remove - GET /notifications/{tracking_id} - GET /notifications/{slug}/{tracking_number} - GET /last_checkpoint/{tracking_id} - GET /last_checkpoint/{slug}/{tracking_number} - GET /trackings/{slug}/{tracking_number} - PUT /trackings/{slug}/{tracking_number} - DELETE /trackings/{slug}/{tracking_number} - POST /trackings/{slug}/{tracking_number}/retrack - POST /trackings/{slug}/{tracking_number}/mark-as-completed | Endpoints removed |
What do I need to do?
Make the following updates to your application's code:
- Replace the "Add notifications" and "Remove notifications" endpoints with the "Update tracking" endpoint to update customers. Refer to the documentation on updating tracking endpoints for more information.
- Replace the "Get tracking notifications" endpoint with the "Get tracking" endpoint to retrieve customer's details. Refer to the documentation on get tracking endpoints for more details.
- Replace the last_checkpoint endpoints with the GET /tracking/{id} endpoint.
- The GET /tracking/{id} endpoint will respond to all checkpoints in the tracking information. Retrieve the last item in the checkpoints array returned by these endpoints to obtain the most recent checkpoint.
- Replace GET /trackings/{slug}/{tracking_number} endpoint with GET /trackings/{id} endpoint. Refer to the documentation on get tracking endpoints for more details.
- Replace PUT /trackings/{slug}/{tracking_number} endpoint with PUT /trackings/{id} endpoint. Refer to the documentation on update tracking endpoints for more details.
- Replace DELETE /trackings/{slug}/{tracking_number} endpoint with DELETE /trackings/{id} endpoint. Refer to the documentation on delete tracking endpoints for more details.
- Replace POST /trackings/{slug}/{tracking_number}/retrack endpoint with POST /trackings/{id}/retrack endpoint. Refer to the documentation on retrack tracking endpoints for more details.
- Replace POST /trackings/{slug}/{tracking_number}/mark-as-completed endpoint with POST /trackings/{id}/mark-as-completed endpoint. Refer to the documentation on mark tracking as completed endpoints for more details.
3. New SDK
4. Tracking Model New Fields Added
New Fields | Description |
---|---|
carbon_emissions | The model contains the total amount of carbon emissions generated by the shipment. This is a paid service available only for Enterprise plan users. Please contact your customer success manager if you need this. |
events | The specific event(s) that occurred to a shipment, such as, returned_to_sender . You can find the full list of events and reasons here. |
location_id | The location_id refers to the place where you fulfilled the items. If you provide a location_id , the system will automatically use it as the tracking's origin address. |
shipping_method | It refers to the chosen method for delivering the package. Merchants typically offer various shipping methods to consumers during the checkout process, such as, Local Delivery, Free Express Worldwide Shipping, etc. If you have this information, pass the shipping_method while creating or updating the tracking pass the shipping_method while creating or updating the tracking if you have this information. |
failed_delivery_attempts | This field dynamically tracks failed delivery attempts during the delivery of the shipment, allowing you to identify the carriers responsible for the most failures, analyze the root cause, and improve carriers' delivery SOP. |
signature_requirement | Signature requirement confirmation is a service offered by shipping carriers that provides an extra level of security and proof of delivery for shipments. When using the service, the recipient's signature is required upon delivery. |
legacy_id | The length of the tracking ID has been increased from 24 characters to 32 characters. We will use the legacy_id field to store the original 24-character tracking ID to maintain compatibility with existing data. Therefore, all tracking endpoints will continue to work with the legacy_id field as before. |
shipment_weight | The shipment weight and unit are obtained from the carrier by default. In scenarios where the carrier does not provide the weight, users can input it manually. AfterShip will prioritize returning the weight value provided by the carrier whenever available. |
aftership_tracking_url | The field contains the tracking page URL of the individual shipment. It will display the default tracking page or a variation based on any applicable segmentation rules. |
aftership_tracking_order_url | The field contains the order URL that displays the tracking page for the entire order, including all shipments. It will show the default tracking page or a variation based on any applicable segmentation rules. |
first_mile.tracking_number | The tracking number of the first-mile carrier. |
first_mile.slug | The Unique code of the carrier responsible for the first mile of the shipping of the package |
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. |
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". |
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". |
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. |
customers.*.role | The role of the customer indicates whether the customer is an individual or a company. |
customers.*.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. |
checkpoints.*.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?
For all new fields, simply parse the new field in the API response and the webhook body if you want to fetch the field; otherwise, no action is required.
5. Tracking Model Fields Updated
5.1 Coordinates field replaced by Coordinate
The existing array field checkpoints.*.coordinates
will be deprecated and replaced with object checkpoints.*.coordinate
.
What's the difference?
Change | Before | After |
---|---|---|
The existing array field |
coordinates Array[number] Example:
|
coordinate Object Example:
|
What do I need to do?
- Remove the parsing for the
coordinates
field. - Parse the new field
coordinate
in the API response and the webhook body if you are interested in this information; otherwise, no action is required.
5.2 Tracking ID format changed
The length of the tracking ID has been increased from 24 characters to 32 characters. The original 24-character ID will continue to be maintained and stored in the new legacy_id
field. Both IDs can uniquely identify a tracking. We recommend using the 32-character ID, as the legacy ID will eventually be deprecated in upcoming releases.
What's the difference?
Change | Before | After |
---|---|---|
The length of the tracking ID has been changed from 24 characters to 32 characters. | my2uktymyz72xld1f7l3h01z | c17ed4faec0a4831b675f445aad72e4e |
What do I need to do?
- Extend the length of the tracking ID to 32 characters if you are using this field. Otherwise, no further action is required.
5.3 Slug format change
Currently, the slug in detect couriers supports both an array of strings and comma-separated string formats. Moving forward, we will change it to support only the array of strings format.
What's the difference?
Change | Before | After |
---|---|---|
slug no longer supports comma-separated string format when detecting couriers. | ["ups", "fedex"] or "ups,fedex" | ["ups", "fedex"] |
What do I need to do?
- If your input for
slug
is in comma-separated string format, please convert it to an array of strings. Otherwise, no further action is required.
5.4 order_promised_delivery_date new value format
The order_promised_delivery_date
now supports time and timezone information.
What's the difference?
Change | Before | After |
---|---|---|
Supports new value format | - YYYY-MM-DD | - YYYY-MM-DD - YYYY-MM-DDTHH:mm:ss - YYYY-MM-DDTHH:mm:ssZ |
What do I need to do?
- Parse the field with time and timezone in the API response and the webhook body if you want to fetch the field. Otherwise, no further action is required.
- Specify the
order_promised_delivery_date
with time and timezone in the API request body if you want to input the field. Otherwise, no further action is required.
5.5 expected_delivery renamed and structure changed
The expected_delivery
field will be renamed to courier_estimated_delivery_date
and will support time range values.
What's the difference?
Before | After |
---|---|
Example: |
Example:
|
What do I need to do?
- Remove the parsing for the
expected_delivery
" field. - Parse the new field
courier_estimated_delivery_date
in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.
5.6 tracking.next_couriers renamed and structure changed
The tracking.next_couriers
field will be replaced with tracking.last_mile
.
Before | After |
---|---|
|
|
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.
5.7 tracking.customer_name replaced
The tracking.customer_name
field will be replaced with tracking.customers.*.name
.
Before | After |
---|---|
|
|
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.*.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.
5.8 tracking.emails replaced
The tracking.emails
field will be replaced with tracking.customers.*.email
.
Before | After |
---|---|
|
|
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.*.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.
5.9 tracking.smses replaced
The tracking.smses
field will be replaced with tracking.customers.*.phone_number
.
Before | After |
---|---|
|
|
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.*.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.
5.10 tracking.tracking_ship_date format updated
The tracking.tracking_ship_date
field date format has been updated and will support more date-time formats.
Before | After |
---|---|
|
|
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.
5.11 tracking.transit_time formula updated
We're aligning our transit time calculation with carrier standards for improved accuracy. Our previous method included the pick-up date, resulting in an extra day compared to carriers. Now, transit time starts on the first business day after pick-up, aligning with carriers, where transit time begins on the first business day after pick-up. This change simplifies SLA management and shipping performance monitoring for merchants.
Change | Before | After |
---|---|---|
Formula updated | Pick up date is considered as 1 transit day - For delivered shipments: Transit time (in days) = Delivered date - Pick-up date + 1 - For undelivered shipments: Transit time (in days) = Current date - Pick-up date + 1 | Pick up date is not considered as 1 day in transit - For delivered shipments: Transit time (in days) = Delivered date - Pick-up date - For undelivered shipments: Transit time (in days) = Current date - Pick-up date |
What do I need to do?
- Be aware of the formula change and adjust your app's code where you use the value to ensure it won't break your system.
6. Tracking Model Fields Renamed
The following fields have been renamed:
Before | After |
---|---|
tracking.courier_destination_country_iso3 | tracking.courier_destination_country_region |
tracking.origin_country_iso3 | tracking.origin_country_region |
tracking.destination_country_iso3 | tracking.destination_country_region |
tracking.tracking_origin_country | tracking.tracking_origin_country_region |
tracking.tracking_destination_country | tracking.tracking_destination_country_region |
tracking.checkpoints.*.country | tracking.checkpoints.*.country_region |
tracking.checkpoints.*.country_name | tracking.checkpoints.*.country_region_name |
tracking.aftership_estimated_delivery_date.confidence_score | tracking.aftership_estimated_delivery_date.confidence_code |
tracking.delivery_time | tracking.transit_time |
tracking.first_estimated_delivery.source enum value - AI Predictive EDD | AfterShip EDD |
tracking.latest_estimated_delivery.source enum value - AI Predictive EDD | AfterShip EDD |
What do I need to do?
- Remove the parsing for the old field.
- Parse the new field in the API response and the webhook body if you want to retrieve data from the new field. Otherwise, no further action is required.
7. Tracking Endpoints Common Changes
7.1 New fields added in tracking
Please refer to the Tracking Model New Fields Added
7.2 Fields updated in tracking
Please refer to the Tracking Model Fields Updated and Tracking Model Fields Renamed
7.3 Removed the tracking object wrapper from the request body
Before | After |
---|---|
|
|
What do I need to do?
Remove the tracking object wrapper from the request body when you create/update a tracking or detect couriers.
7.4 Removed the tracking object wrapper from the response body
Before | After |
---|---|
|
|
What do I need to do?
Remove the tracking object wrapper from the response body when using the tracking endpoints.
8. Tracking Endpoints Specific Changes
8.1 GET /trackings endpoint
8.1.1 Cursor Pagination
Use cursor parameters instead of page parameters to improve search performance. Additionally, we have standardized the response body envelope for consistency.
What's the difference?
Change | Before | After |
---|---|---|
Query parameters updates | Using page parameters to traverse search results. | Use the cursor to get data for the next page. |
Response body updates | Returns all query parameters. | Removed query parameters Added pagination object with cursor. |
What do I need to do?
Make the following updates to your application's code:
- Do not fetch query parameters from the response.
- Iterate search results using the cursor instead of relying on page number.
8.1.2 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 behaviour.
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 a400 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.
8.1.3 Parameters renamed
The following fields have been renamed:
Before | After |
---|---|
delivery_time | transit_time |
What do I need to do?
- Put the new field in the API request parameters if you want to use the field. Otherwise, no further action is required.
8.1.4 Parameters added
New Fields | Description |
---|---|
order_id | A globally-unique identifier for the order. Use commas for multiple values. |
What do I need to do?
- Put the new field in the API request parameters if you want to use the field. Otherwise, no further action is required.
8.2 POST /trackings endpoint
Please refer to the Tracking Endpoints Common Changes.
8.3 GET /trackings/:id endpoint
Please refer to the Tracking Endpoints Common Changes.
8.4 PUT /trackings/:id endpoint
8.4.1 Support updating tracking_ship_date for non-pending trackings
Regardless of the tracking status, you can update the value of the tracking_ship_date
field.
What do I need to do?
Include the field in the API request body if you want to update it. Otherwise, no further action is required.
8.5 DELETE /trackings/:id endpoint
Please refer to the Tracking Endpoints Common Changes.
8.6 POST /trackings/:id/retrack endpoint
Please refer to the Tracking Endpoints Common Changes.
8.7 POST /trackings/:id/mark-as-complete endpoint
8.7.1 New fields added in the request body
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 the |
The request body:
|
The request body:
|
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.
8.7.2 Create a new checkpoint when tracking is marked as completed
A new checkpoint will be created when the user marks the tracking as completed.
Before | After |
---|---|
|
|
What do I need to do?
Parse the new field tracking.checkpoints
in the API response and the webhook body if you want to retrieve data. Otherwise, no further action is required
9. Courier Model Fields Renamed
The following fields/enum values have been renamed:
Before | After |
---|---|
courier.service_from_country_iso3 | courier.service_from_country_region |
courier.required_fields enum value - tracking_origin_country | tracking_origin_country_region |
courier.required_fields enum value - tracking_destination_country | tracking_destination_country_region |
What do I need to do?
- Remove the parsing for the old field.
- Parse the new field in the API response if you want to retrieve data from the new field. Otherwise, no further action is required.
10. Courier Endpoints Changes
10.1 GET /couriers
Please refer to the Courier Model Fields Renamed.
10.2 GET /couriers/all
Please refer to the Courier Model Fields Renamed.
10.3 POST /couriers/detect
10.3.1 Fields updated in the request body
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. - Add 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 retrieve data from these fields. Otherwise, no further action is required.
11. Estimated Delivery Date Endpoint fields Renamed
The following fields have been renamed:
Before | After |
---|---|
estimated_delivery_date.origin_address.country | estimated_delivery_date.origin_address.country_region |
estimated_delivery_date.destination_address.country | estimated_delivery_date.destination_address.country_region |
What do I need to do?
- Remove the parsing for the old field.
- Parse the new field in the API response if you want to retrieve data from the new field. Otherwise, no further action is required.
12. Estimated Delivery Date Endpoints Changes
12.1 POST /estimated-delivery-date/predict-batch
12.1.1 New field id for EDD endpoint
The reference ID acts as a unique identifier to associate the estimated delivery date value generated by AfterShip EDD to its corresponding shipment.
What do I need to do?
Parse the new field in the API response if you want to fetch the field. Otherwise, no further action is required.
12.1.2 New field confidence_code for EDD endpoint
Indicates the confidence level and associated reason for an AI EDD prediction request. For a comprehensive list of confidence codes, refer to this document.
What do I need to do?
Parse the new field in the API response if you want to fetch the field. Otherwise, no further action is required.
12.1.3 Add validation check for Batch prediction for the Estimated Delivery Date API
We have added validation checks for the origin_address.postal_code
and destination_address.postal_code
fields in the Tracking AI EDD. In case of invalid input, the API will now return META.CODE 4008 to indicate the errors.
What do I need to do?
Provide valid values for origin_address.postal_code
and destination_address.postal_code
in your API request otherwise, the API will return an error.
13. Webhook Changes
13.1 New fields added in tracking
Please refer to the Tracking model new fields added
13.2 Fields updated in tracking
Please refer to the Tracking model fields updated
14. What if I don’t migrate?
After Oct 9, 2025, any requests made to the legacy version will result in a 404 Not Found error. and therefore, we encourage you to complete the migration at your earliest convenience.