Build a B2B Storefront
What you will build
Section titled “What you will build”By the end of this tutorial, you will have a B2B storefront that:
- Displays a product catalog with categories and variants
- Applies customer-specific and volume-based pricing
- Routes orders through an approval workflow before submission
- Manages buyer organizations with multiple cost centers
- Handles purchase orders and credit terms
This tutorial uses Commerce Configured. The patterns apply to B2B scenarios where buyers need negotiated pricing, purchasing controls, and organizational hierarchies.
Before you start
Section titled “Before you start”Ensure your Commerce instance is running and you can access the admin panel at /episerver/cms. Verify that you have administrator-level permissions for catalog management and customer configuration.
Step 1: Configure the B2B organization structure
Section titled “Step 1: Configure the B2B organization structure”B2B commerce requires an organizational hierarchy. Buyers belong to organizations, and each organization can have budgets, cost centers, and approval rules.
Navigate to Commerce > Customers and create your first buyer organization.
using Insite.Core.Interfaces.Data;
using Insite.Model.Entities;
public void CreateBuyerOrganization(
IUnitOfWork unitOfWork)
{
var customer = new Customer
{
CompanyName = "Acme Manufacturing",
CustomerType = "B2B",
IsActive = true,
DefaultWarehouse = "MAIN",
CurrencyCode = "USD"
};
unitOfWork.GetRepository<Customer>().Insert(customer);
unitOfWork.Save();
} Step 2: Set up the product catalog
Section titled “Step 2: Set up the product catalog”Create a catalog structure suited for B2B buyers. Industrial and wholesale catalogs typically organize by product function rather than brand.
- Navigate to Commerce > Catalog Management
- Create a catalog named “Industrial Supplies”
- Add top-level categories: “Fasteners”, “Safety Equipment”, “Tools”
- Under each category, create subcategories for specific product lines
public class IndustrialProduct
{
public string Name { get; set; }
public string Sku { get; set; }
public string ManufacturerPartNumber { get; set; }
public string UnitOfMeasure { get; set; } = "EA";
public decimal MinimumOrderQuantity { get; set; } = 1;
public decimal PackSize { get; set; } = 1;
public bool RequiresQuote { get; set; }
public string HazmatClassification { get; set; }
} Step 3: Create product variants with B2B attributes
Section titled “Step 3: Create product variants with B2B attributes”B2B variants need attributes beyond size and color. Add specifications like material grade, certifications, and compliance codes.
public void CreateIndustrialVariant(
IContentRepository repo,
ContentReference productRef)
{
var variant = repo.GetDefault<VariationContent>(productRef);
variant.Name = "Hex Bolt M10x50 Grade 8.8 Zinc";
variant.Code = "HB-M10-50-88-ZN";
// B2B-specific properties
variant["Material"] = "Carbon Steel";
variant["Grade"] = "8.8";
variant["Finish"] = "Zinc Plated";
variant["CertificationStandard"] = "ISO 4014";
variant["CountryOfOrigin"] = "DE";
repo.Save(variant,
SaveAction.Publish, AccessLevel.NoAccess);
} Step 4: Configure customer-specific pricing
Section titled “Step 4: Configure customer-specific pricing”B2B buyers expect negotiated prices. Set up pricing tiers that vary by customer group, volume, and contract terms.
public void SetContractPricing(
IPriceDetailService priceService,
string variantCode)
{
var prices = new List<IPriceDetailValue>
{
// List price for all customers
new PriceDetailValue
{
CatalogKey = new CatalogKey(variantCode),
MarketId = new MarketId("US"),
CustomerPricing = CustomerPricing.AllCustomers,
MinQuantity = 0,
UnitPrice = new Money(4.50m, Currency.USD)
},
// Contract price for Acme Manufacturing
new PriceDetailValue
{
CatalogKey = new CatalogKey(variantCode),
MarketId = new MarketId("US"),
CustomerPricing = new CustomerPricing(
CustomerPricing.PriceType.PriceGroup,
"AcmeContract2026"),
MinQuantity = 0,
UnitPrice = new Money(3.25m, Currency.USD)
},
// Volume discount at 500+ units
new PriceDetailValue
{
CatalogKey = new CatalogKey(variantCode),
MarketId = new MarketId("US"),
CustomerPricing = CustomerPricing.AllCustomers,
MinQuantity = 500,
UnitPrice = new Money(2.90m, Currency.USD)
}
};
priceService.Save(prices);
} Step 5: Set up cost centers and budgets
Section titled “Step 5: Set up cost centers and budgets”Assign budgets to cost centers so buyers can track spending by department or project.
- Navigate to Commerce > Customers > [Organization]
- Under Cost Centers, create entries like “Production Floor”, “Maintenance”, “R&D”
- Assign a monthly or annual budget to each cost center
- Link users to their authorized cost centers
When a buyer places an order, they select a cost center. The system validates that the order amount does not exceed the remaining budget.
Step 6: Build the storefront catalog page
Section titled “Step 6: Build the storefront catalog page”Create a catalog browsing experience that shows B2B-relevant data: SKU, pack size, unit of measure, and availability.
@model CatalogViewModel
<div class="product-grid">
@foreach (var product in Model.Products)
{
<div class="product-card">
<img src="@product.ThumbnailUrl" alt="@product.Name" />
<h3>@product.Name</h3>
<p class="sku">SKU: @product.Sku</p>
<p class="price">
@product.CustomerPrice.ToString("C")
<span class="uom">/ @product.UnitOfMeasure</span>
</p>
<p class="pack">Pack: @product.PackSize</p>
<p class="availability">@product.AvailabilityStatus</p>
<form method="post">
<input type="number" name="qty"
min="@product.MinOrderQty"
step="@product.PackSize"
value="@product.MinOrderQty" />
<button type="submit">Add to Cart</button>
</form>
</div>
}
</div> Step 7: Implement the quick order pad
Section titled “Step 7: Implement the quick order pad”B2B buyers often know exactly what they need. A quick order pad lets them enter SKUs and quantities directly.
async function submitQuickOrder(lines) {
// lines = [{ sku: 'HB-M10-50-88-ZN', qty: 200 }, ...]
const response = await fetch('/api/cart/bulk-add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ lines }),
});
const result = await response.json();
// Show validation: invalid SKUs, below-minimum qty
if (result.errors.length > 0) {
displayErrors(result.errors);
}
// Show successfully added items
updateCartCount(result.cartItemCount);
return result;
} Step 8: Configure the approval workflow
Section titled “Step 8: Configure the approval workflow”Define approval rules so that orders above a threshold or from certain cost centers require manager sign-off before submission.
- Navigate to Commerce > Settings > Approval Rules
- Create a rule: “Orders over $5,000 require manager approval”
- Create a rule: “All orders from R&D cost center require VP approval”
- Assign approvers by role within each organization
public class OrderApprovalRule
{
public string Name { get; set; }
public decimal? AmountThreshold { get; set; }
public string CostCenter { get; set; }
public string ApproverRole { get; set; }
public bool RequireAllApprovers { get; set; }
}
// Example rules
var rules = new List<OrderApprovalRule>
{
new OrderApprovalRule
{
Name = "High Value Orders",
AmountThreshold = 5000m,
ApproverRole = "PurchasingManager"
},
new OrderApprovalRule
{
Name = "R&D Purchases",
CostCenter = "RD-001",
ApproverRole = "VPEngineering",
RequireAllApprovers = true
}
}; Step 9: Build the approval dashboard
Section titled “Step 9: Build the approval dashboard”Create a view where approvers can review, approve, or reject pending orders.
public async Task<List<PendingApproval>> GetPendingApprovals(
string approverUserId)
{
return await _orderRepository
.GetOrders()
.Where(o => o.Status == "PendingApproval")
.Where(o => o.RequiredApprovers
.Contains(approverUserId))
.OrderByDescending(o => o.SubmittedDate)
.Select(o => new PendingApproval
{
OrderNumber = o.OrderNumber,
Submitter = o.PlacedBy,
CostCenter = o.CostCenter,
Total = o.OrderTotal,
LineCount = o.LineItems.Count,
SubmittedDate = o.SubmittedDate
})
.ToListAsync();
} Step 10: Configure payment terms and purchase orders
Section titled “Step 10: Configure payment terms and purchase orders”B2B transactions often use purchase orders and net terms instead of credit card payments. Configure payment methods that support PO numbers and invoicing.
- Navigate to Commerce > Settings > Payment Methods
- Add a “Purchase Order” payment method
- Configure net terms: Net 30, Net 60, or custom terms per customer
- Set credit limits per organization
Step 11: Set up order notifications
Section titled “Step 11: Set up order notifications”Configure email notifications so buyers get order confirmations, approvers get approval requests, and fulfillment teams get picking instructions.
public class B2BNotificationConfig
{
public static void Configure()
{
// Notify buyer when order is submitted
OrderEvents.OnSubmitted += (order) =>
SendEmail(order.PlacedByEmail,
"order-submitted", order);
// Notify approver when approval is needed
OrderEvents.OnPendingApproval += (order) =>
SendEmail(order.ApproverEmail,
"approval-needed", order);
// Notify buyer when order is approved
OrderEvents.OnApproved += (order) =>
SendEmail(order.PlacedByEmail,
"order-approved", order);
// Notify fulfillment when ready to ship
OrderEvents.OnReleased += (order) =>
SendEmail("fulfillment@company.com",
"ready-to-fulfill", order);
}
} Step 12: Test the complete B2B flow
Section titled “Step 12: Test the complete B2B flow”Walk through the entire buyer journey to verify everything works end to end.
| Scenario | Expected result |
|---|---|
| Browse catalog as authenticated buyer | Customer-specific pricing displays |
| Add items via quick order pad | SKU validation, minimum quantity enforced |
| Select cost center at checkout | Budget validation passes |
| Submit order over $5,000 | Order enters “Pending Approval” status |
| Approve order as manager | Order moves to “Submitted”, buyer notified |
| Reject order with comment | Buyer notified with rejection reason |
| Submit order under threshold | Order bypasses approval, submits directly |
| Submit PO with net-30 terms | Order created with PO number, no payment capture |
Verify the completed storefront
Section titled “Verify the completed storefront”Run through the test scenarios above with at least two buyer accounts (one standard, one requiring approval) and verify that pricing, budgets, and workflows behave correctly. Check the admin dashboard to confirm orders appear with the right statuses and cost center assignments.