@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.
- package/content/learn/architecture.mdx +166 -263
- package/content/learn/introduction.mdx +9 -1
- package/content/learn/use-cases.mdx +70 -0
- package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
- package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
- package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
- package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
- package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
- package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
- package/content/platform/attribute/overview.mdx +37 -33
- package/content/platform/attribute/reference/data-models.mdx +53 -38
- package/content/platform/attribute/reference/events.mdx +47 -24
- package/content/platform/attribute/reference/links.mdx +98 -27
- package/content/platform/attribute/reference/service.mdx +71 -32
- package/content/platform/attribute/reference/workflows.mdx +158 -28
- package/content/platform/catalog/concepts/master-products.mdx +39 -37
- package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
- package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
- package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
- package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
- package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
- package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
- package/content/platform/catalog/overview.mdx +39 -35
- package/content/platform/catalog/reference/data-models.mdx +154 -43
- package/content/platform/catalog/reference/events.mdx +41 -25
- package/content/platform/catalog/reference/links.mdx +196 -28
- package/content/platform/catalog/reference/service.mdx +57 -35
- package/content/platform/catalog/reference/workflows.mdx +124 -30
- package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
- package/content/platform/commission/concepts/rule-matching.mdx +53 -63
- package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
- package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
- package/content/platform/commission/guides/create-a-rate.mdx +101 -53
- package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
- package/content/platform/commission/overview.mdx +43 -35
- package/content/platform/commission/reference/data-models.mdx +59 -45
- package/content/platform/commission/reference/events.mdx +28 -34
- package/content/platform/commission/reference/links.mdx +42 -33
- package/content/platform/commission/reference/service.mdx +103 -28
- package/content/platform/commission/reference/workflows.mdx +101 -27
- package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
- package/content/platform/offer/concepts/shipping.mdx +28 -29
- package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
- package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
- package/content/platform/offer/guides/create-an-offer.mdx +112 -60
- package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
- package/content/platform/offer/overview.mdx +39 -32
- package/content/platform/offer/reference/data-models.mdx +77 -47
- package/content/platform/offer/reference/events.mdx +44 -18
- package/content/platform/offer/reference/links.mdx +92 -40
- package/content/platform/offer/reference/service.mdx +66 -31
- package/content/platform/offer/reference/workflows.mdx +146 -37
- package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
- package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
- package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
- package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
- package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
- package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
- package/content/platform/order-group/overview.mdx +42 -32
- package/content/platform/order-group/reference/data-models.mdx +48 -31
- package/content/platform/order-group/reference/events.mdx +29 -17
- package/content/platform/order-group/reference/links.mdx +90 -29
- package/content/platform/order-group/reference/service.mdx +55 -31
- package/content/platform/order-group/reference/workflows.mdx +83 -24
- package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
- package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
- package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
- package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
- package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
- package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
- package/content/platform/payout/overview.mdx +43 -34
- package/content/platform/payout/reference/data-models.mdx +63 -36
- package/content/platform/payout/reference/events.mdx +56 -30
- package/content/platform/payout/reference/links.mdx +52 -22
- package/content/platform/payout/reference/service.mdx +72 -33
- package/content/platform/payout/reference/workflows.mdx +80 -19
- package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
- package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
- package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
- package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
- package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
- package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
- package/content/platform/product-edit/overview.mdx +41 -34
- package/content/platform/product-edit/reference/data-models.mdx +73 -47
- package/content/platform/product-edit/reference/events.mdx +39 -29
- package/content/platform/product-edit/reference/links.mdx +32 -24
- package/content/platform/product-edit/reference/service.mdx +45 -26
- package/content/platform/product-edit/reference/workflows.mdx +173 -31
- package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
- package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
- package/content/platform/review/concepts/the-review-model.mdx +52 -45
- package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
- package/content/platform/review/guides/create-a-review.mdx +109 -39
- package/content/platform/review/guides/moderate-a-review.mdx +83 -37
- package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
- package/content/platform/review/overview.mdx +43 -33
- package/content/platform/review/reference/data-models.mdx +41 -27
- package/content/platform/review/reference/events.mdx +55 -37
- package/content/platform/review/reference/links.mdx +80 -22
- package/content/platform/review/reference/service.mdx +61 -33
- package/content/platform/review/reference/workflows.mdx +80 -24
- package/content/platform/store/concepts/lifecycle.mdx +68 -44
- package/content/platform/store/concepts/store-entity.mdx +45 -27
- package/content/platform/store/concepts/team.mdx +56 -35
- package/content/platform/store/guides/create-a-store.mdx +102 -35
- package/content/platform/store/guides/manage-the-team.mdx +122 -32
- package/content/platform/store/guides/moderate-a-store.mdx +107 -38
- package/content/platform/store/overview.mdx +41 -34
- package/content/platform/store/reference/data-models.mdx +132 -57
- package/content/platform/store/reference/events.mdx +42 -17
- package/content/platform/store/reference/links.mdx +67 -49
- package/content/platform/store/reference/service.mdx +105 -33
- package/content/platform/store/reference/workflows.mdx +304 -24
- package/content/references/api/conventions.mdx +20 -0
- package/content/resources/integrations/magento2.mdx +162 -0
- package/content/resources/integrations/overview.mdx +10 -0
- package/content/resources/integrations/stripe-connect.mdx +1 -1
- package/content/resources/tutorials/custom-api-route.mdx +3 -2
- package/llms.txt +113 -111
- package/package.json +1 -1
|
@@ -1,35 +1,315 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Seller module workflows"
|
|
3
3
|
sidebarTitle: "Workflows"
|
|
4
|
-
description: "
|
|
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
|
|
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
|
-
|
|
9
|
+
```ts
|
|
10
|
+
import { approveSellerWorkflow } from "@mercurjs/core/workflows"
|
|
12
11
|
|
|
13
|
-
|
|
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
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
306
|
+
Updates the profile of every member that matches `selector`. Returns `MemberDTO[]`.
|
|
24
307
|
|
|
25
|
-
|
|
|
308
|
+
| Input | Type | Description |
|
|
26
309
|
| --- | --- | --- |
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
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
|
-
|
|
34
|
-
|
|
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
|
|
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: "
|
|
64
|
+
fetchOptions: { credentials: "omit" },
|
|
65
|
+
auth: vendorAuth(),
|
|
65
66
|
})
|
|
66
67
|
```
|
|
67
68
|
|