shopify-admin-refund-and-reorder

SkillCommerce & finance

Process a full or partial refund on an order and optionally create a replacement draft order for the customer.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the shopify-admin-refund-and-reorder skill

What this skill tells your AI

The instructions your AI receives, as published by 40rty-ai/shopify-admin-skills in skills/customer-support/shopify-admin-refund-and-reorder/SKILL.md and read by ahel’s review.

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 <domain>
  • API scopes: read_orders, write_orders

Parameters

ParameterTypeRequiredDefaultDescription
storestringyesStore domain (e.g., mystore.myshopify.com)
formatstringnohumanOutput format: human or json
dry_runboolnofalsePreview operations without executing mutations
order_idstringyesGID of the order (e.g., gid://shopify/Order/12345)
refund_line_itemsarraynoall refundableArray of {line_item_id, quantity} to refund; if omitted, refunds all refundable quantities
reasonstringnootherRefund reason: customer, fraud, inventory, declined, other
create_replacementboolnofalseIf true, create a draft order with the same line items after refund
notify_customerboolnotrueSend 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: <order_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: <reason> 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 <name>" Expected output: draftOrder.id, draftOrder.name, draftOrder.invoiceUrl, userErrors

GraphQL Operations

# 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
    }
  }
}
# 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
    }
  }
}
# 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: <store domain>                       ║
║  Started: <YYYY-MM-DD HH:MM UTC>             ║
╚══════════════════════════════════════════════╝

After each step, emit:

[N/TOTAL] <QUERY|MUTATION>  <OperationName>
          → Params: <brief summary of key inputs>
          → Result: <count or outcome>

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:               <name>
  Refund ID:           <id>
  Amount refunded:     <amount> <currency>
  Replacement draft:   <draft order name or "none">
  Errors:              0
  Output:              none
══════════════════════════════════════════════

For format: json, emit:

{
  "skill": "refund-and-reorder",
  "store": "<domain>",
  "started_at": "<ISO8601>",
  "completed_at": "<ISO8601>",
  "dry_run": false,
  "steps": [
    { "step": 1, "operation": "OrderForRefund", "type": "query", "params_summary": "order <id>", "result_summary": "<status>", "skipped": false },
    { "step": 2, "operation": "RefundCreate", "type": "mutation", "params_summary": "<n> line items, reason: <reason>", "result_summary": "refund <id>", "skipped": false },
    { "step": 3, "operation": "DraftOrderCreate", "type": "mutation", "params_summary": "<n> line items, customer <id>", "result_summary": "draft <name>", "skipped": false }
  ],
  "outcome": {
    "order_name": "<name>",
    "refund_id": "<id>",
    "amount_refunded": "<amount>",
    "currency": "<currency>",
    "draft_order_name": "<name or null>",
    "draft_order_invoice_url": "<url or null>",
    "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

ErrorCauseRecovery
refundableQuantity is 0Line item already fully refundedCheck order refund history
userErrors from refundCreateInvalid refund amounts or order not refundableCheck displayFinancialStatus — must not be REFUNDED
userErrors from draftOrderCreateInvalid line items or customerVerify product variants still exist
Order not foundInvalid order GIDUse 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.

Signals

GitHub stars
187
Forks
18
Last commit
Aug 2026

ahel review

  • S4info
    community integration — published by 40rty-ai, not shopify

Automated review, not a security audit. Ruleset v1.

Advanced
Catalog kind
skill
Gateway key
shopify-admin-refund-and-reorder
Source
github.com/40rty-ai/shopify-admin-skills