refund_order
Refund specific line items or shipping costs on a Shopify order. Choose restock behavior per item: no restock, cancel, or return to location. Optionally send customer notification. Returns refund GID and total.
Instructions
Issue a refund against an order — for specific line items (with quantities and optional restock behaviour), for shipping, or both. Returns the new refund's GID and total amount refunded. To refund a full order use cancel_order with refund=true instead (one-step). Use this tool when refunding partially: just one item, just shipping, an adjustment without item breakdown, or a return that needs explicit restock-to-location handling. The restockType per line item controls inventory behaviour: NO_RESTOCK (default — the items aren't coming back), CANCEL (restock as if cancelled), RETURN (restock with a return record at the given locationId). Pass notify: true to email the customer.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Order GID or numeric ID to refund. | |
| refundLineItems | No | Specific line items to refund with quantities. Omit to do a refund without item-level breakdown (use for shipping-only or adjustment refunds). | |
| shipping | No | Refund part or all of shipping. Pass {fullRefund: true} to refund everything paid in shipping; or {amount: '5.00'} for a specific amount. | |
| currency | No | ISO currency code. Required for multi-currency stores; defaults to the order's currency otherwise. | |
| note | No | Internal note explaining the refund. | |
| notify | No | Email the customer a refund notification. |
Implementation Reference
- src/tools/orders.ts:502-554 (handler)The tool handler function for 'refund_order'. Registered via server.tool() with name 'refund_order'. Accepts args validated by refundOrderSchema, calls the REFUND_CREATE_MUTATION GraphQL mutation, and returns the refund GID and total refunded amount.
server.tool( "refund_order", "Issue a refund against an order — for specific line items (with quantities and optional restock behaviour), for shipping, or both. Returns the new refund's GID and total amount refunded. To refund a full order use cancel_order with refund=true instead (one-step). Use this tool when refunding partially: just one item, just shipping, an adjustment without item breakdown, or a return that needs explicit restock-to-location handling. The `restockType` per line item controls inventory behaviour: NO_RESTOCK (default — the items aren't coming back), CANCEL (restock as if cancelled), RETURN (restock with a return record at the given locationId). Pass `notify: true` to email the customer.", refundOrderSchema, async (args) => { const input: Record<string, unknown> = { orderId: toGid(args.id, "Order"), notify: args.notify, }; if (args.refundLineItems) { input.refundLineItems = args.refundLineItems.map((li) => ({ lineItemId: li.lineItemId, quantity: li.quantity, restockType: li.restockType, locationId: li.locationId, })); } if (args.shipping) input.shipping = args.shipping; if (args.currency) input.currency = args.currency; if (args.note) input.note = args.note; const data = await client.graphql<{ refundCreate: { refund: { id: string; totalRefundedSet: { shopMoney: { amount: string; currencyCode: string }; }; note?: string | null; } | null; userErrors: ShopifyUserError[]; }; }>(REFUND_CREATE_MUTATION, { input }); throwIfUserErrors(data.refundCreate.userErrors, "refundCreate"); const r = data.refundCreate.refund; if (!r) { return { content: [ { type: "text" as const, text: "refundCreate returned no refund." }, ], }; } const total = `${r.totalRefundedSet.shopMoney.amount} ${r.totalRefundedSet.shopMoney.currencyCode}`; return { content: [ { type: "text" as const, text: `Refunded ${total} on ${args.id} — refund ${r.id}`, }, ], }; }, ); - src/tools/orders.ts:291-321 (schema)The input schema (refundOrderSchema) for the 'refund_order' tool. Defines fields: id (order GID/numeric ID), refundLineItems (array of line items with quantities and restock options), shipping (full refund or specific amount), currency, note, and notify (email notification).
const refundOrderSchema = { id: z .string() .describe("Order GID or numeric ID to refund."), refundLineItems: z .array(refundLineItemSchema) .optional() .describe( "Specific line items to refund with quantities. Omit to do a refund without item-level breakdown (use for shipping-only or adjustment refunds).", ), shipping: z .object({ fullRefund: z.boolean().optional(), amount: z.string().optional().describe("Specific shipping refund amount as decimal string."), }) .optional() .describe( "Refund part or all of shipping. Pass {fullRefund: true} to refund everything paid in shipping; or {amount: '5.00'} for a specific amount.", ), currency: z .string() .optional() .describe( "ISO currency code. Required for multi-currency stores; defaults to the order's currency otherwise.", ), note: z.string().optional().describe("Internal note explaining the refund."), notify: z .boolean() .default(false) .describe("Email the customer a refund notification."), }; - src/tools/orders.ts:276-289 (schema)The refundLineItemSchema used within refundOrderSchema. Defines lineItemId, quantity, restockType (NO_RESTOCK/CANCEL/RETURN), and locationId for per-item refund details.
const refundLineItemSchema = z.object({ lineItemId: z.string().describe("LineItem GID from the order."), quantity: z.number().int().min(1).describe("How many of this line item to refund."), restockType: z .enum(["NO_RESTOCK", "CANCEL", "RETURN"]) .default("NO_RESTOCK") .describe( "How to handle inventory: NO_RESTOCK (don't restock), CANCEL (restock as if cancelled), RETURN (restock as a return).", ), locationId: z .string() .optional() .describe("Location GID to restock to (required when restockType is CANCEL or RETURN)."), }); - src/tools/orders.ts:502-554 (registration)Registration of the 'refund_order' tool via server.tool() call inside registerOrderTools() function. Called from src/server.ts:58.
server.tool( "refund_order", "Issue a refund against an order — for specific line items (with quantities and optional restock behaviour), for shipping, or both. Returns the new refund's GID and total amount refunded. To refund a full order use cancel_order with refund=true instead (one-step). Use this tool when refunding partially: just one item, just shipping, an adjustment without item breakdown, or a return that needs explicit restock-to-location handling. The `restockType` per line item controls inventory behaviour: NO_RESTOCK (default — the items aren't coming back), CANCEL (restock as if cancelled), RETURN (restock with a return record at the given locationId). Pass `notify: true` to email the customer.", refundOrderSchema, async (args) => { const input: Record<string, unknown> = { orderId: toGid(args.id, "Order"), notify: args.notify, }; if (args.refundLineItems) { input.refundLineItems = args.refundLineItems.map((li) => ({ lineItemId: li.lineItemId, quantity: li.quantity, restockType: li.restockType, locationId: li.locationId, })); } if (args.shipping) input.shipping = args.shipping; if (args.currency) input.currency = args.currency; if (args.note) input.note = args.note; const data = await client.graphql<{ refundCreate: { refund: { id: string; totalRefundedSet: { shopMoney: { amount: string; currencyCode: string }; }; note?: string | null; } | null; userErrors: ShopifyUserError[]; }; }>(REFUND_CREATE_MUTATION, { input }); throwIfUserErrors(data.refundCreate.userErrors, "refundCreate"); const r = data.refundCreate.refund; if (!r) { return { content: [ { type: "text" as const, text: "refundCreate returned no refund." }, ], }; } const total = `${r.totalRefundedSet.shopMoney.amount} ${r.totalRefundedSet.shopMoney.currencyCode}`; return { content: [ { type: "text" as const, text: `Refunded ${total} on ${args.id} — refund ${r.id}`, }, ], }; }, ); - src/tools/orders.ts:97-108 (helper)The REFUND_CREATE_MUTATION GraphQL mutation used by the refund_order handler to perform the refund via the Shopify Admin API.
const REFUND_CREATE_MUTATION = /* GraphQL */ ` mutation RefundCreate($input: RefundInput!) { refundCreate(input: $input) { refund { id totalRefundedSet { shopMoney { amount currencyCode } } note } userErrors { field message } } } `;