Surface: POS UI Extensions, Cart API, pos.home.tile.render / pos.home.modal.render
API version: 2026-07
POS app: 11.15.0 (iOS)
Reproduced: 2026-09-25 on a development store, and reported by a merchant on a production store
Summary
When a cashier sells a physical gift card on POS, they scan or enter the pre-printed code and POS attaches that activation code to the gift card line. If an extension then calls shopify.cart.bulkCartUpdate() and includes the gift card line in lineItems exactly as read from shopify.cart.current.value, with its original uuid, POS accepts the write, returns the same line with the same uuid, and no error is raised. The activation code, however, is no longer attached. At checkout Shopify creates a new gift card with a generated code instead of activating the physical card, so the customer leaves with a card that has no balance and the merchant has a digital gift card record that matches nothing they issued.
Nothing on the LineItem type carries the code, and no Cart API method reads, sets or preserves it, so an extension has no way to keep it across a bulk write. We have worked around this by never using bulkCartUpdate on a cart that contains an isGiftCard: true line. We are posting the full evidence so Shopify can decide whether this is expected behaviour, and so other developers using bulkCartUpdate know to guard for it.
Steps to reproduce
- On a store with a gift card product, open POS 11.15.0 and tap the Add gift card tile.
- Choose Physical gift card, pick a value (we used $100), and enter a code (we used
1111 1111; any 8 to 20 alphanumeric characters). - Add it to the cart. The cart now has one line,
isGiftCard: true. - From a POS UI extension, read
shopify.cart.current.value.lineItemsand callbulkCartUpdatewith that array passed through unchanged, plus one additional custom sale line. (Our extension adds a fee line; the additional line is not required to trigger the behaviour, but it is what our extension does.) - Proceed to checkout and complete the sale.
Expected: the gift card created for the order carries the code entered in step 2.
Actual: the gift card created for the order carries a new, generated code. The physical card is never activated.
Control: repeat steps 1 to 3, then add the extra line with addCustomSale() instead of bulkCartUpdate(). The code survives and the physical card is activated at checkout.
What the extension sees
We instrumented the extension to walk every own, non-enumerable and prototype-level key on the cart and on each line at four points: before the write, the payload we sent, the cart returned by bulkCartUpdate, and shopify.cart.current.value immediately after and again after a settle poll.
The gift card line, as read before the write (POS 11.15.0, API 2026-07). This is the complete key set; nothing else is present at any level:
{
"uuid": "b0de1abc-a6ab-4640-878e-5881125ac70e",
"title": undefined,
"productId": 10254232191295,
"variantId": 52265994453311,
"taxable": false,
"taxLines": [],
"price": 100,
"quantity": 1,
"sku": undefined,
"vendor": undefined,
"properties": {},
"discounts": [],
"isGiftCard": true,
"requiresSellingPlan": false,
"hasSellingPlanGroups": false,
"sellingPlan": undefined,
"attributedUserId": undefined
}
The entered code 1111 1111 does not appear in any field, including properties.
The line as returned by bulkCartUpdate, and as read from shopify.cart.current.value afterwards: identical to the above, same uuid, same seventeen keys, same values. There is no observable difference between the line before and after the write, yet the activation is gone.
Cart API surface on this build (Reflect.ownKeys on shopify.cart and its prototype chain):
addAddress, addCartCodeDiscount, addCartProperties, addCustomSale, addLineItem,
addLineItemProperties, addLineItemSellingPlan, applyCartDiscount,
bulkAddLineItemProperties, bulkCartUpdate, bulkSetLineItemDiscounts, clearCart,
current, deleteAddress, removeAllDiscounts, removeCartDiscount,
removeCartProperties, removeCustomer, removeLineItem, removeLineItemDiscount,
removeLineItemProperties, removeLineItemSellingPlan, setAttributedStaff,
setAttributedStaffToLineItem, setCustomer, setLineItemDiscount, updateDefaultAddress
None of these relate to gift card codes.
What the documentation says
LineItem.isGiftCard: “Determines whether this line item is a gift card. Gift cards have special handling requirements and business logic. Use for implementing gift card-specific workflows.” The requirements are not described elsewhere on the page.CartUpdateInput.lineItems: “An array of line items to set during bulk update. Completely replaces existing cart contents—removes all current items and adds the provided ones.”- The Cart Line Item API page describes the same field set and confirms it is read-only.
- Neither page mentions gift card codes, physical card activation, or what state carries over when a line is resent with its existing
uuid.
We read the “completely replaces” wording as consistent with what we observe: the line is recreated, and the activation code, which lives outside the LineItem type, is not part of what gets recreated. If that is the intended contract, the gap is that nothing warns that a gift card line cannot be round-tripped, and nothing lets an extension detect a physical card versus a digital one (both present identically) or opt the line out of the replace.
Timeline note
The merchant who reported this has been on our bulkCartUpdate code path since late July 2026 and states the problem began in the second week of September. We have not been able to test earlier POS builds, so we cannot say whether 11.13 or earlier preserved the activation across a bulk write. We note only that POS 11.14.0 (Aug 31) and 11.15.0 (Sept 14) both changed gift card and cart handling per their release notes, and that our extension’s cart-writing code has not changed since Aug 28.
What we would find useful
Any one of these would let extensions handle gift card carts safely:
- Confirmation of the contract. Is it expected that a gift card line resent through
bulkCartUpdatewith its originaluuidloses its physical activation? If so, a sentence on thebulkCartUpdateandisGiftCarddocs would save other developers from orphaning cards. - Preservation by
uuid. If POS matched an incoming line to the existing line byuuidand carried the activation state over, extensions that pass merchant lines through unchanged would be safe with no API change. - Visibility. A read-only field on
LineItemindicating that the gift card line has an activation code attached (or that it is a physical card) would let extensions gate their writes precisely instead of onisGiftCardalone. - A non-replacing bulk option. A
bulkCartUpdatemode that adds and removes lines without recreating the ones that are unchanged.
Our workaround
We check for any isGiftCard: true line among the lines we would pass through and, if present, apply our changes with addCustomSale and removeLineItem instead of bulkCartUpdate. This is confirmed safe on 11.15.0. It costs the atomicity that bulkCartUpdate was adopted for, and it routes every gift card cart, digital included, down the slower path because the two are indistinguishable from the extension.
Happy to provide any other information that may help. Thanks!