POS UI extensions / 2026-10Breaking change

Cart API writes
now reject unless POS confirms them

Until now, mutations resolved as successful even when the cart didn't actually change. Starting with 2026-10, the promise rejects when POS can't confirm the write, so every call site needs error handling.

On this page
  1. What's changing (in 30 seconds)
  2. How it works: 2026-07 and earlier vs. 2026-10
  3. Affected Cart API mutations
  4. The 2 rejection messages
  5. Which apps are affected and which aren't
  6. Migration steps and code examples
  7. 5 key points for developers
  8. 3 business use cases
  9. One-line summary for proposals

1What's changing

POS returns a result for every cart write, and the only result that confirms the cart changed is a success result.
Starting with API version 2026-10, Cart API mutations will reject unless POS confirms the write. Dropped writes that used to go unnoticed now surface as errors for the caller.

2026-07 and earlier: resolves regardless of outcome

Mutations resolve whether or not POS applied the write. Apps can't tell applied writes from dropped ones, so they may show a fee or discount as "applied" even though the cart hasn't changed.

2026-10: rejects if unconfirmed

Mutations resolve only when POS confirms the write. Otherwise they reject, so the app can respond right away by retrying, showing staff a message, or rolling back its own state.

2How it works: 2026-07 and earlier vs. 2026-10

2026-07 Before 2026-10 After cart mutation e.g. applyCartDiscount POS Applied or dropped Always resolves Regardless of outcome Dropped writes go unnoticed Shows "discount applied" but the cart hasn't changed cart mutation e.g. applyCartDiscount POS Returns a result success → resolve Cart change confirmed Unconfirmed → reject Two types of messages Handle at the call site Retry Notify staff Roll back state
Why it matters : Today, dropped cart writes happen silently, so they go unnoticed. Rejecting them turns this silent data loss into an error the caller can see.

3Affected Cart API mutations

Mutations that reject unconfirmed writes in 2026-10 (15)

Cart & line items
bulkCartUpdate removeLineItem
Cart discounts
applyCartDiscount addCartCodeDiscount removeAllDiscounts
Customer
setCustomer removeCustomer
Line item properties
addLineItemProperties bulkAddLineItemProperties removeLineItemProperties
Line item discounts
setLineItemDiscount bulkSetLineItemDiscounts removeLineItemDiscount
Selling plans
addLineItemSellingPlan removeLineItemSellingPlan

Note: These categories were added on this page for readability and aren't in the original article.

New in 2026-10

NEW
updateLineItemQuantity

These mutations are new in 2026-10 and have rejected unconfirmed writes since their first release. No version with the old behavior exists.

4The two rejection messages

Rejected (cart unchanged)
POS refused the cart update. The cart was not changed.

POS didn't accept the write, and the cart is unchanged. This happens when POS is no longer accepting cart changes, for example after the cashier has moved on to payment. Once the cart is editable again,a retry may succeed.

Unconfirmed (outcome unknown)
POS could not confirm the cart update.

The outcome is unknown, andthe write may have been partially applied.Re-reading the cart before retryingis required.

These two messages are specific to unconfirmed writes. Cart mutations can also be rejected for other reasons, such as an invalid discount value or a customer that can't be found. Only match on the message when you need to tell these two cases apart.
CaseCart stateRecommended action
refusedUnchangedRetry once the cart is editable again
could not confirmUnknown (possibly partially written)Re-read the cart, then retry
Other rejectionsNot specifiedHandle each cause separately, such as an invalid discount value or a customer that can't be found

5Affected vs. unaffected apps

Affected

Extensions declaring 2026-10 or later

api_version = "2026-10" or later: apps whose POS UI extensions call even one of the mutations above.

Not affected

Staying on 2026-07 or earlier

Current behavior continues unchanged. 2026-07 remains usable until its API versioning support period ends.

Behavior changes

Already using try/catch

Instead of continuing as if an unconfirmed write had succeeded, your existing catch / .catch() handler will now run.

The change applies per extension, not per store. It's determined by the API version each extension declares.

6Migration steps and code examples

Note: Calls that used to resolve will now reject. If you don't catch the rejection, the rest of the handler won't run. That includes cleanup, such as rendering UI after the write or clearing a loading state.
Before
await shopify.cart.applyCartDiscount('FixedAmount', 'Winter discount', '5.00');
setDiscountApplied(true);
After
try {
 await shopify.cart.applyCartDiscount('FixedAmount', 'Winter discount', '5.00');
 setDiscountApplied(true);
} catch (error) {
 setDiscountApplied(false);
 showToast('Could not update the cart. Try again before payment.');
}
1

Find every call site

Check every place in your extension that calls the affected cart mutations.

2
catch

Add rejection handling to each one

Add a try/catch or .catch() , and write code that rolls back state and shows a message.

3

api_version = "2026-10" Upgrade to

Only bump the version once error handling is in place.

If you can't migrate right away, stay on 2026-07 or earlier. You won't be affected, so you can safely upgrade once error handling is in place. If you upgrade without it, the handler will stop at the first unconfirmed write, leaving spinners stuck on screen or skipping confirmation steps.

75 key points for developers

await

1. An uncaught await halts everything after it

If a rejection isn't caught, neither post-write UI rendering nor loading-state cleanup will run. "The spinner never goes away" and "the confirmation step gets skipped" are typical symptoms. Put cleanup somewhere that also runs on errors.

Refused Unknown

2. "Refused" and "unknown" need different retry strategies

With refused, the cart hasn't changed, so you can retry as-is once it's editable again. With could not confirm, the write may have partially gone through, sore-read the cart firstbefore retrying. Retrying blindly risks applying the change twice.

3. Only branch on the message when you need to

Calls can also reject for reasons other than these two messages, such as an invalid discount value or a customer that can't be found. As a rule, catch every rejection, and only check the message when you need to tell the two cases apart.

07 10

4. The switch applies per extension

The scope is set not by the store but by each extension's api_version . Apps with multiple extensions can migrate gradually, adding error handling to one extension at a time before upgrading it.

update Qty

5. The new updateLineItemQuantity can reject from day one

Added in 2026-10, updateLineItemQuantity is designed to reject from its very first release. If you switch to this mutation, design on the assumption that a resolved call means the cart changed, and write a catch from the start.

83 practical use cases

-5.00
USE CASE 1

Stop discounts and fees showing as applied when they never took effect

Problem
When a POS extension adds a discount or fee, it can show as "applied" even though the cart hasn't changed (behavior in 2026-07 and earlier).
Solution
Wrap every call site in try/catch, and in the catch reset the flag and show a toast (see the After example in the article). Then upgrade api_version = "2026-10" .
Impact
Write failures that used to happen silently become errors staff can see, so they can retry before payment.
Technical note
In the catch, reset the UI state (e.g., setDiscountApplied(false)). Don't forget to clear the loading state too.
Rejected → Retry Unknown → Reload
USE CASE 2

Build app-wide retry handling for each type of rejection

Problem
The right way to retry depends on whether the rejection is "rejected (the cart didn't change)" or "unknown (some writes may have gone through)."
Solution
Tell them apart using the two messages. For rejected, retry once the cart is editable again. For unknown, reload the cart before retrying. Handle any other rejection based on its reason.
Impact
Avoids the double-applies that blind retries cause, while still catching cases that succeed on retry automatically.
Technical note
Only branch on the message when you need to tell these two cases apart. The default should be to catch every rejection.
10 10 07
USE CASE 3

Migrate multiple POS extensions to 2026-10 safely, one at a time

Problem
There are several extensions that modify the cart, and fixing them all at once is hard.
Solution
As each extension gets its error handling, upgrade its api_version to 2026-10. Leave the others on 2026-07 for now.
Impact
Because the change applies per extension, you can migrate gradually without breaking production behavior.
Technical note
2026-07 keeps working until its API versioning support period ends. The article doesn't give a deadline, so check the API versioning documentation.

9One-line summary for proposals

"In POS UI extensions 2026-10, POS rejects cart writes it can't confirm.
Writes that used to be dropped silently now show up as errors, so add a catch to every call site before you upgrade the version.
Extensions that can't be updated in time can stay on 2026-07."