In Shopify GraphQL Admin API, we have a use case where an item becomes ₹0 after applying a BXGY (Buy X Get Y) discount. Is there a way to refund an amount against such a line item via GraphQL, given that its final price is zero?

We have a use case in Shopify GraphQL Admin API where a line item becomes ₹0 after applying a BXGY (Buy X Get Y) discount. We would like to issue a refund against this item (for example, in case of returns or adjustments). Since the line item’s final price is zero, is there any supported way via GraphQL to refund an amount tied to that item, or any recommended workaround to handle such scenarios?

Hey @Anubhav_Kaushik! Yes, you can include a $0 BXGY line item in refundCreate. The mutation calculates refund amounts from the discounted price, so the system will calculate a 0 refund for that item. You can still include it in refundLineItems for tracking and restocking purposes.

I tested this on a dev store with a 100% discounted line item (simulating BXGY at 0). Both suggestedRefund and refundCreate handled it without errors. The refund record was created, the order stayed in PAID status, and no money moved. Here’s the mutation that worked:

mutation {
  refundCreate(input: {
    orderId: "gid://shopify/Order/ORDER_ID"
    refundLineItems: [
      {
        lineItemId: "gid://shopify/LineItem/LINE_ITEM_ID"
        quantity: 1
        restockType: RETURN
      }
    ]
    transactions: []
  }) {
    refund {
      id
    }
    userErrors {
      field
      message
    }
  }
}

When transactions is empty, the system auto-determines the refund amount (0 in this case). For restockType, use RETURN if the item was fulfilled, CANCEL if it wasn’t, or NO_RESTOCK if you don’t need inventory changes.

HI Donald

In my case i want to refund more than 0 . I want to calculate refund amount based on a custom logic.

Got it, so you want to refund a custom amount (not the system-calculated 0) against that BXGY line item. That’s doable with refundCreate, you just need to pass an explicit transactions array instead of leaving it empty.

When you pass transactions: [], the system auto-calculates the refund amount from the line item’s discounted price, which gives you 0 for a BXGY item. If you specify a transaction with your own amount, the system uses that instead. You’ll still include the line item in refundLineItems for tracking and restocking purposes. Here’s what that looks like:

mutation RefundBXGYItem($input: RefundInput!, $idempotencyKey: String!) {
  refundCreate(input: $input) @idempotent(key: $idempotencyKey) {
    refund {
      id
      totalRefundedSet {
        presentmentMoney {
          amount
          currencyCode
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

{
  "input": {
    "orderId": "gid://shopify/Order/ORDER_ID",
    "refundLineItems": [
      {
        "lineItemId": "gid://shopify/LineItem/LINE_ITEM_ID",
        "quantity": 1,
        "restockType": "RETURN"
      }
    ],
    "transactions": [
      {
        "parentId": "gid://shopify/OrderTransaction/PARENT_TRANSACTION_ID",
        "amount": "50.00",
        "kind": "REFUND",
        "gateway": "your_gateway",
        "orderId": "gid://shopify/Order/ORDER_ID"
      }
    ]
  },
  "idempotencyKey": "a-unique-uuid-per-request"
}

The parentId should be the ID of the original SALE or CAPTURE transaction on the order (query the order’s transactions field to find it). Set amount to whatever your custom logic calculates. This works as long as the total refunded doesn’t exceed the total captured on the order. If it needs to exceed that, add allowOverRefunding: true to the input.

One thing to note on the @idempotent directive in the example above. It’s required starting in API version 2026-04 for refundCreate, so I’d recommend including it now even if you’re on an earlier version.

I tested this on a dev store with a line item discounted to 0 (with discount allocations, simulating BXGY) and a custom refund amount, and it went through without errors. That said, I tested against a manual gateway. If you’re using a live payment gateway, it’s worth confirming it handles the mismatch between line item value and refund amount gracefully since gateways can vary. Let me know how it goes!