The production constraint
The requirement looked simple at first: give approved partners better pricing, show that pricing clearly, and keep checkout frictionless. The hard part was what could not change.
The store needed to keep one public catalog, one inventory model, and one merchandising surface. No duplicated wholesale products. No separate storefront. No manual discount code. No hidden second version of the same SKU waiting to drift from the real product data.
That constraint matters more than the percentage. Once partner pricing is implemented by duplicating products or routing partners to a shadow storefront, every future change becomes two changes: inventory, PDP copy, images, collections, SEO, merchandising, analytics, and checkout QA. A partner portal should not create a second store inside the store.
This was also not a native Shopify Plus B2B catalog build yet. The implementation needed to work on Shopify Advanced today while keeping a clean path toward Shopify Plus B2B Companies, Company Locations, and Catalogs later. That means the design had to separate three things: who the customer is, what price rule they qualify for, and how checkout receives the final discount.
Recognition comes before pricing
The first rule was that partners log in through standard Shopify customer accounts. That keeps authentication aligned with Shopify instead of introducing a custom login island that checkout cannot trust.
Once the customer is authenticated, the storefront can recognize whether they belong to a partner segment or carry an approved partner tag. The important detail is that the UI should not collapse all eligible customers into one hard-coded state like isPartner = true forever. That is fine as a local display flag, but the source of truth should stay segment-based so future partner groups can receive different rules.
A good data model looks more like this:
| Layer | Responsibility |
|---|
| Customer account | Proves who is logged in |
| Segment or tag | Decides which pricing rule applies |
| Pricing rule config | Defines the discount model and exclusions |
| Storefront UI | Displays the eligible price before checkout |
| Discount logic | Applies the final cart math automatically |
That structure leaves room for future segments: cafes, studios, wholesale testers, launch partners, or regional partners. They might all be "partners" in the UI, but they should not all be forced into the same pricing model in code.
The standard catalog rule
For the standard catalog, the partner rule was a flat 30% reduction from retail price. It applies site-wide except for one 500g SKU that has its own volume pricing model.
The display rule is as important as the math. A logged-in partner should see the original retail price with a strikethrough, the partner price clearly visible, and an explicit Partner pricing label on both product cards and product detail pages.
That label is not decoration. It tells the customer why the price changed. Without it, partners wonder whether they are seeing a sale, a bug, a market price, or a checkout-only discount that may disappear later.
The operational rule is also clear: the storefront can calculate and display the expected partner price, but checkout-safe discount logic still needs to apply the actual savings. Display-only pricing is not enough. If the cart and checkout do not agree with the PDP, trust breaks immediately.
The single-SKU volume exception
One 500g SKU did not belong in the flat discount rule. It needed tiered unit pricing based on cart quantity:
| Quantity | Unit price |
|---|
| 1-2 | $350 |
| 3-6 | $175 |
| 7-19 | $150 |
| 20+ | $125 |
This should be visible on the PDP before add to cart. Partners should not need to guess whether adding three units changes the price. The product page should show the quantity breaks directly, then the cart should reflect the same rule after quantity changes.
The important architectural choice is to treat this as a SKU-specific exception, not a second catalog. The product stays the same product. The variant stays the same variant. The rule targets that SKU and only that SKU.
That keeps inventory, product content, and merchandising unified while still allowing a different commercial model for one product.
Cart and checkout should apply pricing automatically
Partner pricing should not depend on manual discount codes. Codes create leakage risk, support work, and inconsistent behavior when a partner forgets the code or shares it with a non-partner.
The better behavior is automatic application from buyer context. The cart should know whether the buyer is eligible, which segment applies, which SKUs are excluded, and which tier wins when quantities change.
Mixed carts need special attention. A cart can contain standard discounted products, the volume-priced SKU, and free accessory products. The discount layer needs to prevent unwanted stacking and inconsistent totals.
In this case, free products were disabled for partners because partners already receive a stronger commercial benefit. That is not just a UX rule. It needs enforcement in the actual cart and checkout path, otherwise the PDP can say one thing while checkout allows another.
Why Functions-compatible logic matters
Shopify's discount system can apply automatic discounts at cart and checkout, and Shopify Functions are the right category of tool when native discount types are too simple for the rule. Functions-compatible logic is especially important when you need exclusions, quantity tiers, customer eligibility, and conflict handling to run close to checkout instead of only in theme code.
For this kind of partner portal, I would be careful with any app that only changes the storefront display. The app or custom function needs to support the exact SKU constraint, quantity breaks, customer eligibility, and non-stacking behavior in a way Shopify checkout will honor.
The storefront should make the pricing understandable. The backend discount logic should make it true.
Future migration to native B2B
The clean future state is Shopify Plus B2B with Companies, Company Locations, and Catalogs where appropriate. That does not mean the Advanced-plan build should be thrown away later.
The migration stays manageable if today's implementation avoids three traps:
- Do not duplicate products or variants for wholesale pricing.
- Do not bury pricing rules directly inside scattered React components.
- Do not model every partner as one generic permanent state.
If eligibility already lives around customer segments or tags, and pricing rules are isolated from product data, the future migration can map those concepts into native B2B structures later. Company-specific catalogs, negotiated pricing, and location-aware checkout rules become a planned upgrade path instead of a rebuild from a messy workaround.
The principle I would keep
Partner pricing is not only a discount feature. It is a trust feature.
The partner sees that they are recognized. The product card shows the correct price. The PDP explains volume incentives. The cart updates without a code. Checkout applies the same logic. Free-product exceptions are enforced. Inventory remains unified.
That is the difference between a partner portal that feels native to the store and one that feels like a discount hack sitting beside it.
If your partner pricing logic is starting to leak across product data, theme code, and checkout exceptions, the useful work is drawing the boundary before another workaround becomes permanent.