Simulators
Storefront carts
A Storefront cart is the basket a shopper fills before checkout, and the simulator keeps it as Shopify does: cartCreate makes one, the cart… mutations change it and cart(id:) reads it. Create a cart with two units of a variant, add another variant and a note, and read the cart back:
STOREFRONT="$RYSTIC_URL/api/2026-10/graphql.json"
curl -s "$STOREFRONT" -H "X-Shopify-Storefront-Access-Token: placeholder" -H "Content-Type: application/json" -d '{"query": "mutation { cartCreate(input: {lines: [{merchandiseId: \"gid://shopify/ProductVariant/1040\", quantity: 2}]}) { cart { id totalQuantity checkoutUrl } userErrors { message } } }"}' | jq -c '.data.cartCreate.cart | {id, totalQuantity}'
# -> {"id":"gid://shopify/Cart/c000000000001?key=00000001","totalQuantity":2}
curl -s "$STOREFRONT" -H "X-Shopify-Storefront-Access-Token: placeholder" -H "Content-Type: application/json" -d '{"query": "mutation { cartLinesAdd(cartId: \"gid://shopify/Cart/c000000000001?key=00000001\", lines: [{merchandiseId: \"gid://shopify/ProductVariant/1041\", quantity: 1}]) { cart { totalQuantity } userErrors { message } } }"}' | jq -c '.data.cartLinesAdd.cart'
# -> {"totalQuantity":3}
curl -s "$STOREFRONT" -H "X-Shopify-Storefront-Access-Token: placeholder" -H "Content-Type: application/json" -d '{"query": "mutation { cartNoteUpdate(cartId: \"gid://shopify/Cart/c000000000001?key=00000001\", note: \"Gift wrap\") { cart { note } userErrors { message } } }"}' | jq -c '.data.cartNoteUpdate.cart'
# -> {"note":"Gift wrap"}
curl -s "$STOREFRONT" -H "X-Shopify-Storefront-Access-Token: placeholder" -H "Content-Type: application/json" -d '{"query": "{ cart(id: \"gid://shopify/Cart/c000000000001?key=00000001\") { id totalQuantity note } }"}' | jq -c '.data.cart'
# -> {"id":"gid://shopify/Cart/c000000000001?key=00000001","note":"Gift wrap","totalQuantity":3}
Cart ids
A cart’s id carries its key, gid://shopify/Cart/<token>?key=<key>, and every mutation and read takes the whole id. The first cart a simulator makes is c000000000001 with key 00000001, and the ids restart on reset. The default scenario’s own cart is gid://shopify/Cart/c1acme1190?key=a1190k.
What a cart holds
A cart’s totalQuantity follows its lines: cartLinesAdd, cartLinesUpdate and cartLinesRemove move it. A cart also holds a note, attributes, a buyer identity, discount codes, delivery addresses, selected delivery options and metafields, each with its own mutation.
A discount code is recorded on the cart and reported applicable: false, because the simulator holds no discounts to apply it.
Refusals
cartCreate and cartLinesAdd refuse a variant the store does not hold: they return cart: null and one user error. For variant 9, the error has code INVALID and the message The merchandise with id gid://shopify/ProductVariant/9 does not exist., on this field:
| Mutation | User error field |
|---|---|
cartCreate | ["input", "lines", "0", "merchandiseId"] |
cartLinesAdd | ["lines", "0", "merchandiseId"] |
A mutation that names a cart the simulator does not hold returns one of four results:
| Mutation | Result for an unknown cart |
|---|---|
cartLinesAdd | cart: null and the user error The specified cart does not exist. on ["cartId"] |
cartNoteUpdate, cartLinesUpdate, cartSelectedDeliveryOptionsUpdate, cartDeliveryAddressesAdd | a null payload and a top-level error with code NOT_FOUND |
cartAttributesUpdate, cartBuyerIdentityUpdate, cartDiscountCodesUpdate, cartLinesRemove, the other three cartDeliveryAddresses… mutations | cart: null and an empty userErrors |
cartMetafieldsSet, cartMetafieldDelete | the result for a cart that exists, since they do not check the cart |
Checkout
A cart’s checkoutUrl points back at the simulator, on the host you reached it on.
Differs from Shopify: no checkout page is served behind checkoutUrl.
Read checkoutUrl to test that your code hands the shopper on, and treat the order as a record you seed.