In Shopify, the [`FulfillmentOrder`](/docs/api/admin-graphql/latest/objects/FulfillmentOrder) object models an end-to-end fulfillment process and is available in the GraphQL Admin API. The `FulfillmentOrder` object enables fulfillment data to sync accurately between Shopify and apps.

> Deprecated:
> By API version 2023-07, all apps should be using the [`FulfillmentOrder`](/docs/api/admin-graphql/latests/objects/FulfillmentOrder) object to manage fulfillments.
> Apps using the following GraphQL Admin API objects to fulfill orders are using a legacy workflow that is no longer supported as of API version 2022-07:
>
> - [`Order`](/docs/api/admin-graphql/latest/objects/Order)
> - [`Fulfillment`](/docs/api/admin-graphql/latest/objects/Fulfillment)


This guide describes how to migrate your app to use fulfillment orders to manage fulfillments.

## Requirements

- You've built an [order management](/docs/apps/build/orders-fulfillment/order-management-apps) or [fulfillment service](/docs/apps/build/orders-fulfillment/fulfillment-service-apps) app.
- Your app is using the `Fulfillment` and `Order` API objects to fulfill orders, instead of the `FulfillmentOrder` object.

> Note:
> After the migration, `FulfillmentOrder` operations such as [`FulfillmentCreateV2`](/docs/api/admin-graphql/latest/mutations/fulfillmentCreateV2) are going to cancel pending/open legacy fulfillments and replace them.
>
> This will trigger update callbacks for the cancelled fulfillments. Consider the impact of receiving these callbacks before the migration.
>
> For example, you might want to avoid automatically performing actions when the legacy Fulfillment callbacks trigger.

## Step 1: Determine the permissions your app requires

To migrate your app, you need to update your app's permissions. The permissions that you request depend on the [type of app](#types-of-apps) that you've built and the access to fulfillment orders associated with the [types of locations](#types-of-locations) that your app needs.

### Types of apps

You can create the following types of apps:

| Type of app | Permissions |
|---|---|
| [Order management app](/docs/apps/build/orders-fulfillment/order-management-apps) | <ul><li>Manage fulfillment orders assigned to merchant-managed locations: <ul><li>`read_merchant_managed_fulfillment_orders`</li><li>`write_merchant_managed_fulfillment_orders`</li></ul></li><li>Manage fulfillment orders assigned to locations managed by other fulfillment services: <ul><li>`read_third_party_fulfillment_orders`</li><li> `write_third_party_fulfillment_orders`</li></ul></li></ul> |
| [Fulfillment service app](/docs/apps/build/orders-fulfillment/fulfillment-service-apps) | Manage fulfillment orders assigned to locations belonging to the app: <ul><li>`read_assigned_fulfillment_orders`</li><li>`write_assigned_fulfillment_orders`</li></ul> |

> Note:
> If an app combines the functions of an order management app and a fulfillment service,
then the app should request all access scopes to manage all assigned and all unassigned fulfillment orders.

### Types of locations

You can have the following types of locations on a shop:

| Type of location | Description |
|---|---|
| Merchant-managed location | A location that's created by the merchant. |
| Fulfillment service-managed location | A location that's created by a fulfillment service app.<br></br>When an app creates a [fulfillment service](/docs/api/admin-rest/latest/resources/fulfillmentservice), a new location is automatically created on the shop and associated with that fulfillment service. |

## Step 2: Update your app's permissions

> Tip: If you [configure your app using Shopify CLI](/docs/apps/build/cli-for-apps/app-configuration), then your app will automatically use [Shopify managed installation](/docs/apps/build/authentication-authorization/app-installation). You can skip this step.

When you've determined the additional permissions your app requires, you can update your app for [new installations](#new-installations) and [existing installations](#existing-installations).

### New installations

For new installations, include the additional scopes in the permissions that your app requests as part of [authorization code grant](/docs/apps/build/authentication-authorization/access-tokens/authorization-code-grant).

### Existing installations

- If your app has the `write_fulfillments` access scope, then it can request any of the following access scopes: `write_assigned_fulfillment_orders`, `write_merchant_managed_fulfillment_orders`, `write_third_party_fulfillment_orders`.
- If your app has the `read_fulfillments` access scope, then it can request any of the following access scopes: `read_assigned_fulfillment_orders`,`read_merchant_managed_fulfillment_orders`, `read_third_party_fulfillment_orders`.
- If your app has the `write_orders` access scope, and it doesn't have the `read_fulfillments` or `write_fulfillments` access scopes, it means that it's not a fulfillment service, and it doesn't own a dedicated location. As a result, it doesn't need the `read_assigned_fulfillment_orders` or `write_assigned_fulfillment_orders` access scopes. Instead, your app can request the `write_merchant_managed_fulfillment_orders` and `write_third_party_fulfillment_orders` access scopes.
- If your app has the `read_orders` access scopes, and it doesn't have the `read/write_fulfillments` access scopes, then it can request the `write_merchant_managed_fulfillment_orders` and `write_third_party_fulfillment_orders` access scopes.

> Caution:
> If you have `read_fulfillments` but not `write_fulfillments` permission, then you can request only the `read_*` scopes.

## Step 3: Opt in to fulfillment orders as a fulfillment service

Legacy fulfillment services are different from fulfillment services that use fulfillment orders in the following ways:

- Shopify doesn't automatically create pending fulfillments for the fulfillment service when fulfillment is requested.
- Shopify creates successful fulfillments instead of pending fulfillments for the fulfillment service when a fulfilled order is imported.

The communication pattern between Shopify and the app has changed, and no longer relies on `fulfillment/create` webhooks. Instead, the communication relies on explicit POSTs to the callback URL and the callback URL handles all fulfillment and cancellation requests.

Before a fulfillment service can switch to the fulfillment order-based workflow, the fulfillment service should be updated to register a callback URL and to implicitly switch to the new workflow.
You can use the GraphQL Admin API's [`fulfillmentServiceUpdate`](/docs/api/admin-graphql/latest/mutations/fulfillmentserviceupdate) mutation for setting `callback_url` and `fulfillment_orders_opt_in` values:

<p>
<div class="react-stacked-code-block ThemeMode-dim" data-preset="stacked">
<script data-option="title" data-value="POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json"></script>


<p>
<div class="react-code-block" data-preset="basic">
<div class="react-code-block-preload ThemeMode-dim">
<div class="react-code-block-preload-bar basic-codeblock"></div>
<div class="react-code-block-preload-placeholder-container">
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>

</div>
</div>

<script data-option="title" data-value="GraphQL mutation"></script>

<script type="text/plain" data-language="graphql">
RAW_MD_CONTENTmutation {
  fulfillmentServiceUpdate(
    id: "gid://shopify/FulfillmentService/5",
    fulfillmentOrdersOptIn: true,
    callbackUrl: "https://www.myapp.com/callback_url",
  ) {
    fulfillmentService {
      fulfillmentOrdersOptIn
  }
}
END_RAW_MD_CONTENT</script>

</div>
</p>

<p>
<div class="react-code-block" data-preset="basic">
<div class="react-code-block-preload ThemeMode-dim">
<div class="react-code-block-preload-bar basic-codeblock"></div>
<div class="react-code-block-preload-placeholder-container">
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>
<div class="react-code-block-preload-code-container">
<div class="react-code-block-preload-codeline-number"></div>
<div class="react-code-block-preload-codeline"></div>
</div>

</div>
</div>

<script data-option="title" data-value="JSON response"></script>
<script data-option="nocopy" data-value="true"></script>

<script type="text/plain" data-language="json">
RAW_MD_CONTENT{
    "data": {
        "fulfillmentServiceUpdate": {
            "fulfillmentService": {
                "fulfillmentOrdersOptIn": true
            }
        }
    }
}
END_RAW_MD_CONTENT</script>

</div>
</p>


</div>
</p>


After you've opted in to the fulfillment order-based workflow, the fulfillment service app should act as it's described in [Manage fulfillments as a fulfillment service app](/docs/apps/build/orders-fulfillment/fulfillment-service-apps/build-for-fulfillment-services) section.

> Note:
> Unless granting the API permissions, order management apps don't need any additional pre-configuration to switch to the fulfillment order based APIs, or to temporarily rollback to the legacy fulfillment workflow.

## Step 4: Manage fulfillments using fulfillment orders

After you've updated your app, and opted in legacy fulfillment services to use fulfillment orders, you can start managing fulfillments using fulfillment orders as an [order management app](/docs/apps/build/orders-fulfillment/order-management-apps/build-fulfillment-solutions) or a [fulfillment service app](/docs/apps/build/orders-fulfillment/fulfillment-service-apps/build-for-fulfillment-services).

## Next steps

- Learn more about [the benefits of adopting fulfillment orders workflows](https://www.shopify.com/ca/partners/blog/shopify-fulfillment-orders-api).
- Manage fulfillments as an [order management app](/docs/apps/build/orders-fulfillment/order-management-apps/build-fulfillment-solutions).
- Manage fulfillments as a [fulfillment service app](/docs/apps/build/orders-fulfillment/fulfillment-service-apps/build-for-fulfillment-services).
- Learn about the recommended workflow for using the GraphQL Admin API to track orders placed through [third-party marketplaces](/docs/apps/build/orders-fulfillment/order-management-apps/track-orders-other-platforms).