
import PaginationFields from "../../../src/reference/subbly-sdk/types/Pagination.mdx";
import ProductOneTimeFields from "../../../src/reference/subbly-sdk/types/ProductOneTime.mdx";
import ProductSubscriptionFields from "../../../src/reference/subbly-sdk/types/ProductSubscription.mdx";
import ProductVariantFields from "../../../src/reference/subbly-sdk/types/ProductVariant.mdx";
import ProductPlanFields from "../../../src/reference/subbly-sdk/types/ProductPlan.mdx";

<SdkPage group="products" />

A shop sells two kinds of product. A one-time product holds **variants**; a
subscription product holds **plans**. A parent product is what you list and show
on a page; a variant or a plan is what a customer buys, and its `id` is the
`productId` you send to `subbly.cart.addItem`.

Every method here takes an optional `headers` argument to price one response in
another currency; see [Currency](/reference/subbly-sdk#currency).

<Method id="list" signature="subbly.products.list(params?, headers?)">

Gets a page of the shop's parent products.

<Params>
  <Param name="params" optional type="ProductsListParams">
    Which products to return.
    <Properties label="params">
      <Param name="page" optional type="number">
        Page to return, counted from 1.
      </Param>

      <Param name="perPage" optional type="number">
        How many products per page.
      </Param>

      <Param name="tags" optional type="string[]">
        Keep only products with these tags.
      </Param>

      <Param name="type" optional type="'one_time' | 'subscription'">
        Keep only one-time products, or only subscription products.
      </Param>

      <Param name="slugs" optional type="string[]">
        Keep only products with these slugs.
      </Param>

      <Param name="digital" optional type="boolean">
        `true` keeps only digital products, `false` only physical ones.
      </Param>

      <Param name="giftCard" optional type="boolean">
        `true` keeps only gift cards, `false` leaves them out.
      </Param>

      <Param name="expand" optional type="string[]">
        Relations to include: `variants`, `variants.parent`, `plans`,
        `plans.parent` and `metadata`. Without them a product carries no
        buyable children.
      </Param>
    </Properties>
  </Param>

  <Param name="headers" optional type="ProductRequestHeaders">
    Extra request headers, such as `x-currency`.
  </Param>
</Params>

<Returns type="Promise<ProductsListResponse>">
One page of products.
<Properties>
  <Param name="data" type="ParentProduct[]">
    The products on this page. Each one is a one-time product or a subscription
    product; narrow on `type`.
    <Properties label="product" collapsed>
      <ParamGroup title="One-time products (type: 'one_time')" defaultOpen={false}>
        <ProductOneTimeFields />
      </ParamGroup>

      <ParamGroup title="Subscription products (type: 'subscription')" defaultOpen={false}>
        <ProductSubscriptionFields />
      </ParamGroup>
    </Properties>
  </Param>

  <Param name="pagination" type="Pagination">
    Where this page sits in the full list.
    <Properties label="pagination" collapsed>
      <PaginationFields />
    </Properties>
  </Param>
</Properties>
</Returns>

<Example>

```js title="List the products"
const { data, pagination } = await subbly.products.list({
  page: 1,
  perPage: 10,
  expand: ['variants.parent']
})
```

```js title="List the subscription products only"
const { data } = await subbly.products.list({
  type: 'subscription',
  expand: ['plans']
})
```

</Example>

</Method>

<Method id="load" signature="subbly.products.load(productId, params?, headers?)">

Loads one parent product, with its variants or its plans.

<Params>
  <Param name="productId" required type="number">
    ID of the parent product.
  </Param>

  <Param name="params" optional type="ProductsResourceParams">
    Extra data to include.
    <Properties label="params">
      <Param name="expand" optional type="string[]">
        Relations to include: `variants`, `variants.parent`, `plans`,
        `plans.parent` and `metadata`.
      </Param>
    </Properties>
  </Param>

  <Param name="headers" optional type="ProductRequestHeaders">
    Extra request headers, such as `x-currency`.
  </Param>
</Params>

<Returns type="Promise<ParentProduct>">
The product. Narrow on `type` to read `variants` or `plans`.
<Properties label="product" collapsed>
  <ParamGroup title="One-time products (type: 'one_time')" defaultOpen={false}>
    <ProductOneTimeFields />
  </ParamGroup>

  <ParamGroup title="Subscription products (type: 'subscription')" defaultOpen={false}>
    <ProductSubscriptionFields />
  </ParamGroup>
</Properties>
</Returns>

<Example>

```js title="Load a product"
const product = await subbly.products.load(123, {
  expand: ['variants.parent', 'plans.parent']
})

const buyable = product.type === 'subscription' ? product.plans : product.variants
```

</Example>

</Method>

<Method id="load-variant" signature="subbly.products.loadVariant(productId, params?, headers?)">

Loads one product variant, the buyable child of a one-time product.

Pass a **variant** ID, not the ID of its parent. The endpoint behind this method
also serves plans, so the declared result is a variant or a plan; use
`subbly.products.loadPlan` when you hold a plan ID.

<Params>
  <Param name="productId" required type="number">
    ID of the variant.
  </Param>

  <Param name="params" optional type="ProductsResourceParams">
    Extra data to include.
    <Properties label="params">
      <Param name="expand" optional type="string[]">
        Relations to include. `parent` loads the product the variant belongs to.
      </Param>
    </Properties>
  </Param>

  <Param name="headers" optional type="ProductRequestHeaders">
    Extra request headers, such as `x-currency`.
  </Param>
</Params>

<Returns type="Promise<Product>">
The variant, or the plan when the ID belongs to one.
<Properties label="product" collapsed>
  <ParamGroup title="Variant" defaultOpen={false}>
    <ProductVariantFields />
  </ParamGroup>

  <ParamGroup title="Plan" defaultOpen={false}>
    <ProductPlanFields />
  </ParamGroup>
</Properties>
</Returns>

<Example>

```js title="Load a variant"
const variant = await subbly.products.loadVariant(456, { expand: ['parent'] })

await subbly.cart.addItem({ productId: variant.id, quantity: 1 })
```

</Example>

</Method>

<Method id="load-plan" signature="subbly.products.loadPlan(productId, params?, headers?)">

Loads one subscription plan, the buyable child of a subscription product. Older
material calls a plan a pricing.

`loadPlan` and `loadVariant` call the same endpoint; only the type of the result
differs. Use `loadPlan` when the ID belongs to a plan.

<Params>
  <Param name="productId" required type="number">
    ID of the plan.
  </Param>

  <Param name="params" optional type="ProductsResourceParams">
    Extra data to include.
    <Properties label="params">
      <Param name="expand" optional type="string[]">
        Relations to include. `parent` loads the product the plan belongs to.
      </Param>
    </Properties>
  </Param>

  <Param name="headers" optional type="ProductRequestHeaders">
    Extra request headers, such as `x-currency`.
  </Param>
</Params>

<Returns type="Promise<ProductPlan>">
The plan.
<Properties label="plan" collapsed>
  <ProductPlanFields />
</Properties>
</Returns>

<Example>

```js title="Load a plan"
const plan = await subbly.products.loadPlan(789, { expand: ['parent'] })

console.log(plan.frequencyCount, plan.frequencyUnit)
```

</Example>

</Method>
