Skip to content

Conversation

@kdaviduik
Copy link
Contributor

@kdaviduik kdaviduik commented Jan 23, 2026

WHY are these changes introduced?

Closes https://github.com/Shopify/developer-tools-team/issues/964

The Storefront API 2025-10 introduces cartGiftCardCodesAdd which appends gift card codes to the cart without replacing existing ones. This simplifies the common use case of adding a single gift card code.

Before (2025-07): You had to fetch existing codes, merge them with the new code, then call cartGiftCardCodesUpdate:

const existingCodes = cart.appliedGiftCards.map(gc => gc.lastCharacters);
await cart.updateGiftCardCodes([...existingCodes, 'NEW_CODE']);

After (2025-10): Just add the new code:

await cart.addGiftCardCodes(['NEW_CODE']);

WHAT is this pull request doing?

  • Add cartGiftCardCodesAddDefault query implementation
  • Add cart.addGiftCardCodes(codes) method to cart handler
  • Add CartForm.ACTIONS.GiftCardCodesAdd form action
  • Add types, tests, docs, and examples
  • Update skeleton template to use new Add action
  • Remove UpdateGiftCardForm from skeleton (Add + Remove covers all use cases)

HOW to test your changes?

  1. In a Hydrogen project using SFAPI 2025-10:
const cart = createCartHandler({storefront, getCartId, setCartId});
await cart.addGiftCardCodes(['YOUR_GIFT_CARD_CODE']);
  1. Or via CartForm:
<CartForm action={CartForm.ACTIONS.GiftCardCodesAdd}>
  <input name="giftCardCode" placeholder="Gift card code" />
  <button>Apply</button>
</CartForm>

Note

I think it makes more sense to only fix the recipes once we've finished merging all PRs into the stack, so we can just fix them once at the end. I started up a discussion here in case anyone has different opinions :)

Checklist

  • I've read the Contributing Guidelines
  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've added a changeset if this PR contains user-facing or noteworthy changes
  • I've added tests to cover my changes
  • I've added or updated the documentation

Copy link
Contributor Author

kdaviduik commented Jan 23, 2026

@shopify
Copy link
Contributor

shopify bot commented Jan 23, 2026

Oxygen deployed a preview of your kd-2025-10-giftCardCodesAdd branch. Details:

Storefront Status Preview link Deployment details Last update (UTC)
Skeleton (skeleton.hydrogen.shop) ✅ Successful (Logs) Preview deployment Inspect deployment January 27, 2026 5:20 PM
sitemap ✅ Successful (Logs) Preview deployment Inspect deployment January 27, 2026 5:21 PM
metaobjects ✅ Successful (Logs) Preview deployment Inspect deployment January 27, 2026 5:21 PM
custom-cart-method ✅ Successful (Logs) Preview deployment Inspect deployment January 27, 2026 5:22 PM
third-party-queries-caching ✅ Successful (Logs) Preview deployment Inspect deployment January 27, 2026 5:21 PM

Learn more about Hydrogen's GitHub integration.

@kdaviduik kdaviduik changed the title chore: document updated cartDeliveryAddressesUpdate empty array behavior feat(cart): add cartGiftCardCodesAdd mutation Jan 23, 2026
@kdaviduik kdaviduik force-pushed the kd-2025-10-giftCardCodesAdd branch 2 times, most recently from 254bc3e to f0d7fc3 Compare January 23, 2026 04:44
@kdaviduik kdaviduik marked this pull request as ready for review January 23, 2026 04:58
@kdaviduik kdaviduik requested a review from a team as a code owner January 23, 2026 04:58
Comment on lines 24 to 39
## Verified API Behavior (E2E tested 2026-01-21)

| Scenario | Behavior |
|----------|----------|
| Valid gift card code | Applied successfully |
| UPPERCASE code | Works (API is case-insensitive) |
| Duplicate code in same call | Idempotent - applied once, no error |
| Re-applying already applied code | Idempotent - no error, no duplicate |
| Multiple different codes | All applied successfully |
| Invalid code | Silently rejected (no error surfaced) |
| Code with whitespace | Rejected (API does not trim whitespace) |
| Empty input | Graceful no-op |

**Key finding:** The API handles duplicate gift card codes gracefully - submitting an already-applied code results in silent success (idempotent behavior), not an error. No `DUPLICATE_GIFT_CARD` error code exists.

**Note on whitespace:** The API does NOT trim whitespace from codes. Ensure codes are trimmed before submission if accepting user input.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we think this would be useful information for people building with Hydrogen? I figured it wouldn't hurt but I could go either way on this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i think it’s good to note

i’d just change the wording on "Key Finding" into "Note", as these aren’t findings, they are the ways we (Shopify) have designed the API

Comment on lines +97 to +102
type CartGiftCardCodesAddRequire = {
action: 'GiftCardCodesAdd';
inputs: {
giftCardCodes: string[];
} & OtherFormData;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the future we can probably reduce these types by half with a util like

type ActionWithRequiredInputs<T extends {inputs?: unknown}> = T & {inputs: T['inputs']};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is something I'd love to do in the future! Added it to the list. I think that's out of scope for this PR (and the overall 2025-10 API change) though

Comment on lines 312 to 318
| CartCreateRequire
| CartDiscountCodesUpdateRequire
| CartGiftCardCodesUpdateRequire
| CartGiftCardCodesAddRequire
| CartGiftCardCodesRemoveRequire
| CartLinesAddRequire
| CartLinesUpdateRequire
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Re: lines +309 to +327]

did not test LSP for performance benchmarks BUT

we can delete all the ___Require types and replace this type with

type WithRequiredInputsDistributive<T extends {inputs?: unknown}> = T extends unknown ? T & {inputs: NonNullable<T['inputs']>} : never;
export type CartActionInput = WithRequiredInputsDistributive<CartActionInputProps>

is this something that we want? i could open a separate PR for that.

Pros: fewer manual types to write, fewer mistakes, less maintenance
Cons: LSP may be a liltle bit slower

"no" is a perfectly good answer to this

See this comment inline on Graphite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GiftCardCodesAdd: 'GiftCardCodesAdd',
GiftCardCodesRemove: 'GiftCardCodesRemove',
LinesAdd: 'LinesAdd',
LinesRemove: 'LinesRemove',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Re: line +376]

} as const  satisfies Record<CartActionInput['action'], CartActionInput['action']>;

See this comment inline on Graphite.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding this has revealed that we may have a typo in MetaFieldDelete (it’s actually MetaFieldsDelete

unless these are unrelated to CartActionInput

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing MetafieldDelete in the schema
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah but this has to agree with the cart actions not the graphql API, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I looked into this a bit more and it looks like for this one it's a typo in terms of it being inconsistent with the other entries, but nothing seems to actually be broken. Wouldn't hurt to fix if this means no breaking changes for consumers, but that's out of scope for this PR

Copy link
Contributor

@fredericoo fredericoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

besides my type nitpicks and the typo found, it all works great and code is gud

@fredericoo fredericoo changed the base branch from 2025-10-sfapi-caapi-update to graphite-base/3401 January 23, 2026 11:52
@kdaviduik kdaviduik force-pushed the kd-2025-10-giftCardCodesAdd branch from f0d7fc3 to cbf41a0 Compare January 27, 2026 02:04
@kdaviduik kdaviduik changed the base branch from graphite-base/3401 to 2025-10-sfapi-caapi-update January 27, 2026 02:04
@kdaviduik kdaviduik changed the base branch from 2025-10-sfapi-caapi-update to graphite-base/3401 January 27, 2026 02:13
@kdaviduik kdaviduik force-pushed the kd-2025-10-giftCardCodesAdd branch from cbf41a0 to c24fd25 Compare January 27, 2026 02:18
@kdaviduik kdaviduik changed the base branch from graphite-base/3401 to 2025-10-sfapi-caapi-update January 27, 2026 02:18
@kdaviduik kdaviduik force-pushed the kd-2025-10-giftCardCodesAdd branch from c24fd25 to 9268ed7 Compare January 27, 2026 02:28
@kdaviduik kdaviduik force-pushed the 2025-10-sfapi-caapi-update branch from 04f9469 to bce6ffc Compare January 27, 2026 02:28
@kdaviduik kdaviduik changed the base branch from 2025-10-sfapi-caapi-update to graphite-base/3401 January 27, 2026 02:52
@kdaviduik kdaviduik force-pushed the kd-2025-10-giftCardCodesAdd branch from 9268ed7 to 79d73b7 Compare January 27, 2026 02:52
@kdaviduik kdaviduik changed the base branch from graphite-base/3401 to 2025-10-article-reference January 27, 2026 02:52
@kdaviduik kdaviduik force-pushed the 2025-10-article-reference branch from 6b7fd54 to b79b6fc Compare January 27, 2026 17:15
@kdaviduik kdaviduik changed the base branch from 2025-10-article-reference to main January 27, 2026 17:17
@kdaviduik kdaviduik changed the base branch from main to 2025-10-article-reference January 27, 2026 17:17
Adds the new `cartGiftCardCodesAdd` mutation available in Storefront API 2025-10.

## What
- Add `cartGiftCardCodesAddDefault` query implementation
- Add `cart.addGiftCardCodes(codes)` method to cart handler
- Add `CartForm.ACTIONS.GiftCardCodesAdd` form action
- Add types, tests, docs, and examples
- Update skeleton template to use new Add action
- Remove UpdateGiftCardForm from skeleton (Add + Remove covers all use cases)

## Why
The Storefront API 2025-10 introduces `cartGiftCardCodesAdd` which appends gift card
codes to the cart without replacing existing ones. This simplifies the common use case
of adding a single gift card code - previously you had to fetch existing codes, merge
them with the new code, then call `cartGiftCardCodesUpdate`.

## Usage
```typescript
// Via cart handler
await cart.addGiftCardCodes(['SUMMER2025']);

// Via CartForm
<CartForm action={CartForm.ACTIONS.GiftCardCodesAdd}>
  <input name="giftCardCode" />
  <button>Apply</button>
</CartForm>
```

Related: #3271
@kdaviduik kdaviduik force-pushed the kd-2025-10-giftCardCodesAdd branch from 79d73b7 to 403c1f5 Compare January 27, 2026 17:18
Base automatically changed from 2025-10-article-reference to main January 27, 2026 17:23
@kdaviduik kdaviduik merged commit 9d7d46b into main Jan 27, 2026
17 of 18 checks passed
@kdaviduik kdaviduik deleted the kd-2025-10-giftCardCodesAdd branch January 27, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants