Post-purchase operations are often where ecommerce platforms reveal their real limitations. Processing a return takes too many manual steps. A swap gets stuck in a loop between support and the warehouse. Fulfillment tracking requires logging into a separate system. These friction points add up, and for growing operations they become a serious bottleneck.
Medusa.js approaches order management differently. Instead of giving you a locked workflow, it gives you a structured set of modules and APIs that you can use to build the exact post-purchase experience your business needs. This guide covers how Medusa handles fulfillment, returns, and swaps at a technical level, what the key entities are, and how developers can put these building blocks to work.
How Medusa Thinks About Order Management
How Medusa Thinks About Order Management
In Medusa, order management is not a single feature, it is a collection of interconnected modules. The Order Module handles the lifecycle of an order from creation through payment, fulfillment, and completion. The Fulfillment Module takes care of shipping and delivery operations. These two modules communicate through a consistent API layer, meaning every action you take against an order, whether creating a shipment, processing a return, or completing a swap, is recorded, versioned, and accessible via the same interface.
This structure makes Medusa well-suited as a headless OMS (Order Management System). Businesses that run multiple storefronts, sales channels, or fulfillment locations can route all orders into a single Medusa backend and handle every post-purchase workflow from one place. The modular design also means you can replace any piece, for example swapping out the default fulfillment provider for a custom integration with a 3PL, without rewriting core commerce logic.
Order Module | Fulfillment Module |
|---|---|
Creates and tracks orders | Handles shipping providers |
Manages returns, swaps, claims | Creates and ships fulfillments |
Records payment transactions | Tracks shipment via tracking links |
Versions every order change | Integrates with third-party logistics |
The Order Lifecycle in Medusa
The Order Lifecycle in Medusa
Every order in Medusa moves through a clear status progression. A cart is created when a customer begins shopping. Once payment is authorized and the checkout is completed, the cart converts into an order. From there, the order progresses through payment capture, fulfillment creation, and shipment, ending in a completed state.
Medusa tracks the status of both the payment and the fulfillment separately. An order can have its payment captured while fulfillment is still pending, or it can be partially fulfilled where some line items ship before others. This level of granularity is important for businesses that deal with mixed inventory, pre-orders, or multi-warehouse operations.
Order Status Values
The payment_status field tells you where the money is: pending, captured, partially_refunded, refunded, canceled, or requires_action. The fulfillment_status field tells you where the items are: not_fulfilled, partially_fulfilled, fulfilled, partially_shipped, shipped, partially_returned, returned, canceled, or requires_action. Together these two fields give you a complete picture of any order at a glance.
Fulfillment in Medusa.js
Fulfillment in Medusa.js
A fulfillment in Medusa represents the act of sending items to a customer. When the admin creates a fulfillment for an order, they select which line items to include and in what quantity. Medusa allows partial fulfillments, so an order with five different products can be fulfilled in separate batches as stock becomes available.
Creating a Fulfillment
Fulfillments are created through the admin API. The request passes the order ID and an array of items with their quantities. Once created, the fulfillment object is associated with the order and the fulfillment_status of the order updates accordingly. If all items are fulfilled, the status becomes fulfilled. If only some items are included, it becomes partially_fulfilled.
The fulfillment provider handles the actual interaction with a shipping service. By default, Medusa ships with a manual fulfillment provider, which is useful for testing and for businesses that handle shipping outside of any automated system. For production, you connect a real provider, whether that is a custom service class pointing to a 3PL, or an existing plugin for carriers like FedEx, DHL, or regional couriers used in the Indian market.
Creating a Shipment from a Fulfillment
Once a fulfillment exists, you create a shipment for it. In Medusa, a shipment is represented by a TrackingLink entity that stores a tracking number and associates it with the fulfillment. You can add multiple tracking numbers to a single fulfillment if items ship across multiple packages. The tracking number then becomes available on the storefront or through any customer notification system you have wired up.
Canceling a Fulfillment
A fulfillment can be canceled before shipment if needed. This might happen when an item turns out to be out of stock after the fulfillment was created, or if the customer contacts support before dispatch. Canceling a fulfillment updates the order status and, depending on your inventory configuration, restores the reserved stock to available quantity.
Returns in Medusa.js
Returns in Medusa.js
Returns are one of the most operationally complex parts of any ecommerce business. Medusa handles them through a structured Return Merchandise Authorization (RMA) flow that keeps the order history intact and automatically updates inventory and payment records when a return is processed.
How a Return Is Initiated
A return can be initiated in two ways. The customer can request a return through the storefront, specifying which items they want to send back. Alternatively, a merchant can create a return directly from the admin panel on behalf of the customer. In both cases, a return object is created and linked to the original order.
When the return is created, the customer can be assigned a shipping method for sending items back. This is configured through return shipping options in the Medusa admin settings. Each shipping option can be set as a return option and configured with a cost or offered free of charge depending on your returns policy.
Marking a Return as Received
When the physical items arrive at your warehouse, the merchant marks the return as received in the admin. Medusa then validates whether the returned items match what was requested. If everything checks out, the payment is refunded automatically through the original payment provider. The fulfillment_status of the order updates to returned if all items were returned, or partially_returned if only some items came back.
If there is a mismatch between the requested return and what was actually received, the fulfillment_status is set to requires_action, flagging the order for manual review. This prevents incorrect refunds from being processed automatically.
Canceling a Return
A return that has not yet been marked as received can be canceled by the merchant. This is useful when the customer changes their mind or when communication reveals the return request was made in error. Canceling a return does not affect the original order or its payment status.
Swaps in Medusa.js
Swaps in Medusa.js
A swap is a combined operation that handles both a return and a new fulfillment in a single flow. When a customer wants to exchange a product, perhaps a wrong size, a different color, or a replacement for a damaged item, a swap lets you manage both sides of that transaction without creating separate manual entries.
The Swap Creation Process
When a swap is created in Medusa, several things happen in sequence. First, Medusa validates that the order can support a swap. The payment must already be captured and the order must have been fulfilled. If those conditions are met, a return is automatically created and linked to the swap for the items the customer is sending back. A new cart is also created for the swap, representing the replacement items the customer will receive.
The customer then completes a checkout-like process for the swap cart, providing shipping details and authorizing any additional payment if the replacement items cost more than the original. If the replacement costs less, Medusa calculates the difference and issues a refund.
The difference_due Field
Every swap has a difference_due attribute that determines the payment direction. A positive value means the customer owes additional payment for the swap. A negative value means the customer is owed a refund. A zero value means the items being exchanged are of equal value. The merchant processes the payment or refund after the swap is confirmed, using the standard payment provider already connected to the order.
Fulfilling a Swap
Once the swap cart is completed and payment is handled, the merchant creates a fulfillment for the new items. This follows the same flow as a standard order fulfillment. A shipment is created from the fulfillment, a tracking number is added, and the swap fulfillment_status updates to reflect progress. The swap is associated with the original order, so the full exchange history is visible from the order detail view in the admin.
Claims: The Third Post-Purchase Flow
Claims: The Third Post-Purchase Flow
Alongside returns and swaps, Medusa also supports claims. A claim is raised when a customer reports an issue with their delivery, such as a damaged item, a missing product, or an incorrect shipment. The merchant can respond to a claim in three ways: issue a refund, ship a replacement, or do both.
Claims are processed through the admin API and follow a similar pattern to swaps. A return is automatically linked to the claim for the items being reported, and a new fulfillment can be created if replacement items need to be shipped. All claim actions are tracked against the original order, maintaining a complete and auditable order history.
Integrating Third-Party Fulfillment Providers
Integrating Third-Party Fulfillment Providers
Medusa is built to work with any fulfillment provider. The platform defines an AbstractFulfillmentService interface that your provider must implement. The required methods cover creating a fulfillment, canceling a fulfillment, and optionally handling returns. When any of these actions is triggered through the Medusa API, the corresponding method in your provider service is called.
This means you can integrate Medusa with any 3PL, regional courier, or in-house warehouse management system. The storefront and admin experience stays the same regardless of which provider is behind the scenes. For teams building on top of Medusa in India, this is particularly useful since it allows integration with local logistics partners without forcing you to change how orders are managed at the platform level.
The official Medusa documentation on the Order Management System architecture covers how to wire fulfillment events, listen to order lifecycle hooks, and integrate third-party systems end-to-end. It is the most comprehensive resource for teams building advanced OMS workflows on Medusa.
Listening to Order Events
Listening to Order Events
Medusa emits events throughout the order lifecycle that you can subscribe to in your backend. Events like order.fulfillment_created, order.return_requested, and order.placed let you trigger asynchronous tasks such as sending customer notifications, syncing data with an ERP, or updating a warehouse management system.
This event-driven approach keeps your integrations decoupled from the core order logic. Instead of patching every order API call to add side effects, you write event subscribers that react to changes. If your notification service goes down, the event can be retried without affecting the order flow itself.
Teams at Askan Technologies use this pattern extensively when building custom Medusa implementations for clients. If you want to see how these workflows fit into a full production setup, our Medusa.js ecommerce development services page covers the kinds of integrations and custom OMS architectures we build for businesses across industries.
Making Order Data Work for Your Operations Team
Making Order Data Work for Your Operations Team
A well-configured Medusa order management setup means your operations team spends less time on manual tasks and more time on exceptions. Standard fulfillments are created and tracked through the admin. Returns follow a defined flow with automatic refund triggers. Swaps give customers a clean exchange experience without support tickets bouncing between teams.
The key is configuring the system before you launch. Set up your shipping options, including return shipping options. Connect your payment provider so refunds process automatically. Define your fulfillment provider so shipments are created with real tracking numbers. Test the complete order lifecycle end to end, from checkout through return, before your store goes live.
Order management is often treated as an afterthought in platform selection, but for any business that expects volume, it is one of the most critical decisions you make. Medusa gives you the structure to handle it properly and the flexibility to adapt it as your operations grow.
Written by
Raj Thilak
Chief Quality Officer
