Skip to content

medusa-plugin-company

@evolve-framework/medusa-plugin-company · v1.0.0

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

  1. 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-dom
    Requirements6
    node>=20
    @medusajs/cli2.21.2
    @medusajs/framework2.21.2
    @medusajs/medusa2.21.2
    @tanstack/react-query5.64.2
    react-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

  • company and employee models, 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 createCompaniesWorkflow and createEmployeesWorkflow
  • 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.