
import CartFields from "../../../src/reference/subbly-sdk/types/SubblyCart.mdx";
import AddressPayloadFields from "../../../src/reference/subbly-sdk/types/AddressStorePayload.mdx";
import SurveyAnswerFields from "../../../src/reference/subbly-sdk/types/SurveyAnswers.mdx";
import MetadataFields from "../../../src/reference/subbly-sdk/types/MetadataObject.mdx";
import DeliveryFields from "../../../src/reference/subbly-sdk/types/ShippingMethodDelivery.mdx";
import PickupFields from "../../../src/reference/subbly-sdk/types/ShippingMethodPickup.mdx";
import StartDateFields from "../../../src/reference/subbly-sdk/types/StartDates.mdx";

<SdkPage group="cart" />

`subbly.cart` is both the data and the methods. It carries every cart field
straight on the object — `subbly.cart.id`, `subbly.cart.items`,
`subbly.cart.total` — and the methods below change it. Each of those methods
copies the response onto the same object and resolves with it, so the value you
`await` and `subbly.cart` are one and the same. There is only ever one cart per
SDK instance, and fields the response leaves out keep their old values.

Amounts are whole numbers in the minor unit of the cart currency; see
[Amounts and dates](/reference/subbly-sdk#amounts-and-dates).

Most methods take an optional `params.expand` list; the values it accepts are
under [Expand parameters](/reference/subbly-sdk#expand-parameters).

<Method id="create" signature="subbly.cart.create(payload?, params?)">

Creates a new cart and stores its ID in the `subbly_cart_id` cookie for 365
days. It replaces whatever cart the SDK already held, so call it once, and use
`subbly.cart.load` to come back to a cart you already have.

The cookie is a plain one on `path=/`, with no `Secure`, `HttpOnly` or
`SameSite` attribute.

<Params>
  <Param name="payload" optional type="CartCreatePayload">
    What the new cart starts with. Pass `null` or leave it out for an empty
    cart. The TypeScript type is the wider update payload, but the create
    endpoint reads only the four fields below; set anything else with
    `subbly.cart.update` afterwards.

    <Properties label="payload">
      <Param name="currencyCode" optional type="string">
      Currency of the cart, such as `EUR`. Defaults to the shop currency.
      </Param>
      <Param name="couponCode" optional type="string | null">
      Coupon code to apply straight away.
      </Param>
      <Param name="giftCardCode" optional type="string | null">
      Gift card code to apply straight away.
      </Param>
      <Param name="referralId" optional type="number | null">
      ID of the referral that led to this cart.
      </Param>
    </Properties>
  </Param>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The cart, which is `subbly.cart` itself.
<Properties label="cart" collapsed>
  <CartFields />
</Properties>
</Returns>

<Example>

```js title="Create a cart"
const cart = await subbly.cart.create()
```

```js title="Create a cart in a currency, with a coupon"
const cart = await subbly.cart.create(
  { currencyCode: 'EUR', couponCode: 'WELCOME10' },
  { expand: ['coupon', 'items.product'] },
)
```

</Example>

</Method>

<Method id="load" signature="subbly.cart.load(cartId?, params?)">

Loads a cart by ID into `subbly.cart`. Leave the ID out to refresh the cart the
SDK already holds.

Unlike `create`, this does not write the cookie. `Subbly.init` writes it itself
after a successful load.

<Params>
  <Param name="cartId" optional type="string">
  UUID of the cart. Leave it out to reload the cart already held. With no ID and
  no cart held, the call throws `Error('Cart ID is required')` at once, without
  reaching the network.
  </Param>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The cart, which is `subbly.cart` itself. Its fields are written out under
[Create a cart](#create).
</Returns>

<Example>

```js title="Load a cart by ID"
const cart = await subbly.cart.load('aaea067c-6364-4157-82e9-71b6edfd84a0')
```

```js title="Refresh the cart in hand"
await subbly.cart.load(undefined, { expand: ['items.product'] })
```

</Example>

</Method>

<Method id="update" signature="subbly.cart.update(payload, params?)">

Changes the cart itself rather than its items: who is buying, where it ships,
how it ships, which discounts apply, and when a subscription starts. Send only
the fields you change.

Most of it works for a guest. Three fields point at records only a signed-in
customer has: `paymentMethodId`, `shippingAddressId` and `billingAddressId`.

<Params>
  <Param name="payload" required type="CartUpdatePayload">
    The fields to change. Every one is optional.

    <Properties label="payload" collapsed>
      <Param name="customer" optional type="object | null">
      Guest details on the cart. Use it before the customer signs in.
      <Properties label="customer">
        <Param name="email" optional type="string">
        Email address.
        </Param>
        <Param name="firstName" optional type="string">
        Given name.
        </Param>
        <Param name="lastName" optional type="string">
        Family name.
        </Param>
        <Param name="marketingConsent" optional type="boolean">
        Whether the guest agreed to marketing email.
        </Param>
        <Param name="tosConsent" optional type="boolean">
        Whether the guest accepted the terms.
        </Param>
        <Param name="externalId" optional type="string | null">
        Your own ID for this guest.
        </Param>
      </Properties>
      </Param>
      <Param name="shippingAddress" optional type="object | null">
      A delivery address written straight onto the cart, for a guest with no
      saved addresses.
      <Properties label="shippingAddress" collapsed>
        <AddressPayloadFields />
      </Properties>
      </Param>
      <Param name="billingAddress" optional type="object | null">
      A billing address written straight onto the cart. Same fields as
      `shippingAddress`.
      </Param>
      <Param name="pickupInfo" optional type="object | null">
      Who collects the order at a pick-up point.
      <Properties label="pickupInfo">
        <Param name="firstName" required type="string">
        Given name of the person collecting.
        </Param>
        <Param name="lastName" required type="string">
        Family name of the person collecting.
        </Param>
        <Param name="phone" required type="string">
        Phone number.
        </Param>
        <Param name="pickupPointType" optional type="string">
        `mondial_relay` when the point comes from Mondial Relay.
        </Param>
        <Param name="pickupPointId" optional type="string">
        ID of the point at the provider.
        </Param>
      </Properties>
      </Param>
      <Param name="currencyCode" optional type="string">
      Currency of the cart. This is the only way to change it.
      </Param>
      <Param name="couponCode" optional type="string | null">
      Coupon code to apply. Send `null` to take the coupon off.
      </Param>
      <Param name="giftCardCode" optional type="string | null">
      Gift card code to apply. Send `null` to take the gift card off.
      </Param>
      <Param name="referralId" optional type="number | null">
      ID of the referral that led to this cart.
      </Param>
      <Param name="giftInfo" optional type="object | null">
      Gift settings for the cart.
      <Properties label="giftInfo">
        <Param name="startsAt" optional type="string | null">
        When the gift starts, from `subbly.cart.getGiftingDates()`.
        </Param>
        <Param name="numberOfOrders" optional type="number | null">
        How many shipments the gift covers.
        </Param>
        <Param name="message" optional type="string | null">
        Message for the recipient.
        </Param>
        <Param name="recipientEmail" optional type="string | null">
        Email of the recipient.
        </Param>
      </Properties>
      </Param>
      <Param name="startsAt" optional type="string | null">
      When the subscription starts, from `subbly.cart.getStartDates()`.
      </Param>
      <Param name="shippingMethodId" optional type="number | null">
      ID of the delivery option, from `subbly.cart.getShippingMethods` or
      `subbly.cart.getLocalPickups`.
      </Param>
      <Param name="shippingCarrierId" optional type="number | null">
      ID of the carrier, from the `carrier` of a shipping option.
      </Param>
      <Param name="shippingCarrierService" optional type="string | null">
      Carrier service code, from `carrier.serviceCodes`.
      </Param>
      <Param name="shippingAddressId" optional type="number | null">
      ID of a saved address or pick-up info of the signed-in customer.
      </Param>
      <Param name="billingAddressId" optional type="number | null">
      ID of a saved address of the signed-in customer.
      </Param>
      <Param name="paymentMethodId" optional type="number | null">
      ID of a saved payment method, from `subbly.wallet.list`.
      </Param>
      <Param name="onboardingTemplateId" optional type="number | null">
      ID of the onboarding template to apply.
      </Param>
      <Param name="metadata" optional type="MetadataObject[] | null">
      Metafield values to save on the cart.
      <Properties label="metadata">
        <MetadataFields />
      </Properties>
      </Param>
    </Properties>
  </Param>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The updated cart, which is `subbly.cart` itself. Its fields are written out
under [Create a cart](#create).
</Returns>

<Example>

```js title="Set the guest details"
await subbly.cart.update({
  customer: {
    email: 'ada@example.com',
    firstName: 'Ada',
    lastName: 'Lovelace',
    tosConsent: true,
  },
})
```

```js title="Set the delivery address and the method"
await subbly.cart.update({
  shippingAddress: {
    firstName: 'Ada',
    lastName: 'Lovelace',
    phone: '+442071234567',
    addressOne: '12 Marylebone Road',
    addressTwo: null,
    city: 'London',
    zip: 'NW1 5JD',
    countryId: 826,
  },
  shippingMethodId: 91,
})
```

```js title="Remove the coupon"
await subbly.cart.update({ couponCode: null })
```

</Example>

</Method>

<Method id="add-item" signature="subbly.cart.addItem(payload, params?)">

Adds a product, a plan or a bundle to the cart. Adding the same one-time item
again raises its quantity instead of making a second line.

The payload has a shape per kind of item. All three share `productId`,
`quantity` and `metadata`; the rest depends on what you are adding.

<Params>
  <Param name="payload" required type="CartItemAddPayload">
    The item to add.

    <Properties label="payload" collapsed>
      <Param name="productId" required type="number">
      What to add: a variant ID for a one-time product, a plan ID for a
      subscription.
      </Param>
      <Param name="quantity" optional type="number">
      How many. Defaults to 1.
      </Param>
      <Param name="metadata" optional type="MetadataObject[] | null">
      Metafield values to save on the line.
      <Properties label="metadata">
        <MetadataFields />
      </Properties>
      </Param>
      <ParamGroup title="One-time products">
        <Param name="addon" optional type="boolean">
        `true` adds the item alongside a subscription already in the cart.
        </Param>
        <Param name="addonDuration" optional type="number">
        How long the add-on rides along: `1` for one charge, `0` for every
        charge.
        </Param>
        <Param name="giftCard" optional type="object | null">
        Who a gift card goes to.
        <Properties label="giftCard">
          <Param name="customerEmail" optional type="string | null">
          Email of the recipient.
          </Param>
          <Param name="customerName" optional type="string | null">
          Name of the recipient.
          </Param>
          <Param name="message" optional type="string | null">
          Message for the recipient.
          </Param>
        </Properties>
        </Param>
      </ParamGroup>
      <ParamGroup title="Subscriptions">
        <Param name="options" optional type="object[] | null">
        The customer's answers to the plan's survey, one entry per question.
        <Properties label="option">
          <SurveyAnswerFields />
        </Properties>
        </Param>
      </ParamGroup>
      <ParamGroup title="Bundles">
        <Param name="bundle" optional type="object">
        What goes inside the bundle.
        <Properties label="bundle">
          <Param name="items" required type="object[]">
          The picked items, each `{ productId, quantity }` from
          `subbly.bundles.loadItems`.
          </Param>
          <Param name="preferences" required type="object[]">
          The answers to the bundle preferences, each
          `{ attributeId, values }`. Send `[]` when there are none.
          </Param>
        </Properties>
        </Param>
        <Param name="options" optional type="object[] | null">
        Survey answers, when the bundle plan also has a survey. Same shape as
        for a subscription.
        </Param>
      </ParamGroup>
    </Properties>
  </Param>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The updated cart, which is `subbly.cart` itself. Its fields are written out
under [Create a cart](#create). The call rejects with `code: 'out_of_stock'`
when the product ran out.
</Returns>

<Example>

```js title="Add a one-time product"
await subbly.cart.addItem({ productId: 3301, quantity: 2 })
```

```js title="Add a subscription with survey answers"
await subbly.cart.addItem({
  productId: 8801,
  options: [
    { questionId: 11, answers: [{ id: 41 }] },
    { questionId: 12, answers: [{ content: 'No nuts, please' }] },
  ],
})
```

```js title="Add a bundle"
await subbly.cart.addItem({
  productId: 8801,
  quantity: 1,
  bundle: {
    items: [
      { productId: 3301, quantity: 2 },
      { productId: 3307, quantity: 1 },
    ],
    preferences: [{ attributeId: 9, values: [31] }],
  },
})
```

</Example>

</Method>

<Method id="update-item" signature="subbly.cart.updateItem(cartItemId, payload, params?)">

Changes one line in the cart: the quantity, the survey answers, the gift details
or the bundle contents. To change which product a line is for, remove it and add
the new one.

<Params>
  <Param name="cartItemId" required type="string">
  UUID of the line, from `cart.items[].id`.
  </Param>
  <Param name="payload" required type="CartResourceUpdateItemPayload">
    What to change. Every field is optional, and the shape follows the kind of
    item the line holds.

    <Properties label="payload" collapsed>
      <Param name="quantity" optional type="number">
      How many.
      </Param>
      <ParamGroup title="One-time products">
        <Param name="addon" optional type="boolean">
        `true` keeps the item alongside a subscription in the cart.
        </Param>
        <Param name="addonDuration" optional type="number">
        `1` for one charge, `0` for every charge.
        </Param>
        <Param name="giftCard" optional type="object | null">
        Who a gift card goes to, with `customerEmail`, `customerName` and
        `message`.
        </Param>
      </ParamGroup>
      <ParamGroup title="Subscriptions">
        <Param name="options" optional type="object[] | null">
        The survey answers, one entry per question. Send the full set; it
        replaces what was there.
        <Properties label="option">
          <SurveyAnswerFields />
        </Properties>
        </Param>
      </ParamGroup>
      <ParamGroup title="Bundles">
        <Param name="bundle" optional type="object">
        The new bundle contents, with `items` and `preferences` exactly as in
        `subbly.cart.addItem`.
        </Param>
        <Param name="options" optional type="object[] | null">
        Survey answers, when the bundle plan also has a survey.
        </Param>
      </ParamGroup>
    </Properties>
  </Param>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The updated cart, which is `subbly.cart` itself. Its fields are written out
under [Create a cart](#create).
</Returns>

<Example>

```js title="Change the quantity"
const [line] = subbly.cart.items

await subbly.cart.updateItem(line.id, { quantity: 3 })
```

</Example>

</Method>

<Method id="remove-item" signature="subbly.cart.removeItem(cartItemId, params?)">

Removes one line from the cart.

<Params>
  <Param name="cartItemId" required type="string">
  UUID of the line, from `cart.items[].id`.
  </Param>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The updated cart, which is `subbly.cart` itself. Its fields are written out
under [Create a cart](#create).
</Returns>

<Example>

```js title="Remove an item"
const [line] = subbly.cart.items

await subbly.cart.removeItem(line.id)
```

</Example>

</Method>

<Method id="get-start-dates" signature="subbly.cart.getStartDates()">

Gets the dates on which the subscription in the cart can start. Send the one the
customer picks to `subbly.cart.update` as `startsAt`.

It uses the cart the SDK holds, so load or create a cart first.

<Returns type="Promise<CartResourceStartDatesResponse>">
The dates allowed. The API fills one of the two fields and sets the other to
`null`: a fixed list of dates, or an open range. Handle both.
<Properties label="dates">
  <StartDateFields />
</Properties>
</Returns>

<Example>

```js title="Get the start dates"
const { availableDates, range } = await subbly.cart.getStartDates()

const startsAt = availableDates?.length ? availableDates[0] : range?.[0]

await subbly.cart.update({ startsAt })
```

</Example>

</Method>

<Method id="get-gifting-dates" signature="subbly.cart.getGiftingDates()">

Gets the dates on which a gift subscription in the cart can start. Send the one
the customer picks to `subbly.cart.update` as `giftInfo.startsAt`.

<Returns type="Promise<CartResourceGiftingDatesResponse>">
The dates allowed, in the same shape `subbly.cart.getStartDates` returns.
<Properties label="dates">
  <StartDateFields />
</Properties>
</Returns>

<Example>

```js title="Get the gifting dates"
const { availableDates, range } = await subbly.cart.getGiftingDates()

const startsAt = availableDates?.length ? availableDates[0] : range?.[0]

await subbly.cart.update({
  giftInfo: {
    startsAt,
    numberOfOrders: 3,
    message: 'Happy birthday',
    recipientEmail: 'grace@example.com',
  },
})
```

</Example>

</Method>

<Method id="get-shipping-methods" signature="subbly.cart.getShippingMethods(params)">

Gets the delivery options available for the cart at a destination. Send the ID
of the one the customer picks to `subbly.cart.update` as `shippingMethodId`.

Only `countryId` and `zip` are needed. Pass the rest when a carrier quotes on
the full address.

<Params>
  <Param name="params" required type="CartShippingMethodsParams">
    Where the order is going.

    <Properties label="params">
      <Param name="countryId" required type="number">
      ID of the country, from `subbly.countries.list()`. The field is
      `countryId`, not `country`.
      </Param>
      <Param name="zip" required type="string">
      Postal or ZIP code of the destination.
      </Param>
      <Param name="regionId" optional type="number">
      ID of the region, from the country's `regions[].id`.
      </Param>
      <Param name="firstName" optional type="string">
      Given name of the recipient.
      </Param>
      <Param name="lastName" optional type="string">
      Family name of the recipient.
      </Param>
      <Param name="phone" optional type="string">
      Phone number of the recipient.
      </Param>
      <Param name="addressOne" optional type="string">
      First address line.
      </Param>
      <Param name="addressTwo" optional type="string | null">
      Second address line.
      </Param>
      <Param name="city" optional type="string">
      City.
      </Param>
      <Param name="expand" optional type="string[]">
      Relations to include: `method` and `carrier`.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<ShippingMethodDelivery[]>">
The delivery options. Read `type` first: it is `shipping_option` for a carrier
delivery and `local_delivery` for the shop's own, and it decides which of the
fields below are set.
<Properties label="method" collapsed>
  <DeliveryFields />
</Properties>
</Returns>

<Example>

```js title="Get the shipping methods"
const methods = await subbly.cart.getShippingMethods({
  countryId: 826,
  zip: 'NW1 5JD',
  expand: ['carrier'],
})

await subbly.cart.update({ shippingMethodId: methods[0].id })
```

</Example>

</Method>

<Method id="get-local-pickups" signature="subbly.cart.getLocalPickups()">

Gets the pick-up points available for the cart. Send the ID of the one the
customer picks to `subbly.cart.update` as `shippingMethodId`, along with
`pickupInfo` for who collects the order.

<Returns type="Promise<ShippingMethodPickup[]>">
The pick-up points. The array is empty when the shop offers none.
<Properties label="point" collapsed>
  <PickupFields />
</Properties>
</Returns>

<Example>

```js title="Get the pick-up points"
const points = await subbly.cart.getLocalPickups()

await subbly.cart.update({
  shippingMethodId: points[0].id,
  pickupInfo: {
    firstName: 'Ada',
    lastName: 'Lovelace',
    phone: '+442071234567',
  },
})
```

</Example>

</Method>

<Method id="attach-customer" signature="subbly.cart.attachCustomer(params?)">

Assigns the cart to the signed-in customer. It sets `attached` to `true` and
`customerId` to their ID, and clears the guest details in `customer`. Call it
after the customer signs in and before you charge the cart.

It needs a signed-in customer.

<Params>
  <Param name="params" optional type="CartResourceParams">
    Relations to include.

    <Properties label="params">
      <Param name="expand" optional type="string[]">
      The relations to fill in. The values are listed at the top of this page.
      </Param>
    </Properties>
  </Param>
</Params>

<Returns type="Promise<CartModel>">
The attached cart, which is `subbly.cart` itself. Its fields are written out
under [Create a cart](#create).
</Returns>

<Example>

```js title="Attach the customer after a log-in"
await subbly.auth.login({ email, password })
await subbly.cart.attachCustomer({ expand: ['items.product'] })
```

</Example>

</Method>
