--- displayed_sidebar: modules slug: /modules/carts-and-checkout/backend/add-fulfillment-provider --- import TypeList from "@site/src/components/TypeList" # How to Create a Fulfillment Provider In this document, you’ll learn how to create a fulfillment provider in the Medusa backend and the methods you must implement in it. If you’re unfamiliar with the Shipping architecture in Medusa, make sure to [check out the overview first](https://docs.medusajs.com/modules/carts-and-checkout/shipping). ## Overview A fulfillment provider is the shipping provider used to fulfill orders and deliver them to customers. An example of a fulfillment provider is FedEx. By default, a Medusa Backend has a `manual` fulfillment provider which has minimal implementation. It allows you to accept orders and fulfill them manually. However, you can integrate any fulfillment provider into Medusa, and your fulfillment provider can interact with third-party shipping providers. A fulfillment provider is a service that extends the `AbstractFulfillmentService` and implements its methods. So, adding a fulfillment provider is as simple as creating a service file in `src/services`. The file's name is the fulfillment provider's class name as a slug and without the word `Service`. For example, if you're creating a `MyFulfillmentService` class, the file name is `src/services/my-fulfillment.ts`. ```ts title=src/services/my-fulfillment.ts import { AbstractFulfillmentService } from "@medusajs/medusa" class MyFulfillmentService extends AbstractFulfillmentService { // methods here... } export default MyFulfillmentService ``` --- ## Identifier Property The `FulfillmentProvider` entity has 2 properties: `identifier` and `is_installed`. The `identifier` property in the fulfillment provider service is used when the fulfillment provider is added to the database. The value of this property is also used to reference the fulfillment provider throughout Medusa. For example, it is used to [add a fulfillment provider](https://docs.medusajs.com/api/admin#regions\_postregionsregionfulfillmentproviders) to a region. ```ts class MyFulfillmentService extends AbstractFulfillmentService { static identifier = "my-fulfillment" // ... } ``` --- ## constructor You can use the `constructor` of your fulfillment provider to access the different services in Medusa through dependency injection. You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the service. Additionally, if you’re creating your fulfillment provider as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, you can access it in the constructor. ### Example ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... constructor(container, options) { super(container) // you can access options here // you can also initialize a client that // communicates with a third-party service. this.client = new Client(options) } // ... } ``` ### Parameters `","description":"An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"config","type":"`Record`","description":"If this fulfillment provider is created in a plugin, the plugin's options are passed in this parameter.","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="new AbstractFulfillmentService"/> ___ ## Methods ### getFulfillmentOptions This method is used when retrieving the list of fulfillment options available in a region, particularly by the [List Fulfillment Options API Route](https://docs.medusajs.com/api/admin#regions\_getregionsregionfulfillmentoptions). For example, if you’re integrating UPS as a fulfillment provider, you might support two fulfillment options: UPS Express Shipping and UPS Access Point. Each of these options can have different data associated with them. #### Example ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async getFulfillmentOptions(): Promise { return [ { id: "my-fulfillment", }, { id: "my-fulfillment-dynamic", }, ] } } ``` #### Returns ### validateFulfillmentData This method is called when a shipping method is created. This typically happens when the customer chooses a shipping option during checkout, when a shipping method is created for an order return, or in other similar cases. The shipping option and its data are validated before the shipping method is created. You can use the provided parameters to validate the chosen shipping option. For example, you can check if the `data` object passed as a second parameter includes all data needed to fulfill the shipment later on. If any of the data is invalid, you can throw an error. This error will stop Medusa from creating a shipping method and the error message will be returned as a result of the API Route. #### Example ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async validateFulfillmentData( optionData: Record, data: Record, cart: Cart ): Promise> { if (data.id !== "my-fulfillment") { throw new Error("invalid data") } return { ...data, } } } ``` #### Parameters `","description":"The context of the cart which can include info like IP or user agent.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"metadata","type":"`Record`","description":"An optional key-value map with additional details","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channel_id","type":"`null` \\| `string`","description":"The sales channel ID the cart is associated with.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channel","type":"[SalesChannel](../../entities/classes/entities.SalesChannel.mdx)","description":"The details of the sales channel associated with the cart.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"sales_channels","type":"[SalesChannel](../../entities/classes/entities.SalesChannel.mdx)[]","description":"The associated sales channels.","optional":true,"defaultValue":"","expandable":true,"children":[]},{"name":"shipping_total","type":"`number`","description":"The total of shipping","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"discount_total","type":"`number`","description":"The total of discount rounded","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"raw_discount_total","type":"`number`","description":"The total of discount","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"item_tax_total","type":"`null` \\| `number`","description":"The total of items with taxes","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"shipping_tax_total","type":"`null` \\| `number`","description":"The total of shipping with taxes","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"tax_total","type":"`null` \\| `number`","description":"The total of tax","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"refunded_total","type":"`number`","description":"The total amount refunded if the order associated with this cart is returned.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"total","type":"`number`","description":"The total amount of the cart","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"subtotal","type":"`number`","description":"The subtotal of the cart","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"refundable_amount","type":"`number`","description":"The amount that can be refunded","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_total","type":"`number`","description":"The total of gift cards","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_tax_total","type":"`number`","description":"The total of gift cards with taxes","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="validateFulfillmentData"/> #### Returns `","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="validateFulfillmentData"/> ### validateOption Once the admin creates the shipping option, the data of the shipping option will be validated first using this method. This method is called when the [Create Shipping Option API Route](https://docs.medusajs.com/api/admin#shipping-options\_postshippingoptions) is used. #### Example For example, you can use this method to ensure that the `id` in the `data` object is correct: ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async validateOption( data: Record ): Promise { return data.id === "my-fulfillment" } } ``` #### Parameters #### Returns ### canCalculate This method is used to determine whether a shipping option is calculated dynamically or flat rate. It is called if the `price_type` of the shipping option being created is set to calculated. #### Example ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async canCalculate( data: Record ): Promise { return data.id === "my-fulfillment-dynamic" } } ``` #### Parameters #### Returns ### calculatePrice This method is used in different places, including: 1. When the shipping options for a cart are retrieved during checkout. If a shipping option has their `price_type` set to calculated, this method is used to set the amount of the returned shipping option. 2. When a shipping method is created. If the shipping option associated with the method has their `price_type` set to `calculated`, this method is used to set the `price` attribute of the shipping method in the database. 3. When the cart's totals are calculated. #### Example An example of calculating the price based on some custom logic: ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async calculatePrice( optionData: Record, data: Record, cart: Cart ): Promise { return cart.items.length * 1000 } } ``` If your fulfillment provider does not provide any dynamically calculated rates you can return any static value or throw an error. For example: ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async calculatePrice( optionData: Record, data: Record, cart: Cart ): Promise { throw new Error("Method not implemented.") } } ``` #### Parameters `","description":"The context of the cart which can include info like IP or user agent.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"metadata","type":"`Record`","description":"An optional key-value map with additional details","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channel_id","type":"`null` \\| `string`","description":"The sales channel ID the cart is associated with.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channel","type":"[SalesChannel](../../entities/classes/entities.SalesChannel.mdx)","description":"The details of the sales channel associated with the cart.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"sales_channels","type":"[SalesChannel](../../entities/classes/entities.SalesChannel.mdx)[]","description":"The associated sales channels.","optional":true,"defaultValue":"","expandable":true,"children":[]},{"name":"shipping_total","type":"`number`","description":"The total of shipping","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"discount_total","type":"`number`","description":"The total of discount rounded","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"raw_discount_total","type":"`number`","description":"The total of discount","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"item_tax_total","type":"`null` \\| `number`","description":"The total of items with taxes","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"shipping_tax_total","type":"`null` \\| `number`","description":"The total of shipping with taxes","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"tax_total","type":"`null` \\| `number`","description":"The total of tax","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"refunded_total","type":"`number`","description":"The total amount refunded if the order associated with this cart is returned.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"total","type":"`number`","description":"The total amount of the cart","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"subtotal","type":"`number`","description":"The subtotal of the cart","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"refundable_amount","type":"`number`","description":"The amount that can be refunded","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_total","type":"`number`","description":"The total of gift cards","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_tax_total","type":"`number`","description":"The total of gift cards with taxes","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="calculatePrice"/> #### Returns ### createFulfillment This method is used when a fulfillment is created for an order, a claim, or a swap. #### Example Here is a basic implementation of `createFulfillment` for a fulfillment provider that does not interact with any third-party provider to create the fulfillment: ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async createFulfillment( data: Record, items: LineItem[], order: Order, fulfillment: Fulfillment ) { // No data is being sent anywhere // No data to be stored in the fulfillment's data object return {} } } ``` #### Parameters `","description":"An optional key-value map with additional details","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"includes_tax","type":"`boolean`","description":"Indicates if the line item unit\\_price include tax","optional":false,"defaultValue":"false","expandable":false,"featureFlag":"tax_inclusive_pricing","children":[]},{"name":"original_item_id","type":"`null` \\| `string`","description":"The ID of the original line item. This is useful if the line item belongs to a resource that references an order, such as a return or an order edit.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"order_edit_id","type":"`null` \\| `string`","description":"The ID of the order edit that the item may belong to.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"order_edit","type":"`null` \\| [OrderEdit](../../entities/classes/entities.OrderEdit.mdx)","description":"The details of the order edit.","optional":true,"defaultValue":"","expandable":true,"children":[]},{"name":"refundable","type":"`null` \\| `number`","description":"The amount that can be refunded from the given Line Item. Takes taxes and discounts into consideration.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"subtotal","type":"`null` \\| `number`","description":"The subtotal of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"tax_total","type":"`null` \\| `number`","description":"The total of tax of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"total","type":"`null` \\| `number`","description":"The total amount of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"original_total","type":"`null` \\| `number`","description":"The original total amount of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"original_tax_total","type":"`null` \\| `number`","description":"The original tax total amount of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"discount_total","type":"`null` \\| `number`","description":"The total of discount of the line item rounded","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"raw_discount_total","type":"`null` \\| `number`","description":"The total of discount of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_total","type":"`null` \\| `number`","description":"The total of the gift card of the line item","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"order","type":"[Order](../../entities/classes/entities.Order.mdx)","description":"The details of the created resource, which is either an order, a claim, or a swap:\n- If the resource the fulfillment is being created for is a claim, the `is_claim` property in the object will be `true`.\n- If the resource the fulfillment is being created for is a swap, the `is_swap` property in the object will be `true`.\n- Otherwise, the resource is an order.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"id","type":"`string`","description":"The order's ID","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"created_at","type":"`Date`","description":"The date with timezone at which the resource was created.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"updated_at","type":"`Date`","description":"The date with timezone at which the resource was updated.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"object","type":"`\"order\"`","description":"","optional":false,"defaultValue":"\"order\"","expandable":false,"children":[]},{"name":"status","type":"[OrderStatus](../../entities/enums/entities.OrderStatus.mdx)","description":"The order's status","optional":false,"defaultValue":"pending","expandable":false,"children":[]},{"name":"fulfillment_status","type":"[FulfillmentStatus](../../entities/enums/entities.FulfillmentStatus.mdx)","description":"The order's fulfillment status","optional":false,"defaultValue":"not_fulfilled","expandable":false,"children":[]},{"name":"payment_status","type":"[PaymentStatus](../../entities/enums/entities.PaymentStatus.mdx)","description":"The order's payment status","optional":false,"defaultValue":"not_paid","expandable":false,"children":[]},{"name":"display_id","type":"`number`","description":"The order's display ID","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"cart_id","type":"`string`","description":"The ID of the cart associated with the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"cart","type":"[Cart](../../entities/classes/entities.Cart.mdx)","description":"The details of the cart associated with the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"customer_id","type":"`string`","description":"The ID of the customer associated with the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"customer","type":"[Customer](../../entities/classes/entities.Customer.mdx)","description":"The details of the customer associated with the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"email","type":"`string`","description":"The email associated with the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"billing_address_id","type":"`string`","description":"The ID of the billing address associated with the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"billing_address","type":"[Address](../../entities/classes/entities.Address.mdx)","description":"The details of the billing address associated with the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"shipping_address_id","type":"`string`","description":"The ID of the shipping address associated with the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"shipping_address","type":"[Address](../../entities/classes/entities.Address.mdx)","description":"The details of the shipping address associated with the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"region_id","type":"`string`","description":"The ID of the region this order was created in.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"region","type":"[Region](../../entities/classes/entities.Region.mdx)","description":"The details of the region this order was created in.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"currency_code","type":"`string`","description":"The 3 character currency code that is used in the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"currency","type":"[Currency](../../entities/classes/entities.Currency.mdx)","description":"The details of the currency used in the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"tax_rate","type":"`null` \\| `number`","description":"The order's tax rate","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"discounts","type":"[Discount](../../entities/classes/entities.Discount.mdx)[]","description":"The details of the discounts applied on the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"gift_cards","type":"[GiftCard](../../entities/classes/entities.GiftCard.mdx)[]","description":"The details of the gift card used in the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"shipping_methods","type":"[ShippingMethod](../../entities/classes/entities.ShippingMethod.mdx)[]","description":"The details of the shipping methods used in the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"payments","type":"[Payment](../../entities/classes/entities.Payment.mdx)[]","description":"The details of the payments used in the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"fulfillments","type":"[Fulfillment](../../entities/classes/entities.Fulfillment.mdx)[]","description":"The details of the fulfillments created for the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"returns","type":"[Return](../../entities/classes/entities.Return.mdx)[]","description":"The details of the returns created for the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"claims","type":"[ClaimOrder](../../entities/classes/entities.ClaimOrder.mdx)[]","description":"The details of the claims created for the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"refunds","type":"[Refund](../../entities/classes/entities.Refund.mdx)[]","description":"The details of the refunds created for the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"swaps","type":"[Swap](../../entities/classes/entities.Swap.mdx)[]","description":"The details of the swaps created for the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"draft_order_id","type":"`string`","description":"The ID of the draft order this order was created from.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"draft_order","type":"[DraftOrder](../../entities/classes/entities.DraftOrder.mdx)","description":"The details of the draft order this order was created from.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"edits","type":"[OrderEdit](../../entities/classes/entities.OrderEdit.mdx)[]","description":"The details of the order edits done on the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"items","type":"[LineItem](../../entities/classes/entities.LineItem.mdx)[]","description":"The details of the line items that belong to the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"gift_card_transactions","type":"[GiftCardTransaction](../../entities/classes/entities.GiftCardTransaction.mdx)[]","description":"The gift card transactions made in the order.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"canceled_at","type":"`Date`","description":"The date the order was canceled on.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"metadata","type":"`Record`","description":"An optional key-value map with additional details","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"no_notification","type":"`boolean`","description":"Flag for describing whether or not notifications related to this should be send.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotency_key","type":"`string`","description":"Randomly generated key used to continue the processing of the order in case of failure.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"external_id","type":"`null` \\| `string`","description":"The ID of an external order.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channel_id","type":"`null` \\| `string`","description":"The ID of the sales channel this order belongs to.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channel","type":"[SalesChannel](../../entities/classes/entities.SalesChannel.mdx)","description":"The details of the sales channel this order belongs to.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"shipping_total","type":"`number`","description":"The total of shipping","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"shipping_tax_total","type":"`null` \\| `number`","description":"The tax total applied on shipping","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"discount_total","type":"`number`","description":"The total of discount rounded","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"raw_discount_total","type":"`number`","description":"The total of discount","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"item_tax_total","type":"`null` \\| `number`","description":"The tax total applied on items","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"tax_total","type":"`null` \\| `number`","description":"The total of tax","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"refunded_total","type":"`number`","description":"The total amount refunded if the order is returned.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"total","type":"`number`","description":"The total amount of the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"subtotal","type":"`number`","description":"The subtotal of the order","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"paid_total","type":"`number`","description":"The total amount paid","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"refundable_amount","type":"`number`","description":"The amount that can be refunded","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_total","type":"`number`","description":"The total of gift cards","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"gift_card_tax_total","type":"`number`","description":"The total of gift cards with taxes","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"sales_channels","type":"[SalesChannel](../../entities/classes/entities.SalesChannel.mdx)[]","description":"The associated sales channels.","optional":true,"defaultValue":"","expandable":true,"featureFlag":"medusa_v2","children":[]},{"name":"returnable_items","type":"[LineItem](../../entities/classes/entities.LineItem.mdx)[]","description":"The details of the line items that are returnable as part of the order, swaps, or claims","optional":true,"defaultValue":"","expandable":true,"children":[]}]},{"name":"fulfillment","type":"[Fulfillment](../../entities/classes/entities.Fulfillment.mdx)","description":"The fulfillment being created.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"id","type":"`string`","description":"The fulfillment's ID","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"created_at","type":"`Date`","description":"The date with timezone at which the resource was created.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"updated_at","type":"`Date`","description":"The date with timezone at which the resource was updated.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"claim_order_id","type":"`string`","description":"The ID of the Claim that the Fulfillment belongs to.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"claim_order","type":"[ClaimOrder](../../entities/classes/entities.ClaimOrder.mdx)","description":"The details of the claim that the fulfillment may belong to.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"swap_id","type":"`string`","description":"The ID of the Swap that the Fulfillment belongs to.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"swap","type":"[Swap](../../entities/classes/entities.Swap.mdx)","description":"The details of the swap that the fulfillment may belong to.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"order_id","type":"`string`","description":"The ID of the Order that the Fulfillment belongs to.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"order","type":"[Order](../../entities/classes/entities.Order.mdx)","description":"The details of the order that the fulfillment may belong to.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"no_notification","type":"`boolean`","description":"Flag for describing whether or not notifications related to this should be sent.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"provider_id","type":"`string`","description":"The ID of the Fulfillment Provider responsible for handling the fulfillment.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"location_id","type":"`null` \\| `string`","description":"The ID of the stock location the fulfillment will be shipped from","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"provider","type":"[FulfillmentProvider](../../entities/classes/entities.FulfillmentProvider.mdx)","description":"The details of the fulfillment provider responsible for handling the fulfillment.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"items","type":"[FulfillmentItem](../../entities/classes/entities.FulfillmentItem.mdx)[]","description":"The Fulfillment Items in the Fulfillment. These hold information about how many of each Line Item has been fulfilled.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"tracking_links","type":"[TrackingLink](../../entities/classes/entities.TrackingLink.mdx)[]","description":"The Tracking Links that can be used to track the status of the Fulfillment. These will usually be provided by the Fulfillment Provider.","optional":false,"defaultValue":"","expandable":true,"children":[]},{"name":"tracking_numbers","type":"`string`[]","description":"The tracking numbers that can be used to track the status of the fulfillment.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"data","type":"`Record`","description":"This contains all the data necessary for the Fulfillment provider to handle the fulfillment.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"shipped_at","type":"`Date`","description":"The date with timezone at which the Fulfillment was shipped.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"canceled_at","type":"`Date`","description":"The date with timezone at which the Fulfillment was canceled.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"metadata","type":"`Record`","description":"An optional key-value map with additional details","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotency_key","type":"`string`","description":"Randomly generated key used to continue the completion of the fulfillment in case of failure.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="createFulfillment"/> #### Returns `","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="createFulfillment"/> ### cancelFulfillment This method is called when a fulfillment is cancelled by the admin. This fulfillment can be for an order, a claim, or a swap. #### Example This is the basic implementation of the method for a fulfillment provider that doesn't interact with a third-party provider to cancel the fulfillment: ```ts class MyFulfillmentService extends FulfillmentService { // ... async cancelFulfillment( fulfillment: Record ): Promise { return {} } } ``` #### Parameters #### Returns ### createReturn Fulfillment providers can also be used to return products. A shipping option can be used for returns if the `is_return` property is true or if an admin creates a Return Shipping Option from the settings. This method is used when the admin [creates a return request](https://docs.medusajs.com/api/admin#orders\_postordersorderreturns) for an order, [creates a swap](https://docs.medusajs.com/api/admin#orders\_postordersorderswaps) for an order, or when the [customer creates a return of their order](https://docs.medusajs.com/api/store#returns\_postreturns). The fulfillment is created automatically for the order return. #### Example This is the basic implementation of the method for a fulfillment provider that does not contact with a third-party provider to fulfill the return: ```ts class MyFulfillmentService extends AbstractFulfillmentService { // ... async createReturn( returnOrder: CreateReturnType ): Promise> { return {} } } ``` #### Parameters #### Returns `","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="createReturn"/> ### getFulfillmentDocuments This method is used to retrieve any documents associated with a fulfillment. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. #### Example ```ts class MyFulfillmentService extends FulfillmentService { // ... async getFulfillmentDocuments( data: Record ): Promise { // assuming you contact a client to // retrieve the document return this.client.getFulfillmentDocuments() } } ``` #### Parameters #### Returns ### getReturnDocuments This method is used to retrieve any documents associated with a return. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. #### Example ```ts class MyFulfillmentService extends FulfillmentService { // ... async getReturnDocuments( data: Record ): Promise { // assuming you contact a client to // retrieve the document return this.client.getReturnDocuments() } } ``` #### Parameters `","description":"The data attribute of the return that you're retrieving the documents for.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="getReturnDocuments"/> #### Returns ### getShipmentDocuments This method is used to retrieve any documents associated with a shipment. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. #### Example ```ts class MyFulfillmentService extends FulfillmentService { // ... async getShipmentDocuments( data: Record ): Promise { // assuming you contact a client to // retrieve the document return this.client.getShipmentDocuments() } } ``` #### Parameters `","description":"The `data` attribute of the shipment that you're retrieving the documents for.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="getShipmentDocuments"/> #### Returns ### retrieveDocuments This method is used to retrieve any documents associated with an order and its fulfillments. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. #### Example ```ts class MyFulfillmentService extends FulfillmentService { // ... async retrieveDocuments( fulfillmentData: Record, documentType: "invoice" | "label" ): Promise { // assuming you contact a client to // retrieve the document return this.client.getDocuments() } } ``` #### Parameters `","description":"The `data` attribute of the order's fulfillment.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"documentType","type":"`\"label\"` \\| `\"invoice\"`","description":"The type of document to retrieve.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="retrieveDocuments"/> #### Returns --- ## Test Implementation :::note If you created your fulfillment provider in a plugin, refer to [this guide on how to test plugins](https://docs.medusajs.com/development/plugins/create#test-your-plugin). ::: After finishing your fulfillment provider implementation: 1\. Run the `build` command in the root of your Medusa backend: ```bash npm2yarn npm run build ``` 2\. Start the backend with the `develop` command: ```bash npx medusa develop ``` 3\. Enable your fulfillment provider in one or more regions. You can do that either using the [Admin APIs](https://docs.medusajs.com/api/admin#regions_postregionsregionfulfillmentproviders) or the [Medusa Admin](https://docs.medusajs.com/user-guide/regions/providers#manage-fulfillment-providers). 4\. To test out your fulfillment provider implementation, create a cart and complete an order. You can do that either using the [Next.js starter](https://docs.medusajs.com/starters/nextjs-medusa-starter) or [using Medusa's APIs and clients](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-cart).