- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
How to Create a Fulfillment Provider Module
In this document, you’ll learn how to create a fulfillment provider module and the methods you must implement in its main service.
1. Create Module Directory#
Start by creating a new directory for your module. For example, src/modules/my-fulfillment
.
2. Create the Fulfillment Provider Service#
Create the file src/modules/my-fulfillment/service.ts
that holds the module's main service. It must extend the AbstractFulfillmentProviderService
class imported from @medusajs/framework/utils
:
constructor#
The constructor allows you to access resources from the module's container using the first parameter, and the module's options using the second parameter.
If you're creating a client or establishing a connection with a third-party service, do it in the constructor.
Example
1import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"2import { Logger } from "@medusajs/framework/types"3 4type InjectedDependencies = {5 logger: Logger6}7 8type Options = {9 apiKey: string10}11 12class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {13 protected logger_: Logger14 protected options_: Options15 // assuming you're initializing a client16 protected client17 18 constructor(19 { logger }: InjectedDependencies,20 options: Options21 ) {22 super()23 24 this.logger_ = logger25 this.options_ = options26 }27}28 29export default MyFulfillmentProviderService
identifier#
Each fulfillment provider has a unique identifier defined in its class. The provider's ID
will be stored as fp_{identifier}_{id}
, where {id}
is the provider's id
property in the medusa-config.ts
.
Example
getFulfillmentOptions#
This method retrieves the shipping options this fulfillment provider supports.
Example
1// other imports...2import { FulfillmentOption } from "@medusajs/framework/types"3 4class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {5 // ...6 async getFulfillmentOptions(): Promise<FulfillmentOption[]> {7 return [8 {9 id: "express"10 },11 {12 id: "return-express",13 is_return: true14 }15 ]16 }17}
Returns
Promise
Promise<FulfillmentOption[]>The list of fulfillment options.
Promise
Promise<FulfillmentOption[]>validateFulfillmentData#
This method validates the data
property of a shipping method and returns it. The returned data
is stored in the shipping method's data
property.
Your fulfillment provider can use the data
property to store additional information useful for
handling the fulfillment later. For example, you may store an ID from the third-party fulfillment
system.
Example
1class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {2 // ...3 async validateFulfillmentData(4 optionData: any,5 data: any,6 context: any7 ): Promise<any> {8 // assuming your client retrieves an ID from the9 // third-party service10 const externalId = await this.client.getId()11 12 return {13 ...data,14 externalId15 }16 }17}
Parameters
optionData
Record<string, unknown>data
property of the shipping option.data
Record<string, unknown>data
property of the shipping method.context
Record<string, unknown>Returns
Promise
Promise<any>the data to store in the data
property of the shipping method.
Promise
Promise<any>data
property of the shipping method.validateOption#
This method validates the data
property of a shipping option when it's created.
The data
property can hold useful information that's later added to the data
attribute
of shipping methods created from this option.
Example
Parameters
data
Record<string, unknown>Returns
Promise
Promise<boolean>Whether the data is valid.
Promise
Promise<boolean>canCalculate#
This method indicates whether a shippin option's price is calculated during checkout or is fixed.
Example
Parameters
data
Record<string, unknown>data
property of the shipping option.Returns
Promise
Promise<boolean>Whether the price is calculated for the shipping option.
Promise
Promise<boolean>calculatePrice#
This method calculates the price of a shipping option, or a shipping method when it's created.
The Medusa application uses the canCalculate method first to check whether the shipping option's price is calculated.
If it returns true
, Medusa uses this method to retrieve the calculated price.
Example
1class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {2 // ...3 async calculatePrice(optionData: any, data: any, context: any): Promise<number> {4 // assuming the client can calculate the price using5 // the third-party service6 const price = await this.client.calculate(data)7 return price8 }9}
Parameters
optionData
Record<string, unknown>data
property of a shipping option.data
Record<string, unknown>context
CartDTO & object & Record<string, unknown>The context details, such as the cart or customer.
context
CartDTO & object & Record<string, unknown>Returns
Promise
Promise<CalculatedShippingOptionPrice>The calculated price
Promise
Promise<CalculatedShippingOptionPrice>createFulfillment#
This method is used when a fulfillment is created. If the method returns in the object a
data
property, it's stored in the fulfillment's data
property.
The data
property is useful when handling the fulfillment later,
as you can access information useful for your integration.
You can also use this method to perform an action with the third-party fulfillment service.
Example
1class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {2 // ...3 async createFulfillment(4 data: any,5 items: any,6 order: any,7 fulfillment: any8 ): Promise<any> {9 // assuming the client creates a fulfillment10 // in the third-party service11 const externalData = await this.client.create(12 fulfillment,13 items14 )15 16 return {17 data: {18 ...data,19 ...externalData20 }21 }22 }23}
Parameters
data
objectdata
property of the shipping method this fulfillment is created for.items
object[]order
undefined | objectfulfillment
Record<string, unknown>Returns
Promise
Promise<any>The data to store in the fulfillment's data
property.
Promise
Promise<any>data
property.cancelFulfillment#
This method is used when a fulfillment is canceled. Use it to perform operations with the third-party fulfillment service.
Example
Parameters
fulfillment
Record<string, unknown>Returns
Promise
Promise<any>This method is used when a fulfillment is canceled. Use it to perform operations
with the third-party fulfillment service.
Promise
Promise<any>getFulfillmentDocuments#
This method retrieves the documents of a fulfillment.
Example
Parameters
data
Record<string, unknown>data
property of the fulfillment.Returns
Promise
Promise<never[]>The fulfillment's documents.
Promise
Promise<never[]>createReturnFulfillment#
This method is used when a fulfillment is created for a return. If the method returns in the object a
data
property, it's stored in the fulfillment's data
property.
The data
property is useful when handling the fulfillment later,
as you can access information useful for your integration.
Use this method to perform actions necessary in the third-party fulfillment service.
Example
1class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {2 // ...3 async createReturnFulfillment(fulfillment: any): Promise<any> {4 // assuming the client creates a fulfillment for a return5 // in the third-party service6 const externalData = await this.client.createReturn(7 fulfillment8 )9 10 return {11 data: {12 ...fulfillment.data,13 ...externalData14 }15 }16 }17}
Parameters
fulfillment
Record<string, unknown>Returns
Promise
Promise<any>The data to store in the fulfillment's data
property.
Promise
Promise<any>data
property.getReturnDocuments#
This method retrieves documents for a return's fulfillment.
Example
Parameters
data
Record<string, unknown>data
property of the fulfillment.Returns
Promise
Promise<never[]>The fulfillment's documents.
Promise
Promise<never[]>getShipmentDocuments#
This method retrieves the documents for a shipment.
Example
Parameters
data
Record<string, unknown>data
property of the shipmnet.Returns
Promise
Promise<never[]>The shipment's documents.
Promise
Promise<never[]>retrieveDocuments#
This method retrieves the documents of a fulfillment of a certain type.
Example
1class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {2 // ...3 async retrieveDocuments(4 fulfillmentData: any,5 documentType: any6 ): Promise<void> {7 // assuming the client retrieves documents8 // from a third-party service9 return await this.client.documents(10 fulfillmentData,11 documentType12 )13 }14}
Parameters
fulfillmentData
Record<string, unknown>data
property of the fulfillment.documentType
stringinvoice
.Returns
Promise
Promise<void>3. Create Module Definition File#
Create the file src/modules/my-fulfillment/index.ts
with the following content:
This exports the module's definition, indicating that the MyFulfillmentProviderService
is the module's service.
4. Use Module#
To use your Fulfillment Module Provider, add it to the providers
array of the Fulfillment Module in medusa-config.ts
:
1module.exports = defineConfig({2 // ...3 modules: [4 {5 resolve: "@medusajs/medusa/fulfillment",6 options: {7 providers: [8 // default provider9 {10 resolve: "@medusajs/medusa/fulfillment-manual",11 id: "manual",12 },13 {14 resolve: "./src/modules/my-fulfillment",15 id: "my-fulfillment",16 options: {17 // provider options...18 },19 },20 ],21 },22 },23 ]24})
5. Test it Out#
Before you use your fulfillment provider, in the Medusa Admin:
- Add the fulfillment provider to a location.
- Add in the location a delivery shipping option that uses the provider.
Then, place an order, choosing the shipping option you created during checkout, and create a fulfillment in the Medusa Admin. The fulfillment is created using your provider.