Skip to main content

Overview

Selling to businesses breaks an assumption most storefronts make: that a customer is a person. A business buyer is a person acting for an organization — one that has other buyers, several delivery sites, a VAT number, and a finance team who wants to see everything anyone ordered. A company in Spree models that. And because real organizations aren’t flat, a company can be a tree: a parent with subsidiaries, divisions, regional units, each with its own people and addresses. A node is one of two kinds, and the difference is about tax, not hierarchy: Trees are capped at five levels, and the root must always be a company.

Membership covers a subtree

Someone belongs to a company through a membership, and that standing reaches everything below the node — not just the node itself. So a buyer attached to “Acme Europe” can act for Sales and Operations beneath it, without anyone creating three memberships. Give someone standing at the root and they cover the whole group. This is why authorization always asks “does this person have standing on this node or any of its ancestors”, never “is this person a member of exactly this node”.
In open source, every member can do everything within their standing — buy, see the subtree’s orders, and manage addresses and members. There are no company roles; the role label on a membership is cosmetic.To restrict what individual people may do, see company governance below.

Adding people

Both the dashboard and the storefront add members the same way — by email:
What comes back depends on whether that email is already a customer:
  • An existing customer becomes a member straight away.
  • An unknown email produces an invitation, valid for 30 days, and an email with a link.
You can tell which by the ID prefix — cmem_ for a membership, cinv_ for an invitation. Accepting an invitation either signs an existing customer in, or registers a new account with the invited email. Either way it ends as a membership:
Memberships are always active and always backed by a real customer. Anything still waiting lives on the invitation, so there’s no such thing as a half-active member.

Buying for a company

A cart and an order can name a company. That’s what turns a personal purchase into a company one — it decides which addresses are on offer, whose tax registration applies, and who else will see the order.
A buyer with exactly one membership doesn’t need to choose; it resolves on its own. A buyer who belongs to several names the node — and it must be one they have standing on. The company is frozen onto the order at completion, like the addresses and prices. Reorganize the tree next year and last year’s order still explains itself.
That subtree rollup is the feature a finance team actually asks for: one place showing what the whole organization spent, without chasing individual accounts.

The shared address book

A company keeps its own addresses — ship-to sites, a billing address — separate from any individual’s. They’re labelled, and one of each kind can be the default.
Note that a delivery site is just an address. Ten warehouses do not mean ten company nodes — nodes exist for organizational and legal structure, addresses for where things go.

Addresses inherit downwards

Listing a node’s addresses returns its own entries and the ones it inherits from the nodes above it, so a division can ship to the headquarters site it shares. Writing one stays with the node that owns it: a division can add and edit its own entries, and reads its parent’s without being able to change them. Each entry’s owner names the node it belongs to, so a client can tell inherited entries apart from the node’s own.

Picking an address at checkout

A member buying for their company ships to the company’s sites, not only to their own saved addresses. Set the company on the cart with company_id first, then ask the cart which addresses it can use:
This call needs a signed-in customer. Unlike the rest of the cart endpoints, a guest cart token is not enough: what comes back is the account’s address books rather than the cart’s own contents. A guest cart has neither book, so the list would be empty anyway. The list holds the buyer’s own address book plus the address book of the company set on the cart, limited to the countries the cart’s market sells to. Every entry in it is accepted as shipping_address_id or billing_address_id, so a picker built from it never offers an address the checkout cannot use. A buyer who belongs to a single company still has to set it on the cart: until then, only their own addresses are listed and accepted. An address belonging to anyone else is rejected, and completing the order copies the chosen address onto it, leaving the book entry free to be renamed or retired later. Each entry carries the owner it is filed under — { id, type, name }, where type is customer or company — so a picker can group and label the two books from one response. An inherited site names the node that owns it rather than the one the cart is for, so a division’s own docks and the headquarters docks it shares are told apart. Staff placing an order get the same reach: shipping_address_id and billing_address_id on the Admin API’s order creation accept the company’s sites, and use_customer_default_address fills the slots from the company’s defaults when the request names a company with company_id. Without one it takes the customer’s own defaults, even for a buyer who belongs to a single company — prefilling follows what the caller asked for rather than inferring an organization on their behalf.

Tax

Tax registrations and exemption certificates live only on legal entities, and a purchase resolves tax through the node’s nearest company ancestor.
The walk stops at the first company node, whether or not it holds a registration. A subsidiary with no VAT number of its own therefore has none — it never quietly borrows its parent’s, because in most jurisdictions that would be a false declaration.
Exemption certificates hang off a legal entity and are scoped to the country or state that issued them. Check whether a certificate is active rather than reading its status — a verified certificate stops exempting once it expires, and active accounts for that. See Taxes for how these reach the tax calculation.

Company governance

Open source deliberately trusts every member equally. That’s the right default for a company of five people, and the wrong one for a company of five hundred — where a junior buyer should not be able to place a £40,000 order, remove their manager, or see what another division spent. Company governance adds that control. It works through the same endpoints and the same data, so nothing about your storefront integration changes when it’s switched on — the calls you already make simply start enforcing.

Requires a Spree Enterprise licence

Company roles, order approvals, spending limits and governance audit history are part of Spree Enterprise. See what’s included, or talk to the team about your use case.

Company roles

Where open source has a cosmetic label, Enterprise has real roles built from a fixed set of capabilities: Roles are data, edited by the company’s own administrator rather than by your staff — the buying organization manages its own structure, which is the point of self-service. Guards prevent someone granting themselves more than they hold. These are entirely separate from staff roles. A company role never reaches anything belonging to the store.

Order approvals

A member without place_orders submits their basket instead of completing it. Someone with approve_orders reviews and releases it. Checkout returns a well-known approval_required response rather than a generic failure, so a storefront can show the right message and the right next step. The approval history is append-only — who asked, who decided, when.

Spending limits

Limits are set per member or per node, with a reset period — £5,000 a month for a buyer, £50,000 for a division. They’re enforced at completion, alongside approvals, so an over-limit basket is caught before payment rather than after.

Restricted self-service

The same storefront endpoints — the company directory, address book, member management, order history — become capability-gated. A member without view_company_purchases sees their own node’s orders and not the group’s; a member without manage_company_members can read the team but not change it.
Nothing about the data model changes. Governance enforces through a policy layer and the checkout validation hooks, over the same companies, memberships and endpoints described on this page. You can build a B2B storefront against open source today and have it work unchanged when governance is enabled.
Payment terms and net invoicing, quotes, and a packaged buyer portal are on the Enterprise roadmap — talk to the team if those matter to your timeline.

Managing companies as staff

Moving a branch is an update with a new parent_id. Deleting a node removes its whole subtree, and is refused outright once any order exists beneath it — history doesn’t get deleted to tidy up an org chart. Each row carries children_count and members_count. children_count is the node’s direct sub-units. members_count is the number of distinct customers holding a membership on the node or on any node below it, so somebody who is a member of both a parent and one of its sub-units is counted once rather than twice.
  • Catalogs — giving a company its own range and prices
  • Customers — the accounts memberships are built on
  • Taxes — registrations and exemptions
  • Orders — company purchases