Need line-item data from a customer's self-serve cancellation request before it's approved

Hi everyone!

I’m trying to build a solution that reacts to when a customer has submitted a self-serve cancellation request. I need this so that I can, as quickly as possible, let a distributor know not to handle the order – it can’t wait till the cancellation has been approved, as the distributor gets orders ready quite fast and sometimes orders come in during the night when there is no one to approve the cancellation request.

I’ve found a solution in using Order.events (a BasicEvent with action: "requested_edit_requested"), but this method only tells me that a cancellation request was submitted for the order as a whole – not which line items or quantities the customer flagged.

I’ve spent a lot of time on this, but I keep hitting dead ends. What I’ve ruled out so far, with evidence:

  • FulfillmentOrder.requestStatus / the REST CancellationRequest resource – Shopify’s own docs confirm this represents “a cancellation request made by the merchant or an order management app to a fulfillment service,” i.e. merchant→3PL, not customer-initiated. Confirmed live: an order actively showing the customer banner had requestStatus: "UNSUBMITTED" on its only fulfillment order.
  • Order.returnStatus / Order.returns – came back NO_RETURN / [] on the same order, despite the active banner. Not it.
  • Order.cancellation (OrderCancellation type) – only exposes a single staffNote field. Not it.
  • Webhook topics – nothing dedicated exists. fulfillment_orders/cancellation_request_submitted and siblings are explicitly the merchant/app→3PL flow again, confirmed by their own docs description.

The only trace I’ve found anywhere is Order.events, specifically a BasicEvent with action: "requested_edit_requested" (and later action: "requested_edit_resolved" once a staff member closes the request out). But its message is just human-readable text (“X requested cancellation of N items”), and its arguments/additionalData only contain {"customer_name": "..."} – no line item IDs, SKUs, or quantities.

Is there genuinely no structured, item-level way to read this via the Admin API today? Is it on a roadmap anywhere? Has anyone found an undocumented field, or a workaround (e.g. via the Customer Account API, or correlating checkout/cart tokens some other way)? Any pointers appreciated – happy to share more of what I’ve tried.

Hey @Jonas_Skafte, can you share more details about the order status when it’s cancelled. Since you mention the distributer fills orders really fast, are the fulfillment orders already requested when it’s cancelled?

Hi @KyleG-Shopify – thanks for the quick reply!

A couple of relevant details:

My distributor isn’t a registered Shopify fulfillment service, so I’m not using FulfillmentOrder’s request/accept/reject flow with them. A separate automation reads new orders via the Admin GraphQL API and sends the details to the distributor directly, outside Shopify’s fulfillment lifecycle. So fulfillmentOrders[].requestStatus stays UNSUBMITTED throughout – it never reflects the real state with the distributor.

On the order I tested against, the timeline was:

  • Order placed: 21:22
  • My integration processed it: 21:23
  • Customer’s cancellation request: 21:24

So the order is typically already with the distributor by the time a cancellation request can exist. Orders also get “locked” there a couple of hours after receipt – if we don’t act on a cancellation request before then, we end up calling them to check whether it’s too late.

Two things that would help a lot:

  1. A webhook for when a cancellation is requested.
  2. Line-item-specific data via GraphQL, so partial cancellations don’t require zeroing the whole order.

Hope that’s possible, even partly. Thanks!