---
description: 'Learn how to manage draft orders using the admin REST APIs. This guide includes how to manage draft orders including listing and creating them, manage their line items, and register their payment.'
addHowToData: true
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# How to Manage Draft Orders

In this document, you’ll learn how to manage draft orders using the admin REST APIs.

## Overview

Using the draft orders admin REST APIs, you can manage draft orders and perform other related functionalities.

### Scenario

You want to add or use the following admin functionalities:

- Manage draft orders, including listing, creating, updating, and deleting draft orders.
- Managing line items in draft orders, including adding, updating, and deleting items from a draft order.
- Authorize and capture a draft order’s payment.

---

## Prerequisities

### Medusa Components

It is assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.

### JS Client

This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.

If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).

### Medusa React

This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.

If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#usage).

### Authenticated Admin User

You must be an authenticated admin user before following along with the steps in the tutorial.

You can learn more about [authenticating as an admin user in the API reference](/api/admin/#section/Authentication).

---

## List Draft Orders

You can list draft orders by sending a request to the [List Draft Orders endpoint]( /api/admin#tag/Draft-Orders/operation/GetDraftOrders):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.list()
.then(({ draft_orders, limit, offset, count }) => {
  console.log(draft_orders.length)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDraftOrders } from "medusa-react"

const DraftOrders = () => {
  const { draft_orders, isLoading } = useAdminDraftOrders()

  return (
    <div>
      {isLoading && <span>Loading...</span>}
      {draft_orders && !draft_orders.length && (
        <span>No Draft Orders</span>
      )}
      {draft_orders && draft_orders.length > 0 && (
        <ul>
          {draft_orders.map((order) => (
            <li key={order.id}>{order.display_id}</li>
          ))}
        </ul>
      )}
    </div>
  )
}

export default DraftOrders
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/admin/draft-orders`, {
  credentials: "include",
})
.then((response) => response.json())
.then(({ draft_orders, limit, offset, count }) => {
  console.log(draft_orders.length)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X GET '<BACKEND_URL>/admin/draft-orders' \
-H 'Authorization: Bearer <API_TOKEN>'
```

</TabItem>
</Tabs>

This endpoint does not require any path or query parameters. You can pass search or pagination query parameters as explained in the [API reference]( /api/admin#tag/Draft-Orders/operation/GetDraftOrders).

The request returns an array of draft order objects along with [pagination parameters]( /api/admin#section/Pagination).

---

## Create a Draft Order

You can create a draft order by sending a request to the [Create Draft Order endpoint]( /api/admin#tag/Draft-Orders/operation/PostDraftOrders):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.create({
  email,
  region_id,
  items: [
    {
      // defined product
      quantity: 1,
      variant_id,
    },
    {
      // custom product
      quantity: 1,
      unit_price: 1000,
      title: "Custom Product",
    },
  ],
  shipping_methods: [
    {
      option_id,
      // for custom shipping price
      price,
    },
  ],
})
.then(({ draft_order }) => {
  console.log(draft_order.id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminCreateDraftOrder } from "medusa-react"

const CreateDraftOrder = () => {
  const createDraftOrder = useAdminCreateDraftOrder()
  // ...

  const handleCreate = () => {
    createDraftOrder.mutate({
      email,
      region_id,
      items: [
        {
          // defined product
          quantity: 1,
          variant_id,
        },
        {
          // custom product
          quantity: 1,
          unit_price: 1000,
          title: "Custom Product",
        },
      ],
      shipping_methods: [
        {
          option_id,
          // for custom shipping price
          price,
        },
      ],
    })
  }

  // ...
}

export default CreateDraftOrder
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/admin/draft-orders`, {
  credentials: "include",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email,
    region_id,
    items: [
      {
        // defined product
        quantity: 1,
        variant_id,
      },
      {
        // custom product
        quantity: 1,
        unit_price: 1000,
        title: "Custom Product",
      },
    ],
    shipping_methods: [
      {
        option_id,
        // for custom shipping price
        price,
      },
    ],
  }),
})
.then((response) => response.json())
.then(({ draft_order }) => {
  console.log(draft_order.id)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X POST '<BACKEND_URL>/admin/draft-orders' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
  "email": "<EMAIL>",
  "region_id": "<REGION_ID>",
  "items": [
    {
      "quantity": 1,
      "variant_id": "<VARIANT_ID>"
    },
    {
      "quantity": 1,
      "unit_price": 1000,
      "title": "Custom Product"
    }
  ],
  "shipping_methods": [
    {
      "option_id": "<OPTION_ID>",
      "price": 1000
    }
  ]
}'
```

</TabItem>
</Tabs>

This endpoint requires the following request body parameters:

- `email`: a string indicating the email of the customer to associate this draft order with.
- `region_id`: a string indicating the ID of the region this draft order belongs to.
- `shipping_methods`: an array of objects, each object being a shipping method to use for the draft order. The object is required to have the `option_id` property which is the ID of the shipping option to use. You can optionally specify a `price` property to set a custom amount for the price.

You can also pass other optional parameters. For example, the `items` array can be passed to add line items to the draft order. There are two types of items that you can add:

1. Defined product variants. This is done by passing the `variant_id` property, with its value being the ID of the product variant to add.
2. Custom products that aren’t defined in your store. This is done by passing the `unit_price` property with its value being the price of the custom product, and the `title` property with its value being the title of the custom product.

You must also pass for each item its quantity.

To learn about other optional request body parameters, such as passing shipping or billing addresses, check out the [API reference]( /api/admin#tag/Draft-Orders/operation/PostDraftOrders).

The request returns the created draft order as an object.

---

## Retrieve Draft Order

You can retrieve a draft order by sending a request to the [Get Draft Order endpoint]( /api/admin#tag/Draft-Orders/operation/GetDraftOrdersDraftOrder):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.retrieve(draftOrderId)
.then(({ draft_order }) => {
  console.log(draft_order.id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDraftOrder } from "medusa-react"

const DraftOrder = () => {
  const { 
    draft_order, 
    isLoading, 
  } = useAdminDraftOrder(draftOrderId)
 
  return (
    <div>
      {isLoading && <span>Loading...</span>}
      {draft_order && <span>{draft_order.display_id}</span>}
      
    </div>
  )
}

export default DraftOrder
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}`, {
  credentials: "include",
})
.then((response) => response.json())
.then(({ draft_order }) => {
  console.log(draft_order.id)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X GET '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>' \
-H 'Authorization: Bearer <API_TOKEN>'
```

</TabItem>
</Tabs>

This endpoint requires the draft order’s ID as a path parameter.

The request returns the draft order as an object.

---

## Update Draft Order

You can update a draft order by sending a request to the [Update Draft Order endpoint]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrder):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.update(draftOrderId, {
  email: "user@example.com",
})
.then(({ draft_order }) => {
  console.log(draft_order.id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminUpdateDraftOrder } from "medusa-react"

const UpdateDraftOrder = () => {
  const updateDraftOrder = useAdminUpdateDraftOrder(
    draftOrderId
  )
  // ...

  const handleUpdate = () => {
    updateDraftOrder.mutate({
      email: "user@example.com",
    })
  }

  // ...
}

export default UpdateDraftOrder
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}`, {
  credentials: "include",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: "user@example.com",
  }),
})
.then((response) => response.json())
.then(({ draft_order }) => {
  console.log(draft_order.id)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
    "email": "user@example.com"
}'
```

</TabItem>
</Tabs>

This endpoint requires the draft order’s ID as a path parameter.

In the request body, you can pass any of the draft order’s fields to update. In the example above, you update the `email` field. Check out the [API reference]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrder) to learn about other accepted request body parameters.

The request returns the updated draft order as an object.

---

## Manage Line Items

### Add Line Items

You can add line items to a draft order by sending a request to the [Create Line Items endpoint]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrderLineItems):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.addLineItem(draftOrderId, {
  quantity: 1,
})
.then(({ draft_order }) => {
  console.log(draft_order.cart.items)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDraftOrderAddLineItem } from "medusa-react"

const AddLineItem = () => {
  const addLineItem = useAdminDraftOrderAddLineItem(
    draftOrderId
  )
  // ...

  const handleAdd = () => {
    addLineItem.mutate({
      quantity: 1,
    })
  }

  // ...
}

export default AddLineItem
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

<!-- eslint-disable max-len -->

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/line-items`, {
    credentials: "include",
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      quantity: 1,
    }),
  })
  .then((response) => response.json())
  .then(({ draft_order }) => {
    console.log(draft_order.cart.items)
  })
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/line-items' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
    "quantity": 1
}'
```

</TabItem>
</Tabs>

This endpoint requires the ID of the draft order as a path parameter.

In the request body, it’s required to pass the `quantity` parameter, which is a number indicating the quantity of the item in the draft order. You can also pass other optional parameters based on the type of line item you’re adding.

There are two types of items that you can add:

1. Defined product variants. This is done by passing the `variant_id` parameter, with its value being the ID of the product variant to add.
2. Custom products that aren’t defined in your store. This is done by passing the `unit_price` parameter with its value being the price of the custom product, and the `title` property with its value being the title of the custom product.

Check the [API reference]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrderLineItems) for a full list of request body parameters.

The request returns the updated draft order as an object. You can access the draft order’s items by accessing the `carts` property in the draft item, then the `items` property. The `items` property is an array of line item objects.

### Update Line Item

You can update a line item by sending a request to the [Update Line Item endpoint]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrderLineItemsItem):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.updateLineItem(draftOrderId, itemId, {
  quantity: 1,
})
.then(({ draft_order }) => {
  console.log(draft_order.cart.items)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDraftOrderUpdateLineItem } from "medusa-react"

const UpdateLineItem = () => {
  const updateLineItem = useAdminDraftOrderUpdateLineItem(
    draftOrderId
  )
  // ...

  const handleUpdate = () => {
    updateLineItem.mutate({
      item_id,
      quantity: 1,
    })
  }

  // ...
}

export default UpdateLineItem
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

<!-- eslint-disable max-len -->

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/line-items/${itemId}`, {
  credentials: "include",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    quantity: 1,
  }),
})
.then((response) => response.json())
.then(({ draft_order }) => {
  console.log(draft_order.cart.items)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/line-items/<ITEM_ID>' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
    "quantity": 1
}'
```

</TabItem>
</Tabs>

This endpoint requires the draft order and line item’s IDs as path parameters.

In the request body, you can pass any of the line item’s fields as parameters to update them. In the example above, you pass the `quantity` parameter to update the quantity of the item. Check out the [API reference]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrderLineItemsItem) for a full list of request body parameters.

The request returns the updated draft order as an object. You can access the draft order’s items by accessing the `carts` property in the draft item, then the `items` property. The `items` property is an array of line item objects.

### Delete Line Item

You can delete a line item by sending a request to the [Delete Line Item endpoint]( /api/admin#tag/Draft-Orders/operation/DeleteDraftOrdersDraftOrderLineItemsItem):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.removeLineItem(draftOrderId, itemId)
.then(({ draft_order }) => {
  console.log(draft_order.cart.items)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDraftOrderRemoveLineItem } from "medusa-react"

const DeleteLineItem = () => {
  const deleteLineItem = useAdminDraftOrderRemoveLineItem(
    draftOrderId
  )
  // ...

  const handleDelete = () => {
    deleteLineItem.mutate(itemId)
  }

  // ...
}

export default DeleteLineItem
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

<!-- eslint-disable max-len -->

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/line-items/${itemId}`, {
  credentials: "include",
  method: "DELETE",
})
.then((response) => response.json())
.then(({ draft_order }) => {
  console.log(draft_order.cart.items)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X DELETE '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/line-items/<ITEM_ID>' \
-H 'Authorization: Bearer <API_TOKEN>'
```

</TabItem>
</Tabs>

This endpoint requires the draft order and line item’s IDs as path parameters.

The request returns the updated draft order as an object. You can access the draft order’s items by accessing the `carts` property in the draft item, then the `items` property. The `items` property is an array of line item objects.

---

## Register Draft Order Payment

Registering the draft order’s payment leads to authorizing and capturing the payment using the `system` payment method. This would complete the draft order and create an order from it.

You can register the draft order payment by sending a request to the [Register Draft Order Payment endpoint]( /api/admin#tag/Draft-Orders/operation/PostDraftOrdersDraftOrderRegisterPayment):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.markPaid(draftOrderId)
.then(({ order }) => {
  console.log(order.id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDraftOrderRegisterPayment } from "medusa-react"

const RegisterPayment = () => {
  const registerPayment = useAdminDraftOrderRegisterPayment(
    draftOrderId
  )
  // ...

  const handlePayment = () => {
    registerPayment.mutate()
  }

  // ...
}

export default RegisterPayment
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/pay`, {
  credentials: "include",
  method: "POST",
})
.then((response) => response.json())
.then(({ order }) => {
  console.log(order.id)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/pay' \
-H 'Authorization: Bearer <API_TOKEN>'
```

</TabItem>
</Tabs>

This endpoint requires the draft order’s ID as a path parameter.

The request returns the order created from the draft order as an object.

---

## Delete a Draft Order

You can delete a draft order by sending a request to the [Delete Draft Order endpoint]( /api/admin#tag/Draft-Orders/operation/DeleteDraftOrdersDraftOrder):

<Tabs groupId="request-type" isCodeTabs={true}>
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.admin.draftOrders.delete(draftOrderId)
.then(({ id, object, deleted }) => {
  console.log(id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useAdminDeleteDraftOrder } from "medusa-react"

const DeleteDraftOrder = () => {
  const deleteDraftOrder = useAdminDeleteDraftOrder(
    draftOrderId
  )
  // ...

  const handleDelete = () => {
    deleteDraftOrder.mutate()
  }

  // ...
}

export default DeleteDraftOrder
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}`, {
  credentials: "include",
  method: "DELETE",
})
.then((response) => response.json())
.then(({ id, object, deleted }) => {
  console.log(id)
})
```

</TabItem>
<TabItem value="curl" label="cURL">

```bash
curl -L -X DELETE '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>' \
-H 'Authorization: Bearer <API_TOKEN>'
```

</TabItem>
</Tabs>

This endpoint requires the draft order’s ID as a path parameter.

The request returns the following fields:

- `id`: The ID of the deleted draft order.
- `object`: The type of object that was deleted. In this case, the value will be `draft-order`.
- `deleted`: A boolean value indicating whether the draft order was deleted.

---

## See Also

- [How to manage orders](./manage-orders.mdx)
- [Orders architecture overview](../orders.md)
