@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,35 +1,315 @@
1
1
  ---
2
- title: "Workflows"
2
+ title: "Seller module workflows"
3
3
  sidebarTitle: "Workflows"
4
- description: "Seller and member workflows, service methods, and events."
4
+ description: "Every store, lifecycle, business-detail, and team workflow in the Seller module, with inputs, hooks, and events."
5
5
  ---
6
6
 
7
- This reference lists the workflows, service methods, and events for the Store
8
- domain. Import workflows from `@mercurjs/core/workflows` and run them against the
9
- Medusa container.
7
+ This reference lists every workflow that writes Seller module data. Import them from `@mercurjs/core/workflows` and run them against the Medusa container: `await workflow(container).run({ input })`. Workflows roll back their completed steps when a later step fails.
10
8
 
11
- ## Seller workflows
9
+ ```ts
10
+ import { approveSellerWorkflow } from "@mercurjs/core/workflows"
12
11
 
13
- | Workflow | Input | Purpose |
12
+ await approveSellerWorkflow(container).run({
13
+ input: { seller_id: "sel_01JD8Q1234567" },
14
+ })
15
+ ```
16
+
17
+ Workflows that take `additional_data` pass it to their hooks. Register a hook handler with `workflow.hooks.<hookName>(handler)`.
18
+
19
+ ## createSellersWorkflow
20
+
21
+ Creates one or more stores, links each to the default region plus `region_ids`, and invites one member per store with `role_seller_administration`. Returns `SellerDTO[]`.
22
+
23
+ | Input | Type | Description |
24
+ | --- | --- | --- |
25
+ | `sellers` | `CreateSellerDTO & { member, region_ids? }[]` | Store fields; `status` defaults to `pending_approval` |
26
+ | `sellers[].member` | `{ email: string }` | Required, the address that gets the invite |
27
+ | `sellers[].region_ids` | `string[]` | Optional, regions besides the default one |
28
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
29
+
30
+ - **Hooks**: `validate` (`{ input }`), `sellersCreated` (`{ sellers, additional_data }`)
31
+ - **Events**: `seller.created` per store, `member_invite.created` per invite
32
+
33
+ ## createSellerAccountWorkflow
34
+
35
+ Creates one store in `pending_approval` and adds a member as its owner with `role_seller_administration`. Returns `SellerDTO`.
36
+
37
+ | Input | Type | Description |
38
+ | --- | --- | --- |
39
+ | `auth_identity_id` | `string` | The auth identity to attach the member to |
40
+ | `seller` | `CreateSellerDTO` | Store fields; `status` is forced to `pending_approval` |
41
+ | `member_id` | `string` | Optional, an existing member to make owner |
42
+ | `member_email` | `string` | Used when `member_id` is absent to upsert a member |
43
+ | `first_name`, `last_name` | `string` | Optional, set on a new member |
44
+ | `address` | `UpdateSellerAddressDTO` | Optional, written through `updateSellerAddressWorkflow` |
45
+ | `professional_details` | `UpdateProfessionalDetailsDTO` | Optional |
46
+ | `payment_details` | `UpdatePaymentDetailsDTO` | Optional |
47
+ | `region_ids` | `string[]` | Optional, regions besides the default one |
48
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
49
+
50
+ - **Hooks**: `validate` (`{ input }`), `sellerAccountCreated` (`{ seller, member_id, additional_data }`)
51
+ - **Events**: `seller.created`
52
+
53
+ ## updateSellersWorkflow
54
+
55
+ Updates every store that matches `selector` with the same `update`. Returns `SellerDTO[]`.
56
+
57
+ | Input | Type | Description |
58
+ | --- | --- | --- |
59
+ | `selector` | `Record<string, unknown>` | Filters, such as `{ id: "sel_01JD8Q1234567" }` |
60
+ | `update` | `UpdateSellerDTO` | Fields to set |
61
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
62
+
63
+ - **Hooks**: `sellersUpdated` (`{ sellers, additional_data }`)
64
+ - **Events**: `seller.updated` per store
65
+
66
+ ## deleteSellersWorkflow
67
+
68
+ Soft deletes stores by id. Compensation restores them.
69
+
70
+ | Input | Type | Description |
71
+ | --- | --- | --- |
72
+ | `ids` | `string[]` | Seller ids |
73
+
74
+ - **Hooks**: none
75
+ - **Events**: `seller.deleted` per store
76
+
77
+ ## approveSellerWorkflow
78
+
79
+ Moves a `pending_approval` store to `open`, clears `status_reason`, and sets `approved_at` if it’s empty.
80
+
81
+ | Input | Type | Description |
82
+ | --- | --- | --- |
83
+ | `seller_id` | `string` | The store to approve |
84
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
85
+
86
+ - **Hooks**: `sellerApproved` (`{ seller_id, additional_data }`)
87
+ - **Events**: `seller.approved`
88
+
89
+ ## suspendSellerWorkflow
90
+
91
+ Moves a `pending_approval` or `open` store to `suspended`, saves `reason` in `status_reason`, and sets `rejected_at` if it’s empty.
92
+
93
+ | Input | Type | Description |
94
+ | --- | --- | --- |
95
+ | `seller_id` | `string` | The store to suspend |
96
+ | `reason` | `string` | Optional |
97
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
98
+
99
+ - **Hooks**: `sellerSuspended` (`{ seller_id, additional_data }`)
100
+ - **Events**: `seller.suspended`
101
+
102
+ ## unsuspendSellerWorkflow
103
+
104
+ Moves a `suspended` store to `open` and clears `status_reason`.
105
+
106
+ | Input | Type | Description |
107
+ | --- | --- | --- |
108
+ | `seller_id` | `string` | The store to reopen |
109
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
110
+
111
+ - **Hooks**: `sellerUnsuspended` (`{ seller_id, additional_data }`)
112
+ - **Events**: `seller.unsuspended`
113
+
114
+ ## terminateSellerWorkflow
115
+
116
+ Moves a `pending_approval` or `suspended` store to `terminated` and saves `reason` in `status_reason`. Fails for an `open` store.
117
+
118
+ | Input | Type | Description |
119
+ | --- | --- | --- |
120
+ | `seller_id` | `string` | The store to terminate |
121
+ | `reason` | `string` | Optional |
122
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
123
+
124
+ - **Hooks**: `sellerTerminated` (`{ seller_id, additional_data }`)
125
+ - **Events**: `seller.terminated`
126
+
127
+ ## unterminateSellerWorkflow
128
+
129
+ Moves a `terminated` store to `suspended` and clears `status_reason`.
130
+
131
+ | Input | Type | Description |
132
+ | --- | --- | --- |
133
+ | `seller_id` | `string` | The store to restore |
134
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
135
+
136
+ - **Hooks**: `sellerUnterminated` (`{ seller_id, additional_data }`)
137
+ - **Events**: `seller.unterminated`
138
+
139
+ ## linkSellerRegionsWorkflow
140
+
141
+ Adds and removes store region links in one run. Fails if a region or seller doesn’t exist, or if a store would be left with no region.
142
+
143
+ | Input | Type | Description |
144
+ | --- | --- | --- |
145
+ | `add` | `{ seller_id, region_id }[]` | Optional, links to create |
146
+ | `remove` | `{ seller_id, region_id }[]` | Optional, links to dismiss |
147
+
148
+ - **Hooks**: none
149
+ - **Events**: none
150
+
151
+ ## updateSellerAddressWorkflow
152
+
153
+ Creates or updates a store’s `SellerAddress`. Returns `SellerAddressDTO`.
154
+
155
+ | Input | Type | Description |
156
+ | --- | --- | --- |
157
+ | `seller_id` | `string` | The store |
158
+ | `data` | `UpdateSellerAddressDTO` | Address fields |
159
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
160
+
161
+ - **Hooks**: `addressUpdated` (`{ address, additional_data }`)
162
+ - **Events**: none
163
+
164
+ ## updateSellerProfessionalDetailsWorkflow
165
+
166
+ Creates or updates a store’s `ProfessionalDetails`. Returns `ProfessionalDetailsDTO`.
167
+
168
+ | Input | Type | Description |
169
+ | --- | --- | --- |
170
+ | `seller_id` | `string` | The store |
171
+ | `data` | `UpdateProfessionalDetailsDTO` | `corporate_name`, `registration_number`, `tax_id` |
172
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
173
+
174
+ - **Hooks**: `professionalDetailsUpdated` (`{ professional_details, additional_data }`)
175
+ - **Events**: none
176
+
177
+ ## deleteSellerProfessionalDetailsWorkflow
178
+
179
+ Deletes a store’s `ProfessionalDetails`, if it has any.
180
+
181
+ | Input | Type | Description |
182
+ | --- | --- | --- |
183
+ | `seller_id` | `string` | The store |
184
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
185
+
186
+ - **Hooks**: `professionalDetailsDeleted` (`{ seller_id, additional_data }`)
187
+ - **Events**: none
188
+
189
+ ## updateSellerPaymentDetailsWorkflow
190
+
191
+ Creates or updates a store’s `PaymentDetails`. Returns `PaymentDetailsDTO`.
192
+
193
+ | Input | Type | Description |
194
+ | --- | --- | --- |
195
+ | `seller_id` | `string` | The store |
196
+ | `data` | `UpdatePaymentDetailsDTO` | Bank account fields |
197
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
198
+
199
+ - **Hooks**: `paymentDetailsUpdated` (`{ payment_details, additional_data }`)
200
+ - **Events**: none
201
+
202
+ ## inviteSellerWorkflow
203
+
204
+ Sends an email that invites someone to register a new store. It creates a notification with the template `newSellerInvitation` on the `email` channel, and writes no Seller module records.
205
+
206
+ | Input | Type | Description |
207
+ | --- | --- | --- |
208
+ | `email` | `string` | The prospective seller |
209
+ | `registration_url` | `string` | Optional, the link in the email’s button |
210
+
211
+ - **Hooks**: none
212
+ - **Events**: none
213
+
214
+ ## createMemberInvitesWorkflow
215
+
216
+ Creates team invites with signed tokens. Fails if an email already belongs to the store. Returns `MemberInviteDTO[]`.
217
+
218
+ | Input | Type | Description |
219
+ | --- | --- | --- |
220
+ | `[].seller_id` | `string` | The store |
221
+ | `[].email` | `string` | The invitee |
222
+ | `[].role_id` | `string` | A `SellerRole` value |
223
+
224
+ The input is an array of invites, not an object.
225
+
226
+ - **Hooks**: none
227
+ - **Events**: `member_invite.created` per invite
228
+
229
+ ## resendMemberInviteWorkflow
230
+
231
+ Deletes an invite and creates a replacement with the same email and role, a new token, and a new expiry. Returns `MemberInviteDTO[]`.
232
+
233
+ | Input | Type | Description |
234
+ | --- | --- | --- |
235
+ | `invite_id` | `string` | The invite to replace |
236
+ | `seller_id` | `string` | The store that owns it |
237
+
238
+ - **Hooks**: none
239
+ - **Events**: `member_invite.created`
240
+
241
+ ## deleteMemberInviteWorkflow
242
+
243
+ Deletes an invite.
244
+
245
+ | Input | Type | Description |
246
+ | --- | --- | --- |
247
+ | `invite_id` | `string` | The invite to delete |
248
+
249
+ - **Hooks**: none
250
+ - **Events**: none
251
+
252
+ ## acceptMemberInviteWorkflow
253
+
254
+ Validates an invite token, upserts the member by email, creates the membership with the invite’s role, and deletes the invite. The member becomes owner when the store has no owner yet. Returns `MemberDTO`.
255
+
256
+ | Input | Type | Description |
257
+ | --- | --- | --- |
258
+ | `invite_token` | `string` | The token from the invite |
259
+ | `auth_identity_id` | `string` | The invitee’s auth identity |
260
+ | `member_id` | `string` | Optional; when set, the auth identity isn’t updated |
261
+ | `first_name`, `last_name` | `string` | Optional, set on a new member |
262
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
263
+
264
+ - **Hooks**: `validate` (`{ input, invite }`), `memberInviteAccepted` (`{ member, invite, additional_data }`)
265
+ - **Events**: `member_invite.accepted`
266
+
267
+ ## addSellerMemberWorkflow
268
+
269
+ Adds an existing member to a store. Returns the `SellerMember`.
270
+
271
+ | Input | Type | Description |
272
+ | --- | --- | --- |
273
+ | `seller_id` | `string` | The store |
274
+ | `member_id` | `string` | The existing member |
275
+ | `role_id` | `string` | A `SellerRole` value |
276
+
277
+ - **Hooks**: none
278
+ - **Events**: `seller_member.created`
279
+
280
+ ## updateMemberRoleWorkflow
281
+
282
+ Changes the role on a membership. Fails for the owner membership.
283
+
284
+ | Input | Type | Description |
14
285
  | --- | --- | --- |
15
- | `createSellersWorkflow` | `{ sellers[], additional_data? }` | Create stores with defaults |
16
- | `updateSellersWorkflow` | `{ selector, update }` | Update store fields |
17
- | `deleteSellersWorkflow` | `{ ids[] }` | Delete stores |
18
- | `approveSellerWorkflow` | `{ seller_id, additional_data? }` | `pending_approval` → `open` |
19
- | `suspendSellerWorkflow` | `{ seller_id }` | `open` → `suspended` |
20
- | `unsuspendSellerWorkflow` | `{ seller_id }` | `suspended` → `open` |
21
- | `terminateSellerWorkflow` | `{ seller_id }` | → `terminated` (irreversible) |
286
+ | `seller_member_id` | `string` | The membership id (`selmem_…`) |
287
+ | `role_id` | `string` | A `SellerRole` value |
288
+
289
+ - **Hooks**: none
290
+ - **Events**: `seller_member.updated`
291
+
292
+ ## removeSellerMemberWorkflow
293
+
294
+ Deletes a membership and keeps the `Member` record. Fails for the owner membership.
295
+
296
+ | Input | Type | Description |
297
+ | --- | --- | --- |
298
+ | `seller_member_id` | `string` | The membership id |
299
+ | `seller_id` | `string` | The store, included in the event payload |
300
+
301
+ - **Hooks**: none
302
+ - **Events**: `seller_member.deleted`
303
+
304
+ ## updateMemberWorkflow
22
305
 
23
- ## Member workflows
306
+ Updates the profile of every member that matches `selector`. Returns `MemberDTO[]`.
24
307
 
25
- | Workflow | Input | Purpose |
308
+ | Input | Type | Description |
26
309
  | --- | --- | --- |
27
- | `inviteSellerWorkflow` | `{ email, seller_id }` | Create + send a member invite |
28
- | `acceptMemberInviteWorkflow` | `{ token }` | Accept an invite, link the member |
29
- | `addSellerMemberWorkflow` | `{ seller_id, member }` | Add a member directly |
30
- | `removeSellerMemberWorkflow` | `{ seller_id, member_id }` | Revoke access |
31
- | `updateMemberRoleWorkflow` | `{ id, role_id }` | Change a member's role |
310
+ | `selector` | `Record<string, unknown>` | Filters, such as `{ id: "mem_01JD8Q1234567" }` |
311
+ | `update` | `{ first_name?, last_name?, locale? }` | Profile fields |
312
+ | `additional_data` | `Record<string, unknown>` | Optional, passed to hooks |
32
313
 
33
- To work with records directly instead of through a workflow, see the
34
- [Service reference](/platform/store/reference/service). To run side effects when
35
- a store changes, see the [Event reference](/platform/store/reference/events).
314
+ - **Hooks**: `membersUpdated` (`{ members, additional_data }`)
315
+ - **Events**: none
@@ -35,6 +35,26 @@ A handful of vendor routes are public by design: seller registration (`POST /ven
35
35
 
36
36
  Store routes are public. Customer authentication (session or bearer) is **required** for `/store/order-groups` and **optional** for `/store/offers` and `/store/products`, where it enriches the pricing context when present. Public seller routes only return sellers whose status is `open` and who are not inside a scheduled closure window.
37
37
 
38
+ ### With the client
39
+
40
+ `@mercurjs/client` carries the credential for you. Pass `auth` once and every request resolves it fresh, so a token stored after login is picked up by the next call:
41
+
42
+ ```typescript
43
+ import { createClient, adminAuth, vendorAuth, apiKeyAuth, publishableKeyAuth } from "@mercurjs/client"
44
+
45
+ // inside the admin or vendor panel, or a plugin's dashboard code
46
+ const admin = createClient({ baseUrl, auth: adminAuth() })
47
+ const vendor = createClient({ baseUrl, auth: vendorAuth() })
48
+
49
+ // a server-side integration with a secret API key
50
+ const integration = createClient({ baseUrl, auth: apiKeyAuth(() => process.env.MERCUR_API_KEY) })
51
+
52
+ // a storefront
53
+ const store = createClient({ baseUrl, auth: publishableKeyAuth(() => publishableKey) })
54
+ ```
55
+
56
+ `adminAuth()` and `vendorAuth()` read the same token stores the panels write on login (`adminTokenStore`, `vendorTokenStore`, `vendorSellerStore`), so dashboard extensions share the user's session without knowing a storage key. `createTokenStore(key)` builds your own store, falling back to memory where `localStorage` is unavailable. A `401` clears the bearer store unless you pass `onUnauthorized`.
57
+
38
58
  ## Pagination
39
59
 
40
60
  List endpoints use offset pagination with two query parameters:
@@ -0,0 +1,162 @@
1
+ ---
2
+ title: "Magento 2 marketplace integration"
3
+ sidebarTitle: "Magento 2"
4
+ description: "Turn your Magento 2 or Adobe Commerce store into a multi-vendor marketplace with Mercur. Install the connector, sync seller offers, and split each order per seller."
5
+ ---
6
+
7
+ The Magento 2 connector lets a store you already run sell marketplace offers next to its own catalog. Magento keeps the storefront, cart, checkout, payment capture and your first-party products. Mercur keeps sellers, their offers, the split of one checkout into one order per seller, commission lines and payouts.
8
+
9
+ The integration has two halves:
10
+
11
+ - **`@mercurjs/magento2-connector-plugin`**, a plugin for your Mercur API that adds outbound webhooks, an external payment provider and a few admin routes
12
+ - **`mercurjs/magento2-connector`**, a Composer package of Magento modules that mirrors sellers and offers into Magento and talks to Mercur during checkout
13
+
14
+ <Tip>
15
+ This page is the setup guide. The connector's source, module layout and development workflow live in the [magento2-connector repository](https://github.com/mercurjs/magento2-connector).
16
+ </Tip>
17
+
18
+ ## Quick start
19
+
20
+ <Steps>
21
+ <Step title="Install the plugin in Mercur">
22
+ Add the plugin and register its payment provider in `medusa-config.ts`:
23
+
24
+ ```ts
25
+ module.exports = withMercur({
26
+ plugins: [
27
+ { resolve: "@mercurjs/magento2-connector-plugin", options: {} },
28
+ ],
29
+ modules: [
30
+ {
31
+ resolve: "@medusajs/medusa/payment",
32
+ options: {
33
+ providers: [
34
+ {
35
+ resolve: "@mercurjs/magento2-connector-plugin/providers/payment-external",
36
+ id: "external",
37
+ },
38
+ ],
39
+ },
40
+ },
41
+ ],
42
+ })
43
+ ```
44
+
45
+ Run `medusa db:migrate` afterwards. The provider is registered as `pp_external_external`; it records a payment Magento already captured instead of charging anyone.
46
+
47
+ Then enable it for the region your Magento website sells in: open the region in the Mercur admin and add **pp_external_external** to its payment providers. The shadow cart cannot complete without it.
48
+ </Step>
49
+ <Step title="Install the Magento package">
50
+ In your Magento root. The package is installed from its Git repository until it is published to Packagist, so add the repository first:
51
+
52
+ ```bash
53
+ composer config repositories.mercur vcs https://github.com/mercurjs/magento2-connector
54
+ composer require mercurjs/magento2-connector:dev-main
55
+ bin/magento module:enable Mercur_Core Mercur_Process Mercur_Connector \
56
+ Mercur_OfferIndexer Mercur_Catalog Mercur_Settlement Mercur_Frontend Mercur_GraphQl
57
+ # Only on stores that run Multi-Source Inventory:
58
+ bin/magento module:enable Mercur_Inventory
59
+ bin/magento setup:upgrade
60
+ bin/magento setup:di:compile
61
+ bin/magento cache:flush
62
+ ```
63
+ </Step>
64
+ <Step title="Get API details">
65
+ You need four values from Mercur:
66
+
67
+ - **Admin API key**: create a secret API key under **Settings → API keys**. If your deployment runs a roles module, bind it to a role that holds only the `integrations` permission; without one the key has full admin access, so treat it like an admin password
68
+ - **Publishable API key**: the publishable key of the sales channel the shadow cart is created in
69
+ - **Sales channel ID** and **Region ID**: the channel and the region whose prices the Magento website shows, one region per website
70
+ </Step>
71
+ <Step title="Connect Magento">
72
+ In Magento open **Stores → Configuration → Mercur → Marketplace** and enter the API URL and the four values above. Choose a best offer rule: lowest price, your own stock first, or premium sellers first.
73
+ </Step>
74
+ <Step title="Register the webhook">
75
+ In the Mercur admin open **Settings → Magento → Add endpoint**, enter `https://your_shop_domain/mercur/webhook`, keep every event selected, and copy the signing secret. The connector needs the fulfillment, shipment, delivery, return and refund events to keep orders in step. It is shown once. Paste it into the Magento configuration under **Webhooks → Signing secret**.
76
+ </Step>
77
+ <Step title="Run the first sync">
78
+ Push your taxonomy, then mirror everything:
79
+
80
+ ```bash
81
+ bin/magento mercur:sync taxonomy
82
+ bin/magento mercur:sync full
83
+ ```
84
+
85
+ Cron keeps the mirror current afterwards: sellers every 15 minutes, offers every 5 minutes, published products hourly, a full resync every night. Each run is a process under **Mercur → Processes** in the Magento admin.
86
+ </Step>
87
+ </Steps>
88
+
89
+ ## How a mixed order flows
90
+
91
+ A shopper buys one of your own products and one seller offer in the same checkout and pays once:
92
+
93
+ 1. The product page lists every active seller offer next to your own stock, with its price for that website, any price list strike-through, quantity tiers and an estimated delivery date. Adding an offer marks the cart line as a marketplace line priced by the offer and labels it "Sold by" the seller. The same works through REST and GraphQL with `mercur_offer_id`.
94
+ 2. The cart and the checkout group the marketplace lines by seller. Magento copies them into a shadow Mercur cart, asks Mercur for each seller's shipping options and lets the shopper pick one per seller; the sum is the "Seller shipping" total. Your own carriers only price your own lines, and a cart of seller lines only gets the "Shipped by the sellers" method.
95
+ 3. The shopper pays in Magento. The invoice includes seller shipping.
96
+ 4. After the order is placed, Magento records the capture on the external payment provider and completes the Mercur cart. Mercur answers with an order group, one order per seller, and Magento stores those ids on the order and its lines.
97
+ 5. Sellers fulfill in the vendor panel. Each shipped fulfillment becomes its own Magento shipment with its tracking numbers, so partial and multi-parcel deliveries show up as they happen. Deliveries, returns and cancellations update the line's marketplace status, shown to the shopper in their account and to you in the admin.
98
+ 6. Mercur computes commission lines when the cart completes and pays sellers from the recorded capture.
99
+
100
+ If Mercur is unreachable at step 4, the Magento order still succeeds and the `order_retry` process completes the Mercur side on its next run.
101
+
102
+ ## Refunds
103
+
104
+ | Starts in | What happens |
105
+ | --- | --- |
106
+ | Magento | A credit memo on marketplace lines is reported to Mercur per seller order, with seller shipping split by what each seller charged, so commission lines and payout balances follow |
107
+ | Mercur, a seller or operator refund | Mercur sends `order.refund_requested`; Magento creates an adjustment credit memo and refunds the shopper online when the invoice was captured online |
108
+ | Mercur, a canceled seller order | Magento refunds that seller's lines and shipping |
109
+
110
+ A `refunds` process every 15 minutes picks up any refund whose webhook did not arrive.
111
+
112
+ ## Essential practices
113
+
114
+ ### One region per website
115
+
116
+ Offer prices are read for the region configured on each Magento website, including Mercur price lists. A store with a US and an EU website needs two Mercur regions and two website-scoped values of **Mercur region ID**, and each website's base currency must match its region's currency.
117
+
118
+ ### Set delivery estimates
119
+
120
+ Under **Mercur → Marketplace → Delivery estimates** set the order cut-off time, business days and transit days for each website. A Mercur shipping option can carry its own `transit_days_min` and `transit_days_max` in its data.
121
+
122
+ ### Keep the operator's stock as a candidate
123
+
124
+ Your own product is always one of the ways to buy a SKU. The best offer rule decides whether it wins over a cheaper seller; `operator_first` keeps your stock on top whenever it is in stock.
125
+
126
+ ### Let webhooks drive, keep cron as the floor
127
+
128
+ Offer, seller and product events enqueue the matching delta sync within a minute. The cron schedules exist so the mirror heals after a missed delivery; a full nightly resync removes anything a delta could not see.
129
+
130
+ ## Your products or seller offers
131
+
132
+ | Situation | What happens |
133
+ | --- | --- |
134
+ | A product only you sell | A normal Magento line: your price, your stock, your carriers |
135
+ | A product only sellers sell | Imported from Mercur, as a configurable product when its variant axes are Magento attributes; it is in stock while an offer is available and every line is a marketplace line |
136
+ | A product both you and sellers sell | Same SKU, one buy box; the best offer rule picks the default and the shopper can choose another. When you run out, the product stays buyable from sellers |
137
+
138
+ Each seller has a page at `/seller/{handle}` listing what they sell on your store. In the Magento admin, **Mercur → Sellers** and **Mercur → Offers** show the mirror, orders show each seller order with its status, and the product page lists the offers for that SKU.
139
+
140
+ ## Not supported yet
141
+
142
+ - Buyer and seller messaging, order incidents and seller ratings
143
+ - Documents sellers attach to orders
144
+ - A third-party tax engine for seller lines; Magento taxes them with the product's tax class
145
+ - Mercur promotions; Magento cart rules still apply to seller lines
146
+
147
+ ## Next steps
148
+
149
+ <CardGroup cols={2}>
150
+ <Card title="Connector repository" icon="github" href="https://github.com/mercurjs/magento2-connector">
151
+ Modules, development workflow, and the webhook handler registry.
152
+ </Card>
153
+ <Card title="Offer module" icon="tag" href="/platform/offer/overview">
154
+ How offers carry seller SKU, price, inventory and shipping.
155
+ </Card>
156
+ <Card title="Order Group module" icon="layer-group" href="/platform/order-group/overview">
157
+ How one checkout becomes one order per seller.
158
+ </Card>
159
+ <Card title="Commission module" icon="percent" href="/platform/commission/overview">
160
+ How commission lines are computed at completion.
161
+ </Card>
162
+ </CardGroup>
@@ -23,6 +23,16 @@ interface.
23
23
  </Card>
24
24
  </CardGroup>
25
25
 
26
+ ## Storefront platforms
27
+
28
+ A storefront you already run can sell marketplace offers next to its own catalog. Mercur keeps sellers, offers, split orders, commissions and payouts; the platform keeps checkout and payment.
29
+
30
+ <CardGroup cols={2}>
31
+ <Card title="Magento 2" icon="store" href="/resources/integrations/magento2">
32
+ Set up the Magento 2 connector.
33
+ </Card>
34
+ </CardGroup>
35
+
26
36
  ## Blocks
27
37
 
28
38
  Other integrations ship as installable blocks. You add the block, own its source
@@ -21,7 +21,7 @@ This guide covers both. It walks through setting up Stripe, configuring both pro
21
21
  - A [Stripe account](https://dashboard.stripe.com) with Connect enabled
22
22
  - Stripe Secret API key and Publishable API key
23
23
  - A running Mercur project ([installation guide](/learn/introduction))
24
- - Node.js 20+
24
+ - Node.js 22.22+
25
25
 
26
26
  ## Architecture overview
27
27
 
@@ -54,14 +54,15 @@ A `GET /vendor/sales-summary` endpoint returns the seller's order count. You cal
54
54
  Codegen rewrites the generated `Routes` type that your panel apps already import:
55
55
 
56
56
  ```typescript apps/vendor/src/lib/client.ts
57
- import { createClient, type InferClient } from "@mercurjs/client"
57
+ import { createClient, vendorAuth, type InferClient } from "@mercurjs/client"
58
58
  import type { Routes } from "@acme/api/_generated"
59
59
 
60
60
  declare const __BACKEND_URL__: string
61
61
 
62
62
  export const client: InferClient<Routes> = createClient({
63
63
  baseUrl: __BACKEND_URL__,
64
- fetchOptions: { credentials: "include" },
64
+ fetchOptions: { credentials: "omit" },
65
+ auth: vendorAuth(),
65
66
  })
66
67
  ```
67
68