An API refund on Square creates a return order with a single CUSTOM_AMOUNT line that names no item and breaks out no tax. Your app decides the amount, remembers which item it was for, puts the unit back in stock, and keeps the tax records Square's reports won't. On Flint the refund names the order's line item, and Flint computes the rest:
curl -X POST https://api.withflintpay.com/v1/refunds \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: refund-ord-1042-mug" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ord_1kmn0aExample",
"reason": "defective_product",
"line_items": [
{"order_line_item_id": "li_1kmn0aExample", "quantity": 1}
]
}'
Which path applies to you
What Square supports, by surface
| Square surface | Refund specific items | What the refund order records |
|---|
| Square Point of Sale app | Yes | item_type: ITEM, the catalog item, and its tax and discounts |
| Square Dashboard | Yes | item_type: ITEM, the catalog item, and its tax and discounts |
| Refunds API (RefundPayment) | No: an amount against one payment | One CUSTOM_AMOUNT line with no catalog item |
| Orders API | No: Order.returns is read-only | Reads returns that the app or Dashboard created |
The Orders API row is where most confusion starts. Square's returns page says an application "can use the Orders API for itemized refunds." A developer who tried every route in September 2026 found that Order.returns is read-only, so CreateOrder won't accept a return, and that RefundPayment has no order_id to link a refund to one. The Square staff reply said that sentence describes what an itemized refund looks like once it exists, and that the Point of Sale app can create one because "it drives an internal flow that isn't publicly exposed." Square staff have called itemized refunds a popular feature request since 2024.
The Square workaround: refund an amount, keep the item record yourself
Your app has to do four jobs Square does for itemized refunds in its own apps: work out the amount, refund it, record what it was for, and restock. Start from the order. Each line's total_money already includes its share of order discounts and its tax, so divide that by the quantity, in integer cents:
// Your code works out what one unit cost the buyer.
// total_money is read-only and already includes the line's share of
// order discounts and its tax. quantity is a string.
const { order } = await getOrder(orderId); // GET /v2/orders/{order_id}
const line = order.line_items.find((li) => li.uid === lineUid);
const lineTotal = Number(line.total_money.amount); // 3818 for three mugs
const units = Number(line.quantity); // 3
const base = Math.floor(lineTotal / units); // 1272
const remainder = lineTotal - base * units; // 2 cents left over
// Give the leftover cents to the first units refunded, and check your own
// ledger so this unit hasn't been refunded already.
const alreadyRefunded = await refundedUnits(orderId, lineUid);
const amount = alreadyRefunded < remainder ? base + 1 : base; // 1273
Then refund that amount against the payment. The reason field, up to 192 characters, is the only place on the refund to note the item:
curl https://connect.squareup.com/v2/refunds \
-X POST \
-H "Square-Version: 2026-09-16" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "refund-order-1042-mug-unit-1",
"payment_id": "PAYMENT_ID",
"amount_money": {"amount": 1273, "currency": "USD"},
"reason": "Mug arrived chipped (line 8uSwfzvUImn3IRrvciqlXC, 1 of 3)"
}'
The refund comes back with an order_id for a new refund order. Its return line, abridged here, has no catalog item and says nothing about the mug:
"returns": [
{
"source_order_id": "ORIGINAL_ORDER_ID",
"return_line_items": [
{
"quantity": "1",
"item_type": "CUSTOM_AMOUNT"
}
]
}
]
That leaves three more pieces your app owns from now on:
- A refund ledger keyed by order, line, and unit, so the same item can't be refunded twice and partial refunds add up to the line total. Square only checks the payment's remaining balance.
- A restock call. A refund moves money only. Add the unit back with a
BatchChangeInventory adjustment from UNLINKED_RETURN to IN_STOCK, which Square records as new stock rather than a return of that sale. - Tax records. The return order shows no tax refunded, so the tax you gave back lives in your ledger, and your filing comes from there instead of Square's reports.
The other workaround: refund in Square, then read the refund order
When staff can do the refund, the Square staff reply in the forum suggests the reverse flow: staff refund the items in Square Point of Sale or the Dashboard, and your app syncs from the refund.created and refund.updated webhooks. To see which items came back, retrieve the refund, then the order in its order_id. That refund order, not the original sale, holds the itemized returns. Square staff noted in 2025 that "not all refunds will be itemized," so the code has to handle CUSTOM_AMOUNT returns as well. This keeps the tax and item detail right, and it means your own app can never issue the refund.
The four places hand-built Square item refunds go wrong
Line-item refunds on Flint
Flint is a payments API with orders built in, and cards are processed on Stripe. Because every payment belongs to an order, a refund can name what it is for. Send the order's order_line_item_id with a quantity, as in the first request above, or with an amount_money for a price adjustment. Flint computes the refund from what the line sold for and returns the arithmetic in line_item_allocations:
"line_item_allocations": [
{
"order_line_item_id": "li_1kmn0aExample",
"quantity": 1,
"refunded_money": {"amount": 1273, "currency": "USD"},
"tax_refund_mode": "automatic",
"automatic_refund": {
"subtotal_money": {"amount": 1299, "currency": "USD"},
"discount_money": {"amount": 130, "currency": "USD"},
"tax_money": {"amount": 104, "currency": "USD"},
"total_money": {"amount": 1273, "currency": "USD"}
}
}
]
The subtotal, the item's share of the order discount, and the tax that comes back are all on the refund, so reports and accounting read the item from Flint. Each line keeps its own refunded_quantity and refunded_money. Refunding the same unit twice fails with LINE_ITEM_REFUND_QUANTITY_EXCEEDS_REFUNDABLE instead of succeeding while the payment still has a balance. Shipping and other order charges are refunded the same way, by order_charge_id.
To keep a restocking fee, add an adjustment to the same line:
curl -X POST https://api.withflintpay.com/v1/refunds \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: refund-ord-1042-mug-restock" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ord_1kmn0aExample",
"reason": "customer_changed_mind",
"line_items": [
{
"order_line_item_id": "li_1kmn0aExample",
"quantity": 1,
"refund_adjustments": [
{
"adjustment_type": "restocking_fee",
"applies_to": "none",
"amount_money": {"amount": 200, "currency": "USD"},
"reason": {"code": "restocking_policy"}
}
]
}
]
}'
When the item comes back: a Return restocks it
A refund on Flint moves money and never touches stock, as on Square. The difference is that Flint has a Return for merchandise that comes back. It applies your return policy, records what arrived, refunds the item, and puts it back on sale at the location you name. At a counter that is two calls:
# 1. Open the return for the item the buyer brought back
curl -X POST https://api.withflintpay.com/v1/returns \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: return-ord-1042-create" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ord_1kmn0aExample",
"line_items": [{
"order_line_item_id": "li_1kmn0aExample",
"requested_quantity": 1,
"return_reason_id": "rrsn_1T6HXAX0CEXP6YA5K1T392KJE6"
}]
}'
# 2. Receive it, refund it, and put it back on sale in one call
curl -X POST https://api.withflintpay.com/v1/returns/ret_1kmn0aExample/process \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: return-ord-1042-process" \
-H "Content-Type: application/json" \
-d '{
"completion_behavior": "complete_when_ready",
"receipt": {
"receiving_location_id": "loc_1kmn0aExample",
"source_system": {"source_system_type": "pos", "external_source_id": "store-1042"},
"received_at": "2026-10-15T14:30:00Z"
},
"line_items": [{
"return_line_item_id": "retli_1kmn0aExample",
"decision": {
"decision_basis": "explicit",
"approved_quantity": 1,
"return_required_quantity": 1,
"allowed_resolution_types": ["refund"],
"selected_resolution_type": "refund",
"resolution_mode": "automatic",
"refund_timing": "after_receipt",
"is_inspection_required": false,
"receiving_location_id": "loc_1kmn0aExample"
},
"received_quantity": 1,
"resolution": {"resolution_type": "refund", "quantity": 1}
}]
}'
With no disposition in the request, a received item goes back as sellable and Flint writes the inventory receipt against that location, linked to the return line. For mail-in returns, buyers can start a return from their Flint account, and a warehouse key can record arrivals without the right to refund. Exchanges for another size are a resolution on the same Return.
Square API and Flint item refunds, side by side
| Square Refunds API | Flint Refunds API |
|---|
| Refund one unit of an item | You compute the amount and refund it | line_items with a quantity |
| Item's discount and tax share | You compute it from total_money | Computed and returned on the refund |
| What the refund records | One CUSTOM_AMOUNT line, tax not itemized | The line, quantity, discount, and tax |
| Same item refunded twice | Allowed while the payment has a balance | Rejected per line |
| Restocking fee | Refund a smaller amount and note it | A restocking_fee adjustment |
| Back in stock | Your adjustment, recorded as new stock | A Return disposition, linked to the sale |
| Exchanges | Square products only | An exchange resolution on a Return |
Who Flint is built for
Flint is for US businesses that sell on their own website or app and want orders, catalog and inventory, automatic US sales tax, shipping and pickup, returns, and refunds behind one API, paid in US dollars. Buyers can pay from anywhere with a card. Flint handles online and in-app payments only, with no card readers. The Square migration guide maps Square's orders, payments, subscriptions, invoices, and refunds to Flint.
Questions, answered
Can the Square API refund a single item?
No. Square's docs say the Refunds API doesn't support itemized refunds, and RefundPayment takes an amount and a payment ID with no line item field. A Square staff member wrote on the developer forum in September 2026 that itemized returns aren't possible via the API today. Sellers can refund specific items in Square Point of Sale and the Dashboard.
Does the Square Orders API support itemized refunds?
Not for creating them. Square's returns page says an application can use the Orders API for itemized refunds, but a Square staff member clarified in September 2026 that the sentence describes what the returns field looks like when an itemized refund already exists. Order.returns is read-only, so CreateOrder can't create a return.
What does a Square API refund create?
A refund order. The refund's order_id points to it, and its returns field holds one return line with item_type CUSTOM_AMOUNT and no catalog item. A refund made with specific items in Point of Sale or the Dashboard has item_type ITEM, the catalog_object_id, and the item's tax instead.
How do I refund one item with the Square API anyway?
Read the order, take the line's total_money (after its discount and tax) divided by its quantity, and refund that amount with RefundPayment. Record which item the refund was for in your own database, add the unit back to stock with a BatchChangeInventory adjustment, and keep your own tax ledger, because Square's reports won't show the item or its tax as refunded.
Does refunding through the Square API restock inventory?
No. A refund moves money only. The RETURNED_BY_CUSTOMER inventory state is read-only to the Inventory API, so an app restocks with an adjustment from UNLINKED_RETURN to IN_STOCK, which Square records as new stock.
Which payments API refunds by line item?
Flint does. POST /v1/refunds takes the order's line item ID and a quantity or amount, computes the item's share of discounts and tax, and caps each line at what is left on it. A Return on the same order refunds the item and puts it back in stock at the location you name.
Is Flint a good alternative to Square for online orders?
For US businesses selling online or in an app, yes: orders, catalog, inventory, automatic sales tax, returns, and line-item refunds come with the payments API, with cards processed on Stripe. Flint doesn't sell card readers or in-person payments, so in-store sales stay on your current point of sale.
Sources
All sources accessed October 15, 2026.