In this blog, we’ll learn how to complete a Shopify Draft Order using GraphQL inside a Shopify Remix app — with one simple and clean code example.
When you create a Draft Order in Shopify, it stays in a “draft” state until it’s completed.
Learn – How to Create a Shopify Draft Order in Shopify Remix Using GraphQL?
Completing the draft order officially turns it into a real Shopify order. In this tutorial, we’ll walk through how to complete a draft order with paymentPending: true, which is especially useful when you want to send an invoice and allow the customer to pay later.

What You’ll Learn
- How to write a GraphQL mutation to complete a Draft Order
- How to handle it in a Remix action() function
- How to build a simple form to trigger the action
Steps to Complete a Shopify Draft Order in Shopify Remix Using GraphQL:
// app/routes/complete-draft-order.jsx
import { json } from "@remix-run/node";
import { Form } from "@remix-run/react";
import { authenticate } from "../shopify.server";
// GraphQL mutation to complete the draft order with payment pending
const COMPLETE_DRAFT_ORDER_MUTATION = `
mutation draftOrderComplete($id: ID!, $paymentPending: Boolean) {
draftOrderComplete(id: $id, paymentPending: $paymentPending) {
draftOrder {
id
invoiceUrl
order {
id
}
}
userErrors {
field
message
}
}
}
`;
// Remix action to handle the POST request
export const action = async ({ request }) => {
const { admin } = await authenticate.admin(request);
const formData = await request.formData();
const draftOrderId = formData.get("draftOrderId");
try {
const response = await admin.graphql(COMPLETE_DRAFT_ORDER_MUTATION, {
variables: {
id: draftOrderId,
paymentPending: true,
},
});
const result = response.data.draftOrderComplete;
if (result.userErrors?.length > 0) {
return json({ success: false, error: result.userErrors[0].message });
}
return json({
success: true,
orderId: result.draftOrder.order.id,
invoiceUrl: result.draftOrder.invoiceUrl,
});
} catch (error) {
return json({ success: false, error: error.message });
}
};
// UI Form to trigger completion
export default function CompleteDraftOrder() {
return (
<div style={{ padding: 20 }}>
<h2>Complete Draft Order</h2>
<Form method="post">
<input
type="hidden"
name="draftOrderId"
value="gid://shopify/DraftOrder/1234567890" // Replace this with your actual Draft Order GID
/>
<button type="submit">Complete Order (Payment Pending)</button>
</Form>
</div>
);
}
What Happens When You Submit the Form?
- Shopify completes the draft order and marks it as paymentPending.
- You receive a response containing the order ID and invoice URL (if available).
- If there are issues, the mutation returns userErrors, which you can display to the user.
Notes
- Make sure your app has the required access scopes: write_draft_orders and write_orders.
- Replace the dummy draftOrderId with the real one you created earlier.
- You can also use this to send invoices or build custom workflows
You’ve now completed a Shopify Draft Order in Remix using GraphQL.