@mercurjs/docs 2.3.8-canary.3 → 2.3.9-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/content/learn/architecture.mdx +166 -263
  2. package/content/learn/introduction.mdx +9 -1
  3. package/content/learn/use-cases.mdx +70 -0
  4. package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
  5. package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
  6. package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
  7. package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
  8. package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
  9. package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
  10. package/content/platform/attribute/overview.mdx +37 -33
  11. package/content/platform/attribute/reference/data-models.mdx +53 -38
  12. package/content/platform/attribute/reference/events.mdx +47 -24
  13. package/content/platform/attribute/reference/links.mdx +98 -27
  14. package/content/platform/attribute/reference/service.mdx +71 -32
  15. package/content/platform/attribute/reference/workflows.mdx +158 -28
  16. package/content/platform/catalog/concepts/master-products.mdx +39 -37
  17. package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
  18. package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
  19. package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
  20. package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
  21. package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
  22. package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
  23. package/content/platform/catalog/overview.mdx +39 -35
  24. package/content/platform/catalog/reference/data-models.mdx +154 -43
  25. package/content/platform/catalog/reference/events.mdx +41 -25
  26. package/content/platform/catalog/reference/links.mdx +196 -28
  27. package/content/platform/catalog/reference/service.mdx +57 -35
  28. package/content/platform/catalog/reference/workflows.mdx +124 -30
  29. package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
  30. package/content/platform/commission/concepts/rule-matching.mdx +53 -63
  31. package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
  32. package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
  33. package/content/platform/commission/guides/create-a-rate.mdx +101 -53
  34. package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
  35. package/content/platform/commission/overview.mdx +43 -35
  36. package/content/platform/commission/reference/data-models.mdx +59 -45
  37. package/content/platform/commission/reference/events.mdx +28 -34
  38. package/content/platform/commission/reference/links.mdx +42 -33
  39. package/content/platform/commission/reference/service.mdx +103 -28
  40. package/content/platform/commission/reference/workflows.mdx +101 -27
  41. package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
  42. package/content/platform/offer/concepts/shipping.mdx +28 -29
  43. package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
  44. package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
  45. package/content/platform/offer/guides/create-an-offer.mdx +112 -60
  46. package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
  47. package/content/platform/offer/overview.mdx +39 -32
  48. package/content/platform/offer/reference/data-models.mdx +77 -47
  49. package/content/platform/offer/reference/events.mdx +44 -18
  50. package/content/platform/offer/reference/links.mdx +92 -40
  51. package/content/platform/offer/reference/service.mdx +66 -31
  52. package/content/platform/offer/reference/workflows.mdx +146 -37
  53. package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
  54. package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
  55. package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
  56. package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
  57. package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
  58. package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
  59. package/content/platform/order-group/overview.mdx +42 -32
  60. package/content/platform/order-group/reference/data-models.mdx +48 -31
  61. package/content/platform/order-group/reference/events.mdx +29 -17
  62. package/content/platform/order-group/reference/links.mdx +90 -29
  63. package/content/platform/order-group/reference/service.mdx +55 -31
  64. package/content/platform/order-group/reference/workflows.mdx +83 -24
  65. package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
  66. package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
  67. package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
  68. package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
  69. package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
  70. package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
  71. package/content/platform/payout/overview.mdx +43 -34
  72. package/content/platform/payout/reference/data-models.mdx +63 -36
  73. package/content/platform/payout/reference/events.mdx +56 -30
  74. package/content/platform/payout/reference/links.mdx +52 -22
  75. package/content/platform/payout/reference/service.mdx +72 -33
  76. package/content/platform/payout/reference/workflows.mdx +80 -19
  77. package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
  78. package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
  79. package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
  80. package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
  81. package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
  82. package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
  83. package/content/platform/product-edit/overview.mdx +41 -34
  84. package/content/platform/product-edit/reference/data-models.mdx +73 -47
  85. package/content/platform/product-edit/reference/events.mdx +39 -29
  86. package/content/platform/product-edit/reference/links.mdx +32 -24
  87. package/content/platform/product-edit/reference/service.mdx +45 -26
  88. package/content/platform/product-edit/reference/workflows.mdx +173 -31
  89. package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
  90. package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
  91. package/content/platform/review/concepts/the-review-model.mdx +52 -45
  92. package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
  93. package/content/platform/review/guides/create-a-review.mdx +109 -39
  94. package/content/platform/review/guides/moderate-a-review.mdx +83 -37
  95. package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
  96. package/content/platform/review/overview.mdx +43 -33
  97. package/content/platform/review/reference/data-models.mdx +41 -27
  98. package/content/platform/review/reference/events.mdx +55 -37
  99. package/content/platform/review/reference/links.mdx +80 -22
  100. package/content/platform/review/reference/service.mdx +61 -33
  101. package/content/platform/review/reference/workflows.mdx +80 -24
  102. package/content/platform/store/concepts/lifecycle.mdx +68 -44
  103. package/content/platform/store/concepts/store-entity.mdx +45 -27
  104. package/content/platform/store/concepts/team.mdx +56 -35
  105. package/content/platform/store/guides/create-a-store.mdx +102 -35
  106. package/content/platform/store/guides/manage-the-team.mdx +122 -32
  107. package/content/platform/store/guides/moderate-a-store.mdx +107 -38
  108. package/content/platform/store/overview.mdx +41 -34
  109. package/content/platform/store/reference/data-models.mdx +132 -57
  110. package/content/platform/store/reference/events.mdx +42 -17
  111. package/content/platform/store/reference/links.mdx +67 -49
  112. package/content/platform/store/reference/service.mdx +105 -33
  113. package/content/platform/store/reference/workflows.mdx +304 -24
  114. package/content/references/api/conventions.mdx +20 -0
  115. package/content/resources/integrations/magento2.mdx +162 -0
  116. package/content/resources/integrations/overview.mdx +10 -0
  117. package/content/resources/integrations/stripe-connect.mdx +1 -1
  118. package/content/resources/tutorials/custom-api-route.mdx +3 -2
  119. package/llms.txt +113 -111
  120. package/package.json +1 -1
@@ -1,55 +1,145 @@
1
1
  ---
2
- title: "Manage the team"
2
+ title: "Manage a store's team from server code"
3
3
  sidebarTitle: "Manage the team"
4
- description: "Invite and add store members from server code."
4
+ description: "Invite members, accept invites, add existing members, change roles, and remove members with the Seller module workflows."
5
5
  ---
6
6
 
7
- In this guide, you'll learn how to manage a store's team from your own server
8
- code. You can invite members, add them directly, and update their roles.
7
+ Manage a store’s team from your own server code when you migrate staff from another system, sync people from an identity provider, or build your own team screens. Every change runs through a workflow that validates the owner rules and emits an event.
9
8
 
10
- ## Invite a member
9
+ ## Before you begin
11
10
 
12
- `inviteSellerWorkflow` creates a `MemberInvite` and sends the invitation email.
13
- The invitee sets up access and is linked to the store when they accept.
11
+ You need the following in place:
14
12
 
15
- ```ts title="src/api/custom/invite/route.ts"
16
- import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
17
- import { inviteSellerWorkflow } from "@mercurjs/core/workflows"
13
+ - A store id, such as `sel_01JD8Q1234567`
14
+ - A notification provider for email, if you send invite links from a subscriber
18
15
 
19
- export async function POST(req: MedusaRequest, res: MedusaResponse) {
20
- await inviteSellerWorkflow(req.scope).run({
21
- input: {
22
- email: "ops@acme.com",
23
- seller_id: req.params.id,
24
- },
25
- })
16
+ ## Invite and onboard a member
26
17
 
27
- res.sendStatus(200)
28
- }
29
- ```
18
+ <Steps>
19
+ <Step title="Create the invite">
20
+ `createMemberInvitesWorkflow` takes an array of invites, each with `seller_id`, `email`, and `role_id`. It signs a token for each one and fails if an email already belongs to the store.
21
+
22
+ ```ts
23
+ import { SellerRole } from "@mercurjs/types"
24
+ import { createMemberInvitesWorkflow } from "@mercurjs/core/workflows"
25
+
26
+ const { result: invites } = await createMemberInvitesWorkflow(
27
+ container
28
+ ).run({
29
+ input: [
30
+ {
31
+ seller_id: "sel_01JD8Q1234567",
32
+ email: "ops@acme.com",
33
+ role_id: SellerRole.ORDER_MANAGEMENT,
34
+ },
35
+ ],
36
+ })
37
+ ```
38
+ </Step>
39
+ <Step title="Send the invite link">
40
+ The workflow emits `member_invite.created` once per invite, with `id`, `token`, and `expires_at`. Mercur doesn’t email team invites itself, so send the link from a subscriber.
41
+
42
+ ```ts title="src/subscribers/member-invite-created.ts"
43
+ import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
44
+ import { Modules } from "@medusajs/framework/utils"
45
+ import { MercurModules } from "@mercurjs/types"
46
+
47
+ export default async function inviteCreated({
48
+ event,
49
+ container,
50
+ }: SubscriberArgs<{ id: string; token: string }>) {
51
+ const sellers = container.resolve(MercurModules.SELLER)
52
+ const invite = await sellers.retrieveMemberInvite(event.data.id)
53
+ await container.resolve(Modules.NOTIFICATION).createNotifications({
54
+ to: invite.email,
55
+ channel: "email",
56
+ template: "member-invite",
57
+ data: { token: event.data.token },
58
+ })
59
+ }
60
+
61
+ export const config: SubscriberConfig = { event: "member_invite.created" }
62
+ ```
63
+ </Step>
64
+ <Step title="Accept the invite">
65
+ When the invitee signs up or signs in, run `acceptMemberInviteWorkflow` with the token and their auth identity. It returns the member.
66
+
67
+ ```ts
68
+ import { acceptMemberInviteWorkflow } from "@mercurjs/core/workflows"
30
69
 
31
- ## Add a member directly
70
+ const { result: member } = await acceptMemberInviteWorkflow(
71
+ req.scope
72
+ ).run({
73
+ input: {
74
+ invite_token: "your_invite_token",
75
+ auth_identity_id: req.auth_context.auth_identity_id,
76
+ first_name: "Ola",
77
+ last_name: "Nordmann",
78
+ },
79
+ })
80
+ ```
32
81
 
33
- When you already have the user, for example during a migration, add them to a
34
- store without the invite step. Use `addSellerMemberWorkflow`.
82
+ The workflow upserts the member by email, creates the membership with the invite’s role, and deletes the invite. Pass `member_id` when the person is already a member of another store, so the workflow leaves their auth identity as it is.
83
+ </Step>
84
+ </Steps>
85
+
86
+ ## Resend or revoke an invite
87
+
88
+ `resendMemberInviteWorkflow` takes `invite_id` and `seller_id`. It deletes the invite and creates a fresh one with a new token and expiry, then emits `member_invite.created` again. `deleteMemberInviteWorkflow` takes `invite_id` and deletes the invite without a replacement.
89
+
90
+ ## Add an existing member directly
91
+
92
+ Skip the invite when the person already has a `Member` record, for example after a migration. `addSellerMemberWorkflow` creates the membership and returns it.
35
93
 
36
94
  ```ts
95
+ import { SellerRole } from "@mercurjs/types"
37
96
  import { addSellerMemberWorkflow } from "@mercurjs/core/workflows"
38
97
 
39
98
  await addSellerMemberWorkflow(container).run({
40
99
  input: {
41
- seller_id: "sel_123",
42
- member: { email: "ops@acme.com" },
100
+ seller_id: "sel_01JD8Q1234567",
101
+ member_id: "mem_01JD8Q1234567",
102
+ role_id: SellerRole.SUPPORT,
43
103
  },
44
104
  })
45
105
  ```
46
106
 
47
- <Tip>
48
- Every store must keep at least one admin member. A workflow that would remove or
49
- demote the last admin fails instead of leaving a store unadministered.
50
- </Tip>
107
+ The membership is unique on `(seller_id, member_id)`, so adding the same member twice fails.
108
+
109
+ ## Change a role or remove a member
110
+
111
+ Both workflows take the membership id, `seller_member_id`, not the member id. Both reject the owner membership with a `NOT_ALLOWED` error.
112
+
113
+ ```ts
114
+ import { SellerRole } from "@mercurjs/types"
115
+ import {
116
+ removeSellerMemberWorkflow,
117
+ updateMemberRoleWorkflow,
118
+ } from "@mercurjs/core/workflows"
119
+
120
+ await updateMemberRoleWorkflow(container).run({
121
+ input: {
122
+ seller_member_id: "selmem_01JD8Q1234567",
123
+ role_id: SellerRole.ACCOUNTING,
124
+ },
125
+ })
126
+
127
+ await removeSellerMemberWorkflow(container).run({
128
+ input: {
129
+ seller_member_id: "selmem_01JD8Q1234567",
130
+ seller_id: "sel_01JD8Q1234567",
131
+ },
132
+ })
133
+ ```
134
+
135
+ Removing a membership keeps the `Member` record, so the person keeps access to their other stores.
136
+
137
+ ## Update a member’s profile
138
+
139
+ `updateMemberWorkflow` changes `first_name`, `last_name`, and `locale` on members that match a `selector`. It exposes a `membersUpdated` hook and doesn’t emit an event.
51
140
 
52
- ## Accept an invite
141
+ ## Next steps
53
142
 
54
- The invitee's acceptance runs through `acceptMemberInviteWorkflow`. It links the
55
- member to the store, and if the email already exists, it reuses their account.
143
+ - [How store teams work](/platform/store/concepts/team)
144
+ - [Event reference](/platform/store/reference/events)
145
+ - [Workflows reference](/platform/store/reference/workflows)
@@ -1,59 +1,128 @@
1
1
  ---
2
- title: "Moderate stores"
2
+ title: "Approve, suspend, and terminate stores"
3
3
  sidebarTitle: "Moderate stores"
4
- description: "Approve, suspend, and terminate stores from server code."
4
+ description: "Move stores through their lifecycle from server code, extend each transition with a hook, and react to the events."
5
5
  ---
6
6
 
7
- In this guide, you'll learn how to drive a store through its lifecycle from your
8
- own server code. Each transition has a dedicated workflow, so the side effects
9
- (events, notifications, and compensation) run consistently.
7
+ Drive a store through its lifecycle from your own server code, for example to auto-approve vetted sellers or to suspend a store when a risk check fails. Each transition is a workflow that validates the current status, writes the change, emits an event, and exposes a hook.
10
8
 
11
- ## Approve a store
9
+ ## Moderate a store
12
10
 
13
- Move a `pending_approval` store to `open` with `approveSellerWorkflow`.
11
+ <Steps>
12
+ <Step title="Approve a pending store">
13
+ `approveSellerWorkflow` moves a `pending_approval` store to `open` and stamps `approved_at`.
14
14
 
15
- ```ts title="src/api/custom/approve/route.ts"
16
- import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
17
- import { approveSellerWorkflow } from "@mercurjs/core/workflows"
15
+ ```ts title="src/api/admin/stores/[id]/vet/route.ts"
16
+ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
17
+ import { approveSellerWorkflow } from "@mercurjs/core/workflows"
18
18
 
19
- export async function POST(req: MedusaRequest, res: MedusaResponse) {
20
- await approveSellerWorkflow(req.scope).run({
21
- input: { seller_id: req.params.id },
22
- })
19
+ export async function POST(req: MedusaRequest, res: MedusaResponse) {
20
+ await approveSellerWorkflow(req.scope).run({
21
+ input: { seller_id: req.params.id },
22
+ })
23
23
 
24
- res.sendStatus(200)
25
- }
26
- ```
24
+ res.sendStatus(200)
25
+ }
26
+ ```
27
+ </Step>
28
+ <Step title="Suspend and reinstate a store">
29
+ `suspendSellerWorkflow` takes an optional `reason`, which it saves in `status_reason`. `unsuspendSellerWorkflow` reopens the store and clears the reason.
27
30
 
28
- ## Suspend and reinstate
31
+ ```ts
32
+ import {
33
+ suspendSellerWorkflow,
34
+ unsuspendSellerWorkflow,
35
+ } from "@mercurjs/core/workflows"
29
36
 
30
- Freeze an `open` store's operations, then reinstate it once the issue is resolved.
37
+ await suspendSellerWorkflow(container).run({
38
+ input: { seller_id: "sel_01JD8Q1234567", reason: "Chargeback review" },
39
+ })
31
40
 
32
- ```ts
33
- import {
34
- suspendSellerWorkflow,
35
- unsuspendSellerWorkflow,
36
- } from "@mercurjs/core/workflows"
37
-
38
- await suspendSellerWorkflow(container).run({ input: { seller_id } })
39
- // ...later
40
- await unsuspendSellerWorkflow(container).run({ input: { seller_id } })
41
- ```
41
+ await unsuspendSellerWorkflow(container).run({
42
+ input: { seller_id: "sel_01JD8Q1234567" },
43
+ })
44
+ ```
45
+ </Step>
46
+ <Step title="Terminate a store">
47
+ `terminateSellerWorkflow` accepts a `pending_approval` or `suspended` store. Suspend an `open` store first.
48
+
49
+ ```ts
50
+ import { terminateSellerWorkflow } from "@mercurjs/core/workflows"
51
+
52
+ await terminateSellerWorkflow(container).run({
53
+ input: { seller_id: "sel_01JD8Q1234567", reason: "Policy breach" },
54
+ })
55
+ ```
42
56
 
43
- ## Terminate a store
57
+ To undo it, run `unterminateSellerWorkflow`. It returns the store to `suspended`, and you reopen it with `unsuspendSellerWorkflow`.
58
+ </Step>
59
+ </Steps>
60
+
61
+ ## Reject a pending application
62
+
63
+ Mercur has no separate reject workflow. Run `suspendSellerWorkflow` on the `pending_approval` store with a `reason`: it stamps `rejected_at` and keeps the store out of the Store API. Terminate it afterwards if the decision is final.
64
+
65
+ ## Handle a failed transition
66
+
67
+ Each workflow checks the starting status and fails with a `NOT_ALLOWED` error when the transition isn’t allowed. Nothing is written in that case. Pass `throwOnError: false` to read the error instead of catching it.
44
68
 
45
69
  ```ts
70
+ import { MedusaError } from "@medusajs/framework/utils"
46
71
  import { terminateSellerWorkflow } from "@mercurjs/core/workflows"
47
72
 
48
- await terminateSellerWorkflow(container).run({ input: { seller_id } })
73
+ const { errors } = await terminateSellerWorkflow(container).run({
74
+ input: { seller_id: "sel_01JD8Q1234567" },
75
+ throwOnError: false,
76
+ })
77
+
78
+ const notAllowed = errors.some(
79
+ ({ error }) => error.type === MedusaError.Types.NOT_ALLOWED
80
+ )
81
+ ```
82
+
83
+ An `open` store makes `notAllowed` true here, with the message “Cannot terminate an open seller. Suspend or close first.”
84
+
85
+ The workflow also fails when the seller id doesn’t exist, because its lookup step runs with `throwIfKeyNotFound`.
86
+
87
+ ## Extend a transition with a hook
88
+
89
+ Each lifecycle workflow exposes a hook that receives `seller_id` and `additional_data`. Register a handler to run your own step inside the transition.
90
+
91
+ ```ts title="src/workflows/hooks/seller-approved.ts"
92
+ import { approveSellerWorkflow } from "@mercurjs/core/workflows"
93
+
94
+ approveSellerWorkflow.hooks.sellerApproved(
95
+ async ({ seller_id }, { container }) => {
96
+ const logger = container.resolve("logger")
97
+ logger.info(`Store ${seller_id} approved`)
98
+ }
99
+ )
49
100
  ```
50
101
 
51
- <Warning>
52
- Termination is irreversible. All orders and payouts must be resolved first.
53
- </Warning>
102
+ The other hooks follow the same shape: `sellerSuspended`, `sellerUnsuspended`, `sellerTerminated`, and `sellerUnterminated`.
103
+
104
+ ## Run side effects from a subscriber
105
+
106
+ Subscribe to the lifecycle events for work that shouldn’t block the transition, such as emails. Each event carries `{ id }`, the seller id.
107
+
108
+ ```ts title="src/subscribers/store-suspended.ts"
109
+ import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
110
+
111
+ export default async function storeSuspended({
112
+ event,
113
+ container,
114
+ }: SubscriberArgs<{ id: string }>) {
115
+ const logger = container.resolve("logger")
116
+ logger.info(`Store ${event.data.id} suspended`)
117
+ }
118
+
119
+ export const config: SubscriberConfig = {
120
+ event: "seller.suspended",
121
+ }
122
+ ```
54
123
 
55
- ## React to lifecycle changes
124
+ ## Next steps
56
125
 
57
- To run your own side effects when a store's status changes, subscribe to the
58
- events these workflows emit instead of polling. The
59
- [Event reference](/platform/store/reference/events) lists the event names.
126
+ - [Store statuses and transitions](/platform/store/concepts/lifecycle)
127
+ - [Event reference](/platform/store/reference/events)
128
+ - [Workflows reference](/platform/store/reference/workflows)
@@ -1,46 +1,53 @@
1
1
  ---
2
- title: "Store"
2
+ title: "Stores"
3
3
  sidebarTitle: "Overview"
4
- description: "Manage sellers, their teams, and their lifecycle on the marketplace."
4
+ description: "Control who sells on your marketplace, who works on each store, and when a store can trade."
5
5
  ---
6
6
 
7
- Use Mercur to control who is allowed to sell on your marketplace and what each
8
- person on a store's team can do.
7
+ Use Mercur to decide who can sell on your marketplace and what each person on a store’s team can do.
9
8
 
10
- Governing your sellers starts here. The Store domain decides who may sell,
11
- enforces role-based access so every member acts only within their store, and
12
- keeps each store's data isolated from the rest. On top of that control layer, a
13
- store carries its own team, a governed account lifecycle, and the business
14
- details used to settle payouts. Every offer, order, payout, and storefront page
15
- belongs to a store, and all of it is exposed directly through the Admin and
16
- Vendor APIs.
9
+ A store is the account a seller trades under. Offers, orders, payouts, and storefront pages all link back to it, and its team works only inside it. The Seller module holds the store record, its business details, its members and invites, and its status. Other marketplace modules attach to a store through module links, never through direct references.
10
+
11
+ <img className="block dark:hidden" src="/images/figures/store-overview-light.svg" alt="A Stores list from the Seller module showing four stores, each with its status, currency, member count, and premium flag, in front of the Team panel for acme-supplies with three members and their seller roles." />
12
+ <img className="hidden dark:block" src="/images/figures/store-overview-dark.svg" alt="A Stores list from the Seller module showing four stores, each with its status, currency, member count, and premium flag, in front of the Team panel for acme-supplies with three members and their seller roles." />
17
13
 
18
14
  <Note>
19
- A store is the `Seller` entity. The Admin and Vendor panels call it a "Store".
20
- The API and core modules call the same record a `Seller` (id prefix `sel`). You
21
- never need to know Medusa to work with stores.
15
+ The Admin and Vendor panels call it a store. The code calls the same record a `Seller` (id prefix `sel`), and you resolve its module with `MercurModules.SELLER` from `@mercurjs/types`.
22
16
  </Note>
23
17
 
24
18
  ## Key features
25
19
 
26
- - **Role-based access control:** many-to-many members, roles resolved per store, and a store switcher for users who belong to several stores.
27
- - **Store isolation:** each store sees and acts on only its own data.
28
- - **Governed lifecycle:** a four-state account model with operator-only transitions.
29
- - **Self-service onboarding:** create stores yourself, or let sellers register publicly.
30
- - **Scheduled closures:** temporary offline windows that don't change account status.
31
- - **Premium placement:** an operator-only flag the storefront uses for featured curation.
32
- - **Single-currency accounts:** each store settles in exactly one currency.
20
+ The Seller module covers the full life of a store account:
21
+
22
+ - **Many-to-many teams**: a member can belong to several stores and picks the active one per request
23
+ - **Owner protection**: the store’s owner membership can’t be removed or have its role changed
24
+ - **Seller roles**: each membership stores one of five `SellerRole` values, from administration to support
25
+ - **Token-based invites**: signed invite tokens that expire after 7 days by default
26
+ - **Governed lifecycle**: four statuses, each transition run by its own workflow with a hook and an event
27
+ - **Scheduled closures**: a `closed_from` and `closed_to` window that hides a store from the Store API without changing its status
28
+ - **Premium flag**: an `is_premium` boolean the operator sets for featured placement
29
+ - **Region assignment**: every store links to one or more regions, starting with the default region
30
+
31
+ ## How it works
32
+
33
+ A store moves from creation to trading in a fixed order:
34
+
35
+ 1. A seller registers, or your code runs `createSellersWorkflow`, and the store starts in `pending_approval`
36
+ 2. The workflow links the store to the default region and to any `region_ids` you pass
37
+ 3. The first member joins as owner, either at registration or by accepting the invite the workflow sends
38
+ 4. The operator runs `approveSellerWorkflow`, and the store becomes `open`
39
+ 5. The Store API lists the store and its offers while it’s `open` and outside a closure window
33
40
 
34
41
  ## Get started
35
42
 
36
- Learn how the domain fits together.
43
+ Learn how stores, teams, and statuses fit together.
37
44
 
38
45
  <CardGroup cols={2}>
39
46
  <Card title="The store" icon="store" href="/platform/store/concepts/store-entity">
40
- The seller entity, its profile, currency, and business identity.
47
+ The seller record, its currency, regions, and business details.
41
48
  </Card>
42
49
  <Card title="Team & members" icon="users" href="/platform/store/concepts/team">
43
- Multi-user stores, roles, invites, and the store switcher.
50
+ Members, owners, roles, invites, and the active store.
44
51
  </Card>
45
52
  <Card title="Lifecycle" icon="arrows-rotate" href="/platform/store/concepts/lifecycle">
46
53
  Statuses, transitions, scheduled closures, and premium.
@@ -49,38 +56,38 @@ Learn how the domain fits together.
49
56
 
50
57
  ## Examples
51
58
 
52
- Build against the Store domain in your own code.
59
+ Build against stores in your own server code.
53
60
 
54
61
  <CardGroup cols={2}>
55
62
  <Card title="Create a store" icon="plus" href="/platform/store/guides/create-a-store">
56
- Run `createSellersWorkflow` from a route or seed script.
63
+ Run `createSellersWorkflow` from a route or a seed script.
57
64
  </Card>
58
65
  <Card title="Moderate stores" icon="gavel" href="/platform/store/guides/moderate-a-store">
59
- Approve, suspend, and terminate stores in code.
66
+ Approve, suspend, terminate, and reinstate stores in code.
60
67
  </Card>
61
68
  <Card title="Manage the team" icon="user-plus" href="/platform/store/guides/manage-the-team">
62
- Invite and add members programmatically.
69
+ Invite, add, re-role, and remove members.
63
70
  </Card>
64
71
  </CardGroup>
65
72
 
66
73
  ## Resources
67
74
 
68
- Data models, workflows, service methods, and events for the Store domain.
75
+ The data models, links, workflows, service methods, and events behind stores.
69
76
 
70
77
  <CardGroup cols={2}>
71
78
  <Card title="Data models" icon="table" href="/platform/store/reference/data-models">
72
- The `Seller`, `Member`, and related entities.
79
+ `Seller`, `Member`, `SellerMember`, `MemberInvite`, and the satellite records.
73
80
  </Card>
74
81
  <Card title="Links" icon="link" href="/platform/store/reference/links">
75
- How the Store domain links to other modules.
82
+ How a store connects to orders, offers, payouts, regions, and more.
76
83
  </Card>
77
84
  <Card title="Workflows" icon="diagram-project" href="/platform/store/reference/workflows">
78
- Seller and member lifecycle workflows.
85
+ Store, lifecycle, and team workflows with their hooks.
79
86
  </Card>
80
87
  <Card title="Service" icon="gear" href="/platform/store/reference/service">
81
- Module service methods for working with records directly.
88
+ Seller module service methods for direct reads and writes.
82
89
  </Card>
83
90
  <Card title="Events" icon="bell" href="/platform/store/reference/events">
84
- Events emitted as stores and members change.
91
+ Events emitted as stores, members, and invites change.
85
92
  </Card>
86
93
  </CardGroup>