B2B WooCommerce stores backed by NetSuite face a specific UX problem: the customer portal. Consumer-focused WooCommerce account pages show orders and basic account details. B2B buyers expect more — open invoices, available credit, account-specific pricing, and full order history going back years. All of that data lives in NetSuite. Getting it into the WooCommerce customer portal without building a custom ERP dashboard is the integration challenge most B2B implementations underestimate.
What B2B Buyers Actually Need in a Portal
The requirements that come up in almost every B2B WooCommerce project:
- Invoice history with payment status (paid, open, overdue) and a download link for the PDF
- Current available credit against their NetSuite credit limit
- Account-specific pricing reflected in the catalog — not the default price level
- Order history that includes orders placed offline or through a sales rep, not just orders placed through the WooCommerce checkout
- Ability to pay outstanding invoices directly through the portal
None of this exists in WooCommerce natively. All of it requires pulling live data from NetSuite and surfacing it in the customer account area.
The Data Architecture
The portal data falls into two categories: data that changes rarely (customer record, credit limit, assigned price level) and data that changes frequently (open invoices, recent orders, available credit balance). Treat them differently in your sync strategy.
Slow-changing data can be cached aggressively — sync it when the customer logs in and cache for 15–60 minutes. Fast-changing data (invoice payment status, available credit) should be fetched on-demand when the portal page loads, with a short cache of 2–5 minutes to prevent excessive API calls from page refreshes.
In NetSuite’s data model, the relevant records are:
- Customer record — credit limit, balance, assigned price level, terms
- Invoice transactions — open and closed invoices, amounts, due dates
- Sales Order transactions — all orders regardless of channel
- Customer Payment records — payment history against invoices
Syncing Account-Specific Pricing to WooCommerce
NetSuite’s pricing model assigns customers to price levels (Price Level 1, Wholesale, VIP, etc.). Each price level has item-specific pricing in the pricing table. The integration needs to fetch the customer’s assigned price level from their NetSuite record, then query item prices at that level and apply them in WooCommerce when that customer is logged in.
WooCommerce doesn’t have a native per-customer price override mechanism for catalog prices. The standard implementation uses a custom pricing plugin or a filter on woocommerce_product_get_price that checks the logged-in customer’s assigned NetSuite price level and returns the correct price from a local cache. The cache is populated by the integration sync and keyed by customer_id + item_id + price_level.
Do not hit the NetSuite pricing API on every product page load. The cache is non-negotiable for performance.
Invoice Portal Implementation
The invoice list is typically a custom WooCommerce account tab backed by a REST API endpoint that proxies NetSuite invoice data. The endpoint:
- Authenticates the WooCommerce session
- Looks up the customer’s NetSuite entity ID (stored as user meta during account creation or first sync)
- Queries NetSuite invoices via SuiteQL:
SELECT id, trandate, duedate, amountremaining, status FROM transaction WHERE recordtype = 'invoice' AND entity = :netsuite_id ORDER BY trandate DESC - Returns the invoice list as JSON to the frontend
PDF invoice downloads require a separate call to NetSuite’s document endpoint, which generates the PDF from the transaction record. Proxy this through your backend — never expose NetSuite credentials or direct API endpoints to the browser.
Credit Limit Display
Available credit is creditlimit - balance from the NetSuite customer record. Fetch it on portal page load with a short cache. Display it prominently — B2B buyers actively use this to decide order size. If the available credit is below a threshold (e.g., less than one average order value), surface a notification prompting the buyer to clear outstanding invoices or contact their account manager.
Handling Offline Orders in Order History
The most common complaint from B2B buyers about WooCommerce portals is that orders placed by phone, EDI, or through a sales rep don’t appear in the portal — only online WooCommerce orders do. The fix is to pull the full order history from NetSuite and display it alongside WooCommerce orders, clearly labeling the channel. This requires a unified order list view that merges NetSuite Sales Orders with WooCommerce orders, deduplicating the ones that originated in WooCommerce (which already exist in both systems). The deduplication key is typically the WooCommerce order ID stored as a custom field on the NetSuite transaction at creation time.