@mercurjs/docs 2.2.1 → 2.3.0-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/home.mdx +107 -0
- package/content/learn/architecture.mdx +168 -83
- package/content/learn/introduction.mdx +161 -56
- package/content/learn/migration-to-2-0.mdx +187 -0
- package/content/learn/why-mercur.mdx +91 -0
- package/content/platform/attribute/concepts/attribute-types.mdx +59 -0
- package/content/platform/attribute/concepts/global-vs-inline.mdx +50 -0
- package/content/platform/attribute/concepts/variant-axes.mdx +61 -0
- package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +69 -0
- package/content/platform/attribute/guides/create-a-variant-axis.mdx +83 -0
- package/content/platform/attribute/guides/create-an-attribute.mdx +81 -0
- package/content/platform/attribute/overview.mdx +87 -0
- package/content/platform/attribute/reference/data-models.mdx +56 -0
- package/content/platform/attribute/reference/events.mdx +41 -0
- package/content/platform/attribute/reference/links.mdx +45 -0
- package/content/platform/attribute/reference/service.mdx +49 -0
- package/content/platform/attribute/reference/workflows.mdx +45 -0
- package/content/platform/catalog/concepts/master-products.mdx +54 -0
- package/content/platform/catalog/concepts/product-seller-allowlist.mdx +48 -0
- package/content/platform/catalog/concepts/status-lifecycle.mdx +58 -0
- package/content/platform/catalog/concepts/variants-categories-collections.mdx +49 -0
- package/content/platform/catalog/guides/allowlist-stores.mdx +59 -0
- package/content/platform/catalog/guides/create-a-master-product.mdx +70 -0
- package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +79 -0
- package/content/platform/catalog/overview.mdx +90 -0
- package/content/platform/catalog/reference/data-models.mdx +66 -0
- package/content/platform/catalog/reference/events.mdx +41 -0
- package/content/platform/catalog/reference/links.mdx +44 -0
- package/content/platform/catalog/reference/service.mdx +52 -0
- package/content/platform/catalog/reference/workflows.mdx +40 -0
- package/content/platform/commission/concepts/order-commission-lines.mdx +65 -0
- package/content/platform/commission/concepts/rule-matching.mdx +86 -0
- package/content/platform/commission/concepts/rules-and-rates.mdx +84 -0
- package/content/platform/commission/guides/batch-update-rules.mdx +58 -0
- package/content/platform/commission/guides/create-a-rate.mdx +72 -0
- package/content/platform/commission/guides/refresh-order-commission-lines.mdx +55 -0
- package/content/platform/commission/overview.mdx +86 -0
- package/content/platform/commission/reference/data-models.mdx +75 -0
- package/content/platform/commission/reference/events.mdx +58 -0
- package/content/platform/commission/reference/links.mdx +45 -0
- package/content/platform/commission/reference/service.mdx +51 -0
- package/content/platform/commission/reference/workflows.mdx +40 -0
- package/content/platform/offer/concepts/pricing-and-inventory.mdx +72 -0
- package/content/platform/offer/concepts/shipping.mdx +48 -0
- package/content/platform/offer/concepts/what-is-an-offer.mdx +65 -0
- package/content/platform/offer/guides/bulk-create-offers.mdx +84 -0
- package/content/platform/offer/guides/create-an-offer.mdx +83 -0
- package/content/platform/offer/guides/manage-offer-inventory.mdx +53 -0
- package/content/platform/offer/overview.mdx +84 -0
- package/content/platform/offer/reference/data-models.mdx +56 -0
- package/content/platform/offer/reference/events.mdx +39 -0
- package/content/platform/offer/reference/links.mdx +60 -0
- package/content/platform/offer/reference/service.mdx +53 -0
- package/content/platform/offer/reference/workflows.mdx +38 -0
- package/content/platform/order-group/concepts/computed-totals.mdx +59 -0
- package/content/platform/order-group/concepts/order-splitting.mdx +61 -0
- package/content/platform/order-group/concepts/the-order-group.mdx +64 -0
- package/content/platform/order-group/guides/list-order-groups.mdx +67 -0
- package/content/platform/order-group/guides/retrieve-an-order-group.mdx +63 -0
- package/content/platform/order-group/guides/split-a-cart.mdx +58 -0
- package/content/platform/order-group/overview.mdx +83 -0
- package/content/platform/order-group/reference/data-models.mdx +40 -0
- package/content/platform/order-group/reference/events.mdx +37 -0
- package/content/platform/order-group/reference/links.mdx +45 -0
- package/content/platform/order-group/reference/service.mdx +50 -0
- package/content/platform/order-group/reference/workflows.mdx +39 -0
- package/content/platform/payout/concepts/account-lifecycle.mdx +75 -0
- package/content/platform/payout/concepts/accounts-and-onboarding.mdx +70 -0
- package/content/platform/payout/concepts/payout-pipeline.mdx +99 -0
- package/content/platform/payout/guides/create-a-payout-account.mdx +59 -0
- package/content/platform/payout/guides/process-a-provider-webhook.mdx +74 -0
- package/content/platform/payout/guides/start-provider-onboarding.mdx +50 -0
- package/content/platform/payout/overview.mdx +86 -0
- package/content/platform/payout/reference/data-models.mdx +61 -0
- package/content/platform/payout/reference/events.mdx +48 -0
- package/content/platform/payout/reference/links.mdx +36 -0
- package/content/platform/payout/reference/service.mdx +53 -0
- package/content/platform/payout/reference/workflows.mdx +32 -0
- package/content/platform/product-edit/concepts/change-actions.mdx +66 -0
- package/content/platform/product-edit/concepts/change-pipeline.mdx +69 -0
- package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +66 -0
- package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +76 -0
- package/content/platform/product-edit/guides/edit-a-product.mdx +74 -0
- package/content/platform/product-edit/guides/request-a-revision.mdx +54 -0
- package/content/platform/product-edit/overview.mdx +85 -0
- package/content/platform/product-edit/reference/data-models.mdx +65 -0
- package/content/platform/product-edit/reference/events.mdx +47 -0
- package/content/platform/product-edit/reference/links.mdx +39 -0
- package/content/platform/product-edit/reference/service.mdx +43 -0
- package/content/platform/product-edit/reference/workflows.mdx +49 -0
- package/content/platform/review/concepts/product-vs-seller-reviews.mdx +63 -0
- package/content/platform/review/concepts/ratings-and-moderation.mdx +64 -0
- package/content/platform/review/concepts/the-review-model.mdx +56 -0
- package/content/platform/review/guides/compute-aggregate-ratings.mdx +57 -0
- package/content/platform/review/guides/create-a-review.mdx +55 -0
- package/content/platform/review/guides/moderate-a-review.mdx +58 -0
- package/content/platform/review/guides/respond-to-a-review.mdx +61 -0
- package/content/platform/review/overview.mdx +87 -0
- package/content/platform/review/reference/data-models.mdx +36 -0
- package/content/platform/review/reference/events.mdx +61 -0
- package/content/platform/review/reference/links.mdx +43 -0
- package/content/platform/review/reference/service.mdx +54 -0
- package/content/platform/review/reference/workflows.mdx +31 -0
- package/content/platform/store/concepts/lifecycle.mdx +62 -0
- package/content/platform/store/concepts/store-entity.mdx +53 -0
- package/content/platform/store/concepts/team.mdx +50 -0
- package/content/platform/store/guides/create-a-store.mdx +55 -0
- package/content/platform/store/guides/manage-the-team.mdx +55 -0
- package/content/platform/store/guides/moderate-a-store.mdx +59 -0
- package/content/platform/store/overview.mdx +86 -0
- package/content/platform/store/reference/data-models.mdx +89 -0
- package/content/platform/store/reference/events.mdx +43 -0
- package/content/platform/store/reference/links.mdx +71 -0
- package/content/platform/store/reference/service.mdx +51 -0
- package/content/platform/store/reference/workflows.mdx +35 -0
- package/content/references/api/admin/commission-rates/create-commission-rate.mdx +1 -1
- package/content/references/api/admin/commission-rates/list-commission-rates.mdx +2 -2
- package/content/references/api/admin/commission-rates/update-commission-rate.mdx +1 -1
- package/content/references/api/admin/offers/batch-create-offers.mdx +3 -3
- package/content/references/api/admin/order-groups/list-order-groups.mdx +1 -1
- package/content/references/api/admin/product-attributes/create-attribute-value.mdx +2 -2
- package/content/references/api/admin/product-attributes/create-product-attribute.mdx +1 -1
- package/content/references/api/admin/product-attributes/update-product-attribute.mdx +1 -1
- package/content/references/api/admin/product-changes/confirm-product-change.mdx +1 -1
- package/content/references/api/admin/products/batch-product-attributes.mdx +1 -1
- package/content/references/api/admin/products/create-product.mdx +1 -1
- package/content/references/api/admin/products/preview-product.mdx +1 -1
- package/content/references/api/admin.mdx +4 -5
- package/content/references/api/conventions.mdx +9 -7
- package/content/references/api/store/carts/add-line-item.mdx +1 -1
- package/content/references/api/store/offers/list-offers.mdx +1 -1
- package/content/references/api/store/order-groups/list-order-groups.mdx +1 -1
- package/content/references/api/store.mdx +4 -13
- package/content/references/api/vendor/members/accept-member-invite.mdx +1 -1
- package/content/references/api/vendor/offers/batch-create-offers.mdx +4 -0
- package/content/references/api/vendor/offers/batch-offer-inventory-items.mdx +2 -0
- package/content/references/api/vendor/offers/create-offer.mdx +13 -1
- package/content/references/api/vendor/offers/list-offers.mdx +4 -0
- package/content/references/api/vendor/offers/retrieve-offer.mdx +4 -0
- package/content/references/api/vendor/offers/update-offer.mdx +12 -0
- package/content/references/api/vendor/payout-accounts/create-onboarding.mdx +1 -1
- package/content/references/api/vendor/products/batch-product-attributes.mdx +1 -1
- package/content/references/api/vendor/products/create-product-variant.mdx +1 -1
- package/content/references/api/vendor/products/create-product.mdx +1 -1
- package/content/references/api/vendor/products/delete-product.mdx +1 -1
- package/content/references/api/vendor/products/update-product.mdx +1 -1
- package/content/references/api/vendor/sellers/create-seller.mdx +2 -2
- package/content/references/api/vendor/sellers/list-sellers.mdx +1 -1
- package/content/references/api/vendor.mdx +6 -5
- package/content/references/configuration.mdx +16 -33
- package/content/references/overview.mdx +34 -52
- package/content/references/panel-extensions/create-page.mdx +194 -0
- package/content/references/panel-extensions/custom-fields.mdx +256 -0
- package/content/references/panel-extensions/overview.mdx +102 -0
- package/content/references/panel-extensions/widgets.mdx +212 -0
- package/content/resources/ai/mcp.mdx +2 -2
- package/content/resources/ai/overview.mdx +21 -16
- package/content/resources/ai/skills.mdx +67 -0
- package/content/resources/best-practices/api-routes.mdx +55 -43
- package/content/resources/best-practices/custom-fields.mdx +116 -92
- package/content/resources/best-practices/frontend.mdx +62 -50
- package/content/resources/best-practices/module-links.mdx +48 -34
- package/content/resources/best-practices/modules.mdx +53 -27
- package/content/resources/best-practices/overview.mdx +45 -17
- package/content/resources/best-practices/subscribers-and-jobs.mdx +37 -24
- package/content/resources/best-practices/types.mdx +38 -23
- package/content/resources/best-practices/workflows.mdx +33 -21
- package/content/resources/customization/custom-fields.mdx +15 -15
- package/content/resources/customization/extend-a-workflow.mdx +7 -4
- package/content/resources/customization/extending-panels.mdx +55 -52
- package/content/resources/deployment/medusa-cloud.mdx +21 -20
- package/content/resources/deployment/self-host.mdx +123 -0
- package/content/resources/integrations/overview.mdx +38 -0
- package/content/resources/integrations/stripe-connect.mdx +39 -38
- package/content/resources/tutorials/add-a-block.mdx +25 -18
- package/content/resources/tutorials/add-a-widget.mdx +32 -23
- package/content/resources/tutorials/add-order-detail-button.mdx +33 -20
- package/content/resources/tutorials/attributes-and-variant-axes.mdx +28 -27
- package/content/resources/tutorials/build-a-block.mdx +26 -15
- package/content/resources/tutorials/custom-api-route.mdx +32 -20
- package/content/resources/tutorials/custom-panel-page.mdx +21 -12
- package/content/resources/tutorials/customize-navigation.mdx +30 -23
- package/content/resources/tutorials/extend-forms-and-tables.mdx +36 -28
- package/content/resources/tutorials/extend-onboarding.mdx +38 -35
- package/content/resources/tutorials/master-products-and-offers.mdx +28 -23
- package/content/telemetry.mdx +3 -3
- package/content/user-guide/admin/attributes/how-tos/create-an-attribute.mdx +64 -0
- package/content/user-guide/admin/attributes/how-tos/manage-possible-values.mdx +40 -0
- package/content/user-guide/admin/attributes/overview.mdx +22 -0
- package/content/user-guide/admin/commissions/how-tos/create-a-commission-rule.mdx +63 -0
- package/content/user-guide/admin/commissions/how-tos/edit-the-global-commission.mdx +48 -0
- package/content/user-guide/admin/commissions/how-tos/manage-a-commission-rule.mdx +45 -0
- package/content/user-guide/admin/commissions/overview.mdx +25 -0
- package/content/user-guide/admin/overview.mdx +20 -12
- package/content/user-guide/admin/product-requests/how-tos/review-a-new-product.mdx +58 -0
- package/content/user-guide/admin/product-requests/how-tos/review-a-product-edit.mdx +48 -0
- package/content/user-guide/admin/product-requests/overview.mdx +25 -0
- package/content/user-guide/vendor/offers/how-tos/create-an-offer.mdx +59 -0
- package/content/user-guide/vendor/offers/how-tos/update-prices-and-stock.mdx +40 -0
- package/content/user-guide/vendor/offers/overview.mdx +22 -0
- package/content/user-guide/vendor/onboarding.mdx +79 -0
- package/content/user-guide/vendor/orders/how-tos/fulfill-an-order.mdx +49 -0
- package/content/user-guide/vendor/orders/how-tos/mark-an-order-as-delivered.mdx +33 -0
- package/content/user-guide/vendor/orders/how-tos/process-a-return.mdx +42 -0
- package/content/user-guide/vendor/orders/how-tos/refund-an-order.mdx +38 -0
- package/content/user-guide/vendor/orders/how-tos/ship-an-order.mdx +40 -0
- package/content/user-guide/vendor/orders/overview.mdx +31 -0
- package/content/user-guide/vendor/overview.mdx +23 -12
- package/content/user-guide/vendor/products/how-tos/edit-a-product.mdx +44 -0
- package/content/user-guide/vendor/products/how-tos/submit-a-product.mdx +63 -0
- package/content/user-guide/vendor/products/overview.mdx +22 -0
- package/llms.txt +176 -142
- package/package.json +1 -1
- package/content/learn/concepts.mdx +0 -84
- package/content/learn/installation.mdx +0 -117
- package/content/learn/mirakl-alternative.mdx +0 -86
- package/content/migration/from-1-x-to-2-0.mdx +0 -152
- package/content/migration/from-2-0-to-2-1.mdx +0 -105
- package/content/migration/overview.mdx +0 -58
- package/content/references/api/store/search/search.mdx +0 -136
- package/content/references/modules/commission.mdx +0 -106
- package/content/references/modules/custom-fields.mdx +0 -45
- package/content/references/modules/media.mdx +0 -55
- package/content/references/modules/offer.mdx +0 -64
- package/content/references/modules/payout.mdx +0 -121
- package/content/references/modules/product-attribute.mdx +0 -111
- package/content/references/modules/product-edit.mdx +0 -80
- package/content/references/modules/search.mdx +0 -112
- package/content/references/modules/seller.mdx +0 -175
- package/content/references/panel-extension-api.mdx +0 -337
- package/content/references/workflows/cart/add-seller-shipping-method-to-cart.mdx +0 -48
- package/content/references/workflows/cart/complete-cart-with-split-orders.mdx +0 -36
- package/content/references/workflows/cart/list-seller-shipping-options-for-cart.mdx +0 -39
- package/content/references/workflows/cart/update-cart-seller-promotions.mdx +0 -42
- package/content/references/workflows/commission/batch-commission-rules.mdx +0 -49
- package/content/references/workflows/commission/create-commission-rates.mdx +0 -41
- package/content/references/workflows/commission/delete-commission-rates.mdx +0 -34
- package/content/references/workflows/commission/refresh-order-commission-lines.mdx +0 -30
- package/content/references/workflows/commission/update-commission-rates.mdx +0 -35
- package/content/references/workflows/media/set-category-images.mdx +0 -41
- package/content/references/workflows/media/set-collection-images.mdx +0 -41
- package/content/references/workflows/member/accept-member-invite.mdx +0 -33
- package/content/references/workflows/member/add-seller-member.mdx +0 -30
- package/content/references/workflows/member/create-member-invites.mdx +0 -34
- package/content/references/workflows/member/delete-member-invite.mdx +0 -24
- package/content/references/workflows/member/remove-seller-member.mdx +0 -28
- package/content/references/workflows/member/resend-member-invite.mdx +0 -28
- package/content/references/workflows/member/update-member-role.mdx +0 -28
- package/content/references/workflows/member/update-member.mdx +0 -35
- package/content/references/workflows/offer/batch-offer-inventory-items.mdx +0 -62
- package/content/references/workflows/offer/create-offers.mdx +0 -65
- package/content/references/workflows/offer/delete-offers.mdx +0 -35
- package/content/references/workflows/offer/update-offers.mdx +0 -53
- package/content/references/workflows/order/cancel-order-fulfillment.mdx +0 -34
- package/content/references/workflows/order/confirm-claim-request.mdx +0 -25
- package/content/references/workflows/order/confirm-exchange-request.mdx +0 -25
- package/content/references/workflows/order/confirm-order-edit-request.mdx +0 -25
- package/content/references/workflows/order/confirm-return-receive.mdx +0 -25
- package/content/references/workflows/order/create-order-fulfillment.mdx +0 -45
- package/content/references/workflows/order-group/get-order-group-detail.mdx +0 -29
- package/content/references/workflows/order-group/get-order-groups-list.mdx +0 -38
- package/content/references/workflows/overview.mdx +0 -72
- package/content/references/workflows/payout/create-onboarding.mdx +0 -36
- package/content/references/workflows/payout/create-payout-account.mdx +0 -33
- package/content/references/workflows/payout/create-payout.mdx +0 -30
- package/content/references/workflows/payout/process-payout-for-webhook.mdx +0 -34
- package/content/references/workflows/product/confirm-products.mdx +0 -48
- package/content/references/workflows/product/create-products.mdx +0 -63
- package/content/references/workflows/product/link-sellers-to-product-category.mdx +0 -40
- package/content/references/workflows/product/link-sellers-to-product.mdx +0 -40
- package/content/references/workflows/product/reject-product.mdx +0 -48
- package/content/references/workflows/product/request-product-change.mdx +0 -48
- package/content/references/workflows/product-attribute/add-product-attributes-to-product.mdx +0 -49
- package/content/references/workflows/product-attribute/create-and-link-product-attributes-to-product.mdx +0 -46
- package/content/references/workflows/product-attribute/create-product-attribute-values.mdx +0 -43
- package/content/references/workflows/product-attribute/create-product-attributes.mdx +0 -56
- package/content/references/workflows/product-attribute/delete-product-attribute-values.mdx +0 -30
- package/content/references/workflows/product-attribute/delete-product-attributes.mdx +0 -30
- package/content/references/workflows/product-attribute/remove-product-attributes-from-product.mdx +0 -29
- package/content/references/workflows/product-attribute/update-product-attribute-values.mdx +0 -44
- package/content/references/workflows/product-attribute/update-product-attributes-on-product.mdx +0 -41
- package/content/references/workflows/product-attribute/update-product-attributes.mdx +0 -48
- package/content/references/workflows/product-attribute/upsert-product-attribute-values.mdx +0 -43
- package/content/references/workflows/product-edit/auto-confirm-product-change.mdx +0 -39
- package/content/references/workflows/product-edit/cancel-product-change.mdx +0 -49
- package/content/references/workflows/product-edit/confirm-product-change.mdx +0 -57
- package/content/references/workflows/product-edit/create-product-change.mdx +0 -72
- package/content/references/workflows/product-edit/reject-product-change.mdx +0 -54
- package/content/references/workflows/product-edit/stage-product-change.mdx +0 -75
- package/content/references/workflows/seller/approve-seller.mdx +0 -36
- package/content/references/workflows/seller/create-seller-account.mdx +0 -59
- package/content/references/workflows/seller/create-seller-defaults.mdx +0 -22
- package/content/references/workflows/seller/create-sellers.mdx +0 -65
- package/content/references/workflows/seller/delete-seller-professional-details.mdx +0 -37
- package/content/references/workflows/seller/delete-sellers.mdx +0 -24
- package/content/references/workflows/seller/invite-seller.mdx +0 -28
- package/content/references/workflows/seller/suspend-seller.mdx +0 -37
- package/content/references/workflows/seller/terminate-seller.mdx +0 -37
- package/content/references/workflows/seller/unsuspend-seller.mdx +0 -36
- package/content/references/workflows/seller/unterminate-seller.mdx +0 -36
- package/content/references/workflows/seller/update-seller-address.mdx +0 -55
- package/content/references/workflows/seller/update-seller-payment-details.mdx +0 -52
- package/content/references/workflows/seller/update-seller-professional-details.mdx +0 -48
- package/content/references/workflows/seller/update-sellers.mdx +0 -57
- package/content/resources/ai/llms.mdx +0 -74
- package/content/resources/integrations/notifications.mdx +0 -39
- package/content/resources/integrations/search.mdx +0 -122
- package/content/resources/tutorials/configure-commissions.mdx +0 -127
- package/content/resources/tutorials/first-marketplace.mdx +0 -45
- package/content/resources/tutorials/handle-product-requests.mdx +0 -80
- package/content/resources/tutorials/import-export-products.mdx +0 -96
- package/content/resources/tutorials/seller-payouts-stripe.mdx +0 -89
- package/content/resources/tutorials/store-setup-checklist.mdx +0 -214
- package/content/tools/api-client.mdx +0 -155
- package/content/tools/cli.mdx +0 -196
- package/content/tools/dashboard-sdk.mdx +0 -35
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Search"
|
|
3
|
-
description: "Mercur's provider-agnostic search module — zero-infrastructure Orama by default, swappable for Algolia, Meilisearch, or your own provider."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Mercur ships a **Search module** in `@mercurjs/core`, modeled on Medusa's pluggable-provider pattern (like the `file` and `notification` modules). The module owns a stable contract — `index`, `remove`, `search` — and delegates storage to exactly one active **provider**. Out of the box that provider is [Orama](https://docs.orama.com): an in-process, in-memory index that needs zero external infrastructure.
|
|
7
|
-
|
|
8
|
-
<Warning>
|
|
9
|
-
The search module is a release-candidate feature and its surface may still evolve before the stable release.
|
|
10
|
-
</Warning>
|
|
11
|
-
|
|
12
|
-
<Info>
|
|
13
|
-
**Everything above the provider is provider-agnostic.** Subscribers index and remove documents on product, offer, and seller events; the store route calls `search.search(query)`; boot reindexing is event-driven. Swapping Orama for Algolia or Meilisearch means changing one provider registration — no changes to subscribers, the store route, or your storefront.
|
|
14
|
-
</Info>
|
|
15
|
-
|
|
16
|
-
## What gets indexed
|
|
17
|
-
|
|
18
|
-
Products **and offers** are searchable. Offers are indexed as **per-offer documents** — one hit per vendor listing — each carrying the offer's scoped price, so search results price identically to `GET /store/offers`. Index updates are driven by subscribers on product, offer, and seller events; you never call `index()` from application code.
|
|
19
|
-
|
|
20
|
-
## Searching from the storefront
|
|
21
|
-
|
|
22
|
-
The Store API exposes one endpoint:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
curl -X POST "http://localhost:9000/store/search" \
|
|
26
|
-
-H "x-publishable-api-key: <key>" \
|
|
27
|
-
-H "Content-Type: application/json" \
|
|
28
|
-
-d '{
|
|
29
|
-
"q": "t-shirt",
|
|
30
|
-
"limit": 12,
|
|
31
|
-
"offset": 0,
|
|
32
|
-
"region_id": "reg_123"
|
|
33
|
-
}'
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
| Field | Description |
|
|
37
|
-
|-------|-------------|
|
|
38
|
-
| `q` | Search query (defaults to `""` — browse mode) |
|
|
39
|
-
| `limit` / `offset` | Pagination (limit 1–100, default 12) |
|
|
40
|
-
| `region_id`, `country_code`, `province` | Pricing context — the provider projects the matching price onto each hit's `calculated_price` |
|
|
41
|
-
| `filters` | Passed straight to the active provider, which owns its shape |
|
|
42
|
-
|
|
43
|
-
The response returns `hits`, `count`, and `facets`.
|
|
44
|
-
|
|
45
|
-
## The default provider: Orama
|
|
46
|
-
|
|
47
|
-
The bundled `search-orama` provider keeps the index in RAM inside the API process. That means:
|
|
48
|
-
|
|
49
|
-
- **Zero setup** — no accounts, keys, or services. Search works on a fresh project.
|
|
50
|
-
- **Boot reindex** — an in-memory index is empty after a restart, so the module emits a reindex event on application start and a subscriber rebuilds the index from the database.
|
|
51
|
-
|
|
52
|
-
<Note>
|
|
53
|
-
In-memory search fits development and small-to-medium catalogs. For large catalogs or multi-instance deployments, use a persistent provider — the index then lives in the external service and the boot reindex is unnecessary.
|
|
54
|
-
</Note>
|
|
55
|
-
|
|
56
|
-
## Swapping in Algolia or Meilisearch
|
|
57
|
-
|
|
58
|
-
Ready-made provider integrations ship as blocks:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
bunx @mercurjs/cli@latest add algolia
|
|
62
|
-
# or
|
|
63
|
-
bunx @mercurjs/cli@latest add meilisearch
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
| Provider | Hosting | Best for |
|
|
67
|
-
|----------|---------|----------|
|
|
68
|
-
| Orama (default) | In-process | Zero-infra development and smaller catalogs |
|
|
69
|
-
| Algolia | Managed SaaS | Fastest setup, hosted relevance tuning |
|
|
70
|
-
| Meilisearch | Self-hosted or cloud | Full control, open source |
|
|
71
|
-
|
|
72
|
-
Each block installs the provider source and prints the configuration steps (API keys, module options). Follow the block's post-install docs to register the provider and set environment variables.
|
|
73
|
-
|
|
74
|
-
## Writing your own provider
|
|
75
|
-
|
|
76
|
-
A provider extends `AbstractSearchProvider` from `@mercurjs/core` and implements three methods:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
import { AbstractSearchProvider } from "@mercurjs/core/modules/search"
|
|
80
|
-
import { SearchDoc, SearchQueryBase, SearchResults } from "@mercurjs/types"
|
|
81
|
-
|
|
82
|
-
export class MySearchProvider extends AbstractSearchProvider {
|
|
83
|
-
static identifier = "my-search"
|
|
84
|
-
|
|
85
|
-
async index(docs: SearchDoc[]): Promise<void> { /* upsert documents */ }
|
|
86
|
-
async remove(ids: string[]): Promise<void> { /* delete by id */ }
|
|
87
|
-
async search(query: SearchQueryBase): Promise<SearchResults> { /* query + facets */ }
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Because subscribers and the store route only talk to the module contract, your provider slots in without touching anything else. Use the Algolia or Meilisearch block source as a working reference.
|
|
92
|
-
|
|
93
|
-
## Verify
|
|
94
|
-
|
|
95
|
-
1. Start a fresh project and `POST /store/search` with an empty `q` — published products return without any search service configured (that's Orama).
|
|
96
|
-
2. Publish a product and search for its title — it appears without a manual reindex (subscribers indexed it).
|
|
97
|
-
3. Restart the API and search again — results still return (the boot reindex rebuilt the in-memory index).
|
|
98
|
-
|
|
99
|
-
## FAQ
|
|
100
|
-
|
|
101
|
-
<AccordionGroup>
|
|
102
|
-
<Accordion title="Can I run two providers at once, e.g. Orama locally and Algolia in production?">
|
|
103
|
-
Only one provider is active at a time — the module has no multi-provider machinery. But because the provider is chosen by configuration, you can register different providers per environment (default Orama in development, Algolia in production) without touching any other code.
|
|
104
|
-
</Accordion>
|
|
105
|
-
<Accordion title="Do I ever need to trigger a reindex manually?">
|
|
106
|
-
Normally no — subscribers keep the index current, and in-memory providers rebuild on boot. A manual full reindex is only interesting after bulk data changes outside normal flows (e.g. direct DB imports); persistent providers ignore the boot event entirely.
|
|
107
|
-
</Accordion>
|
|
108
|
-
<Accordion title="Why does each offer appear as its own search hit?">
|
|
109
|
-
Because pricing and availability are per offer, not per product. One hit per vendor listing lets results carry the correct `calculated_price` for each seller — the same numbers as `GET /store/offers` — instead of an ambiguous product-level price.
|
|
110
|
-
</Accordion>
|
|
111
|
-
</AccordionGroup>
|
|
112
|
-
|
|
113
|
-
## Next steps
|
|
114
|
-
|
|
115
|
-
<CardGroup cols={2}>
|
|
116
|
-
<Card title="Offers" href="/rc/learn/offers">
|
|
117
|
-
Why offers are indexed per seller with scoped prices.
|
|
118
|
-
</Card>
|
|
119
|
-
<Card title="Add a feature with a block" href="/rc/resources/tutorials/add-a-block">
|
|
120
|
-
How provider blocks are installed and configured.
|
|
121
|
-
</Card>
|
|
122
|
-
</CardGroup>
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Configure commissions"
|
|
3
|
-
description: "Set the global commission, add scoped rules for categories and sellers, and confirm the right rate lands on an order."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Commissions are how your marketplace earns. Mercur matches a **commission rate** to every order line item through rules, with one **global commission** as the catch-all. In this tutorial you'll set up a realistic three-tier configuration and verify which rate wins on a real order.
|
|
7
|
-
|
|
8
|
-
<Info>
|
|
9
|
-
**The most specific rate wins.** Rules combine with AND across dimensions and OR within a dimension, and among matching rates the one scoping the most dimensions applies. You never order rates by priority — specificity is the priority. The full algorithm is in [Commission](/rc/learn/commissions).
|
|
10
|
-
</Info>
|
|
11
|
-
|
|
12
|
-
## What you'll build
|
|
13
|
-
|
|
14
|
-
- A global commission of 15% that also commissions shipping.
|
|
15
|
-
- A 12% rate for the Electronics category.
|
|
16
|
-
- An 8% rate for Electronics sold by one specific premium seller.
|
|
17
|
-
|
|
18
|
-
An electronics order from the premium seller should produce commission lines at 8% — not 12%, not 15%.
|
|
19
|
-
|
|
20
|
-
## Set up the rates
|
|
21
|
-
|
|
22
|
-
<Steps>
|
|
23
|
-
<Step title="Set the global commission">
|
|
24
|
-
Every marketplace needs exactly one default rate — the fallback when nothing more specific matches. Create it with `is_default`:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
curl -X POST http://localhost:9000/admin/commission-rates \
|
|
28
|
-
-H "Authorization: Bearer <admin-token>" \
|
|
29
|
-
-H "Content-Type: application/json" \
|
|
30
|
-
-d '{
|
|
31
|
-
"name": "Global Commission",
|
|
32
|
-
"code": "global",
|
|
33
|
-
"type": "percentage",
|
|
34
|
-
"value": 15,
|
|
35
|
-
"is_default": true,
|
|
36
|
-
"include_shipping": true
|
|
37
|
-
}'
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
<Note>
|
|
41
|
-
`include_shipping` only has an effect on the global commission — shipping methods are always commissioned from the global rate, never from scoped rates. In the Admin Panel this lives on the Global Commission card under **Settings → Commissions**.
|
|
42
|
-
</Note>
|
|
43
|
-
</Step>
|
|
44
|
-
<Step title="Add a category-scoped rate">
|
|
45
|
-
A rate becomes scoped by attaching **rules**. Each rule names a dimension (`reference`) and a value (`reference_id`):
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
curl -X POST http://localhost:9000/admin/commission-rates \
|
|
49
|
-
-H "Authorization: Bearer <admin-token>" \
|
|
50
|
-
-H "Content-Type: application/json" \
|
|
51
|
-
-d '{
|
|
52
|
-
"name": "Electronics Commission",
|
|
53
|
-
"code": "electronics",
|
|
54
|
-
"type": "percentage",
|
|
55
|
-
"value": 12,
|
|
56
|
-
"rules": [
|
|
57
|
-
{ "reference": "product_category", "reference_id": "pcat_electronics" }
|
|
58
|
-
]
|
|
59
|
-
}'
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Available dimensions: `product`, `product_type`, `product_collection`, `product_category`, and `seller`.
|
|
63
|
-
</Step>
|
|
64
|
-
<Step title="Add a two-dimension rate for the premium seller">
|
|
65
|
-
Combining a `seller` rule with a `product_category` rule means *both* must match — this rate applies only to that seller's electronics:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
curl -X POST http://localhost:9000/admin/commission-rates \
|
|
69
|
-
-H "Authorization: Bearer <admin-token>" \
|
|
70
|
-
-H "Content-Type: application/json" \
|
|
71
|
-
-d '{
|
|
72
|
-
"name": "Premium seller electronics",
|
|
73
|
-
"code": "premium-electronics",
|
|
74
|
-
"type": "percentage",
|
|
75
|
-
"value": 8,
|
|
76
|
-
"rules": [
|
|
77
|
-
{ "reference": "seller", "reference_id": "slr_premium" },
|
|
78
|
-
{ "reference": "product_category", "reference_id": "pcat_electronics" }
|
|
79
|
-
]
|
|
80
|
-
}'
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Because it scopes two dimensions, it beats the one-dimension Electronics rate whenever both match — regardless of which rate was created first.
|
|
84
|
-
</Step>
|
|
85
|
-
<Step title="Place a test order">
|
|
86
|
-
Commission lines are calculated when an order is placed — rates are never applied retroactively. Place an order containing an electronics item from the premium seller (via your storefront or the Store API), then inspect the order's commission lines.
|
|
87
|
-
</Step>
|
|
88
|
-
</Steps>
|
|
89
|
-
|
|
90
|
-
## Verify
|
|
91
|
-
|
|
92
|
-
1. List the rates and confirm all three exist and are enabled:
|
|
93
|
-
```bash
|
|
94
|
-
curl http://localhost:9000/admin/commission-rates \
|
|
95
|
-
-H "Authorization: Bearer <admin-token>"
|
|
96
|
-
```
|
|
97
|
-
2. On the placed order, each electronics line item from the premium seller has a commission line with `code: "premium-electronics"` and `rate: 8`.
|
|
98
|
-
3. The order's shipping method has a commission line from the **global** rate (because `include_shipping` is on).
|
|
99
|
-
4. Change a rate now and confirm the existing order's commission lines are untouched — `CommissionLine` records are a permanent audit trail.
|
|
100
|
-
|
|
101
|
-
## FAQ
|
|
102
|
-
|
|
103
|
-
<AccordionGroup>
|
|
104
|
-
<Accordion title="How do I charge a flat fee instead of a percentage?">
|
|
105
|
-
Use `"type": "fixed"` with per-currency `values`: `[{ "currency_code": "usd", "amount": 2 }, { "currency_code": "eur", "amount": 1.8 }]`. The scalar `value` is the fallback for currencies without an entry.
|
|
106
|
-
</Accordion>
|
|
107
|
-
<Accordion title="What happens when two rates tie on specificity?">
|
|
108
|
-
Ties break deterministically to the **oldest rate**. But if you find yourself relying on tie-breaking, prefer making one rate more specific — it reads better in the Admin Panel and survives audits.
|
|
109
|
-
</Accordion>
|
|
110
|
-
<Accordion title="Do rate changes affect existing orders?">
|
|
111
|
-
No. Commission is snapshotted into `CommissionLine` records at order placement. Changing or disabling a rate only affects future orders — the lines on past orders are a permanent audit trail that payouts read from.
|
|
112
|
-
</Accordion>
|
|
113
|
-
<Accordion title="Can a rate match multiple values in one dimension?">
|
|
114
|
-
Yes — rules within the same dimension are OR'd. A rate with two `product_category` rules matches items in either category, and still counts as one dimension for specificity.
|
|
115
|
-
</Accordion>
|
|
116
|
-
</AccordionGroup>
|
|
117
|
-
|
|
118
|
-
## Next steps
|
|
119
|
-
|
|
120
|
-
<CardGroup cols={2}>
|
|
121
|
-
<Card title="Commission" href="/rc/learn/commissions">
|
|
122
|
-
The full matching algorithm, calculation pipeline, and data model.
|
|
123
|
-
</Card>
|
|
124
|
-
<Card title="Set up seller payouts" href="/rc/resources/tutorials/seller-payouts-stripe">
|
|
125
|
-
Where commission is deducted — the settlement side of the marketplace.
|
|
126
|
-
</Card>
|
|
127
|
-
</CardGroup>
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Build your first marketplace"
|
|
3
|
-
description: "Go end-to-end: create a project, approve a seller, list a product, place a split order, and watch a payout settle."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<Note>
|
|
7
|
-
This tutorial is being written. The outline below is the intended structure.
|
|
8
|
-
</Note>
|
|
9
|
-
|
|
10
|
-
<Info>
|
|
11
|
-
**One order, three perspectives.** The same purchase looks different on every surface: the customer sees one checkout, the operator sees an order group with per-seller child orders, and each seller sees only their slice. Keeping those three views straight is the core mental model of a Mercur marketplace — this tutorial walks all three.
|
|
12
|
-
</Info>
|
|
13
|
-
|
|
14
|
-
## What you'll build
|
|
15
|
-
|
|
16
|
-
A working marketplace with one approved seller, one product, and one split order that settles into a payout. Prerequisites listed up front.
|
|
17
|
-
|
|
18
|
-
<Steps>
|
|
19
|
-
<Step title="Create the project">
|
|
20
|
-
Condensed link back to [Installation](/rc/learn/installation).
|
|
21
|
-
</Step>
|
|
22
|
-
<Step title="Approve a seller">
|
|
23
|
-
From the Admin Panel.
|
|
24
|
-
</Step>
|
|
25
|
-
<Step title="List a product">
|
|
26
|
-
From the Vendor Panel.
|
|
27
|
-
</Step>
|
|
28
|
-
<Step title="Place a split order">
|
|
29
|
-
From the storefront or Store API.
|
|
30
|
-
</Step>
|
|
31
|
-
<Step title="See the payout">
|
|
32
|
-
From the Vendor Panel.
|
|
33
|
-
</Step>
|
|
34
|
-
</Steps>
|
|
35
|
-
|
|
36
|
-
## Verify
|
|
37
|
-
|
|
38
|
-
A checklist of what "done" looks like — the observable end state to confirm every step worked.
|
|
39
|
-
|
|
40
|
-
## Next steps
|
|
41
|
-
|
|
42
|
-
<CardGroup cols={2}>
|
|
43
|
-
<Card title="Add a feature with a block" href="/rc/resources/tutorials/add-a-block" />
|
|
44
|
-
<Card title="Configure commissions" href="/rc/resources/tutorials/configure-commissions" />
|
|
45
|
-
</CardGroup>
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Handle product requests"
|
|
3
|
-
description: "Walk a vendor's product submission and a follow-up edit through the operator review pipeline — confirm, decline, or send back."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Because Mercur's catalog is [shared](/rc/learn/products), vendors never mutate products directly. New products and edits arrive as **product changes** — reviewable requests the operator confirms, declines, or sends back for revision. This tutorial plays both roles: the vendor submitting, and the operator reviewing.
|
|
7
|
-
|
|
8
|
-
<Info>
|
|
9
|
-
**Nothing touches the live product while a change is pending.** A `ProductChange` bundles ordered actions (`UPDATE`, `VARIANT_ADD`, `ATTRIBUTE_UPDATE`, …) that are applied only on confirmation. Declining or canceling leaves the product exactly as it was — and confirmed changes are never deleted, so the same records double as the product's audit trail.
|
|
10
|
-
</Info>
|
|
11
|
-
|
|
12
|
-
## What you'll build
|
|
13
|
-
|
|
14
|
-
One complete review cycle: a vendor submits a new product, the operator requests a revision, the vendor resubmits, the operator publishes. Then a smaller edit request on the now-live product.
|
|
15
|
-
|
|
16
|
-
## Review outcomes
|
|
17
|
-
|
|
18
|
-
The review queue on the admin product detail offers three outcomes:
|
|
19
|
-
|
|
20
|
-
| Action | Effect |
|
|
21
|
-
|--------|--------|
|
|
22
|
-
| **Confirm** | The product is published into the shared catalog |
|
|
23
|
-
| **Reject** | Status becomes `rejected`; the product stays out of the catalog |
|
|
24
|
-
| **Request changes** | The submission returns to the vendor with a reason (`requires_action_by` / `requires_action_reason`) |
|
|
25
|
-
|
|
26
|
-
## Run the review cycle
|
|
27
|
-
|
|
28
|
-
<Steps>
|
|
29
|
-
<Step title="Submit a product as the vendor">
|
|
30
|
-
In the Vendor Portal, create a product. Vendor-created products enter the catalog with status **`proposed`** — visible only to their creator, not to other sellers or the storefront.
|
|
31
|
-
|
|
32
|
-
Behind the scenes the platform records a `ProductChange` with a `PRODUCT_ADD` action and `created_by` set to the submitting member. That attribution is what keeps the seller's unpublished submissions in their own product list.
|
|
33
|
-
</Step>
|
|
34
|
-
<Step title="Request changes as the operator">
|
|
35
|
-
In the Admin Panel, open the product and choose **Request changes** with a note — say, "add product dimensions". Use the external note for the vendor-visible message; internal notes stay operator-only.
|
|
36
|
-
</Step>
|
|
37
|
-
<Step title="Revise and resubmit as the vendor">
|
|
38
|
-
Back in the Vendor Portal, the product page shows the revision request and the operator's note. The vendor updates the product and resubmits. As the operator, **Confirm** this time — the product's status flips to `published` and it enters the shared catalog for every eligible seller.
|
|
39
|
-
</Step>
|
|
40
|
-
<Step title="Request an edit on the live product">
|
|
41
|
-
Now that the product is published, edits also flow through review. As the vendor, change the product's description. This creates a new `ProductChange` in `pending` with an `UPDATE` action — the live product is unchanged until the operator confirms. Confirm it and watch the description update.
|
|
42
|
-
</Step>
|
|
43
|
-
</Steps>
|
|
44
|
-
|
|
45
|
-
<Note>
|
|
46
|
-
Any seller may propose changes to any published product — the shared catalog is collaborative. Selling-eligibility restrictions limit who may *sell* a product, not who may *suggest improvements* to it.
|
|
47
|
-
</Note>
|
|
48
|
-
|
|
49
|
-
## Verify
|
|
50
|
-
|
|
51
|
-
1. After step 1, the product is `proposed`: visible in the submitting vendor's list, absent from other vendors' lists and the Store API.
|
|
52
|
-
2. After **Request changes**, the vendor sees the revision note; the change is flagged `requires action`.
|
|
53
|
-
3. After the final **Confirm** in step 3, the product is `published` and appears in the Store API.
|
|
54
|
-
4. During step 4, the storefront still shows the old description while the change is `pending` — and the new one after confirmation.
|
|
55
|
-
5. The product's change history lists every change with who requested it, who reviewed it, and when.
|
|
56
|
-
|
|
57
|
-
## FAQ
|
|
58
|
-
|
|
59
|
-
<AccordionGroup>
|
|
60
|
-
<Accordion title="Do all edits require operator review?">
|
|
61
|
-
No — some low-risk edits are **auto-confirmed**: they still create a change record for the audit trail but apply immediately without waiting. Structural changes (variants, attributes, status) go through review.
|
|
62
|
-
</Accordion>
|
|
63
|
-
<Accordion title="Can the vendor withdraw a pending request?">
|
|
64
|
-
Yes — a pending change can be **canceled** by its requester, recorded with the same audit fields (`canceled_by`, timestamp). Once confirmed or declined, the outcome is final; a new change is needed for further edits.
|
|
65
|
-
</Accordion>
|
|
66
|
-
<Accordion title="What's the difference between rejecting and requesting changes?">
|
|
67
|
-
**Reject** is terminal for a submission — the product is marked `rejected` and stays out of the catalog. **Request changes** keeps the change alive and hands it back to the vendor with a reason; it's the "revise and resubmit" path.
|
|
68
|
-
</Accordion>
|
|
69
|
-
</AccordionGroup>
|
|
70
|
-
|
|
71
|
-
## Next steps
|
|
72
|
-
|
|
73
|
-
<CardGroup cols={2}>
|
|
74
|
-
<Card title="Product Requests & Approvals" href="/rc/learn/product-requests">
|
|
75
|
-
The full ProductChange data model, actions, and lifecycle.
|
|
76
|
-
</Card>
|
|
77
|
-
<Card title="Master products & offers" href="/rc/resources/tutorials/master-products-and-offers">
|
|
78
|
-
What happens after publication — sellers listing against the shared record.
|
|
79
|
-
</Card>
|
|
80
|
-
</CardGroup>
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Import and export products via CSV"
|
|
3
|
-
description: "Install the product-import-export block and give vendors CSV import and export drawers on their product list."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Bulk catalog operations belong to vendors, not the operator — a seller migrating from another platform needs to bring hundreds of listings with them. The `product-import-export` block adds CSV import and export to the Vendor Portal: API routes, workflows built on Medusa's product CSV steps, and drawer UIs wired into the product list.
|
|
7
|
-
|
|
8
|
-
<Info>
|
|
9
|
-
**This block is also a masterclass in Mercur's extension model.** It ships backend workflows and routes into your API package, and it adds Import/Export actions to the vendor products area through the panel extension surface. After installing, read its source; you own every file.
|
|
10
|
-
</Info>
|
|
11
|
-
|
|
12
|
-
## What you'll build
|
|
13
|
-
|
|
14
|
-
A vendor product list with **Import** and **Export** header buttons, a working CSV round-trip, and the block's source code in your project.
|
|
15
|
-
|
|
16
|
-
## Install and wire the block
|
|
17
|
-
|
|
18
|
-
<Steps>
|
|
19
|
-
<Step title="Install the block">
|
|
20
|
-
```bash
|
|
21
|
-
bunx @mercurjs/cli@latest add product-import-export
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The CLI copies the block's files into the directories mapped by your `blocks.json` aliases — workflows and routes into the API package, pages and hooks into the vendor app.
|
|
25
|
-
</Step>
|
|
26
|
-
<Step title="Install its dependencies">
|
|
27
|
-
The block uses Medusa's CSV flows and `multer` for uploads. Install them in the **API workspace**, not the project root:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
cd packages/api
|
|
31
|
-
bun add @medusajs/core-flows multer @types/multer
|
|
32
|
-
```
|
|
33
|
-
</Step>
|
|
34
|
-
<Step title="Register the middleware">
|
|
35
|
-
The import route needs its upload middleware. Add it to your API's `middlewares.ts`:
|
|
36
|
-
|
|
37
|
-
```typescript packages/api/src/api/middlewares.ts
|
|
38
|
-
import { defineMiddlewares } from '@medusajs/medusa'
|
|
39
|
-
import { productImportExportMiddlewares } from './vendor/products/middlewares'
|
|
40
|
-
|
|
41
|
-
export default defineMiddlewares({
|
|
42
|
-
routes: [...productImportExportMiddlewares],
|
|
43
|
-
})
|
|
44
|
-
```
|
|
45
|
-
</Step>
|
|
46
|
-
<Step title="Regenerate types">
|
|
47
|
-
The block added `POST /vendor/products/import` and `GET /vendor/products/export`. Regenerate the route map so the vendor app's typed client knows about them:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
bunx @mercurjs/cli@latest codegen
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
<Note>
|
|
54
|
-
No new modules and no migrations — the block reuses Medusa's built-in product CSV steps, so there's nothing to add to `medusa-config.ts` for this one. Always read a block's post-install output: each block declares its own setup steps.
|
|
55
|
-
</Note>
|
|
56
|
-
</Step>
|
|
57
|
-
<Step title="Run a round-trip">
|
|
58
|
-
Start the project and open the Vendor Portal's **Products** page — the header now shows Import and Export next to Create.
|
|
59
|
-
|
|
60
|
-
1. **Export** — opens the drawer at `/products/export` and downloads the seller's current products as CSV.
|
|
61
|
-
2. Edit the CSV: tweak a title, add a row.
|
|
62
|
-
3. **Import** — the drawer at `/products/import` accepts the file, validates rows, and shows an import summary before applying.
|
|
63
|
-
</Step>
|
|
64
|
-
</Steps>
|
|
65
|
-
|
|
66
|
-
## Verify
|
|
67
|
-
|
|
68
|
-
1. The Products header shows Import and Export buttons; the rest of the page (search, filters, pagination) behaves exactly as before.
|
|
69
|
-
2. The exported CSV contains the seller's products — and only theirs; the workflow scopes to the authenticated seller.
|
|
70
|
-
3. After importing the edited CSV, the changed title appears in the product list.
|
|
71
|
-
4. The block's source lives in your repo (e.g. `packages/api/src/workflows/import-seller-products.ts`, `apps/vendor/src/routes/products/page.tsx`) — run `bunx @mercurjs/cli@latest diff product-import-export` to compare against the registry later.
|
|
72
|
-
|
|
73
|
-
## FAQ
|
|
74
|
-
|
|
75
|
-
<AccordionGroup>
|
|
76
|
-
<Accordion title="Can I customize the CSV columns or validation?">
|
|
77
|
-
Yes — the block is source code in your repo. The import workflow (`import-seller-products.ts`) and its validation step are yours to edit; the drawer UI under `routes/products/import/` includes the CSV template helper you can extend.
|
|
78
|
-
</Accordion>
|
|
79
|
-
<Accordion title="I already customized my /products page — will the block overwrite it?">
|
|
80
|
-
The block ships its own `routes/products/page.tsx`. If you already have one, the CLI asks before overwriting (or use `--overwrite` explicitly). Merge by hand in that case: keep your composition and add the block's Import/Export buttons to your `HeaderActions`.
|
|
81
|
-
</Accordion>
|
|
82
|
-
<Accordion title="Does import respect the product approval flow?">
|
|
83
|
-
Imported products enter through the same vendor create path as manual submissions — so they follow the [product-request pipeline](/rc/resources/tutorials/handle-product-requests) and land as `proposed` for operator review, not as instantly published records.
|
|
84
|
-
</Accordion>
|
|
85
|
-
</AccordionGroup>
|
|
86
|
-
|
|
87
|
-
## Next steps
|
|
88
|
-
|
|
89
|
-
<CardGroup cols={2}>
|
|
90
|
-
<Card title="Add a widget" href="/rc/resources/tutorials/add-a-widget">
|
|
91
|
-
Inject a component at a built-in zone with `defineWidgetConfig`.
|
|
92
|
-
</Card>
|
|
93
|
-
<Card title="Build your own block" href="/rc/resources/tutorials/build-a-block">
|
|
94
|
-
Package a feature like this one and publish it to your own registry.
|
|
95
|
-
</Card>
|
|
96
|
-
</CardGroup>
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Set up seller payouts"
|
|
3
|
-
description: "Take a seller from zero to paid: Stripe Connect onboarding, an order through fulfillment, capture, and the automated payout."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Payouts are the last mile of a marketplace — the marketplace collects the customer's payment, deducts its commission, and transfers the remainder to the seller. In Mercur that pipeline is **fully automated**: once a seller is onboarded and an order is fulfilled, scheduled jobs and subscribers handle capture and transfer without any manual step. This tutorial follows one order through the entire pipeline.
|
|
7
|
-
|
|
8
|
-
<Info>
|
|
9
|
-
**Nothing pays out until the seller's account is `ACTIVE`.** Every stage of the pipeline checks the payout account status. A seller who skips onboarding can sell, but their orders sit uncaptured until the authorization window forces the issue — which is exactly why surfacing onboarding status in the vendor portal matters.
|
|
10
|
-
</Info>
|
|
11
|
-
|
|
12
|
-
## What you'll build
|
|
13
|
-
|
|
14
|
-
A working payout loop: a seller with an active Stripe Connect account, one fulfilled order, a captured payment, and a payout record that settles via webhook.
|
|
15
|
-
|
|
16
|
-
## Prerequisites
|
|
17
|
-
|
|
18
|
-
Stripe Connect must be configured first — provider registration, API keys, and **both** webhooks (payment and payout). Follow the [Stripe Connect integration guide](/rc/resources/integrations/stripe-connect) up to and including "Set up webhooks", then come back here. For local development, keep `stripe listen` forwarding running.
|
|
19
|
-
|
|
20
|
-
## Run the pipeline
|
|
21
|
-
|
|
22
|
-
<Steps>
|
|
23
|
-
<Step title="Onboard the seller">
|
|
24
|
-
In the Vendor Portal, the seller opens **Settings → Payouts** and starts onboarding. Under the hood this creates a `PayoutAccount` (status `PENDING`) and an `Onboarding` record holding the Stripe onboarding link:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
curl -X POST http://localhost:9000/vendor/payout-accounts/<account-id>/onboarding \
|
|
28
|
-
-H "Authorization: Bearer <seller-token>" \
|
|
29
|
-
-H "Content-Type: application/json" \
|
|
30
|
-
-d '{ "context": { "return_url": "http://localhost:7001/settings/payouts" } }'
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
The seller completes Stripe's hosted flow (identity, bank account) — in test mode, Stripe's test data completes it in a minute. When Stripe activates the account, the payout webhook delivers an `account.activated` event and Mercur flips the account to `ACTIVE`. No polling — the webhook is the source of truth.
|
|
34
|
-
</Step>
|
|
35
|
-
<Step title="Place and fulfill an order">
|
|
36
|
-
Place an order for one of the seller's listings, then in the Vendor Portal fulfill it. Fulfillment matters: by default, capture requires the order to reach `fulfilled` status (configurable via the payout module's `requiredFulfillmentStatus` option).
|
|
37
|
-
</Step>
|
|
38
|
-
<Step title="Watch the capture">
|
|
39
|
-
A scheduled job runs every 15 minutes looking for orders that are ready: payment `authorized`, seller `ACTIVE`, fulfillment status met, no payout yet. When the capture deadline approaches it emits `order.capture_requested`, and a subscriber captures the payment.
|
|
40
|
-
|
|
41
|
-
To move faster while testing, wait for the next 15-minute tick after fulfillment.
|
|
42
|
-
|
|
43
|
-
<Warning>
|
|
44
|
-
Payment authorizations expire — 7 days by default (`authorizationWindowMs`). Sellers who don't fulfill within the window (`sellerActionWindowMs`, 72h default) risk the capture buffer kicking in or the authorization expiring entirely. Tune these in the payout module options with your fulfillment SLAs in mind.
|
|
45
|
-
</Warning>
|
|
46
|
-
</Step>
|
|
47
|
-
<Step title="The payout lands">
|
|
48
|
-
Once per day (1 AM UTC) a job scans captured orders without payouts and emits `payout.requested` per order. The `createPayoutWorkflow` then:
|
|
49
|
-
|
|
50
|
-
1. Loads the order with its commission lines.
|
|
51
|
-
2. Calculates `payout_amount = order.total − total_commission`.
|
|
52
|
-
3. Calls Stripe to create the transfer and records a `Payout` (status `PENDING`).
|
|
53
|
-
|
|
54
|
-
Stripe's webhook then walks the payout through `PROCESSING` → `PAID` (or `FAILED`).
|
|
55
|
-
</Step>
|
|
56
|
-
</Steps>
|
|
57
|
-
|
|
58
|
-
## Verify
|
|
59
|
-
|
|
60
|
-
1. **Account**: `GET /vendor/payout-accounts/<id>` returns `status: "ACTIVE"` after onboarding.
|
|
61
|
-
2. **Capture**: after fulfillment plus one job tick, the order's payment shows as captured.
|
|
62
|
-
3. **Payout**: `GET /admin/payouts` lists a payout for the order, with `amount` equal to the order total minus the commission lines from your [commission configuration](/rc/resources/tutorials/configure-commissions).
|
|
63
|
-
4. **Vendor view**: the seller sees the payout and its status in the Vendor Portal's payout history.
|
|
64
|
-
5. **Stripe**: the transfer appears on the connected account in the Stripe test dashboard.
|
|
65
|
-
|
|
66
|
-
## FAQ
|
|
67
|
-
|
|
68
|
-
<AccordionGroup>
|
|
69
|
-
<Accordion title="What if the seller never completes onboarding?">
|
|
70
|
-
Their orders stay uncaptured. The capture job skips orders whose seller isn't `ACTIVE`, and once the authorization window lapses the payment expires (an `order.authorization_expired` event fires). Surface the onboarding status prominently and chase incomplete sellers early.
|
|
71
|
-
</Accordion>
|
|
72
|
-
<Accordion title="Why hasn't a payout appeared even though the order is captured?">
|
|
73
|
-
The payout job runs once per day at 1 AM UTC — a captured order waits for the next daily tick. Also check that no payout already exists for the order and that the seller's account is still `ACTIVE` (a `RESTRICTED` account pauses payouts until the provider clears it).
|
|
74
|
-
</Accordion>
|
|
75
|
-
<Accordion title="What do the payout statuses mean?">
|
|
76
|
-
`PENDING` — transfer initiated; `PROCESSING` — the provider is moving funds; `PAID` — settled; `FAILED` / `CANCELED` — the transfer didn't complete. All transitions after `PENDING` come from provider webhook events, so a stuck status usually means the payout webhook isn't reaching your API.
|
|
77
|
-
</Accordion>
|
|
78
|
-
</AccordionGroup>
|
|
79
|
-
|
|
80
|
-
## Next steps
|
|
81
|
-
|
|
82
|
-
<CardGroup cols={2}>
|
|
83
|
-
<Card title="Payout" href="/rc/learn/payouts">
|
|
84
|
-
The full pipeline reference — statuses, jobs, webhook events, module options.
|
|
85
|
-
</Card>
|
|
86
|
-
<Card title="Stripe Connect" href="/rc/resources/integrations/stripe-connect">
|
|
87
|
-
Provider configuration, transfers vs payouts, refunds, and EU considerations.
|
|
88
|
-
</Card>
|
|
89
|
-
</CardGroup>
|