Migrate from legacy to 2025-07

The following guide will help you migrate the API and webhook from the legacy version to version 2025-07.

What's the difference?

ChangeBeforeAfter
Base URLhttps://api.aftership.com/returnscenter/v2https://api.aftership.com/returns/2025-07
as-api-version response header value-2025-07
as-webhook-version request header value-2025-07

What do I need to do?

Make the following updates to your application's code:

  1. Replace the base URL from https://api.aftership.com/returnscenter/v2 to https://api.aftership.com/returns/2025-07.
  2. When editing existing URLs or adding new ones, select the webhook version. Please review your webhook settings for verification.
  3. Parse the header to distinguish between different versions. Otherwise, no action is required.

2.1 Update Return Status (POST /returns/rma/{rma_number}/status-transitions)

What's the difference?

The endpoint has been split into three different endpoints in the 2025-07 version:

  • POST /returns/rma/{rma_number}/approve
  • POST /returns/rma/{rma_number}/resolve
  • POST /returns/rma/{rma_number}/reject

The original endpoint had 4 types of request bodies, each corresponding to a different case. The migration can be done for each of the use cases:

Legacy

preparing...

2025-07

In the new API version, you can call the status endpoint directly. There is no need to manually retrieve from_status as required in the legacy version.

preparing...

Legacy

preparing...

2025-07

In the new API version, you can directly call the reject endpoint.

preparing...

Legacy

preparing...

2025-07

In the initial Returns system, merchants had to provide a label before approving a return, and the API was designed around that workflow. In the latest system, label submission and approval are two separate actions. As of the 2024-10 version, the approve endpoint no longer accepts a label URL. If you still need to provide a label, please use the attach shipment endpoint instead.

Legacy

preparing...

2025-07

In the new API version, you can use the approve endpoint with generate_label.

preparing...

What do I need to do?

  1. Replace the deprecated status-transitions endpoint with the corresponding new endpoint (approve, resolve, or reject).
  2. Remove the from_status and to_status fields from the request payload.
  3. For approvals that require providing a label URL, use the attach shipment endpoint separately after approval.
  4. Add the new optional field notify_customer to control whether the customer receives an email notification.

2.2 Batch mark items as received (POST /returns/rma/{rma_number}/item-receive-batch)

What's the difference?

ChangeBeforeAfter
EndpointPOST /returns/rma/{rma_number}/item-receive-batchPOST /returns/rma/{rma_number}/receive-items
Field namesend_notificationnotify_customer
Response payloadLegacy response structureNew Return Object

Legacy

Request:

preparing...

2025-07

Request:

preparing...

What do I need to do?

  1. Update the endpoint from item-receive-batch to receive-items.
  2. Replace send_notification with notify_customer in the request body.
  3. Update your code to parse the new Return Object structure in the response.

What's the difference?

ChangeBeforeAfter
Field namemerchant_tagsitem_tags
Field namemerchant_imagesmerchant_uploaded_image_urls
Field typemerchant_images is an array of objectsmerchant_uploaded_image_urls is an array of strings
Response payloadLegacy response structureNew ReturnItem Object

Legacy

Request:

preparing...

OR

preparing...

2025-07

Request:

preparing...

OR

preparing...

What do I need to do?

  1. Replace merchant_tags with item_tags.
  2. Replace merchant_images with merchant_uploaded_image_urls and change the structure from an array of objects to an array of strings.
  3. Update your code to parse the new ReturnItem Object structure in the response.

2.4 Batch attach shipments to an RMA (POST /returns/rma/{rma_number}/shipment-batch)

What's the difference?

ChangeBeforeAfter
EndpointPOST /returns/rma/{rma_number}/shipment-batchPOST /returns/rma/{rma_number}/attach-shipments
Field nameshipments\[\*\].label.aftership_tracking_slugshipments\[\*\].slug
Field typeshipments\[\*\].label.total_charge.amount is a numbershipments\[\*\].label.total_charge.amount is a string
Field namesend_notificationnotify_customer
Response payloadLegacy response structureNew Return Object

Legacy

Request:

preparing...

2025-07

Request:

preparing...

What do I need to do?

  1. Update the endpoint from shipment-batch to attach-shipments.
  2. Move aftership_tracking_slug out of the label to the top level of the shipment object and rename it to slug.
  3. Change label.total_charge.amount from a number to a string.
  4. Replace send_notification with notify_customer.
  5. Update your code to parse the new Return Object structure in the response.

What's the difference?

ChangeBeforeAfter
EndpointGET /merchant-tagsGET /item-tags
Field namemerchant_tagsitem_tags

Legacy

Request:

preparing...

2025-07

Request:

preparing...

What do I need to do?

  1. Update the endpoint from /merchant-tags to /item-tags.
  2. Update your code to parse item_tags instead of merchant_tags in the response.

To address several limitations in the Legacy webhook version, we introduced a redesigned webhook starting from the 2024-07 version. The main improvements are as follows:

  1. More detailed events
    The legacy version offered only a small set of events with limited support for real-world scenarios. This made it difficult for merchants to automate their workflows effectively.
  2. Redesigned the payload structure
    Starting July 2024, we introduced two fields in the webhook: modified and data.
  • In the legacy version, the webhook payload consisted solely of an event name and a full Return object. As a result, developers were unable to accurately determine what had changed at the time the event occurred. For example, when receiving a return.shipment.created event, developers couldn't determine which specific shipment had been created based on the event payload.

  • The new webhook introduces a modified field to indicate the specific piece of data that changed or was created in each particular event, aka delta data. For a return.shipment.created event, the modified field includes only the newly created tracking number, label PDF, and related details

  • The data field continues to return the Return object as it exists at the time the event occurs.

If you are using events from the legacy version, we expect you will find corresponding alternatives in the 2025-07 version:

Legacy EventsAlternatives in 2025-07
return.createdreturn.submitted
return.updatedThe return.updated event in the legacy version was a coarse-grained event triggered by any update in the return would trigger this event. In the 2025-07 version, finding a corresponding alternative depends on how you previously used this event. For developers who used this event to receive primary status changes, you can use events such as return.approved, return.resolved, and others.
return.approvedreturn.approved
return.shipment.createdIf the shipment isprovided by the merchant, use return.shipment.provided. If the shipment is provided by the shopper, use return.shipment.recorded instead.
return.shipments.createdIf the shipment is provided by the merchant, use return.shipments.provided. Currently, multiple shipments from shoppers are not supported, so no alternative exists for this case.
return.shipment.updatedreturn.shipment.updated
return.dropoff.createdreturn.dropoff.created
return.dropoff.updatedreturn.dropoff.updated
return.dropoff.shipment.updatedreturn.dropoff.shipment.updated

The following table provides a comprehensive mapping of fields from the legacy Return object to the 2025-07 version. Use it as a reference to update your code when migrating from the legacy API to the 2025-07 version.

What's the difference?

The Return object structure has been significantly refactored in the 2025-07 version. Many fields have been renamed, restructured, or relocated within the object hierarchy. Some fields have been removed entirely, while new fields have been introduced to improve clarity and organization.

What do I need to do?

  1. Review the field mapping table below to identify changes for fields you currently use.
  2. Update your code to use the new field names and paths.
  3. Handle removed fields by using alternative fields or removing dependencies.
  4. Update your data models and parsing logic to match the new Return Object structure.
legacy2025-07remark
statusapproval_statusField name changed. Enum values updated (removed shipped, partially_received, and received). The legacy version incorrectly mixed approval_status and shipping_status.
internal_notesmerchant_noteField renamed
updated_at-Removed. Use other timestamp fields instead.
tracking_number-Removed. Use shipments\[\*\].tracking_number instead. Previously existed because the legacy version was developed before multiple shipments were supported.
order.customer_name-Removed. Contact support if you need this field in the new version.
order.customer_emailorder.customer.emails\[0\]Structure changed from a single string to an array.
order.countryorder.country_regionField renamed. Type changed from string to object.
order.app.keyorder.store.external_idPath changed
order.app.platformorder.store.platformPath changed
exchange_order.idexchange.order.idPath changed
exchange_order.order_numberexchange.order.order_numberPath changed
exchange_order.external_idexchange.order.external_idPath changed
exchange_order.customer_name-Removed
exchange_order.customer_emailexchange.order.customer.emails\[0\]Path and structure changed
exchange_order.countryexchange.order.countryPath changed
exchange_order.app.keyexchange.order.store.external_idPath changed
exchange_order.app.platformexchange.order.store.platformPath changed
return_items[*].external_idreturn_items[*].external_order_item_idPath changed
return_items[*].title-Removed. We no longer provide the ambiguous title field. Instead, we provide product_title and variant_title for you to use separately or in combination
return_items\[\*\].return_quantity-In the new model, we separated the intended_return_quantity (the quantity the shopper submitted in their request) from the return_quantity (the actual quantity that needs to be returned). For scenarios such as green return, keep item, or remove item, the return_quantity may be less than the intended_return_quantity. Please choose the appropriate field based on your use case.
return_items[*].price-Removed. The meaning of this field was ambiguous in the legacy version—it could represent tax-included or tax-excluded prices, discounted or non-discounted amounts, and even different currencies depending on the e-commerce platform. Please refer to the 2025-07 version schema to find the appropriate amount field as a replacement.
return_items\[\*\].image_urlreturn_items\[\*\].product_image_urls\[\*\]Changed from a single URL to an array of URLs
return_items[*].merchant_tags[*]return_items[*].item_tags[*]Path changed
return_items[*].return_images[*].id-Removed. This id is typically not useful.
return_items\[\*\].return_images\[\*\].urlreturn_items\[\*\].shopper_uploaded_image_urls\[\*\]Structure changed from an array of objects to an array of URLs
return_items[*].return_reason.descriptionreturn_items[*].return_reasonPath changed
return_items[*].return_reason.additional_notesreturn_items[*].return_reason_commentPath changed
return_items[*].subreasonreturn_items[*].return_subreasonPath changed
return_items\[\*\].last_received_at-Removed. If you need this value, use the maximum timestamp from the receivings array
return_items[*].exchange_variant.external_idreturn_items[*].exchange_variant.external_variant_idPath changed
return_items\[\*\].bundled_items\[\*\].return_quantity-In the new model, we separated the intended_return_quantity (the quantity the shopper submitted in their request) from return_quantity (the actual quantity that needs to be returned). For scenarios such as green return, keep item, or remove item, the return_quantity may be less than the intended_return_quantity. Please choose the appropriate field based on your use case.
return_items\[\*\].bundled_items\[\*\].last_received_at-Removed. If you need this value, use the maximum timestamp from the receivings array.
return_items\[\*\].bundled_items\[\*\].parent_bundle_external_id-Removed. If you need this value, use the parent item's external_order_item_id.
return_method.cost_of_return.amountcost_of_return.value.amountPath changed. Type changed from number to string
return_method.cost_of_return.currencycost_of_return.value.currencyPath changed
return_method.label.urlshipments[*].label.urlPath changed.
return_method.label.total_charge.amountshipments[*].label.total_charge.amountPath changed. Type changed from number to string
return_method.label.total_charge.currencyshipments[*].label.total_charge.currencyPath changed
return_method.label.aftership_tracking_slugshipments[*].slugPath changed
return_method.label.postmen_courier_slugshipments[*].label.aftership_shipping_slugPath changed
resolution.type-Removed. We have refactored resolution-related content in recent years because refunds and charges can also occur when a resolution is exchange. We recommend using return.outcomes as a replacement.
resolution.exchange_notes-Removed.
refunded_total.amountrefunded_total.amountType changed from number to string
refund_store_credit_referencerefunds[*].store_credit_referencePath changed
shipments[*].items[*].external_idshipments[*].items[*].external_order_item_idPath changed
shipments[*].label.total_charge.amountshipments[*].label.total_charge.amountType changed from number to string
shipments[*].label.aftership_tracking_slugshipments[*].label.slugPath changed
shipments[*].label.postmen_courier_slugshipments[*].label.aftership_shipping_slugPath changed
dropoffs[*].slugdropoffs[*].service_providerPath changed
dropoffs[*].qr_codedropoffs[*].qr_code_urlPath changed
dropoffs[*].items[*].external_iddropoffs[*].items[*].external_order_item_idPath changed
dropoffs[*].shipments[*].items[*].external_iddropoffs[*].shipments[*].items[*].external_order_item_idPath changed
dropoffs[*].shipments[*].courier_slugdropoffs[*].shipments[*].service_provider_carrier_codePath changed

After June 30, 2026, any requests made to the legacy version will result in a 404 Not Found error. Therefore, we encourage you to complete the migration at your earliest convenience.