Order editing and a low-stock badge look like unrelated features. One lets a customer fix their own order after checkout. The other puts "Only 3 left" under an item in Shopify checkout. When we built both into Smart Checkout Widgets this autumn, they ended up with the same rule: if the app can't confirm something with Shopify at that moment, it shows nothing and changes nothing.
This post is the build side. It's for store owners deciding whether to trust an app with their orders, and for developers building something like it. Smart Checkout Widgets is our app, so take this as our account of our own design choices. The merchant setup guides are on the app's site: letting customers edit their own orders and showing stock levels without faking scarcity.

Why both features refuse by default
A refused edit costs the shopper one email to the store, while a wrong one costs the merchant a refund that shouldn't have gone out or a parcel sent to the old flat. Made-up stock counts cost trust, and in the UK they can cost more: since April 6, 2025 the CMA can fine businesses up to 10% of global turnover for misleading availability claims. Given that, every rule below leans towards saying no.
How a checkout stock badge gets a real number
A checkout UI extension can't read stock by itself. The Storefront API token it gets lacks the unauthenticated_read_product_inventory scope, so quantityAvailable isn't there to ask for.
So the extension sends the cart's variant IDs to our server with the checkout session token. The server verifies the token, checks the store is on the Pro plan, and reads inventoryQuantity through the Admin API with the shop's own access. Before any number goes back, it has to pass this function:
// The count a buyer may be told, or null when there is nothing honest to say.
export function sellableQuantity(variant) {
if (!variant) return null;
if (variant.inventoryItem?.tracked !== true) return null;
if (variant.inventoryPolicy !== 'DENY') return null;
const quantity = variant.inventoryQuantity;
if (typeof quantity !== 'number' || !Number.isFinite(quantity) || quantity <= 0) return null;
return quantity;
}- ✓Inventory has to be tracked. An untracked variant has no count to report.
- ✓The policy has to be DENY, meaning the variant stops selling at zero. A variant that keeps selling when out of stock has no real limit, so any number would be invented.
- ✓The count has to be a real number above zero.
Anything else comes back as null and the badge renders nothing. Errors get the same treatment: if Shopify doesn't give a clear answer, the server returns no levels at all rather than a guess. Counts are cached for 60 seconds per variant, because every line in checkout asks and a buyer moving between steps re-renders them all. That means a number can be up to a minute old, and on a busy day an item can sell out between the badge and the payment.
The merchant picks the threshold, from 1 to 1,000, and the badge only shows at or below it. It needs Shopify Plus, because Shopify only opens the checkout page itself to apps on Plus.
How self-serve order editing decides what a customer may change
The order editing block sits on the Thank you and Order status pages, which apps can extend on every Shopify plan except Starter. The block decides nothing on its own. It asks the server what this order allows and renders exactly that. The rules live on the server, and they read Shopify's current view of the order on every request, so an order that started fulfilling or got cancelled a second ago is locked.
Proving the order belongs to the person editing it
When an order comes in, the orders/create webhook opens an edit window and stores a SHA-256 hash of the order's checkout token. Only the buyer's browser has that token, and every edit request has to present it. On the Order status page the customer is signed in, so they also have to be the customer on the order. Any failure looks exactly like "editing not offered", which leaves nothing to probe. Orders without a checkout token, such as POS sales, draft orders and imports, never get a window.
The edit window and the fulfillment hold
The window runs from 15 minutes to 24 hours after the order is placed, with 30 minutes as the default. We stopped at a day because a longer hold starts delaying real shipping. With the hold switched on, the app calls fulfillmentOrderHold on each open fulfillment order, so the warehouse or 3PL can't ship the original version. A worker runs once a minute and releases holds whose window has ended, and the merchant can release one by hand from the order page.
Holds and size swaps need extra permissions: write_order_edits and write access to fulfillment orders. The app asks for them on its Order editing page, never at install, so a store that doesn't use the feature never grants them.
What each change does in Shopify
- ✓Address: an orderUpdate with the country and state or province locked. Shopify doesn't recalculate shipping, tax or duties when an address changes, so a new state could leave the order with the wrong ones.
- ✓Lower a quantity: the app first asks Shopify for a suggestedRefund, the same calculation the Refund button in the admin uses, so tax, discounts and split payments come out right. Then it creates the refund. Paid orders only.
- ✓Swap a size or colour: an order edit that adds the new variant and sets the old line to zero. The app compares the recalculated total with the original, and if it differs by a cent or anything is left to pay, it never commits. An uncommitted edit leaves the order exactly as it was.
- ✓Cancel: orderCancel, which Shopify runs as a background job. The app checks for a few seconds until the order shows as cancelled, so the customer is told what actually happened.
When the app hands the decision back to the merchant
Refunding part of an order that used a discount is where self-serve editing goes wrong. A buy X get Y or spend-over discount could stay on the order after the item that earned it has been refunded. So on any order with a discount or one of the app's free gifts, the customer gets a Request removal button instead. It creates one of Shopify's requested order edits, an API added in version 2026-10, and the merchant accepts or declines it in the admin. A customer can have one request open at a time. Gift cards, subscription lines and the app's own gift lines can't be edited at all.
Where the two features meet
Swaps only offer variants that are in stock. A customer swapping into a medium after checkout can't take it below zero, so the low-stock badge the next buyer sees on that medium is still counting real units.
If you are building this yourself
Most of this applies to any custom app that touches orders or shows stock in checkout. These are the decisions we'd make again:
- ✓Keep the rules on the server and let the extension render only what the server allows. Anyone can inspect an extension's code.
- ✓Read the order fresh from Shopify on every request. A cached order is how you end up refunding one that was already cancelled.
- ✓Let Shopify do the money maths with suggestedRefund and the calculated order. Don't compute tax yourself.
- ✓Ask for sensitive scopes on the page where the feature lives, not at install.
- ✓When the answer is unclear, show nothing.
If you'd rather have someone build it for your store, that's the kind of custom Shopify development we take on.
Order editing and the stock urgency badge are part of the Smart Checkout Widgets Pro plan, $99 a month with unlimited orders and a 7-day free trial. Order editing works on every Shopify plan except Starter; the checkout badge needs Plus.
See Smart Checkout Widgets →



