--- title: Manage B2B catalogs description: >- Learn how to manage published products for customers at different companies by using B2B catalogs. source_url: html: 'https://shopify.dev/docs/apps/build/b2b/manage-catalogs' md: 'https://shopify.dev/docs/apps/build/b2b/manage-catalogs.md' --- # Manage B2B catalogs **Caution:** Starting in API version 2023-04, the [`PriceList.contextRule`](https://shopify.dev/docs/api/admin-graphql/unstable/objects/PriceList#field-pricelist-contextrule) field will be deprecated. If you have an existing app that uses the `contextRule` field, then you should [migrate to catalogs](https://shopify.dev/docs/apps/build/markets/migrate-to-catalogs). Catalogs are used to determine the products that are published to customers in different contexts. For example, a business-to-business (B2B) catalog might specify that customers ordering for a specific B2B company location can purchase only the t-shirt products in the store at a 30% discount. In this guide, you'll learn how to build price lists and publications, and associate them with catalogs to control prices and publishing for a specific B2B company location. **Note:** If you're using the new Markets API, currently in developer preview, then consider managing your B2B catalogs with markets instead of linking them directly to the company location. For more information, refer to the [About Shopify Markets developer preview](https://shopify.dev/docs/apps/build/markets/new-markets). *** ## Requirements * Your app can make [authenticated requests](https://shopify.dev/docs/api/admin-graphql#authentication) to the GraphQL Admin API. * Your app has the `write_products` [access scope](https://shopify.dev/docs/api/usage/access-scopes). Learn how to [configure your access scopes using Shopify CLI](https://shopify.dev/docs/apps/build/cli-for-apps/app-configuration). * You've created [products](https://shopify.dev/docs/api/admin-graphql/latest/mutations/productcreate) and [product variants](https://shopify.dev/docs/api/admin-graphql/latest/mutations/productvariantcreate) in your store. - You're familiar with the concept of [catalogs](https://shopify.dev/docs/apps/build/markets/catalogs-different-markets). - You've [created a company](https://shopify.dev/docs/apps/build/b2b/start-building#step-1-create-a-company) and [created a B2B catalog](https://shopify.dev/docs/apps/build/b2b/start-building#step-2-create-a-b2b-catalog). *** ## Step 1: Associate a price list with the catalog You can associate a price list with the catalog to determine the prices that are shown to customers ordering for that B2B company location. If a price list isn't associated with the catalog, then customers ordering for this B2B company location receive the initial variant prices converted to the market currency. ### Create a new price list Use the [`priceListCreate`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/priceListCreate) mutation to create a new price list for the catalog. You can set the name, a percentage-based adjustment, a currency, and the ID of the catalog to associate. ## POST https://{shop}.myshopify.com/api/{api\_version}/graphql.json ## GraphQL mutation ```graphql mutation priceListCreate($input: PriceListCreateInput!) { priceListCreate(input: $input) { priceList { id } userErrors { field message } } } ``` ## Variables ##### json ```json { "input": { "name": "European prices", "currency": "EUR", "catalogId": "gid://shopify/MarketCatalog/CATALOG-ID", "parent": { "adjustment": { "type": "PERCENTAGE_INCREASE", "value": 10.0 } } } } ``` ##### json ```json { "input": { "name": "Prices for Company's European location", "currency": "EUR", "catalogId": "gid://shopify/CompanyLocationCatalog/CATALOG-ID", "parent": { "adjustment": { "type": "PERCENTAGE_DECREASE", "value": 30.0 }, "settings": { "compareAtMode": "NULLIFY" } } } } ``` ## JSON response ```json { "data": { "priceListCreate": { "priceList": { "id": "gid://shopify/PriceList/ID" }, "userErrors": [] } } } ``` ### Associate an existing price list Use the [`priceListUpdate`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/pricelistupdate) mutation to associate an existing price list with a catalog. You can also make changes to the name, currency, or percentage-based adjustments with the `priceListUpdate` mutation. ## POST https://{shop}.myshopify.com/api/{api\_version}/graphql.json ## GraphQL mutation ```graphql mutation priceListUpdate($id: ID!, $input: PriceListUpdateInput!) { priceListUpdate(id: $id, input: $input) { priceList { id } userErrors { field message } } } ``` ## Variables ##### json ```json { "id": "gid://shopify/PriceList/ID", "input": { "catalogId": "gid://shopify/MarketCatalog/CATALOG-ID" } } ``` ##### json ```json { "id": "gid://shopify/PriceList/ID", "input": { "catalogId": "gid://shopify/CompanyLocationCatalog/CATALOG-ID" } } ``` ## JSON response ```json { "data": { "priceListUpdate": { "priceList": { "id": "gid://shopify/PriceList/ID" }, "userErrors": [] } } } ``` **Prevent orphaned resources:** When using `priceListUpdate` to change a price list's `catalogId`, the price list becomes disassociated from its previous catalog. If the old catalog was dependent on that price list, it becomes a publishing-only catalog and uses store default prices. Ensure the source catalog either gets a new price list or is intended to become a publishing-only catalog. *** ## Step 2: Associate a publication **Caution:** If a publication isn't associated with a B2B catalog, then customers logged into their B2B accounts won't see any products for that location. The publication determines which products are published to customers that are eligible for the catalog. If you have an existing publication, then you can use the [`catalogUpdate`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/catalogupdate) mutation to associate a publication or make other changes to a catalog. **Prevent orphaned resources:** When using `catalogUpdate` to change a catalog's `publicationId`, the **previous publication remains in the system** and becomes orphaned unless you explicitly delete it. Follow this pattern: 1. Query the current publication ID before updating 2. Update the catalog with the new publication ID using `catalogUpdate` 3. Delete the old publication using [`publicationDelete`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/publicationDelete) To create and associate a new publication, use the [`publicationCreate`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/publicationcreate) mutation: ## POST https://{shop}.myshopify.com/api/{api\_version}/graphql.json ## GraphQL mutation ```graphql mutation publicationCreate { publicationCreate(input: { catalogId: "gid://shopify/CompanyLocationCatalog/CATALOG-ID" defaultState: ALL_PRODUCTS }) { publication { id catalog { id title } } userErrors { code field message } } } ``` ## JSON response ```json { "data": { "publicationCreate": { "publication": { "id": "gid://shopify/Publication/123", "catalog": { "id": "gid://shopify/CompanyLocationCatalog/1", "title": "Catalog for Company's European location" } }, "userErrors": [] } } } ``` ### Add products to the publication After you create a publication, you can add products to the publication with the [`publicationUpdate`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/publicationupdate) mutation: ## POST https://{shop}.myshopify.com/api/{api\_version}/graphql.json ## GraphQL mutation ```graphql mutation publicationUpdate { publicationUpdate( id: "gid://shopify/Publication/1", input: { publishablesToAdd: ["gid://shopify/Product/1"], publishablesToRemove: ["gid://shopify/Product/2"] }) { publication { products(first: 10) { edges { node { id } } } } userErrors { field code message } } } ``` ## JSON response ```json { "data": { "publicationUpdate": { "publication": { "products": { "edges": [ { "node": { "id": "gid://shopify/Product/1" } } ] } }, "userErrors": [] } } } ``` *** ## Step 3: Set fixed prices for specific product variants Use the [`priceListFixedPricesAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/priceListFixedPricesAdd) mutation to set a fixed price for specific product variants. If a product variant is [published to the catalog](#step-2-associate-a-publication-optional) and doesn’t have a set fixed price, then its price is automatically calculated using the percentage-based adjustment that’s specified in the [`PriceListParent`](https://shopify.dev/docs/api/admin-graphql/latest/objects/pricelistparent) object. **Warning:** The `priceListFixedPricesAdd` mutation accepts a maximum of 250 prices for each request and acts as an add and replace operation. If a fixed price for a given variant already exists on the price list, then it’s replaced. ## POST https://{shop}.myshopify.com/api/{api\_version}/graphql.json ## GraphQL mutation ```graphql mutation priceListFixedPricesAdd( $priceListId: ID!, $prices: [PriceListPriceInput!]! ) { priceListFixedPricesAdd(priceListId: $priceListId, prices: $prices) { prices { variant { id } } userErrors { field message } } } ``` ## Variables ```json { "priceListId": "gid://shopify/PriceList/ID", "prices": [ { "variantId": "gid://shopify/ProductVariant/ID", "price": { "amount": "10.00", "currencyCode": "EUR" }, "compareAtPrice": { "amount": "12.00", "currencyCode": "EUR" } }, { "variantId": "gid://shopify/ProductVariant/ID-2", "price": { "amount": "15.00", "currencyCode": "EUR" } } ] } ``` ## JSON response ```json { "data": { "priceListFixedPricesAdd": { "prices": [ { "variant" : { "id" : "gid://shopify/ProductVariant/ID" } }, { "variant" : { "id" : "gid://shopify/ProductVariant/ID" } } ], "userErrors": [] } } } ``` ### Delete fixed prices To delete a partial set of fixed prices on a price list, you can use the [`priceListFixedPricesDelete`](https://shopify.dev/docs/api/admin-graphql/unstable/mutations/priceListFixedPricesDelete) mutation. After a fixed price is deleted, the price for the affected product variant is automatically calculated using the price list parent's percentage-based adjustment. To delete fixed prices, you need to specify the variant ID. You can specify a maximum of 250 variant IDs in the array. ## POST https://{shop}.myshopify.com/api/{api\_version}/graphql.json ## GraphQL mutation ```graphql mutation priceListFixedPricesDelete( $priceListId: ID!, $variantIds: [ID!]! ) { priceListFixedPricesDelete(priceListId: $priceListId, variantIds: $variantIds) { userErrors { field message } } } ``` ## Variables ```json { "priceListId": "gid://shopify/PriceList/ID", "variantIds": ["gid://shopify/ProductVariant/ID"] } ``` ## JSON response ```json { "data": { "priceListFixedPricesDelete": { "deletedFixedPriceVariantIds": [ "gid://shopify/ProductVariant/ID" ], "userErrors": [] } } } ``` *** ## Managing multiple catalogs per company location B2B company locations support multiple catalog assignments, enabling the same [two-catalog pattern](https://shopify.dev/docs/apps/build/markets/catalogs-different-markets#two-catalog-pattern-for-scale) used for markets. ### Use case: Separate pricing and product assortments When you have many price lists but fewer product assortments (or vice versa), you can: * Create [pricing-only catalogs](https://shopify.dev/docs/apps/build/markets/catalogs-different-markets#pricing-only-catalogs) (one per price list) * Create [publication-only catalogs](https://shopify.dev/docs/apps/build/markets/catalogs-different-markets#publication-only-catalogs) (one per product assortment) * Assign multiple catalogs to the same company location **Example:** A B2B merchant with 50 different pricing tiers and 10 different product catalogs can create: * 50 pricing-only catalogs + 10 publication-only catalogs = **60 total catalogs** * Instead of 500 full catalogs (50 × 10) ### Customer experience When a B2B customer orders for a company location with multiple catalogs: 1. **Product visibility:** They see products from applicable publication catalogs 2. **Pricing:** They receive prices from applicable pricing catalogs 3. **Multiple pricing catalogs:** If multiple pricing catalogs apply, they receive the lowest price 4. **Multiple publication catalogs:** Products must be published in at least one applicable publication to be visible For more details on this pattern, see [About catalogs for different markets](https://shopify.dev/docs/apps/build/markets/catalogs-different-markets#two-catalog-pattern-for-scale). *** ## Next steps * Learn how to calculate and send invoices for [draft orders for B2B customers](https://shopify.dev/docs/apps/build/b2b/draft-orders). ***