The unmanaged checkout dilemma: why corporate procurement rejects flat B2B carts
When wholesale merchants migrate to Shopify Plus B2B, they frequently treat corporate customer accounts like glorified retail buyers with price lists.
They assign a trade buyer the native ORDERING_ONLY or LOCATION_ADMIN role on a CompanyLocation, link a negotiated B2B catalog, and grant Net 30 payment terms. Under this naive structure, any authenticated employee possessing checkout access can execute orders up to the company location's entire credit limit.
In enterprise trade relationships, this model collapses under corporate governance:
- Unbudgeted Maverick Spend: Junior field technicians and apprentices order specialist tools or premium variant finishes that exceed job project budgets.
- Segregation of Duties Breaches: Financial compliance frameworks strictly require segregation between the individual who requisitions materials and the authority who approves commercial payment.
- PO Number Integrity: Field staff enter placeholder text like 'TBD' or 'verbal approval' into mandatory purchase order fields, generating uncollectable invoices that accounts payable departments reject.
Multi-tier approval hierarchies and threshold derivation
True procurement governance requires multi-tier approval rules that evaluate order value dynamically against both buyer authority limits and organizational thresholds.
Rather than a binary toggle, enterprise purchasing operates across discrete tiers: Tier 1 Auto-Approval (up to €2,500 for direct checkout), Tier 2 Manager Approval (€2,500.01 to €10,000 requiring Location Admin sign-off), Tier 3 Executive Approval (€10,000.01 to €50,000 requiring dual Company Admin sign-offs), and Tier 4 Board Escalation for capital commitments above €50,000.
Within Shopify Plus B2B, these rules map to GraphQL Admin API mutations (orderApprovalRuleCreate). However, rules must be validated at the cart boundary: line totals must be aggregated in integer cents to prevent single-cent floating-point precision leaks.
Furthermore, the submitter must be strictly excluded from the pool of eligible approvers: a branch manager holding LOCATION_ADMIN credentials cannot approve their own €8,000 requisition.
export type ApprovalTier = "TIER_1_AUTO" | "TIER_2_MANAGER" | "TIER_3_EXECUTIVE";
export type ApprovalState = "AUTO_APPROVED" | "PENDING_APPROVAL" | "APPROVED" | "ESCALATED";
export interface CompanyContact {
id: string; // gid://shopify/CompanyContact/123
name: string;
email: string;
role: "ORDERING_ONLY" | "LOCATION_ADMIN" | "COMPANY_ADMIN";
spendingLimitCents: number;
isActive: boolean;
}
export interface OrderApprovalRuleDefinition {
ruleId: string;
minAmountCents: number;
maxAmountCents: number;
tier: ApprovalTier;
requiredRole: "LOCATION_ADMIN" | "COMPANY_ADMIN";
minApproverCount: number;
}
export interface B2BOrderSubmission {
orderDraftId: string;
companyLocationId: string;
submitter: CompanyContact;
lineItems: Array<{ variantId: string; sku: string; unitPriceCents: number; quantity: number }>;
totalAmountCents: number;
}
export function evaluateB2BOrderApprovalRules(
submission: B2BOrderSubmission,
rules: OrderApprovalRuleDefinition[],
locationContacts: CompanyContact[],
fallbackEscalationAdmin?: CompanyContact
) {
const reasons: string[] = [];
const computedTotalCents = submission.lineItems.reduce((acc, l) => acc + l.unitPriceCents * l.quantity, 0);
const breachesSubmitterLimit = computedTotalCents > submission.submitter.spendingLimitCents;
if (breachesSubmitterLimit) {
reasons.push("Order total (€" + Math.round(computedTotalCents / 100) + ") exceeds buyer limit (€" + Math.round(submission.submitter.spendingLimitCents / 100) + ")");
}
const sortedRules = [...rules].sort((a, b) => b.minAmountCents - a.minAmountCents);
const matchedRule = sortedRules.find(r => computedTotalCents >= r.minAmountCents && computedTotalCents <= r.maxAmountCents);
const matchedTier = matchedRule ? matchedRule.tier : "TIER_1_AUTO";
const minApprovalsNeeded = matchedRule ? matchedRule.minApproverCount : 0;
const requiredRole = matchedRule ? matchedRule.requiredRole : "LOCATION_ADMIN";
const requiresApproval = breachesSubmitterLimit || matchedTier !== "TIER_1_AUTO";
if (!requiresApproval) {
return { approvalState: "AUTO_APPROVED" as ApprovalState, matchedTier, requiresApproval: false, eligibleApprovers: [] };
}
// Segregation of duties: Submitter cannot approve their own order
const eligibleApprovers = locationContacts.filter(c => {
if (!c.isActive || c.id === submission.submitter.id) return false;
return requiredRole === "COMPANY_ADMIN" ? c.role === "COMPANY_ADMIN" : (c.role === "LOCATION_ADMIN" || c.role === "COMPANY_ADMIN");
});
const isOrphan = eligibleApprovers.length < minApprovalsNeeded;
let approvalState: ApprovalState = "PENDING_APPROVAL";
let escalationContactId: string | undefined;
if (isOrphan && fallbackEscalationAdmin?.isActive) {
approvalState = "ESCALATED";
escalationContactId = fallbackEscalationAdmin.id;
reasons.push("No active local approvers with " + requiredRole + ". Escalated to " + fallbackEscalationAdmin.name);
}
return { approvalState, matchedTier, requiresApproval: true, reasons, eligibleApprovers, minApprovalsNeeded, escalationContactId };
}Stale price snapshots, inventory expiry, and approval re-validation
The most severe architectural vulnerability in B2B order approval workflows is the approval latency window.
In retail ecommerce, checkout is instantaneous: pricing and inventory are validated in real time. In corporate B2B, the time delta between a junior buyer submitting a requisition and a regional executive approving it typically spans 24 to 72 hours.
During this latency window, commodity catalog prices shift and physical warehouse inventory can sell out to competing online buyers. Because a submitted requisition is merely a draft, it does not lock warehouse stock.
Before an approved requisition transitions into a confirmed order via draftOrderComplete, our synchronization middleware executes an atomic pre-commit validation. If inventory has lapsed or prices have shifted beyond configured tolerance thresholds, the order is locked and returned to the buyer with an annotated revision notice, eliminating uncollectable invoice disputes.
The orphan approver trap and escalation delegation
In commercial contracting and wholesale trade, personnel churn is constant: branch managers resign, project leads relocate, and email accounts are deactivated.
When an approval rule routes to a specific inactive staff account, open requisitions enter an unresolvable terminal state: the buyer cannot approve it, peers cannot view it, and distributor customer service cannot bypass it without violating customer governance.
To eliminate this deadlock, our architecture enforces a hierarchical health-check heartbeat. If the required quorum of active approvers is missing, the engine automatically flags an ESCALATED state and routes the approval ticket to designated root corporate administrators (COMPANY_ADMIN).
For accounts operating with credit facilities, approved orders must simultaneously pass live credit exposure reconciliation. Consult our architecture for Shopify B2B ERP credit limit sync to understand how live ledger ageing prevents over-limit approvals, or review our guide on Shopify B2B trade account onboarding.
When this needs an engineer
You do not need custom order approval rules if your B2B customers are sole proprietors purchasing with credit cards, if your order values rarely exceed €500, or if your trade buyers have uniform, flat purchasing authority across all staff accounts.
You need an engineer when your buyers are enterprise organizations: when purchasing policies mandate multi-tier delegation of authority; when requisitions above €2,500 require branch sign-off and orders above €10,000 require dual corporate sign-off; when submitters must be prevented from self-approving requisitions; when multi-day approval windows risk inventory sell-outs and price drift; and when orphan approver conditions must automatically escalate rather than freezing wholesale cash flow.
Explore our engineering services in Shopify B2B development, inspect our B2B operations case study collection, or examine how supplier governance was architected in the Weldaad Supplier Portal case study.
Send us your procurement hierarchy, spending limit thresholds, and buyer role requirements. We will architect a clean, compliant B2B order approval workflow that respects corporate governance while keeping checkout frictionless.
