medusa-plugin-company
Adds companies and their employees to Medusa v2, so a B2B shop can sell to buying organizations with company prices and a spending limit per employee.
A company is a buying organization; an employee is a person buying on its behalf. A company gets its own Medusa customer group, which is what carries B2B pricing, and employees join it automatically. So B2B prices need no pricing concept Medusa does not already have.
When to use
Install it in a Medusa backend for a B2B storefront, where customers buy on behalf of a company. A shop that only sells to consumers does not need it: a cart or order without a company is left alone, so one Medusa can serve both.
For approvals and spending limits, install
@evolve-framework/medusa-plugin-approval as well. It needs this plugin.
Get started
Install the package with the peer dependencies it needs. It comes from the Evolve registry, which needs a one-time sign-in.
pnpm add @evolve-framework/medusa-plugin-company @medusajs/cli @medusajs/framework @medusajs/medusa @tanstack/react-query react-router-domRequirements6
node>=20@medusajs/cli2.21.2@medusajs/framework2.21.2@medusajs/medusa2.21.2@tanstack/react-query5.64.2react-router-dom7.18.2
For example:
// medusa-config.ts// After adding the plugin, run `npx medusa db:migrate` to create its tables.import { defineConfig } from "@medusajs/framework/utils";
module.exports = defineConfig({ // projectConfig, modules and other plugins as before plugins: [ { resolve: "@evolve-framework/medusa-plugin-company", options: {} }, ],});What it adds
companyandemployeemodels, with a service and migrations- Module links from a company to carts, orders and its customer group, and from an employee to their customer
- Workflows for creating, updating and deactivating both, including customer
group membership, such as
createCompaniesWorkflowandcreateEmployeesWorkflow - Workflow hooks that attach a new cart and a new order to the company named in
metadata.company_id - Store API routes under
/store/companies, scoped to the signed-in customer's own company
There is no admin route to create a company. The merchant creates companies
with createCompaniesWorkflow, for example from a seed script; the workflows
are exported from the package root.
Routes
All routes need a signed-in customer, and act only on a company the customer works for.
GET /store/companies |
the companies the caller buys for |
GET /store/companies/:id |
one company |
POST /store/companies/:id |
update the company, as its administrator |
GET /store/companies/:id/employees |
its employees |
POST /store/companies/:id/employees |
add an existing customer by email, as an administrator |
POST /store/companies/:id/employees/:employeeId |
change a spending limit or admin rights, as an administrator |
DELETE /store/companies/:id/employees/:employeeId |
deactivate an employee, as an administrator |
A person must already have a customer account to become an employee. Medusa has no invitation flow, and inventing one here would make this plugin own account creation and its emails.
Authorization
Every route resolves the caller's employment from the authenticated request. A
company id is not a secret, because it appears in order history. So it is never
the only thing standing between a caller and another company's employee list.
Being a member is enough to read; changing the company or its employees requires
is_admin. A company can never lose its last administrator, because every route
back requires one.
Deactivating an employee is a soft delete: they stop being able to buy for the company, and the orders they already placed still name who placed them.
Attribution
Ported from the Medusa B2B Starter (MIT), which is the reference for the model shape, the module links and the workflow wiring.
Two things differ deliberately. The starter mirrors is_admin onto the
emailpass identity's user_metadata; that is a second copy of a fact that
already has a home, and it ties the plugin to one auth provider, so it is left
out. And the starter's company-creation workflow also creates approval settings,
which makes companies unusable without the approval module. Here the two are
independent, and the approval plugin attaches its own settings when installed.
The Store API routes are not ported. The starter's are shaped for its own Next.js storefront; these are shaped for the Evolve GraphQL contract.

