Refunds API

List and create refunds for an order, or list the store’s refunds across all its orders. Refunds are recorded against the order and reflected in its refund_status. A refund can also put order lines back in stock.

See Webhooks to be told when a refund is created.

Endpoints


List Store Refunds

Retrieve a paginated list of the store’s refunds across all its orders, oldest first. A tool that keeps its own record of refunds, such as one that issues credit notes, can catch up on the refunds it hasn’t seen by paging after the last one it saw, and start its first sync from a date with created_after.

Endpoint: GET /api/v1/refunds/

Scope Required: refunds:read

Query Parameters

Parameter Type Description
after string Cursor for pagination. Refund public ID to return refunds after
before string Cursor for pagination. Refund public ID to return refunds before, for paging back
limit integer Number of refunds to return (default 10, max 100)
created_after string Only refunds created at or after this RFC 3339 time, such as 2026-01-01T00:00:00Z

Every page comes oldest first, whether you page forward with after or back with before. The response reports has_more, which is true when another page lies beyond this one in the direction you’re paging. after and before cannot be used together. created_after combines with either.

Request

curl -X GET "https://studio.easel.engineering/api/v1/refunds/?after=ref_d0b6fmv28q6vn14peun0" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "ref_d0b6fmv28q6vn14peun1",
      "number": 1,
      "order_id": "ord_d0b6fmv28q6vn14peun1",
      "amount": 2598,
      "tax": 0,
      "taxes": [],
      "gift_card_amount": 0,
      "reason": null,
      "restocks": [],
      "created_at": "2023-01-04T08:30:00Z"
    }
  ],
  "has_more": false
}

Error Responses

Invalid query parameter

Status: 400 Bad Request

A malformed after or before, both at once, an invalid limit, or a created_after that isn’t an RFC 3339 time returns INVALID_REQUEST_ERROR, with the offending parameter named in the error message:

{
  "error": "Invalid 'created_after' parameter: must be an RFC 3339 time, such as 2026-01-01T00:00:00Z",
  "code": "INVALID_REQUEST_ERROR"
}

Cursor not found

An after or before that names no refund of the store.

Status: 404 Not Found

{
  "error": "Resource not found",
  "code": "NOT_FOUND"
}

List Refunds

Retrieve the refunds for an order. This endpoint is not paginated.

Endpoint: GET /api/v1/orders/{order_id}/refunds/

Scope Required: refunds:read

Request

curl -X GET "https://studio.easel.engineering/api/v1/orders/ord_d0b6fmv28q6vn14peun0/refunds/" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "ref_d0b6fmv28q6vn14peun0",
      "number": 1,
      "order_id": "ord_d0b6fmv28q6vn14peun0",
      "amount": 500,
      "tax": 34,
      "taxes": [
        {
          "country": "US",
          "region": "CA",
          "name": "Sales tax",
          "rate": "7.25",
          "tax": 34
        }
      ],
      "gift_card_amount": 0,
      "reason": "Damaged item",
      "restocks": [
        {
          "order_variant_id": "orv_d0b6fmv28q6vn14peun0",
          "quantity": 1
        }
      ],
      "created_at": "2023-01-03T10:00:00Z"
    }
  ]
}

Create Refund

Refund an amount against an order. The amount must be greater than zero and is denominated in the store’s smallest currency unit. When the order collected tax, the refund gives back the same share of each jurisdiction’s tax as it does of the order’s total, which the refund’s tax reports.

Orders that bought gift cards

A refund of an order that bought gift cards comes out of the rest of the order first: its other lines, shipping, gift option, and tax. Refunding a returned item never touches a gift card. Past that, the refund gives back the cards’ price and takes it back off them, in the same step, so it can’t be spent again.

By default it gives back only what’s left unspent on the cards, since the buyer already had the rest. Refunding more is a 400 with INVALID_FIELD on amount. With refund_spent_gift_cards set to true it can give back everything not yet refunded, and empties and disables every card the order bought. Each card’s transactions show what a refund took back as returned.

Gift cards carry no tax, so only the rest of the order gives back any.

To put units back in stock, list them in restocks. Restocking is opt-in: without restocks the refund changes no stock, which suits an amount-only refund such as a goodwill credit. Each restocked unit adds one to the variant’s stock and is recorded on the refund. Across all of an order’s refunds, a line can be restocked at most as many units as were ordered, so retrying a request can’t put the same units back twice. Digital products have no stock and can’t be restocked. A restock that brings a variant back into stock emails the shoppers on its restock waitlist, the same as raising the stock directly.

Restocks are checked before any money moves: an invalid restock rejects the whole request and nothing is refunded.

Refunds made outside Easel, such as in the Stripe dashboard, or lost disputes are recorded on the order from Stripe’s webhook but never restock, since Easel can’t know whether the goods came back.

When a gift card paid part of the order, the refund goes back to the buyer’s card first, up to what was charged to it, and the rest back onto the gift card, which needs no Stripe refund. A refund of an order a gift card paid in full goes wholly back onto the card.

Endpoint: POST /api/v1/orders/{order_id}/refunds/

Scope Required: refunds:write

Request Body

{
  "amount": 500,
  "reason": "Damaged item",
  "restocks": [
    {
      "order_variant_id": "orv_d0b6fmv28q6vn14peun0",
      "quantity": 1
    }
  ]
}
Field Type Required Description
amount integer Yes Refund amount in the store’s smallest currency unit (must be greater than zero)
reason string No Reason for the refund
restocks array No Order lines to put back in stock (see below). Omit to restock nothing
refund_spent_gift_cards boolean No Refund the full price of gift cards the order bought, even what was spent of them, which empties and disables them. Omitted or false, a refund gives back only what’s left on them (see below)

Each restocks entry:

Field Type Required Description
order_variant_id string Yes The line’s order_variant_id from the order’s items; each line at most once
quantity integer Yes Units to put back in stock; 0 restocks nothing. At most the line’s quantity less any units earlier refunds restocked

Request

curl -X POST "https://studio.easel.engineering/api/v1/orders/ord_d0b6fmv28q6vn14peun0/refunds/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-12345" \
  -d '{
    "amount": 500,
    "reason": "Damaged item"
  }'

Response

Status: 201 Created

The response body is empty.

Error Responses

Invalid amount

Status: 400 Bad Request

{
  "error": "Amount must be greater than zero",
  "code": "INVALID_FIELD"
}

Amount exceeds the refundable balance, or the order isn’t paid

Status: 400 Bad Request

{
  "error": "Amount exceeds the order's refundable balance",
  "code": "INVALID_FIELD"
}

Invalid restock

A restock that names a line not on the order, names a line twice, has a negative quantity, names a digital product, or asks for more units than the line can still take.

Status: 400 Bad Request

{
  "error": "Restock quantity exceeds the units ordered, less any already restocked",
  "code": "INVALID_FIELD"
}

Order not found

Status: 404 Not Found

{
  "error": "Resource not found",
  "code": "NOT_FOUND"
}

Refund Object

Fields

Field Type Description
id string Refund public ID
number integer Refund number within the order
order_id string Public ID of the refunded order
amount integer Refund amount in the store’s smallest currency unit
tax integer The part of amount that gave back the order’s tax, in proportion to the share of the order refunded
taxes array tax broken down by the order’s jurisdictions, as the order’s taxes name them; empty when the order collected no tax. See Refund Tax Object
gift_card_amount integer Part of amount put back on the order’s gift card rather than its card
reason string|null Reason for the refund
restocks array Units the refund put back in stock; empty when it restocked nothing
created_at string ISO 8601 timestamp

Refund Tax Object

Field Type Description
country string ISO 3166-1 alpha-2 country code
region string|null Subdivision code, such as CA for California, or null for a whole country
name string Name of the tax, such as VAT or Sales tax
rate string Rate as a percentage, such as "23"
tax integer Tax given back in the store’s smallest currency unit

Refund Restock Object

Field Type Description
order_variant_id string The restocked order line
quantity integer Units put back in stock