REST API
Authenticate with WordPress application passwords and resolve any customer's price from outside WordPress. Read endpoints are free; outbound webhooks are Pro.
Everything lives under the WordPress REST namespace smb2b/v1.
Base URL: https://your-store.com/wp-json/smb2b/v1
Authentication
There is no bespoke key system. The API uses WordPress’s own authentication:
- Application passwords (recommended) — create one under Users → Profile → Application Passwords, then use HTTP Basic auth:
Authorization: Basic base64(username:app_password). - Cookie + nonce — for same-origin admin requests, send the
X-WP-Nonceheader.
Admin endpoints require manage_woocommerce (a few require manage_options). Buyer endpoints require a logged-in customer and are scoped to the caller.
Resolve a price
The headline endpoint. It runs the full pricing pipeline — groups, company, quantity bands, rules — for any product, customer and quantity.
GET /price?product_id=123&user_id=45&qty=10
| Parameter | Required | Notes |
|---|---|---|
product_id |
yes | Product or variation id |
user_id |
no | Customer to price for; omit for retail/guest |
qty |
no | Quantity, default 1 — applies quantity bands |
variation_id |
no | For variable products |
{
"success": true,
"message": "Success",
"data": {
"product": { "id": 123, "name": "Espresso beans 1kg", "variation_id": null },
"buyer": { "id": 45, "name": "Jane Buyer", "group_id": 2, "group_name": "Wholesale" },
"qty": 10,
"price": 42.5,
"price_formatted": "$42.50",
"base_price": 50,
"base_price_formatted": "$50.00",
"is_discounted": true,
"savings": 7.5,
"savings_formatted": "$7.50",
"savings_percent": 15,
"source": "group_product",
"source_label": "…",
"rule_id": 8,
"steps": [
{ "level": "group_global", "level_label": "…", "outcome": "applied", "detail": "…", "rule_id": null }
],
"summary": "…"
}
}
price is the number to use. source names the level that won and steps lists every level the resolver checked, in order, with its outcome.
This is the same data the admin “Check a price” screen shows, from the same resolution — so an ERP quoting from this endpoint quotes exactly what checkout will charge.
Read endpoints
| Resource | Endpoint |
|---|---|
| Customer groups | GET /groups, GET /groups/{id} |
| Price rules | GET /rules |
| B2B registrations | GET /registrations |
| Companies (Pro) | GET /companies, GET /companies/{id} |
| Company members (Pro) | GET /companies/{id}/members |
| Quotes (Pro) | GET /quotes, GET /quotes/{id} |
| Credit accounts (Pro) | GET /credit, GET /credit/{companyId} |
Write endpoints (POST/PUT/DELETE) exist on the same routes and back the admin app.
Webhooks (Pro)
Rather than polling, subscribe to events and receive a signed POST. Manage subscriptions under Settings → API & Webhooks.
| Event | Fires when | data |
|---|---|---|
registration.pending |
a B2B registration is submitted for approval | user_id, email, business |
quote.submitted |
a buyer submits a quote request | quote_id |
order.awaiting_approval |
an order is held by the spend-limit approval chain | order_id, reason, total, company |
invoice.overdue |
an overdue reminder goes out for a net-terms invoice | order_id, days_late |
Deliveries are a JSON POST:
{
"event": "quote.submitted",
"created_at": "2026-07-20T10:15:00+00:00",
"data": { "quote_id": 42 }
}
with headers X-SMB2B-Event and X-SMB2B-Signature: sha256=<hmac> — an HMAC-SHA256 of the raw body using the subscription’s signing secret, which is shown once when you create it.
Verifying a delivery
$payload = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $payload, $your_secret);
$signature = $_SERVER['HTTP_X_SMB2B_SIGNATURE'] ?? '';
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit;
}
Deliveries go out asynchronously through Action Scheduler; checkout and registration do not wait on your endpoint. Recent delivery results are listed on the Webhooks screen.
Managing subscriptions from code
The same subscriptions can be managed over the API. These routes require manage_options.
| Action | Endpoint |
|---|---|
| List subscriptions | GET /webhooks |
Create one (url, events[]) |
POST /webhooks — the response carries the signing secret, once |
| Delete one | DELETE /webhooks/{id} |
| Send a test delivery | POST /webhooks/{id}/test |
Unknown event names are dropped when you create a subscription.
Notes
- All money values are in the store’s base currency.
- Timestamps are ISO 8601 UTC.
- Order data is read through the WooCommerce CRUD, so the API is HPOS-safe.
If you are integrating a plugin on the same site — a CRM, for example — you usually want the action hooks rather than webhooks.
Was this page missing something?
Documentation gaps are treated as bugs here.Tell us