> This page is for Developer.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.bigcommerce.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.bigcommerce.com/_mcp/server.

# B2B Storefront

The B2B storefront MCP server exposes Buyer Portal workflows — shopping lists and quotes — to AI agents. These tools run on the same MCP endpoint as the [B2C storefront tools](/developer/api-reference/mcp/storefront/b2c), which stay available on a B2B-enabled store too — a guest can still search products, get product details, and check out without signing in. The Buyer Portal tools on this page are layered on top of that: they're added to a session when the store has B2B Edition enabled and the buyer holds the matching permission, authenticated via [Storefront Session Sync](/developer/api-reference/mcp/storefront-session-sync) — the same mechanism used for logged-in B2C shoppers. Three of the quote tools are the exception — see [How B2B tools are exposed](#how-b2b-tools-are-exposed) below.

## How B2B tools are exposed

B2B tools are additive. Every session — guest, customer, or company account — keeps the catalog and cart tools described on the B2C page. On top of that, a session receives a B2B tool when both of the following are true:

* The store has the B2B MCP integration enabled.
* The authenticated buyer holds the buyer permission that gates the tool.

`request_quote`, `get_quote_details`, and `send_quote_message` are the exception to the second condition: when a store enables guest quotes, a guest can request a quote, view its details, and message the sales representative about it — gated by that store setting rather than by an authenticated buyer permission.

Because tools are gated per permission, two buyers on the same company account can see different tool sets. A junior buyer who can submit a shopping list for approval but not approve one receives `submit_shopping_list_for_approval` and not `approve_shopping_list`.

Buyers authenticate through [Storefront Session Sync](/developer/api-reference/mcp/storefront-session-sync) — there is no dedicated login tool. Product search, cart, and checkout stay available to shoppers who are not signed in to a company account; the B2B tools above (aside from the guest-enabled quote tools) become available once the buyer's company session is synced and their permissions are evaluated.

## Example prompts

* "Add 24 units of the 5-gallon primer to my Q3 restock list."
* "Submit my restock list for approval."
* "Which of my shopping lists are waiting on approval?"
* "Request a quote for everything on the restock list, shipping to our Dallas warehouse."
* "Ask the rep whether the quote can ship before the 15th."
* "Turn quote 1042 into an order."

## Shopping list tools

A shopping list is a company-scoped, collaborative collection of products and quantities. Lists move through an approval workflow before a buyer uses one for ordering: `draft` → `ready_for_approval` → `approved` or `rejected`.

Tools always report and accept `status` as one of `draft`, `ready_for_approval`, `approved`, `rejected`, or `deleted`. Agents never set the status directly — `create_shopping_list` always creates a draft, `update_shopping_list` preserves the current status, and the approval tools own every transition.

#### create_shopping_list

Create a shopping list for the buyer's company account. The list is created as a draft with no items; add items with `add_item_to_shopping_list`.

| Input         | Type   | Required | Description                          |
| ------------- | ------ | -------- | ------------------------------------ |
| `name`        | string | Yes      | Name of the shopping list.           |
| `description` | string | No       | Description of what the list is for. |

Returns the new shopping list, including its `id` and `status` of `draft`.

#### get_shopping_lists

Retrieve the shopping lists the buyer can see, so an agent can pick one to work on. Results are ordered by most recently updated and do not include items or totals — use `get_shopping_list_details` for those.

| Input       | Type    | Required | Description                                                                      |
| ----------- | ------- | -------- | -------------------------------------------------------------------------------- |
| `search`    | string  | No       | Matches part of a list's name, description, or rejection reason.                 |
| `status`    | array   | No       | One or more of `draft`, `ready_for_approval`, `approved`, `rejected`, `deleted`. |
| `mine_only` | boolean | No       | Return only lists the buyer created.                                             |
| `first`     | integer | No       | Number of lists to return.                                                       |
| `offset`    | integer | No       | Number of lists to skip.                                                         |

Returns each list's `id`, `name`, `description`, `status`, `updatedAt`, `isOwner`, `reason`, and `channelName`, plus a `totalCount`.

> **Note**
>
> A buyer whose view permission is scoped to their own records only sees their own lists, regardless of the `mine_only` value.

#### get_shopping_list_details

Get one shopping list with its totals and items. Items are paginated, so an agent can work with large lists without reading every line.

| Input         | Type    | Required | Description                                    |
| ------------- | ------- | -------- | ---------------------------------------------- |
| `id`          | integer | Yes      | Shopping list ID from `get_shopping_lists`.    |
| `item_search` | string  | No       | Matches part of an item's product name or SKU. |
| `item_first`  | integer | No       | Number of items to return.                     |
| `item_offset` | integer | No       | Number of items to skip.                       |

Returns the list header (`id`, `name`, `description`, `status`, `channelName`, `updatedAt`), totals (`grandTotal`, `totalDiscount`, `totalTax`, `isShowGrandTotal`), and `products` with `itemId`, `productId`, `variantId`, `quantity`, `productName`, `baseSku`, `variantSku`, `basePrice`, `discount`, `tax`, `optionList`, `productNote`, `primaryImage`, and `productUrl`, plus `itemTotalCount` and `hasMore` for paging.

> **Note**
>
> This tool and `add_item_to_shopping_list` are the only sources of `itemId`, which `update_shopping_list_item` and `delete_shopping_list_item` require.

#### update_shopping_list

Rename a shopping list or change its description. The list keeps its current approval status.

| Input         | Type    | Required | Description          |
| ------------- | ------- | -------- | -------------------- |
| `id`          | integer | Yes      | Shopping list ID.    |
| `name`        | string  | Yes      | Updated name.        |
| `description` | string  | No       | Updated description. |

Returns the updated shopping list.

#### delete_shopping_list

Delete a shopping list and its items.

| Input | Type    | Required | Description       |
| ----- | ------- | -------- | ----------------- |
| `id`  | integer | Yes      | Shopping list ID. |

Returns `success` and a `message`.

#### add_item_to_shopping_list

Add one or more products to a shopping list. Pass an array to add several products in a single call.

| Input                 | Type    | Required                           | Description                                                                                |
| --------------------- | ------- | ---------------------------------- | ------------------------------------------------------------------------------------------ |
| `shoppingListId`      | integer | Yes                                | Shopping list ID.                                                                          |
| `items`               | array   | Yes                                | Products to add.                                                                           |
| `items[].productId`   | integer | Yes                                | Product entity ID.                                                                         |
| `items[].variantId`   | integer | Yes                                | Variant entity ID.                                                                         |
| `items[].quantity`    | integer | Yes                                | Number of units.                                                                           |
| `items[].optionList`  | array   | Yes (when the product has options) | Option selections as `optionId` and `optionValue` pairs, taken from `get_product_details`. |
| `items[].productNote` | string  | No                                 | Note to store with the line item.                                                          |

Returns the added items, each with its `itemId`.

#### update_shopping_list_item

Change the quantity, variant, options, or note for an item already on a shopping list.

| Input            | Type    | Required                           | Description                                                                                                               |
| ---------------- | ------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `shoppingListId` | integer | Yes                                | Shopping list ID.                                                                                                         |
| `itemId`         | integer | Yes                                | Item ID from `get_shopping_list_details` or `add_item_to_shopping_list`.                                                  |
| `quantity`       | integer | No                                 | Updated quantity.                                                                                                         |
| `variantId`      | integer | No                                 | Updated variant entity ID. If provided, `optionList` is required, regardless of whether the product actually has options. |
| `optionList`     | array   | Yes (when `variantId` is provided) | Full set of option selections for the item.                                                                               |
| `productNote`    | string  | No                                 | Updated note.                                                                                                             |

Returns the updated item.

#### delete_shopping_list_item

Remove one item from a shopping list. To reduce quantity without removing the item, use `update_shopping_list_item`.

| Input            | Type    | Required | Description        |
| ---------------- | ------- | -------- | ------------------ |
| `shoppingListId` | integer | Yes      | Shopping list ID.  |
| `itemId`         | integer | Yes      | Item ID to remove. |

Returns `success` and a `message`.

#### submit_shopping_list_for_approval

Move a draft shopping list to `ready_for_approval` so an approver can review it. Available to buyers who hold the submit-for-approval permission.

| Input | Type    | Required | Description       |
| ----- | ------- | -------- | ----------------- |
| `id`  | integer | Yes      | Shopping list ID. |

Returns the updated shopping list with a `status` of `ready_for_approval`.

#### approve_shopping_list

Approve a shopping list so buyers on the company account can order from it. Available to buyers who hold the approval permission, such as senior buyers and company admins.

| Input | Type    | Required | Description       |
| ----- | ------- | -------- | ----------------- |
| `id`  | integer | Yes      | Shopping list ID. |

Returns the updated shopping list with a `status` of `approved`.

#### reject_shopping_list

Reject a shopping list that is waiting on approval. Gated by the same permission as `approve_shopping_list` — an approver either approves or rejects.

| Input | Type    | Required | Description       |
| ----- | ------- | -------- | ----------------- |
| `id`  | integer | Yes      | Shopping list ID. |

Returns the updated shopping list with a `status` of `rejected`.

#### duplicate_shopping_list

Copy an existing shopping list, including its items, into a new list. Use this for repeat ordering — duplicate last month's list instead of adding every product again.

| Input                  | Type    | Required | Description                   |
| ---------------------- | ------- | -------- | ----------------------------- |
| `sourceShoppingListId` | integer | Yes      | ID of the list to copy.       |
| `name`                 | string  | Yes      | Name for the new list.        |
| `description`          | string  | No       | Description for the new list. |

Returns the new shopping list. Every item is copied onto it, but the response itself only includes the first 20 copied items plus a `hasMore` flag — call `get_shopping_list_details` to page through the rest.

## Quote tools

A quote starts as a buyer request at list price. A sales representative then prices it, and the buyer converts an open quote to an order. Quote tools report `status` as `open`, `ordered`, or `expired`; the sales representative's internal states stay out of the storefront.

#### get_quotes

Retrieve the quotes the buyer can see, with totals so an agent can triage them.

| Input                                    | Type    | Required | Description                                                                       |
| ---------------------------------------- | ------- | -------- | --------------------------------------------------------------------------------- |
| `search`                                 | string  | No       | Matches part of a quote's title or reference.                                     |
| `status`                                 | string  | No       | One of `open`, `ordered`, `expired`.                                              |
| `quoteNumber`                            | string  | No       | Exact quote number.                                                               |
| `quoteTitle`                             | string  | No       | Matches part of the quote title.                                                  |
| `company`                                | string  | No       | Company name on the quote.                                                        |
| `dateCreatedBeginAt`, `dateCreatedEndAt` | string  | No       | Created-date range.                                                               |
| `dateUpdatedBeginAt`, `dateUpdatedEndAt` | string  | No       | Updated-date range.                                                               |
| `dateExpiredBeginAt`, `dateExpiredEndAt` | string  | No       | Expiry-date range, for finding quotes that expire soon.                           |
| `orderBy`                                | string  | No       | Sort field and direction, for example `-quoteNumber`. Defaults to `-quoteNumber`. |
| `first`                                  | integer | No       | Number of quotes to return.                                                       |
| `offset`                                 | integer | No       | Number of quotes to skip.                                                         |

Returns each quote's `id`, `uuid`, `quoteNumber`, `quoteTitle`, `referenceNumber`, `status`, totals (`subtotal`, `discount`, `taxTotal`, `grandTotal`, `totalAmount`), `createdAt`, `updatedAt`, `expiredAt`, `company`, `channelId`, and `channelName`, plus a `totalCount`.

> **Note**
>
> Carry the `id` and `uuid` from this response into `get_quote_details` and `generate_quote_checkout_url` — both require them.

#### request_quote

Request a quote for a set of products. The buyer requests at list price and the sales representative applies pricing afterward, so the tool computes line and quote totals from `basePrice` and does not accept buyer-supplied pricing, discounts, or expiry.

| Input                       | Type    | Required                           | Description                                                                                                                                                                                                           |
| --------------------------- | ------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productList`               | array   | Yes                                | Products to quote.                                                                                                                                                                                                    |
| `productList[].productId`   | integer | Yes                                | Product entity ID.                                                                                                                                                                                                    |
| `productList[].variantId`   | integer | Yes                                | Variant entity ID.                                                                                                                                                                                                    |
| `productList[].sku`         | string  | Yes                                | Variant SKU from `get_product_details`.                                                                                                                                                                               |
| `productList[].productName` | string  | Yes                                | Product name from `get_product_details`.                                                                                                                                                                              |
| `productList[].imageUrl`    | string  | Yes                                | Product image URL from `get_product_details`.                                                                                                                                                                         |
| `productList[].quantity`    | integer | Yes                                | Number of units.                                                                                                                                                                                                      |
| `productList[].basePrice`   | string  | Yes                                | List price from `get_product_details`.                                                                                                                                                                                |
| `productList[].options`     | array   | Yes (when the product has options) | Option selections for the variant.                                                                                                                                                                                    |
| `shippingAddress`           | object  | Yes                                | Ship-to address: `firstName`, `lastName`, `address`, `city`, `zipCode`, `country`, and optional `state`, `apartment`, `phoneNumber`, `companyName`, `label`, `addressId`.                                             |
| `billingAddress`            | object  | Yes                                | Bill-to address, same shape as `shippingAddress`.                                                                                                                                                                     |
| `contactInfo`               | object  | Yes                                | Contact for the quote: `name`, `email`, and optional `companyName`, `phoneNumber`. `email` is required for guest callers; for an authenticated buyer it's accepted but ignored in favor of the buyer's account email. |
| `quoteTitle`                | string  | No                                 | Title for the quote.                                                                                                                                                                                                  |
| `message`                   | string  | No                                 | Opening message to the sales representative.                                                                                                                                                                          |
| `channelId`                 | integer | No                                 | Channel the quote belongs to. Defaults to `1`.                                                                                                                                                                        |

Returns the new quote's `id`, `createdAt`, and `uuid`. The response doesn't include `status` or totals — call `get_quote_details` with those values to retrieve them.

#### get_quote_details

Get one quote with its line items, totals, and message thread.

| Input  | Type    | Required | Description                                      |
| ------ | ------- | -------- | ------------------------------------------------ |
| `id`   | integer | Yes      | Quote ID from `get_quotes`.                      |
| `date` | string  | Yes      | The quote's `createdAt` value from `get_quotes`. |
| `uuid` | string  | Yes      | The quote's `uuid` from `get_quotes`.            |

Returns the quote header (`quoteNumber`, `quoteTitle`, `referenceNumber`, `status`, `notes`, `legalTerms`, `channelId`, `channelName`, `company`, `createdAt`, `updatedAt`, `expiredAt`), totals (`subtotal`, `discount`, `discountType`, `discountValue`, `taxTotal`, `shippingTotal`, `grandTotal`, `totalAmount`), `products` with per-line `basePrice`, `offeredPrice`, `discount`, and `quantity` (`itemId` and `options` are never populated on this response), the buyer and sales representative message thread, `allowCheckout`, buyer-visible attachments, `quoteUrl`, and conversion fields (`cartId`, `cartUrl`, `checkoutUrl`, `orderId`, `bcOrderId`).

> **Tip**
>
> Check `allowCheckout` before calling `generate_quote_checkout_url` — it tells you whether the quote can still convert to an order.

#### send_quote_message

Post a message from the buyer onto a quote, for example to ask about lead time or request a revision.

| Input     | Type    | Required | Description                                  |
| --------- | ------- | -------- | -------------------------------------------- |
| `quoteId` | integer | Yes      | Quote ID.                                    |
| `message` | string  | Yes      | Message to send to the sales representative. |

Returns the updated message thread for the quote.

#### generate_quote_checkout_url

Create a cart and checkout URL from a quote so the buyer can place the order at the quoted prices. The quote must be open and not expired.

| Input  | Type    | Required | Description                           |
| ------ | ------- | -------- | ------------------------------------- |
| `id`   | integer | Yes      | Quote ID.                             |
| `uuid` | string  | Yes      | The quote's `uuid` from `get_quotes`. |

Returns `cartId`, `cartUrl`, and `checkoutUrl` — send the buyer to `checkoutUrl` to complete the order.

## Typical flows

#### Build a shopping list

Call `search_products` and `get_product_details` to identify products and variants, `create_shopping_list` to create the list, then `add_item_to_shopping_list` to add products in a single batched call.

#### Run it through approval

Call `submit_shopping_list_for_approval` as the buyer. An approver calls `approve_shopping_list` or `reject_shopping_list`. Poll status with `get_shopping_lists` filtered to `ready_for_approval`.

#### Request a quote

Call `get_shopping_list_details` to read the approved items, then `request_quote` with those products, the addresses, and contact information.

#### Negotiate

Call `get_quote_details` to read the sales representative's pricing and message thread, and `send_quote_message` to reply.

#### Convert to an order

When `allowCheckout` is true, call `generate_quote_checkout_url` and send the buyer to the returned `checkoutUrl`.

## Reorder with duplicate lists

For recurring purchases, call `duplicate_shopping_list` with the previous list's ID. The copy includes every item, including configurable products, so the agent only adjusts quantities before submitting the new list for approval.