0

Refund Order

by
Published Nov 8, 2023

Refund line items and/or shipping on an order to the original payment method.

Script shopify Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 2 hours ago
1
//native
2

3
/**
4
 * Refund Order
5
 * Refund line items and/or shipping on an order. The amount is computed from the chosen items (plus shipping) and refunded to the original payment method. restock_type is RETURN (back to stock at location_id), CANCEL (unfulfilled items) or NO_RESTOCK.
6
 */
7
export async function main(
8
  auth: RT.Shopify,
9
  order_id: string,
10
  line_items:
11
    | {
12
        line_item_id: string
13
        quantity: number
14
        restock_type?: "RETURN" | "CANCEL" | "NO_RESTOCK"
15
        location_id?: string
16
      }[]
17
    | undefined,
18
  full_shipping_refund: boolean | undefined,
19
  shipping_amount: number | undefined,
20
  note: string | undefined,
21
  notify: boolean | undefined
22
) {
23
  const orderId = order_id.startsWith("gid://")
24
    ? order_id
25
    : `gid://shopify/Order/${order_id}`
26
  const gid = (value: string, type: string) =>
27
    value.startsWith("gid://") ? value : `gid://shopify/${type}/${value}`
28

29
  const endpoint = `https://${auth.store_name}.myshopify.com/admin/api/2026-10/graphql.json`
30
  const headers = {
31
    "X-Shopify-Access-Token": auth.token,
32
    "Content-Type": "application/json",
33
    Accept: "application/json",
34
  }
35
  const refundLineItems = line_items?.length
36
    ? line_items.map((item) => ({
37
        lineItemId: gid(item.line_item_id, "LineItem"),
38
        quantity: item.quantity,
39
        restockType: item.restock_type || "NO_RESTOCK",
40
        locationId: item.location_id
41
          ? gid(item.location_id, "Location")
42
          : undefined,
43
      }))
44
    : undefined
45
  const shipping = full_shipping_refund
46
    ? { fullRefund: true }
47
    : shipping_amount
48
      ? { amount: shipping_amount }
49
      : undefined
50

51
  // Let Shopify compute the refundable amount and the parent transactions to refund against.
52
  const suggestedResponse = await fetch(endpoint, {
53
    method: "POST",
54
    headers,
55
    body: JSON.stringify({
56
      query: `query ($id: ID!, $refundLineItems: [RefundLineItemInput!], $shippingAmount: Money, $refundShipping: Boolean) { order(id: $id) { suggestedRefund(refundLineItems: $refundLineItems, shippingAmount: $shippingAmount, refundShipping: $refundShipping) { suggestedTransactions { gateway kind amountSet { shopMoney { amount } } parentTransaction { id } } } } }`,
57
      variables: {
58
        id: orderId,
59
        refundLineItems,
60
        shippingAmount: shipping?.amount,
61
        refundShipping: shipping?.fullRefund,
62
      },
63
    }),
64
  })
65
  if (!suggestedResponse.ok) {
66
    throw new Error(
67
      `${suggestedResponse.status} ${await suggestedResponse.text()}`
68
    )
69
  }
70
  const suggested = await suggestedResponse.json()
71
  if (suggested.errors) {
72
    throw new Error(JSON.stringify(suggested.errors))
73
  }
74
  const transactions =
75
    suggested.data.order.suggestedRefund.suggestedTransactions.map(
76
      (t: any) => ({
77
        orderId,
78
        parentId: t.parentTransaction?.id,
79
        gateway: t.gateway,
80
        kind: "REFUND",
81
        amount: t.amountSet.shopMoney.amount,
82
      })
83
    )
84

85
  const response = await fetch(endpoint, {
86
    method: "POST",
87
    headers,
88
    body: JSON.stringify({
89
      query: `mutation ($input: RefundInput!, $idempotencyKey: String!) { refundCreate(input: $input) @idempotent(key: $idempotencyKey) { refund { id legacyResourceId createdAt note totalRefundedSet { shopMoney { amount currencyCode } } } order { id name displayFinancialStatus totalRefundedSet { shopMoney { amount currencyCode } } } userErrors { field message } } }`,
90
      variables: {
91
        input: {
92
          orderId,
93
          refundLineItems,
94
          shipping,
95
          transactions,
96
          note: note || undefined,
97
          notify: notify || false,
98
        },
99
        // Required on refundCreate since 2026-04; a fresh key per run (no automatic retries here).
100
        idempotencyKey: crypto.randomUUID(),
101
      },
102
    }),
103
  })
104

105
  if (!response.ok) {
106
    throw new Error(`${response.status} ${await response.text()}`)
107
  }
108

109
  const { data, errors } = await response.json()
110
  if (errors) {
111
    throw new Error(JSON.stringify(errors))
112
  }
113

114
  if (data.refundCreate.userErrors.length) {
115
    throw new Error(JSON.stringify(data.refundCreate.userErrors))
116
  }
117

118
  return data.refundCreate
119
}
120

Other submissions
  • Submitted by hugo697 Typescript (fetch-only)
    Created 528 days ago
    1
    type Shopify = {
    2
      token: string;
    3
      store_name: string;
    4
    };
    5
    /**
    6
     * Creates a refund
    7
     *  Caution For multi-currency orders, the currency property is required whenever the amount property is provided. For more information, see Migrating to support multiple currencies.  Creates a refund. Use the calculate endpoint to produce the transactions to submit.   Note When you use this endpoint with a Partner development store or a trial store, you can create only five refunds per minute.
    8
     */
    9
    export async function main(
    10
      auth: Shopify,
    11
      api_version: string = "2023-10",
    12
      order_id: string,
    13
      body: {
    14
        refund?: {
    15
          currency?: string;
    16
          shipping?: { amount?: number; [k: string]: unknown };
    17
          transactions?: {
    18
            amount?: number;
    19
            gateway?: string;
    20
            kind?: string;
    21
            parent_id?: number;
    22
            [k: string]: unknown;
    23
          }[];
    24
          [k: string]: unknown;
    25
        };
    26
        [k: string]: unknown;
    27
      }
    28
    ) {
    29
      const url = new URL(
    30
        `https://${auth.store_name}.myshopify.com/admin/api/${api_version}/orders/${order_id}/refunds.json`
    31
      );
    32
    
    
    33
      const response = await fetch(url, {
    34
        method: "POST",
    35
        headers: {
    36
          "Content-Type": "application/json",
    37
          "X-Shopify-Access-Token": auth.token,
    38
        },
    39
        body: JSON.stringify(body),
    40
      });
    41
      if (!response.ok) {
    42
        const text = await response.text();
    43
        throw new Error(`${response.status} ${text}`);
    44
      }
    45
      return await response.json();
    46
    }
    47