> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tybritelabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cart & Wishlist

> Reference for the CartWishlistService class in the Tybrite SDK.

The `CartWishlistService` class (accessed via `client.cartWishlist`) manages shopping carts for both authenticated and anonymous users, along with customer wishlists.

## Overview

The cart and wishlist APIs support full variant tracking and a unified media gallery system. This enables customers to save specific product selections (color, size, etc.) with accurate pricing, real-time stock levels, and variant-specific images.

<Note>
  **Sandbox isolation:** Cart and wishlist items created with a `tybrite_pk_test_*` or `tybrite_sk_test_*` key are stored in the sandbox environment and are never visible to production keys. Every response includes a `Tybrite-Environment: sandbox | production` header confirming which environment resolved.
</Note>

## Security Model

Cart and wishlist endpoints accept **publishable keys**, so a leaked publishable key alone is not enough to access another customer's cart. When the request claims a `customer_id` (query or body), Galactic Core requires a customer identity — supply **either** `xAuthToken` (the customer's session JWT from `client.authentication.login` or `verifyOtp`) **or** `xExternalAuth` (a bring-your-own-auth signed assertion, if your store runs its own identity provider); provide one, not both. The resolved customer must match the claimed `customer_id`, otherwise the request returns `403 forbidden`. Anonymous (session-only) carts skip this check and rely on the secrecy of `X-Session-Id`.

<Note>
  All wishlist endpoints (and `mergeCart`) always require a customer identity (`xAuthToken` or `xExternalAuth`) because they are inherently customer-scoped. Only cart reads/writes that omit `customer_id` and rely solely on `xSessionId` may proceed unauthenticated.
</Note>

## Cart Management

### `getCart`

Retrieve the current contents of a cart. This method supports both logged-in customers and anonymous guest sessions.

```typescript theme={null}
// Anonymous (no auth token needed)
const guestCart = await client.cartWishlist.getCart({
  xSessionId: 'guest-uuid-123'
});

// Authenticated (token required — JWT must resolve to customerId)
const cart = await client.cartWishlist.getCart({
  xAuthToken: customerSession.access_token,
  customerId: 'customer-uuid'
});

const firstItem = cart.items[0];
console.log(`Item: ${firstItem.product_name} (${firstItem.variant_name})`);
console.log(`Thumbnail: ${firstItem.thumbnail_url}`);
```

```json Response (200) theme={null}
{
  "items": [
    {
      "id": "09695de2-73ac-45ea-b2cb-76f9751b9846",
      "product_id": "0186665f-f0a1-4c79-976a-919b5b1c2daa",
      "variant_id": "e98631a9-7852-4fe8-8efe-988935d5922a",
      "product_name": "Samsung Galaxy Watch 6",
      "variant_name": "Default",
      "variant_attributes": {},
      "product_sku": "SAM-WATCH-6-44-0186",
      "thumbnail_url": "https://cdn.tybritelabs.com/stores/.../primary-1774785167560.jpg",
      "quantity": 2,
      "unit_price": 299.99,
      "selling_price": 299.99,
      "total_price": 599.98,
      "stock_available": 183,
      "has_variants": false
    }
  ]
}
```

<Note>
  See [Response Objects](#response-objects) below for the full `CartItem` shape, including the `media[]` gallery.
</Note>

### `addToCart`

Add a specific product variant to the cart. If the same variant already exists, its quantity will be incremented.

<Note>
  `variant_id` is required to specify the exact product selection. For products without variants, use the default variant ID.
</Note>

```typescript theme={null}
// Anonymous Cart (no auth token needed)
await client.cartWishlist.addToCart({
  xSessionId: 'guest-uuid-123',
  requestBody: {
    variant_id: 'variant-uuid',
    quantity: 1
  }
});

// Authenticated Cart (token required)
await client.cartWishlist.addToCart({
  xAuthToken: customerSession.access_token,
  requestBody: {
    variant_id: 'variant-uuid',
    quantity: 1,
    customer_id: 'customer-uuid'
  }
});
// → { items: [...] } — the full updated cart (same shape as getCart)
```

### `updateCartItem`

Update variables for a specific item already in the cart, such as changing the quantity.

```typescript theme={null}
// Anonymous (no auth token needed)
await client.cartWishlist.updateCartItem({
  id: 'cart-item-uuid',
  xSessionId: 'guest-uuid-123',
  requestBody: {
    quantity: 5
  }
});

// Authenticated (token required)
await client.cartWishlist.updateCartItem({
  id: 'cart-item-uuid', // The UUID of the item in the cart
  xAuthToken: customerSession.access_token,
  requestBody: {
    quantity: 5,
    customer_id: 'customer-uuid'
  }
});
// → { items: [...] } — the full updated cart with the new quantity + recomputed total_price
```

### `clearCart`

Remove all items from the cart in a single operation.

```typescript theme={null}
// Anonymous (no auth token needed)
await client.cartWishlist.clearCart({
  xSessionId: 'guest-uuid-123'
});

// Authenticated (token required)
await client.cartWishlist.clearCart({
  xAuthToken: customerSession.access_token,
  customerId: 'customer-uuid'
});
// → { items: [] } — the now-empty cart
```

### `removeCartItem`

Remove a specific item from the cart.

```typescript theme={null}
// Anonymous (no auth token needed)
await client.cartWishlist.removeCartItem({
  id: 'cart-item-uuid',
  xSessionId: 'guest-uuid-123'
});

// Authenticated (token required)
await client.cartWishlist.removeCartItem({
  id: 'cart-item-uuid',
  xAuthToken: customerSession.access_token,
  customerId: 'customer-uuid'
});
// → { items: [...] } — the cart with that item removed
```

### `mergeCart`

Combine an anonymous guest cart with a customer's permanent cart. Carts are matched by both `product_id` and `variant_id` to prevent merging different variants of the same product.

<Note>
  `mergeCart` always requires `xAuthToken` — it links a guest session to a customer record, so Galactic Core must verify the caller actually owns that customer.
</Note>

```typescript theme={null}
await client.cartWishlist.mergeCart({
  xAuthToken: customerSession.access_token,
  requestBody: {
    session_id: 'guest-session-uuid',
    customer_id: 'authenticated-customer-uuid'
  }
});
// → { items: [...] } — the merged customer cart (guest lines folded in)
```

## Wishlist Management

<Note>
  All wishlist endpoints require `xAuthToken`. Wishlists are inherently customer-scoped — there is no anonymous mode. The JWT must resolve to the same customer referenced by `customer_id`.
</Note>

### `getWishlist`

Retrieve a customer's saved items, including variant and media details.

```typescript theme={null}
const { items } = await client.cartWishlist.getWishlist({
  xAuthToken: customerSession.access_token,
  customerId: 'customer-uuid'
});
```

```json Response (200) theme={null}
{
  "items": [
    {
      "id": "2dac3a23-afec-4b6a-a369-e7bdb1f3bc32",
      "product_id": "0186665f-f0a1-4c79-976a-919b5b1c2daa",
      "variant_id": "e98631a9-7852-4fe8-8efe-988935d5922a",
      "product_name": "Samsung Galaxy Watch 6",
      "variant_name": "Default",
      "variant_attributes": {},
      "product_sku": "SAM-WATCH-6-44-0186",
      "product_price": 299,
      "thumbnail_url": "https://cdn.tybritelabs.com/stores/.../primary-1774785167560.jpg",
      "stock_available": 183,
      "has_variants": false
    }
  ]
}
```

### `addToWishlist`

Save a specific product variant for later. Wishlists require an authenticated `customer_id`.

```typescript theme={null}
await client.cartWishlist.addToWishlist({
  xAuthToken: customerSession.access_token,
  requestBody: {
    variant_id: 'variant-uuid',
    customer_id: 'customer-uuid'
  }
});
// → 201 { items: [...] } — the full wishlist including the newly saved item
//   (adding a variant already on the wishlist returns 409)
```

### `removeFromWishlist`

Remove an item from the customer's wishlist.

```typescript theme={null}
await client.cartWishlist.removeFromWishlist({
  id: 'wishlist-item-uuid',
  xAuthToken: customerSession.access_token,
  customerId: 'customer-uuid'
});
// → { items: [...] } — the wishlist with that item removed
```

### `moveWishlistToCart`

An atomic operation that removes an item from the wishlist and adds it to the active cart. This operation preserves the `variant_id` and performs stock validation.

```typescript theme={null}
await client.cartWishlist.moveWishlistToCart({
  xAuthToken: customerSession.access_token,
  requestBody: {
    wishlist_item_id: 'wishlist-item-uuid',
    customer_id: 'customer-uuid',
    quantity: 1
  }
});
```

```json Response (200) theme={null}
{
  "success": true,
  "message": "Item moved from wishlist to cart",
  "removed_wishlist_item_id": "2dac3a23-afec-4b6a-a369-e7bdb1f3bc32",
  "items": [
    {
      "id": "845e8724-a3dc-432c-9771-26a4173ec48c",
      "product_id": "0186665f-f0a1-4c79-976a-919b5b1c2daa",
      "variant_id": "e98631a9-7852-4fe8-8efe-988935d5922a",
      "product_name": "Samsung Galaxy Watch 6",
      "variant_name": "Default",
      "product_sku": "SAM-WATCH-6-44-0186",
      "quantity": 1,
      "unit_price": 299.99,
      "selling_price": 299.99,
      "total_price": 299.99
    }
  ]
}
```

***

## Response Objects

### `CartItem` & `WishlistItem`

Both cart and wishlist items include structured data for optimized frontend rendering.

| Field                | Type      | Description                                                       |
| :------------------- | :-------- | :---------------------------------------------------------------- |
| `id`                 | `uuid`    | Item UUID in the cart or wishlist.                                |
| `product_id`         | `uuid`    | The product UUID this item belongs to.                            |
| `variant_id`         | `uuid`    | The specific identifier for the selected variation.               |
| `product_name`       | `string`  | Name of the product.                                              |
| `variant_name`       | `string`  | Display name for the variant (e.g., "Space Gray").                |
| `variant_attributes` | `object`  | JSON attributes like color or size.                               |
| `product_sku`        | `string`  | SKU for the specific variant.                                     |
| `thumbnail_url`      | `string`  | Primary image URL, prioritizing variant media.                    |
| `media`              | `array`   | Full gallery of variant-aware images and videos.                  |
| `quantity`           | `number`  | **(Cart only)** Number of items added.                            |
| `unit_price`         | `number`  | **(Cart only)** Base price per unit.                              |
| `selling_price`      | `number`  | **(Cart only)** Actual price including active sales.              |
| `total_price`        | `number`  | **(Cart only)** `unit_price × quantity`.                          |
| `product_price`      | `number`  | **(Wishlist only)** Current price of the variant.                 |
| `stock_available`    | `number`  | Real-time stock count for the variant.                            |
| `has_variants`       | `boolean` | Whether the product supports variation selection.                 |
| `created_at`         | `string`  | Timestamp of when the item was added.                             |
| `environment`        | `string`  | `production` or `sandbox` — matches the key used to add the item. |

<CodeGroup>
  ```json CartItem Example theme={null}
  {
      "id": "d1de278b-d260-42da-ae4a-8bb5d34477c3",
      "product_id": "b016b91e-8403-44be-80ca-77a2d55e7b2d",
      "variant_id": "6be67ee4-6657-4998-b728-3e99c075c01b",
      "product_name": "Samsung Galaxy S21",
      "variant_name": "Default",
      "variant_attributes": {},
      "product_sku": "SMG-S21-BLK",
      "thumbnail_url": "https://cdn.tybritelabs.com/stores/.../primary-1774785162626.jpg",
      "media": [
          {
              "id": "cb00d540-692d-432e-9661-7757ac998f75",
              "url": "https://cdn.tybritelabs.com/stores/.../primary-1774785162626.jpg",
              "type": "image",
              "alt_text": "Samsung Galaxy S21",
              "position": 0,
              "is_primary": true
          }
      ],
      "quantity": 2,
      "unit_price": 799.99,
      "selling_price": 799.99,
      "total_price": 1599.98,
      "stock_available": 49,
      "has_variants": false,
      "created_at": "2026-04-11T10:54:23Z",
      "updated_at": "2026-04-11T10:54:23Z",
      "environment": "production"
  }
  ```

  ```json WishlistItem Example theme={null}
  {
      "id": "38578dcd-67a7-4adc-9b64-3896d1bd638d",
      "product_id": "b016b91e-8403-44be-80ca-77a2d55e7b2d",
      "variant_id": "6be67ee4-6657-4998-b728-3e99c075c01b",
      "product_name": "Samsung Galaxy S21",
      "variant_name": "Default",
      "variant_attributes": {},
      "product_sku": "SMG-S21-BLK",
      "product_price": 799.99,
      "thumbnail_url": "https://cdn.tybritelabs.com/stores/.../primary-1774785162626.jpg",
      "media": [
          {
              "id": "cb00d540-692d-432e-9661-7757ac998f75",
              "url": "https://cdn.tybritelabs.com/stores/.../primary-1774785162626.jpg",
              "type": "image",
              "alt_text": "Samsung Galaxy S21",
              "position": 0,
              "is_primary": true
          }
      ],
      "stock_available": 49,
      "has_variants": false,
      "created_at": "2026-04-11T10:52:09Z",
      "environment": "production"
  }
  ```
</CodeGroup>

***

## Core Logic

### Stock Validation

Stock checks are enforced against the specific variant during all cart operations. If the requested quantity exceeds `stock_available`, the API returns an `insufficient_stock` error code along with the current available count.

### Pricing Logic

Prices are calculated at the variant level using the `selling_price` field. This ensures that different variations (e.g., larger sizes or premium colors) are priced accurately and that active promotions are automatically applied.

***

## Frontend Patterns

### Variant Selection & Add to Cart

When a user selects a variant and adds it to their cart, branch on whether you have a stored customer session:

```typescript theme={null}
// Read the stored session — set by client.authentication.login / verifyOtp
const customerSession = JSON.parse(localStorage.getItem('tybrite_session') ?? 'null');

const handleAddToCart = async (selectedVariant: Variant, quantity: number) => {
  try {
    if (customerSession?.access_token) {
      // Authenticated path — JWT must resolve to customer_id
      const { items } = await client.cartWishlist.addToCart({
        xAuthToken: customerSession.access_token,
        requestBody: {
          variant_id: selectedVariant.variant_id,
          quantity,
          customer_id: customerSession.customer_id
        }
      });
      // → { items: [...] } — re-render the cart badge from items.length
    } else {
      // Anonymous path — session-only cart
      const { items } = await client.cartWishlist.addToCart({
        xSessionId: sessionId,
        requestBody: {
          variant_id: selectedVariant.variant_id,
          quantity
        }
      });
      // → { items: [...] }
    }
  } catch (error) {
    if (error.code === 'insufficient_stock') {
      alert(`Only ${error.available_stock} items available`);
    }
  }
};
```

<Note>
  **Pro Tip:** Use `xSessionId` for guest users. Tybrite will persist this guest cart until it is either merged via `mergeCart` (which requires `xAuthToken`) or cleared.
</Note>

<Tip>
  When a guest logs in, call `mergeCart` with the freshly minted `xAuthToken` to fold their guest cart into their customer cart before clearing `X-Session-Id`.
</Tip>

***

### Response Codes

| Code  | Meaning                                                             |
| :---- | :------------------------------------------------------------------ |
| `200` | Success on reads, updates, `clearCart`, and `mergeCart`.            |
| `201` | Success on `addToWishlist` — a new wishlist item was created.       |
| `400` | `insufficient_stock`, missing required fields, or invalid body.     |
| `401` | Missing or invalid `xAuthToken`.                                    |
| `403` | The customer token does not match the `customer_id` in the request. |
| `404` | Variant, wishlist item, or cart item not found.                     |
| `409` | Item already in wishlist (on `addToWishlist`).                      |
