6713d76db3
* update configuration * resolve todos + remove events guides * disable v2 docs in v1 navbar * remove v2 from v1 mobile sidebar * resolve build errors * fix build errors * fix lint errors * fix lint
813 lines
23 KiB
Plaintext
813 lines
23 KiB
Plaintext
import { AcademicCapSolid, UsersSolid } from "@medusajs/icons"
|
||
|
||
export const metadata = {
|
||
title: `B2B Recipe`,
|
||
}
|
||
|
||
# {metadata.title}
|
||
|
||
This recipe provides the general steps to implement a B2B store with Medusa.
|
||
|
||
<Note type="soon" title="In Development">
|
||
|
||
This recipe is a work in progress, as some features are not ready yet in Medusa V2.
|
||
|
||
</Note>
|
||
|
||
## Overview
|
||
|
||
In a B2B store, you provide different types of customers with relevant pricing, products, shopping experience, and more.
|
||
|
||
Medusa’s commerce modules, including Sales Channel, Customer, and Pricing modules facilitate implementing this setup. Medusa’s architecture and extendible nature allow you to customize your store based on your use case.
|
||
|
||
<Note title="Related use-case">
|
||
|
||
[Visionary: Frictionless B2B ecommerce with Medusa](https://medusajs.com/blog/visionary/)
|
||
|
||
</Note>
|
||
|
||
---
|
||
|
||
## Create B2B Sales Channel
|
||
|
||
Use sales channels to set product availability per channel. In this case, create a B2B sales channel that includes only B2B products.
|
||
|
||
You can create a sales channel through the Medusa Admin or Admin REST APIs.
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Option 1: Use Medusa Admin",
|
||
text: "Create the sales channel using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#sales-channels_postsaleschannels",
|
||
title: "Option 2: Using the REST APIs",
|
||
text: "Create the sales channel using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
---
|
||
|
||
## Create a Publishable API Key
|
||
|
||
Use publishable API keys to specify the context of client requests:
|
||
|
||
- You associate the publishable API key with one or more sales channels.
|
||
- In a client such as a storefront, you pass the publishable API key in the header of your requests.
|
||
|
||
Then, all products retrieved belong to the associated sales channel(s).
|
||
|
||
You can create a publishable API key through the Medusa Admin or the Admin REST APIs, then associate it with the B2B sales channel. Later, you'll use this key when developing your B2B storefront.
|
||
|
||
{/* TODO add links */}
|
||
|
||
### Create Key
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Option 1: Use Medusa Admin",
|
||
text: "Create the publishable API key using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#api-keys_postapikeys",
|
||
title: "Option 2: Using the REST APIs",
|
||
text: "Create the publishable API key using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
### Associate Key with Sales Channel
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Option 1: Use Medusa Admin",
|
||
text: "Associate the publishable API key with the B2B sales channel using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "#",
|
||
title: "Option 2: Using the REST APIs",
|
||
text: "Associate the publishable API key with the B2B sales channel using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
---
|
||
|
||
## Add Products to B2B Sales Channel
|
||
|
||
You can create new products or add existing ones to the B2B sales channel using the Medusa Admin or Admin REST APIs.
|
||
|
||
### Create Products
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Using Medusa Admin",
|
||
text: "Create products using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#products_postproducts",
|
||
title: "Using REST APIs",
|
||
text: "Create products using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
### Add Products to Sales Channel
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Using Medusa Admin",
|
||
text: "Add the products to the B2B sales channel using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#sales-channels_postsaleschannelsidproductsbatchadd",
|
||
title: "Using REST APIs",
|
||
text: "Add the products to the B2B sales channel using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
---
|
||
|
||
## Create B2B Module with Relationship to Customer Groups
|
||
|
||
Use customer groups to organize your customers into different groups. Then, you can apply different prices for each group.
|
||
|
||
This is useful in B2B sales, as you often negotiate special prices with each customer or company.
|
||
|
||
You can create a B2B module that adds necessary data models to represent a B2B company. Then, you link that company to a customer group. Any customer belonging to that group also belongs to the company, meaning they're a B2B customer.
|
||
|
||
<Note type="soon">
|
||
|
||
Module Relationships is coming soon.
|
||
|
||
</Note>
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "!docs!/basics/modules-and-services",
|
||
title: "Create Module",
|
||
text: "Learn how to create a module in Medusa.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
{
|
||
href: "!docs!/basics/data-models",
|
||
title: "Create Data Models",
|
||
text: "Learn how to create data models.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
{/* <Card
|
||
href="!docs!/advanced-development/modules/module-relationships"
|
||
title="Create Module Relationships"
|
||
text="Learn how to create a relationship between modules."
|
||
startIcon={<AcademicCapSolid />}
|
||
showLinkIcon={false}
|
||
className="mt-1"
|
||
/> */}
|
||
|
||
{/* <Details summaryContent="Example">
|
||
In this section, you'll create a B2B module that has a `Company` data model. The `Company` data model has a relationship to the `CustomerGroup` data model of the Customer Module.
|
||
|
||
Start by creating the `src/modules/b2b` directory.
|
||
|
||
Then, create the file `src/modules/b2b/models/company.ts` with the following content:
|
||
|
||
```ts title="src/modules/b2b/models/company.ts" highlights={[["8", "", "The property will be used to create a relationship to customer groups."]]}
|
||
import { model } from "@medusajs/utils"
|
||
|
||
const Company = model.define("company", {
|
||
id: model.id().primaryKey(),
|
||
name: model.text(),
|
||
city: model.text(),
|
||
country_code: model.text(),
|
||
customer_group_id: model.text().nullable(),
|
||
})
|
||
|
||
export default Company
|
||
```
|
||
|
||
This creates a `Company` data model with some relevant properties. Most importantly, it has a `customer_group_id` property. It'll later be used when creating the relationship to the `CustomerGroup` data model in the Customer Module.
|
||
|
||
Next, create the migration in the file `src/modules/b2b/migrations/Migration20240516081502.ts` with the following content:
|
||
|
||
```ts title="src/modules/b2b/migrations/Migration20240516081502.ts"
|
||
import { Migration } from "@mikro-orm/migrations"
|
||
|
||
export class Migration20240516081502 extends Migration {
|
||
|
||
async up(): Promise<void> {
|
||
this.addSql("create table if not exists \"company\" (\"id\" text not null, \"name\" text not null, \"city\" text not null, \"country_code\" text not null, \"customer_group_id\" text not null, constraint \"company_pkey\" primary key (\"id\"));")
|
||
}
|
||
|
||
async down(): Promise<void> {
|
||
this.addSql("drop table if exists \"company\" cascade;")
|
||
}
|
||
}
|
||
```
|
||
|
||
You'll run the migration to reflect the data model in the database after finishing the module definition.
|
||
|
||
Then, create the module's main service at `src/modules/b2b/service.ts` with the following content:
|
||
|
||
```ts title="src/modules/b2b/service.ts"
|
||
import { MedusaService } from "@medusajs/utils"
|
||
import Company from "./models/company"
|
||
|
||
class B2bModuleService extends MedusaService({
|
||
Company,
|
||
}){
|
||
// TODO add custom methods
|
||
}
|
||
|
||
export default B2bModuleService
|
||
```
|
||
|
||
This creates a `B2bModuleService` that extends the service factory, which generates data-management functionalities for the `Company` data model.
|
||
|
||
Next, create the module definition at `src/modules/b2b/index.ts` with the following content:
|
||
|
||
```ts title="src/modules/b2b/index.ts"
|
||
import B2bModuleService from "./service"
|
||
import { Module } from "@medusajs/utils"
|
||
|
||
export default Module("b2b", {
|
||
service: B2bModuleService,
|
||
})
|
||
```
|
||
|
||
Finally, add the module to the `modules` object in `medusa-config.js`:
|
||
|
||
```js title="medusa-config.js"
|
||
module.exports = defineConfig({
|
||
// ...
|
||
modules: {
|
||
b2bModuleService: {
|
||
resolve: "./modules/b2b",
|
||
definition: {
|
||
isQueryable: true,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
```
|
||
|
||
You can now run migrations with the following commands:
|
||
|
||
```bash npm2yarn
|
||
npx medusa migrations run
|
||
```
|
||
|
||
### Add Create Company API Route
|
||
|
||
To test out using the B2B Module, you'll add an API route to create a company.
|
||
|
||
Start by creating the file `src/types/b2b/index.ts` with some helper types:
|
||
|
||
```ts title="src/types/b2b/index.ts"
|
||
import { CustomerGroupDTO } from "@medusajs/types"
|
||
|
||
export type CompanyDTO = {
|
||
id: string
|
||
name: string
|
||
city: string
|
||
country_code: string
|
||
customer_group_id?: string
|
||
customer_group?: CustomerGroupDTO
|
||
}
|
||
|
||
export type CreateCompanyDTO = {
|
||
name: string
|
||
city: string
|
||
country_code: string
|
||
customer_group_id?: string
|
||
}
|
||
|
||
```
|
||
|
||
Then, create the file `src/workflows/create-company.ts` with the following content:
|
||
|
||
export const workflowHighlights = [
|
||
["23", "tryToCreateCustomerGroupStep", "This step creates the customer group if its data is passed in the `customer_group` property."],
|
||
["36", "createCustomerGroupsWorkflow", "Use the `createCustomerGroupsWorkflow` defined by Medusa to create the customer group."],
|
||
["44", "", "Set the ID of the new customer group in the `customer_group_id` property so that it's added to the created company."],
|
||
["54", "createCompanyStep", "This step creates the company."],
|
||
]
|
||
|
||
```ts title="src/workflows/create-company.ts" highlights={workflowHighlights} collapsibleLines="1-12" expandButtonLabel="Show Imports"
|
||
import {
|
||
StepResponse,
|
||
createStep,
|
||
createWorkflow,
|
||
} from "@medusajs/workflows-sdk"
|
||
import {
|
||
createCustomerGroupsWorkflow,
|
||
} from "@medusajs/core-flows"
|
||
import { CreateCustomerGroupDTO } from "@medusajs/types"
|
||
import { CompanyDTO, CreateCompanyDTO } from "../types/b2b"
|
||
import B2bModuleService from "../modules/b2b/service"
|
||
|
||
export type CreateCompanyWorkflowInput = CreateCompanyDTO & {
|
||
customer_group?: CreateCustomerGroupDTO
|
||
}
|
||
|
||
type CreateCompanyWorkflowOutput = {
|
||
company: CompanyDTO
|
||
}
|
||
|
||
type CreateCustomerGroupStepInput = CreateCompanyWorkflowInput
|
||
|
||
const tryToCreateCustomerGroupStep = createStep(
|
||
"try-to-create-customer-group-step",
|
||
async (
|
||
{
|
||
customer_group,
|
||
...company
|
||
}: CreateCustomerGroupStepInput,
|
||
{ container }) => {
|
||
if (!customer_group) {
|
||
return new StepResponse({ company })
|
||
}
|
||
|
||
// create customer group
|
||
const { result } = await createCustomerGroupsWorkflow(
|
||
container
|
||
).run({
|
||
input: {
|
||
customersData: [customer_group],
|
||
},
|
||
})
|
||
|
||
company.customer_group_id = result[0].id
|
||
|
||
return new StepResponse({ company })
|
||
}
|
||
)
|
||
|
||
export type CreateCompanyStep = {
|
||
companyData: CreateCompanyDTO
|
||
}
|
||
|
||
const createCompanyStep = createStep(
|
||
"create-company-step",
|
||
async (
|
||
{ companyData }: CreateCompanyStep,
|
||
{ container }) => {
|
||
const b2bModuleService: B2bModuleService = container
|
||
.resolve(
|
||
"b2bModuleService"
|
||
)
|
||
|
||
const company = await b2bModuleService.createCompany(
|
||
companyData
|
||
)
|
||
|
||
return new StepResponse({ company })
|
||
}
|
||
)
|
||
|
||
export const createCompanyWorkflow = createWorkflow<
|
||
CreateCompanyWorkflowInput,
|
||
CreateCompanyWorkflowOutput
|
||
>(
|
||
"create-company",
|
||
function (input) {
|
||
const {
|
||
company: companyData,
|
||
} = tryToCreateCustomerGroupStep(input)
|
||
|
||
const company = createCompanyStep({ companyData })
|
||
|
||
return company
|
||
}
|
||
)
|
||
```
|
||
|
||
You create a workflow with two steps:
|
||
|
||
1. The first one tries to create a customer group if its data is provided in the `customer_group` property and sets its value in the `customer_group_id` property.
|
||
2. The second one creates the company.
|
||
|
||
Finally, create the file `src/api/admin/b2b/company/route.ts` with the following content:
|
||
|
||
```ts title="src/api/admin/b2b/company/route.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||
import type {
|
||
MedusaRequest,
|
||
MedusaResponse,
|
||
} from "@medusajs/medusa"
|
||
import {
|
||
CreateCompanyWorkflowInput,
|
||
createCompanyWorkflow,
|
||
} from "../../../../workflows/create-company"
|
||
|
||
type CreateCompanyReq = CreateCompanyWorkflowInput
|
||
|
||
export async function POST(
|
||
req: MedusaRequest<CreateCompanyReq>,
|
||
res: MedusaResponse
|
||
) {
|
||
const { result } = await createCompanyWorkflow(req.scope)
|
||
.run({
|
||
input: req.body,
|
||
})
|
||
|
||
res.json({
|
||
company: result.company,
|
||
})
|
||
}
|
||
```
|
||
|
||
The API route uses the workflow to create the company. It passes the request body as the workflow's input.
|
||
|
||
### Test API Route
|
||
|
||
To test the API route, start the Medusa application:
|
||
|
||
```bash npm2yarn
|
||
npm run dev
|
||
```
|
||
|
||
Next, make sure you authenticate as an admin user as explained in [this Authentication guide](!api!/api/admin#authentication).
|
||
|
||
Then, send a `POST` request to the `/admin/b2b/company` API route:
|
||
|
||
```bash
|
||
curl -X POST 'localhost:9000/admin/b2b/company' \
|
||
--header 'Content-Type: application/json' \
|
||
--header 'Authorization: Bearer {jwt_token}' \
|
||
--data '{
|
||
"name": "Acme",
|
||
"city": "London",
|
||
"country_code": "gb",
|
||
"customer_group": {
|
||
"name": "B2B"
|
||
}
|
||
}'
|
||
```
|
||
|
||
This creates a company and its associated customer group.
|
||
|
||
<Note title="Tip">
|
||
|
||
You can alternatively pass a `customer_group_id` to use an existing customer group.
|
||
|
||
</Note>
|
||
|
||
</Details> */}
|
||
|
||
## Add B2B Customers
|
||
|
||
After adding your B2B customer group, add B2B customers and assign them to the B2B customer group.
|
||
|
||
You can do that through the Medusa Admin or Admin REST APIs.
|
||
|
||
### Create Customers
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Option 1: Use Medusa Admin",
|
||
text: "Create the customers using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#customers_postcustomers",
|
||
title: "Option 2: Using the REST APIs",
|
||
text: "Create the customers using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
### Assign Customers to Groups
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Option 1: Use Medusa Admin",
|
||
text: "Assign the customers to the B2B customer group using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#customer-groups_postcustomergroupsidcustomersbatch",
|
||
title: "Option 2: Using the REST APIs",
|
||
text: "Assign the customers to the B2B customer group using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
---
|
||
|
||
## Create B2B Price List
|
||
|
||
Use price lists to set different prices for each B2B customer group, among other conditions.
|
||
|
||
You can create a price list using the Medusa Admin or the Admin REST APIs. Make sure to set the B2B customer group as a condition.
|
||
|
||
{/* TODO add links */}
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "#",
|
||
title: "Using Medusa Admin",
|
||
text: "Create the price list using the Medusa Admin.",
|
||
startIcon: <UsersSolid />,
|
||
showLinkIcon: false,
|
||
badge: {
|
||
variant: "blue",
|
||
children: "Guide Soon"
|
||
}
|
||
},
|
||
{
|
||
href: "!api!/api/admin#price-lists_postpricelists",
|
||
title: "Using REST APIs",
|
||
text: "Create the price list using the REST APIs.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
---
|
||
|
||
## Create Custom Data Model
|
||
|
||
To implement a more advanced B2B sales flow, add custom data models such as `Company`, `Employee`, `Admin`, and `Buyer` to your B2B module.
|
||
|
||
This provides more granular control of your B2B sales and allows you to build features like privileges, limits, and more.
|
||
|
||
<Card
|
||
href="!docs!/basics/data-models"
|
||
title="Create a Data Model"
|
||
text="Learn how to create a custom data model in a module."
|
||
startIcon={<AcademicCapSolid />}
|
||
showLinkIcon={false}
|
||
/>
|
||
|
||
---
|
||
|
||
## Create an API Route to Check Customers
|
||
|
||
On the frontend clients communicating with your store, such as the storefront, you need to check whether the currently logged-in customer is a B2B customer.
|
||
|
||
The API route can check if the customer has any group with an associated company.
|
||
|
||
<Card
|
||
href="!docs!/basics/api-routes"
|
||
title="Create an API Route"
|
||
text="Learn how to create an API Route in Medusa."
|
||
startIcon={<AcademicCapSolid />}
|
||
showLinkIcon={false}
|
||
/>
|
||
|
||
{/* <Details summaryContent="Example">
|
||
|
||
For example, create the API route `src/api/store/b2b/check-customer/route.ts` with the following content:
|
||
|
||
export const checkCustomerHighlights = [
|
||
["19", "retrieveCustomer", "Retrieve the customer along with its groups."],
|
||
["26", "listCompanies", "List the companies that have a customer group ID matching any of the customer's group IDs."],
|
||
["31", "", "Return whether there are any companies associated with the customer's groups."]
|
||
]
|
||
|
||
```ts title="src/api/store/b2b/check-customer/route.ts" highlights={checkCustomerHighlights} collapsibleLines="1-5" expandButtonLabel="Show Imports"
|
||
import type {
|
||
AuthenticatedMedusaRequest,
|
||
MedusaResponse,
|
||
} from "@medusajs/medusa"
|
||
import { ModuleRegistrationName } from "@medusajs/utils"
|
||
import { ICustomerModuleService } from "@medusajs/types"
|
||
import B2bModuleService from "../../../../modules/b2b/service"
|
||
|
||
export async function GET(
|
||
req: AuthenticatedMedusaRequest,
|
||
res: MedusaResponse
|
||
) {
|
||
const customerModuleService: ICustomerModuleService = req
|
||
.scope.resolve(ModuleRegistrationName.CUSTOMER)
|
||
const b2bModuleService: B2bModuleService = req.scope.resolve(
|
||
"b2bModuleService"
|
||
)
|
||
|
||
const customer = await customerModuleService.retrieveCustomer(
|
||
req.auth_context.actor_id,
|
||
{
|
||
relations: ["groups"],
|
||
}
|
||
)
|
||
|
||
const companies = await b2bModuleService.listCompanies({
|
||
customer_group_id: customer.groups.map((group) => group.id),
|
||
})
|
||
|
||
res.json({
|
||
is_b2b: companies.length > 0,
|
||
})
|
||
}
|
||
```
|
||
|
||
This creates a `GET` API Route at `/store/b2b/check-customer` that:
|
||
|
||
1. Retrieves the customer along with its groups using the Customer Module's main service.
|
||
2. Lists the companies that have a customer group ID matching any of the customer's group IDs.
|
||
3. Return an `is_b2b` field whose value is `true` if there are any companies associated with the customer's groups.
|
||
|
||
Before using the API route, create the file `src/api/middlewares.ts` with the following content:
|
||
|
||
```ts title="src/api/middlewares.ts"
|
||
import {
|
||
MiddlewaresConfig,
|
||
authenticate,
|
||
} from "@medusajs/medusa"
|
||
|
||
export const config: MiddlewaresConfig = {
|
||
routes: [
|
||
{
|
||
matcher: "/store/b2b*",
|
||
middlewares: [
|
||
authenticate("store", ["bearer", "session"]),
|
||
],
|
||
},
|
||
],
|
||
}
|
||
```
|
||
|
||
This ensures that only logged-in customers can use the API route.
|
||
|
||
### Test API Route
|
||
|
||
To test out the API route:
|
||
|
||
1. Start the Medusa application.
|
||
2. Obtain an authentication JWT token for a new customer. Do that by sending a `POST` request to the `/auth/store/emailpass` API Route:
|
||
|
||
```bash
|
||
curl -X POST 'http://localhost:9000/auth/store/emailpass' \
|
||
-H 'Content-Type: application/json' \
|
||
--data-raw '{
|
||
"email": "test@medusajs.com",
|
||
"password": "supersecret"
|
||
}'
|
||
```
|
||
|
||
3. Send a `POST` request to the `/store/customers` API route that registers the customer. Make sure to pass the authentication JWT token from the previous token in the header:
|
||
|
||
```bash
|
||
curl -X POST 'http://localhost:9000/store/customers' \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Authorization: Bearer {jwt_token}' \
|
||
--data-raw '{
|
||
"email": "test@medusajs.com",
|
||
"password": "supersecret"
|
||
}'
|
||
```
|
||
|
||
4. Add the customer to the B2B group as explained in a [previous section](#add-b2b-customers).
|
||
5. Send a `GET` request to the `/store/b2b/check-customer` API route you created in this section:
|
||
|
||
```bash
|
||
curl 'http://localhost:9000/store/b2b/check-customer' \
|
||
--header 'Authorization: Bearer {jwt_token}'
|
||
```
|
||
|
||
You'll receive a JSON response as the following:
|
||
|
||
```json
|
||
{
|
||
"is_b2b": true
|
||
}
|
||
```
|
||
|
||
</Details> */}
|
||
|
||
---
|
||
|
||
## Customize Admin
|
||
|
||
Based on your use case, you may need to customize the Medusa Admin to add new widgets or pages.
|
||
|
||
The Medusa Admin plugin can be extended to add widgets, new pages, and setting pages.
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "!docs!/advanced-development/admin/widgets",
|
||
title: "Create Admin Widget",
|
||
text: "Learn how to add widgets into existing admin pages.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
{
|
||
href: "!docs!/advanced-development/admin/ui-routes",
|
||
title: "Create Admin UI Routes",
|
||
text: "Learn how to add new pages to your Medusa Admin.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
{
|
||
href: "!docs!/advanced-development/admin/setting-pages",
|
||
title: "Create Admin Setting Page",
|
||
text: "Learn how to add new page to the Medusa Admin settings.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
---
|
||
|
||
## Customize Storefront
|
||
|
||
Medusa provides a Next.js storefront to use with your application. You can either customize it or build your own to represent your B2B features.
|
||
|
||
Use the publishable API key you associated with your B2B sales channel in the storefront to ensure only B2B products are retrieved.
|
||
|
||
<CardList items={[
|
||
{
|
||
href: "/nextjs-starter",
|
||
title: "Next.js Storefront",
|
||
text: "Learn how to install and customize the Next.js storefront.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
{
|
||
href: "/storefront-development",
|
||
title: "Storefront Development",
|
||
text: "Find guides for your storefront development.",
|
||
startIcon: <AcademicCapSolid />,
|
||
showLinkIcon: false
|
||
},
|
||
]} />
|
||
|
||
<Card
|
||
href="!api!/api/store#publishable-api-key"
|
||
title="Use Publishable API Keys"
|
||
text="Learn how to use the publishable API key in client requests."
|
||
startIcon={<AcademicCapSolid />}
|
||
showLinkIcon={false}
|
||
className="mt-1"
|
||
/> |