complete_draft_order
Complete an open draft order into a Shopify order. Set paymentPending to true to create the order without capturing payment, ideal for offline collection. Default false captures payment immediately. Returns the new order's GID.
Instructions
Convert an OPEN draft order into a real Shopify order. With paymentPending=false (default), Shopify attempts to capture payment immediately; the call fails if no payment method is on file. With paymentPending=true, the order is created in payment-pending status — useful when collecting payment offline (cash, bank transfer, manual processing). Once completed, the draft transitions to COMPLETED and the new order's GID is returned. The transition is one-way: completed drafts cannot be re-opened or edited via draft tools (use the order tools, or refund/cancel for the resulting order).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | GID of an OPEN draft order. Already-completed drafts are rejected. | |
| paymentPending | No | If true, the resulting order is marked payment-pending — Shopify creates the order but does NOT capture payment. Use when you'll collect payment offline (cash, bank transfer, manual card auth) or via a separate flow. Default false (attempts to capture immediately). |
Implementation Reference
- src/tools/draft_orders.ts:463-497 (handler)The tool handler for 'complete_draft_order': executes the draftOrderComplete GraphQL mutation with optional paymentPending flag, then formats a response with the resulting order info.
server.tool( "complete_draft_order", "Convert an OPEN draft order into a real Shopify order. With paymentPending=false (default), Shopify attempts to capture payment immediately; the call fails if no payment method is on file. With paymentPending=true, the order is created in payment-pending status — useful when collecting payment offline (cash, bank transfer, manual processing). Once completed, the draft transitions to COMPLETED and the new order's GID is returned. The transition is one-way: completed drafts cannot be re-opened or edited via draft tools (use the order tools, or refund/cancel for the resulting order).", completeDraftOrderSchema, async (args) => { const data = await client.graphql<{ draftOrderComplete: { draftOrder: DraftOrder | null; userErrors: ShopifyUserError[]; }; }>(COMPLETE_DRAFT_ORDER_MUTATION, { id: args.id, paymentPending: args.paymentPending ?? false, }); throwIfUserErrors(data.draftOrderComplete.userErrors, "draftOrderComplete"); const d = data.draftOrderComplete.draftOrder; if (!d) { return { content: [ { type: "text" as const, text: "draftOrderComplete returned no draft order." }, ], }; } const orderInfo = d.order ? ` → order ${d.order.name} (${d.order.id})` : ""; return { content: [ { type: "text" as const, text: `Completed draft order ${d.name} [${d.status}]${orderInfo}`, }, ], }; }, - src/tools/draft_orders.ts:249-259 (schema)Zod schema for 'complete_draft_order' input: requires an 'id' (draft order GID) and optional 'paymentPending' boolean.
const completeDraftOrderSchema = { id: z .string() .describe("GID of an OPEN draft order. Already-completed drafts are rejected."), paymentPending: z .boolean() .optional() .describe( "If true, the resulting order is marked payment-pending — Shopify creates the order but does NOT capture payment. Use when you'll collect payment offline (cash, bank transfer, manual card auth) or via a separate flow. Default false (attempts to capture immediately).", ), }; - src/tools/draft_orders.ts:463-498 (registration)The tool is registered on the MCP server via server.tool() inside registerDraftOrderTools(), using the name 'complete_draft_order'.
server.tool( "complete_draft_order", "Convert an OPEN draft order into a real Shopify order. With paymentPending=false (default), Shopify attempts to capture payment immediately; the call fails if no payment method is on file. With paymentPending=true, the order is created in payment-pending status — useful when collecting payment offline (cash, bank transfer, manual processing). Once completed, the draft transitions to COMPLETED and the new order's GID is returned. The transition is one-way: completed drafts cannot be re-opened or edited via draft tools (use the order tools, or refund/cancel for the resulting order).", completeDraftOrderSchema, async (args) => { const data = await client.graphql<{ draftOrderComplete: { draftOrder: DraftOrder | null; userErrors: ShopifyUserError[]; }; }>(COMPLETE_DRAFT_ORDER_MUTATION, { id: args.id, paymentPending: args.paymentPending ?? false, }); throwIfUserErrors(data.draftOrderComplete.userErrors, "draftOrderComplete"); const d = data.draftOrderComplete.draftOrder; if (!d) { return { content: [ { type: "text" as const, text: "draftOrderComplete returned no draft order." }, ], }; } const orderInfo = d.order ? ` → order ${d.order.name} (${d.order.id})` : ""; return { content: [ { type: "text" as const, text: `Completed draft order ${d.name} [${d.status}]${orderInfo}`, }, ], }; }, ); - src/tools/draft_orders.ts:112-124 (helper)The GraphQL mutation string 'COMPLETE_DRAFT_ORDER_MUTATION' that the handler uses to complete a draft order.
const COMPLETE_DRAFT_ORDER_MUTATION = /* GraphQL */ ` mutation DraftOrderComplete($id: ID!, $paymentPending: Boolean) { draftOrderComplete(id: $id, paymentPending: $paymentPending) { draftOrder { id name status order { id name } } userErrors { field message } } } `; - src/tools/draft_orders.ts:4-4 (helper)The 'throwIfUserErrors' helper imported from shopify/client.js, used to handle Shopify user errors in the handler.
import { throwIfUserErrors } from "../shopify/client.js";