--- name: shopify-admin-refund-and-reorder role: customer-support description: "Process a full or partial refund on an order and optionally create a replacement draft order for the customer." toolkit: shopify-admin, shopify-admin-execution api_version: "2025-01" graphql_operations: - order:query - refundCreate:mutation - draftOrderCreate:mutation status: stable compatibility: Claude Code, Cursor, Codex, Gemini CLI --- ## Purpose Processes refunds and creates replacement orders without navigating the Shopify admin UI. This skill handles both the refund and the optional replacement draft order in a single workflow. ## Prerequisites - Authenticated Shopify CLI session: `shopify auth login --store ` - API scopes: `read_orders`, `write_orders` ## Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | store | string | yes | — | Store domain (e.g., mystore.myshopify.com) | | format | string | no | human | Output format: `human` or `json` | | dry_run | bool | no | false | Preview operations without executing mutations | | order_id | string | yes | — | GID of the order (e.g., `gid://shopify/Order/12345`) | | refund_line_items | array | no | all refundable | Array of `{line_item_id, quantity}` to refund; if omitted, refunds all refundable quantities | | reason | string | no | other | Refund reason: `customer`, `fraud`, `inventory`, `declined`, `other` | | create_replacement | bool | no | false | If true, create a draft order with the same line items after refund | | notify_customer | bool | no | true | Send refund notification email to customer | ## Safety > ⚠️ Steps 2 and 3 execute irreversible financial mutations. `refundCreate` cannot be undone — once a refund is processed, the payment cannot be re-captured. `draftOrderCreate` creates a new draft order that must be invoiced and paid separately. Run with `dry_run: true` to verify the refund line items and amounts before committing. Verify `refundableQuantity` per line item from Step 1 before proceeding. ## Workflow Steps 1. **OPERATION:** `order` — query **Inputs:** `id: ` **Expected output:** Full order with `displayFinancialStatus`, `lineItems` (with `refundableQuantity`), `transactions`, `customer`, `shippingAddress`; verify order is refundable before proceeding 2. **OPERATION:** `refundCreate` — mutation **Inputs:** `input.orderId`, `input.refundLineItems` (from parameter or all refundable), `input.notify`, `input.note: ` **Expected output:** `refund.id`, `refund.totalRefundedSet`, `userErrors` 3. **OPERATION:** `draftOrderCreate` — mutation (only if `create_replacement: true`) **Inputs:** `input.lineItems` (from original order line items), `input.customerId`, `input.shippingAddress`, `input.note: "Replacement for order "` **Expected output:** `draftOrder.id`, `draftOrder.name`, `draftOrder.invoiceUrl`, `userErrors` ## GraphQL Operations ```graphql # order:query — validated against api_version 2025-01 query OrderForRefund($id: ID!) { order(id: $id) { id name displayFinancialStatus displayFulfillmentStatus totalPriceSet { shopMoney { amount currencyCode } } lineItems(first: 50) { edges { node { id title quantity refundableQuantity variant { id sku price } } } } transactions(first: 10) { id kind status amountSet { shopMoney { amount currencyCode } } gateway } refunds { id createdAt totalRefundedSet { shopMoney { amount currencyCode } } } customer { id defaultEmailAddress { emailAddress } firstName lastName } shippingAddress { address1 city province country zip } } } ``` ```graphql # refundCreate:mutation — validated against api_version 2025-01 mutation RefundCreate($input: RefundInput!) { refundCreate(input: $input) { refund { id createdAt totalRefundedSet { shopMoney { amount currencyCode } } } userErrors { field message } } } ``` ```graphql # draftOrderCreate:mutation — validated against api_version 2025-01 mutation DraftOrderCreate($input: DraftOrderInput!) { draftOrderCreate(input: $input) { draftOrder { id name invoiceUrl } userErrors { field message } } } ``` ## Session Tracking **Claude MUST emit the following output at each stage. This is mandatory.** **On start**, emit: ``` ╔══════════════════════════════════════════════╗ ║ SKILL: refund-and-reorder ║ ║ Store: ║ ║ Started: ║ ╚══════════════════════════════════════════════╝ ``` **After each step**, emit: ``` [N/TOTAL] → Params: → Result: ``` If `dry_run: true`, prefix every mutation step with `[DRY RUN]` and do not execute it. **On completion**, emit: For `format: human` (default): ``` ══════════════════════════════════════════════ OUTCOME SUMMARY Order: Refund ID: Amount refunded: Replacement draft: Errors: 0 Output: none ══════════════════════════════════════════════ ``` For `format: json`, emit: ```json { "skill": "refund-and-reorder", "store": "", "started_at": "", "completed_at": "", "dry_run": false, "steps": [ { "step": 1, "operation": "OrderForRefund", "type": "query", "params_summary": "order ", "result_summary": "", "skipped": false }, { "step": 2, "operation": "RefundCreate", "type": "mutation", "params_summary": " line items, reason: ", "result_summary": "refund ", "skipped": false }, { "step": 3, "operation": "DraftOrderCreate", "type": "mutation", "params_summary": " line items, customer ", "result_summary": "draft ", "skipped": false } ], "outcome": { "order_name": "", "refund_id": "", "amount_refunded": "", "currency": "", "draft_order_name": "", "draft_order_invoice_url": "", "errors": 0, "output_file": null } } ``` ## Output Format No CSV output. The session completion summary reports the refund ID and amount. If `create_replacement: true`, the draft order name and invoice URL are included in the output. ## Error Handling | Error | Cause | Recovery | |-------|-------|----------| | `refundableQuantity` is 0 | Line item already fully refunded | Check order refund history | | `userErrors` from refundCreate | Invalid refund amounts or order not refundable | Check `displayFinancialStatus` — must not be `REFUNDED` | | `userErrors` from draftOrderCreate | Invalid line items or customer | Verify product variants still exist | | Order not found | Invalid order GID | Use `order-lookup-and-summary` skill to find the correct order ID | ## Best Practices 1. Always run `dry_run: true` first — Step 2 is irreversible. Verify `refundableQuantity` per line item in Step 1 output before committing. 2. For partial refunds, specify `refund_line_items` explicitly — omitting it refunds all refundable items, which may not be intended. 3. The `create_replacement` draft order is not automatically invoiced or fulfilled — share `invoiceUrl` with the customer for payment. 4. Use `notify_customer: false` for internal corrections where the customer should not be alerted. 5. Check `displayFinancialStatus` from Step 1 — if it is `REFUNDED`, there is nothing left to refund.