@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,86 +1,95 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Payouts"
|
|
3
3
|
sidebarTitle: "Overview"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Connect each seller to a payout provider, onboard them, and transfer their share of an order to their own account."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Use Mercur to
|
|
8
|
-
payment provider handles KYC.
|
|
7
|
+
Use Mercur to connect each seller to a payment provider and send them their share of every order.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
total minus commission.
|
|
14
|
-
carrying KYC, and the domain ships with a pluggable provider interface and a
|
|
15
|
-
**Stripe Connect** implementation out of the box. It also runs a fully automated
|
|
16
|
-
capture-and-transfer pipeline driven by scheduled jobs and provider webhooks.
|
|
9
|
+
A payout is a transfer from the marketplace to one seller, for one order. The Payout module holds 3 records: the seller’s payout account, its onboarding state, and the payouts made to it. Every external call goes through a single payout provider. Stripe Connect ships as a package, and a built-in `system` provider runs when you register none.
|
|
10
|
+
|
|
11
|
+
<img className="block dark:hidden" src="/images/figures/payout-overview-light.svg" alt="A Payouts list in front of a Payout accounts list. Payout #12 for ACME is accented: an order total of € 47.00 minus € 4.70 commission gives a € 42.30 payout, marked Paid. Behind it, ACME's payout account is Active and GLOBEX's is Restricted." />
|
|
12
|
+
<img className="hidden dark:block" src="/images/figures/payout-overview-dark.svg" alt="A Payouts list in front of a Payout accounts list. Payout #12 for ACME is accented: an order total of € 47.00 minus € 4.70 commission gives a € 42.30 payout, marked Paid. Behind it, ACME's payout account is Active and GLOBEX's is Restricted." />
|
|
17
13
|
|
|
18
14
|
<Note>
|
|
19
|
-
|
|
20
|
-
provider through a single interface. Stripe Connect ships by default; any
|
|
21
|
-
other processor is a drop-in implementation of the same `IPayoutProvider`
|
|
22
|
-
contract.
|
|
15
|
+
Resolve the module service with `MercurModules.PAYOUT` from `@mercurjs/types`. Import the payout workflows from `@mercurjs/core/workflows`.
|
|
23
16
|
</Note>
|
|
24
17
|
|
|
25
18
|
## Key features
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
20
|
+
The Payout module covers a seller’s connection to the provider and each transfer made through it:
|
|
21
|
+
|
|
22
|
+
- **One provider interface**: `IPayoutProvider` has 4 methods, and the module loads exactly one implementation
|
|
23
|
+
- **Stripe Connect provider**: `@mercurjs/payout-stripe-connect` creates Express accounts, onboarding links, and transfers
|
|
24
|
+
- **One account per store**: `createPayoutAccountWorkflow` refuses a second account for the same seller
|
|
25
|
+
- **Re-runnable onboarding**: `createOnboardingWorkflow` creates the onboarding record once and updates it after that
|
|
26
|
+
- **Webhook-driven statuses**: provider webhooks move accounts and payouts between statuses through `processPayoutForWebhookWorkflow`
|
|
27
|
+
- **Commission-aware amounts**: `createPayoutWorkflow` pays the order total minus the order’s commission lines
|
|
28
|
+
|
|
29
|
+
## How it works
|
|
30
|
+
|
|
31
|
+
A seller moves from no account to a paid order in 5 steps:
|
|
32
|
+
|
|
33
|
+
1. Run `createPayoutAccountWorkflow` for the seller. The provider creates a connected account.
|
|
34
|
+
2. Run `createOnboardingWorkflow`. The provider returns onboarding data, such as a Stripe onboarding link.
|
|
35
|
+
3. The provider posts webhooks to `/hooks/payout`, and the `payout-webhook` subscriber sets the account to `active`, `restricted`, or `rejected`.
|
|
36
|
+
4. Run `createPayoutWorkflow` with an order id. It computes the seller’s share and asks the provider to transfer it.
|
|
37
|
+
5. Later provider webhooks update the payout’s status.
|
|
38
|
+
|
|
39
|
+
<Warning>
|
|
40
|
+
Mercur doesn’t trigger step 4 for you. No scheduled job or subscriber in `@mercurjs/core` captures payments or runs `createPayoutWorkflow`. Call it from your own job, subscriber, or route. See [The payout pipeline](/platform/payout/concepts/payout-pipeline).
|
|
41
|
+
</Warning>
|
|
33
42
|
|
|
34
43
|
## Get started
|
|
35
44
|
|
|
36
|
-
Learn how
|
|
45
|
+
Learn how accounts, onboarding, and transfers fit together.
|
|
37
46
|
|
|
38
47
|
<CardGroup cols={2}>
|
|
39
48
|
<Card title="Accounts & onboarding" icon="id-card" href="/platform/payout/concepts/accounts-and-onboarding">
|
|
40
|
-
The payout account, its onboarding record, and provider data.
|
|
49
|
+
The payout account, its onboarding record, and the provider data they carry.
|
|
41
50
|
</Card>
|
|
42
51
|
<Card title="Account lifecycle" icon="arrows-rotate" href="/platform/payout/concepts/account-lifecycle">
|
|
43
|
-
|
|
52
|
+
Account and payout statuses, and the webhooks that change them.
|
|
44
53
|
</Card>
|
|
45
54
|
<Card title="The payout pipeline" icon="arrows-turn-right" href="/platform/payout/concepts/payout-pipeline">
|
|
46
|
-
|
|
55
|
+
What ships, what you wire yourself, and the provider interface.
|
|
47
56
|
</Card>
|
|
48
57
|
</CardGroup>
|
|
49
58
|
|
|
50
59
|
## Examples
|
|
51
60
|
|
|
52
|
-
Build against
|
|
61
|
+
Build against payouts in your own server code.
|
|
53
62
|
|
|
54
63
|
<CardGroup cols={2}>
|
|
55
64
|
<Card title="Create a payout account" icon="plus" href="/platform/payout/guides/create-a-payout-account">
|
|
56
65
|
Run `createPayoutAccountWorkflow` for a seller.
|
|
57
66
|
</Card>
|
|
58
67
|
<Card title="Start onboarding" icon="link" href="/platform/payout/guides/start-provider-onboarding">
|
|
59
|
-
|
|
68
|
+
Create a provider onboarding link with `createOnboardingWorkflow`.
|
|
60
69
|
</Card>
|
|
61
70
|
<Card title="Process a webhook" icon="bell" href="/platform/payout/guides/process-a-provider-webhook">
|
|
62
|
-
Turn a provider webhook into account and payout status
|
|
71
|
+
Turn a provider webhook into account and payout status changes.
|
|
63
72
|
</Card>
|
|
64
73
|
</CardGroup>
|
|
65
74
|
|
|
66
75
|
## Resources
|
|
67
76
|
|
|
68
|
-
|
|
77
|
+
The data models, links, workflows, service methods, and events behind payouts.
|
|
69
78
|
|
|
70
79
|
<CardGroup cols={2}>
|
|
71
80
|
<Card title="Data models" icon="table" href="/platform/payout/reference/data-models">
|
|
72
|
-
|
|
81
|
+
`PayoutAccount`, `Onboarding`, and `Payout`, with every field.
|
|
73
82
|
</Card>
|
|
74
83
|
<Card title="Links" icon="link" href="/platform/payout/reference/links">
|
|
75
|
-
How
|
|
84
|
+
How payout records link to sellers and orders.
|
|
76
85
|
</Card>
|
|
77
86
|
<Card title="Workflows" icon="diagram-project" href="/platform/payout/reference/workflows">
|
|
78
|
-
|
|
87
|
+
The 4 payout workflows, their steps, and their hooks.
|
|
79
88
|
</Card>
|
|
80
89
|
<Card title="Service" icon="gear" href="/platform/payout/reference/service">
|
|
81
|
-
|
|
90
|
+
Generated and provider-backed methods on the module service.
|
|
82
91
|
</Card>
|
|
83
92
|
<Card title="Events" icon="bell" href="/platform/payout/reference/events">
|
|
84
|
-
|
|
93
|
+
The webhook event, the data-model events, and the reserved event names.
|
|
85
94
|
</Card>
|
|
86
95
|
</CardGroup>
|
|
@@ -1,61 +1,88 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Payout data models"
|
|
3
3
|
sidebarTitle: "Data models"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Every field of PayoutAccount, Onboarding, and Payout, plus the PayoutAccountStatus and PayoutStatus enums."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Payout
|
|
8
|
-
data models and their fields. For the full module overview, see the
|
|
9
|
-
[Payout overview](/platform/payout/overview).
|
|
7
|
+
The Payout module owns 3 data models: `PayoutAccount`, `Onboarding`, and `Payout`. They’re defined in `packages/core/src/modules/payout/models`, and the module service is registered as `MercurModules.PAYOUT`. Every model also gets Medusa’s `created_at`, `updated_at`, and `deleted_at` columns.
|
|
10
8
|
|
|
11
9
|
## PayoutAccount
|
|
12
10
|
|
|
13
|
-
Table `payout_account`, id prefix `pacc`.
|
|
14
|
-
provider. This is the record funds are transferred to.
|
|
11
|
+
A seller’s connection to the payout provider. Table `payout_account`, id prefix `pacc`.
|
|
15
12
|
|
|
16
|
-
| Field | Type |
|
|
13
|
+
| Field | Type | Description |
|
|
17
14
|
| --- | --- | --- |
|
|
18
|
-
| `id` | text | Primary key |
|
|
19
|
-
| `status` | enum | `PayoutAccountStatus`, default `pending` |
|
|
20
|
-
| `data` | json | Provider
|
|
21
|
-
| `context` | json |
|
|
15
|
+
| `id` | `text` | Primary key, such as `pacc_01JD8Q1234567` |
|
|
16
|
+
| `status` | `enum` | `PayoutAccountStatus`, default `pending` |
|
|
17
|
+
| `data` | `json` | Provider account data, default `{}` |
|
|
18
|
+
| `context` | `json`, nullable | Provider context passed at creation |
|
|
22
19
|
|
|
23
|
-
Relations:
|
|
20
|
+
Relations:
|
|
21
|
+
|
|
22
|
+
- **`onboarding`**: `hasOne` `Onboarding`, nullable, mapped by `account`
|
|
23
|
+
- **`payouts`**: `hasMany` `Payout`, mapped by `account`
|
|
24
|
+
|
|
25
|
+
The seller is reached through the `seller_payout_account` link, not a column. See [Links](/platform/payout/reference/links).
|
|
24
26
|
|
|
25
27
|
## Onboarding
|
|
26
28
|
|
|
27
|
-
Table `onboarding`, id prefix `onb`.
|
|
28
|
-
(for Stripe Connect, the onboarding link).
|
|
29
|
+
The provider’s onboarding state for one payout account. Table `onboarding`, id prefix `onb`.
|
|
29
30
|
|
|
30
|
-
| Field | Type |
|
|
31
|
+
| Field | Type | Description |
|
|
31
32
|
| --- | --- | --- |
|
|
32
|
-
| `id` | text | Primary key |
|
|
33
|
-
| `data` | json |
|
|
34
|
-
| `context` | json |
|
|
35
|
-
| `account_id` | text |
|
|
33
|
+
| `id` | `text` | Primary key, such as `onb_01JD8Q1234567` |
|
|
34
|
+
| `data` | `json`, nullable | Provider onboarding data, such as a Stripe account link |
|
|
35
|
+
| `context` | `json`, nullable | Provider context from the last onboarding call |
|
|
36
|
+
| `account_id` | `text` | Foreign key to `PayoutAccount` |
|
|
37
|
+
|
|
38
|
+
Relations:
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
`Onboarding` is one-to-one with `PayoutAccount`. Re-running the onboarding
|
|
39
|
-
workflow updates the existing record rather than creating a second one.
|
|
40
|
-
</Note>
|
|
40
|
+
- **`account`**: `belongsTo` `PayoutAccount`, mapped by `onboarding`
|
|
41
41
|
|
|
42
42
|
## Payout
|
|
43
43
|
|
|
44
|
-
Table `payout`, id prefix `pout`.
|
|
45
|
-
one order.
|
|
44
|
+
One transfer to a seller’s payout account. Table `payout`, id prefix `pout`.
|
|
46
45
|
|
|
47
|
-
| Field | Type |
|
|
46
|
+
| Field | Type | Description |
|
|
48
47
|
| --- | --- | --- |
|
|
49
|
-
| `id` | text | Primary key |
|
|
50
|
-
| `display_id` |
|
|
51
|
-
| `currency_code` | text |
|
|
52
|
-
| `amount` | bigNumber |
|
|
53
|
-
| `data` | json |
|
|
54
|
-
| `status` | enum | `PayoutStatus`, default `pending` |
|
|
55
|
-
| `account_id` | text |
|
|
48
|
+
| `id` | `text` | Primary key, such as `pout_01JD8Q1234567` |
|
|
49
|
+
| `display_id` | `autoincrement` | Human-readable sequence number |
|
|
50
|
+
| `currency_code` | `text` | Currency of the transfer |
|
|
51
|
+
| `amount` | `bigNumber` | Amount sent to the seller |
|
|
52
|
+
| `data` | `json`, nullable | Provider transfer data, such as a Stripe transfer |
|
|
53
|
+
| `status` | `enum` | `PayoutStatus`, default `pending` |
|
|
54
|
+
| `account_id` | `text` | Foreign key to `PayoutAccount` |
|
|
55
|
+
|
|
56
|
+
Relations:
|
|
57
|
+
|
|
58
|
+
- **`account`**: `belongsTo` `PayoutAccount`, mapped by `payouts`
|
|
59
|
+
|
|
60
|
+
Indexes, both limited to rows where `deleted_at IS NULL`:
|
|
61
|
+
|
|
62
|
+
- **`IDX_payout_account_id_created_at`**: on `account_id`, `created_at`
|
|
63
|
+
- **`IDX_payout_status_created_at`**: on `status`, `created_at`
|
|
64
|
+
|
|
65
|
+
`createPayoutWorkflow` sets `amount` to the order total minus the order’s commission lines. The model itself doesn’t store an order id. The order travels to the provider as the idempotency key, and Stripe Connect stores it as the transfer’s `transfer_group` in `data`.
|
|
56
66
|
|
|
57
67
|
## Enums
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
Both enums are exported from `@mercurjs/types`.
|
|
70
|
+
|
|
71
|
+
`PayoutAccountStatus`:
|
|
72
|
+
|
|
73
|
+
| Member | Value |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `PENDING` | `pending` |
|
|
76
|
+
| `ACTIVE` | `active` |
|
|
77
|
+
| `RESTRICTED` | `restricted` |
|
|
78
|
+
| `REJECTED` | `rejected` |
|
|
79
|
+
|
|
80
|
+
`PayoutStatus`:
|
|
60
81
|
|
|
61
|
-
|
|
82
|
+
| Member | Value |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `PENDING` | `pending` |
|
|
85
|
+
| `PROCESSING` | `processing` |
|
|
86
|
+
| `PAID` | `paid` |
|
|
87
|
+
| `FAILED` | `failed` |
|
|
88
|
+
| `CANCELED` | `canceled` |
|
|
@@ -1,48 +1,74 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Payout events"
|
|
3
3
|
sidebarTitle: "Events"
|
|
4
|
-
description: "
|
|
4
|
+
description: "The payout webhook event, the data-model events the Payout module emits, and the reserved PayoutEvents names that nothing emits yet."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Payout
|
|
8
|
-
react to them to capture payments and transfer funds. Subscribe to these events
|
|
9
|
-
to run your own side effects, such as notifications, ledger syncing, or follow-up
|
|
10
|
-
workflows, instead of polling.
|
|
7
|
+
The Payout module has one event of its own, `payout.webhook_received`, which carries provider webhooks to the shipped subscriber. Medusa also emits a created, updated, or deleted event whenever a payout record changes. Subscribe to those for side effects such as seller notifications or ledger syncs.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
## Webhook event
|
|
10
|
+
|
|
11
|
+
The `POST /hooks/payout` route emits this event with a 5000 ms delay and 3 attempts.
|
|
12
|
+
|
|
13
|
+
| Event | Emitted when | Payload |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `payout.webhook_received` | The provider posts to `/hooks/payout` | `{ data, rawData, headers }` |
|
|
16
|
+
|
|
17
|
+
`data` is the parsed body, `rawData` is the raw body, and `headers` are the request headers. The `payout-webhook` subscriber, with subscriber id `payout-webhook-handler`, handles it and runs `processPayoutForWebhookWorkflow`. The event bus serializes `rawData` as a buffer object, and the subscriber turns it back into a `Buffer` before signature checks.
|
|
18
|
+
|
|
19
|
+
## Data-model events
|
|
20
|
+
|
|
21
|
+
`PayoutModuleService` extends `MedusaService`, so Medusa emits an event for each row it creates, updates, or deletes. The name is the module name, the kebab-case model name, and the action. The payload is `{ id }`.
|
|
22
|
+
|
|
23
|
+
| Event | Emitted when |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `payout.payout-account.created` | `createPayoutAccount` inserts an account |
|
|
26
|
+
| `payout.payout-account.updated` | The provider response is stored, or a webhook changes the status |
|
|
27
|
+
| `payout.payout-account.deleted` | The provider call fails and the new account is removed |
|
|
28
|
+
| `payout.onboarding.created` | `createOnboarding` runs for the first time on an account |
|
|
29
|
+
| `payout.onboarding.updated` | `createOnboarding` runs again on the same account |
|
|
30
|
+
| `payout.payout.created` | `createPayouts` inserts a `pending` payout |
|
|
31
|
+
| `payout.payout.updated` | The provider response is stored, or a webhook changes the status |
|
|
32
|
+
| `payout.payout.deleted` | The provider call fails and the new payout is removed |
|
|
33
|
+
|
|
34
|
+
An `updated` event doesn’t say which field changed. Retrieve the record in your subscriber and read its `status`.
|
|
35
|
+
|
|
36
|
+
```ts title="src/subscribers/payout-account-updated.ts"
|
|
13
37
|
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
|
|
38
|
+
import { MercurModules, PayoutAccountStatus } from "@mercurjs/types"
|
|
14
39
|
|
|
15
|
-
export default async function
|
|
40
|
+
export default async function payoutAccountUpdated({
|
|
16
41
|
event,
|
|
17
42
|
container,
|
|
18
|
-
}: SubscriberArgs<{
|
|
19
|
-
const
|
|
20
|
-
|
|
43
|
+
}: SubscriberArgs<{ id: string }>) {
|
|
44
|
+
const payoutService = container.resolve(MercurModules.PAYOUT)
|
|
45
|
+
const account = await payoutService.retrievePayoutAccount(event.data.id)
|
|
46
|
+
|
|
47
|
+
if (account.status === PayoutAccountStatus.RESTRICTED) {
|
|
48
|
+
const logger = container.resolve("logger")
|
|
49
|
+
logger.warn(`Payout account ${account.id} is restricted`)
|
|
50
|
+
}
|
|
21
51
|
}
|
|
22
52
|
|
|
23
53
|
export const config: SubscriberConfig = {
|
|
24
|
-
event: "payout.
|
|
54
|
+
event: "payout.payout-account.updated",
|
|
25
55
|
}
|
|
26
56
|
```
|
|
27
57
|
|
|
28
|
-
|
|
58
|
+
This subscriber logs a warning each time an account lands in `restricted`, which is where you’d send the seller a reminder to finish onboarding.
|
|
29
59
|
|
|
30
|
-
|
|
31
|
-
| --- | --- | --- |
|
|
32
|
-
| `order.capture_requested` | Capture check finds an order ready to capture | The payment-capture subscriber runs `capturePaymentWorkflow` |
|
|
33
|
-
| `order.authorization_expired` | Capture check finds an authorization that already expired | Order is flagged so it isn't retried |
|
|
34
|
-
| `payout.requested` | Daily job finds a captured order not yet paid out | The transfer subscriber runs `createPayoutWorkflow` |
|
|
60
|
+
## Reserved event names
|
|
35
61
|
|
|
36
|
-
|
|
62
|
+
`@mercurjs/types` exports a `PayoutEvents` enum. Nothing in `@mercurjs/core` emits these events or subscribes to them, and the enum carries a TODO to move them to order events.
|
|
37
63
|
|
|
38
|
-
|
|
|
39
|
-
| --- | --- |
|
|
40
|
-
| `
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
64
|
+
| Member | Name |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `OrderCaptureRequested` | `order.capture_requested` |
|
|
67
|
+
| `OrderAuthorizationExpired` | `order.authorization_expired` |
|
|
68
|
+
| `PayoutRequested` | `payout.requested` |
|
|
69
|
+
|
|
70
|
+
You can emit them from your own payout trigger and subscribe to them in your project. See [The payout pipeline](/platform/payout/concepts/payout-pipeline).
|
|
71
|
+
|
|
72
|
+
## Workflow hook
|
|
73
|
+
|
|
74
|
+
`createPayoutWorkflow` exposes a `payoutCreated` hook with `{ order_id, payout_id }`. Use it instead of `payout.payout.created` when you need the order id, because the data-model event carries only the payout id.
|
|
@@ -1,36 +1,66 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Payout module links"
|
|
3
3
|
sidebarTitle: "Links"
|
|
4
|
-
description: "
|
|
4
|
+
description: "The 3 module links that connect payout accounts and payouts to sellers and orders."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
The Payout module never references other modules directly. 3 module links in `packages/core/src/links` connect its records to sellers and orders. Read across them with `query.graph`, and query a link’s own table by its entry name.
|
|
8
|
+
|
|
9
|
+
| Link | Entry name | Cardinality | Created by |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| Seller ↔ payout account | `seller_payout_account` | One to one | `createPayoutAccountWorkflow` |
|
|
12
|
+
| Payout ↔ seller | `payout_seller` | Many payouts to one seller | `createPayoutWorkflow` |
|
|
13
|
+
| Order ↔ payout | `order_payout` | One order to many payouts | Nothing in core |
|
|
14
|
+
|
|
15
|
+
## Seller and payout account
|
|
16
|
+
|
|
17
|
+
Defined in `seller-payout-account-link.ts` between `SellerModule.linkable.seller` and `PayoutModule.linkable.payoutAccount`. Neither side is a list, so a seller has one payout account and an account belongs to one seller. `validateSellerPayoutAccountStep` enforces the one-account rule before a new link is created.
|
|
11
18
|
|
|
12
19
|
```ts
|
|
13
|
-
const { data:
|
|
20
|
+
const { data: [seller] } = await query.graph({
|
|
14
21
|
entity: "seller",
|
|
15
|
-
fields: ["id", "name", "payout_account
|
|
22
|
+
fields: ["id", "name", "payout_account.id", "payout_account.status"],
|
|
23
|
+
filters: { id: "sel_01JD8Q1234567" },
|
|
16
24
|
})
|
|
17
25
|
```
|
|
18
26
|
|
|
19
|
-
##
|
|
27
|
+
## Payout and seller
|
|
28
|
+
|
|
29
|
+
Defined in `payout-seller-link.ts` between `PayoutModule.linkable.payout`, marked `isList: true`, and `SellerModule.linkable.seller`. A seller has many payouts, and each payout has one seller. `createPayoutWorkflow` creates this link right after the payout.
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
```ts
|
|
32
|
+
const { data: payouts } = await query.graph({
|
|
33
|
+
entity: "payout",
|
|
34
|
+
fields: ["id", "amount", "status", "seller.id", "seller.name"],
|
|
35
|
+
filters: { status: "paid" },
|
|
36
|
+
})
|
|
37
|
+
```
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
The Vendor API scopes payouts by querying the link table directly, with `entity: "payout_seller"` and filters on `seller_id` and `payout_id`.
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
## Order and payout
|
|
42
|
+
|
|
43
|
+
Defined in `order-payout-link.ts` between Medusa’s `OrderModule.linkable.order` and `PayoutModule.linkable.payout`, marked `isList: true`. An order can have many payouts.
|
|
44
|
+
|
|
45
|
+
<Warning>
|
|
46
|
+
No workflow in core creates `order_payout` rows, so `order.payouts` is empty by default. To use this link, create it in the `payoutCreated` hook of `createPayoutWorkflow`, which receives `order_id` and `payout_id`.
|
|
47
|
+
</Warning>
|
|
48
|
+
|
|
49
|
+
```ts title="src/workflows/hooks/link-payout-to-order.ts"
|
|
50
|
+
import { createPayoutWorkflow } from "@mercurjs/core/workflows"
|
|
51
|
+
import { ContainerRegistrationKeys, Modules } from "@medusajs/framework/utils"
|
|
52
|
+
import { MercurModules } from "@mercurjs/types"
|
|
53
|
+
|
|
54
|
+
createPayoutWorkflow.hooks.payoutCreated(
|
|
55
|
+
async ({ order_id, payout_id }, { container }) => {
|
|
56
|
+
const link = container.resolve(ContainerRegistrationKeys.LINK)
|
|
57
|
+
|
|
58
|
+
await link.create({
|
|
59
|
+
[Modules.ORDER]: { order_id },
|
|
60
|
+
[MercurModules.PAYOUT]: { payout_id },
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
```
|
|
31
65
|
|
|
32
|
-
|
|
33
|
-
A payout is linked to both the order it settles and the seller it pays. The
|
|
34
|
-
account link is one-to-one, while the seller-payouts and order-payouts links
|
|
35
|
-
are lists.
|
|
36
|
-
</Note>
|
|
66
|
+
Once the hook runs, read an order’s payouts with `fields: ["id", "payouts.id", "payouts.status"]` on the `order` entity.
|
|
@@ -1,53 +1,92 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Payout module service"
|
|
3
3
|
sidebarTitle: "Service"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Resolve the Payout module service, and use its generated data methods and its provider-backed methods."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
`PayoutModuleService` reads and writes payout records, and it’s the only code that calls the payout provider. Resolve it from the container in subscribers, jobs, steps, and routes. Prefer the [workflows](/platform/payout/reference/workflows) when you also need links or a rollback.
|
|
8
|
+
|
|
9
|
+
## Resolve the service
|
|
10
|
+
|
|
11
|
+
The service is registered under `MercurModules.PAYOUT`, whose value is `"payout"`:
|
|
10
12
|
|
|
11
13
|
```ts
|
|
12
14
|
import { MercurModules } from "@mercurjs/types"
|
|
13
15
|
|
|
14
|
-
const
|
|
16
|
+
const payoutService = container.resolve(MercurModules.PAYOUT)
|
|
15
17
|
|
|
16
|
-
const [payouts, count] = await
|
|
17
|
-
status: "paid",
|
|
18
|
-
}
|
|
18
|
+
const [payouts, count] = await payoutService.listAndCountPayouts(
|
|
19
|
+
{ status: "paid" },
|
|
20
|
+
{ take: 20, order: { created_at: "DESC" } }
|
|
21
|
+
)
|
|
19
22
|
```
|
|
20
23
|
|
|
21
24
|
## Generated methods
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
The service extends `MedusaService({ Onboarding, Payout, PayoutAccount })`, so each model gets Medusa’s standard methods:
|
|
24
27
|
|
|
25
|
-
|
|
|
28
|
+
| Model | Methods |
|
|
26
29
|
| --- | --- |
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
| `PayoutAccount` | `retrievePayoutAccount`, `listPayoutAccounts`, `listAndCountPayoutAccounts`, `createPayoutAccounts`, `updatePayoutAccounts`, `deletePayoutAccounts`, `softDeletePayoutAccounts`, `restorePayoutAccounts` |
|
|
31
|
+
| `Onboarding` | `retrieveOnboarding`, `listOnboardings`, `listAndCountOnboardings`, `createOnboardings`, `updateOnboardings`, `deleteOnboardings`, `softDeleteOnboardings`, `restoreOnboardings` |
|
|
32
|
+
| `Payout` | `retrievePayout`, `listPayouts`, `listAndCountPayouts`, `updatePayouts`, `deletePayouts`, `softDeletePayouts`, `restorePayouts` |
|
|
33
|
+
|
|
34
|
+
`createPayouts` isn’t in the `Payout` row because the service overrides it. The generated create and update methods write rows only. They never call the provider.
|
|
35
|
+
|
|
36
|
+
## Provider-backed methods
|
|
37
|
+
|
|
38
|
+
These methods call the payout provider as part of the write.
|
|
39
|
+
|
|
40
|
+
### createPayoutAccount
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
createPayoutAccount(input: CreatePayoutAccountDTO): Promise<PayoutAccountDTO>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Creates the row, calls the provider with `data.account_id` set to the new id, then stores the provider’s `data` and `status`. Deletes the row if the provider throws. `input` takes optional `data` and `context`.
|
|
47
|
+
|
|
48
|
+
### createOnboarding
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
createOnboarding(input: CreateOnboardingDTO): Promise<OnboardingDTO>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Calls the provider with the account’s `data` merged with `input.data`, then creates the onboarding record or updates the existing one. `input` takes `account_id` and optional `data` and `context`.
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
`retrievePayoutAccount`, `listPayoutAccounts`, `updateOnboardings`).
|
|
56
|
+
### createPayouts
|
|
35
57
|
|
|
36
|
-
|
|
58
|
+
```ts
|
|
59
|
+
createPayouts(input: CreatePayoutDTO): Promise<PayoutDTO>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Takes one payout, not an array. Throws a `NOT_ALLOWED` error when the account isn’t `active`. Otherwise it creates a `pending` row, calls the provider, and stores the provider’s `data` and `status`. Deletes the row if the provider throws. `input` takes `account_id`, `amount`, `currency_code`, and optional `data` and `context`.
|
|
63
|
+
|
|
64
|
+
### getWebhookActionAndData
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
getWebhookActionAndData(
|
|
68
|
+
input: PayoutWebhookActionInput
|
|
69
|
+
): Promise<PayoutWebhookResult>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Passes `{ data, rawData, headers }` to the provider and returns its action and Mercur id. It doesn’t change any record.
|
|
37
73
|
|
|
38
|
-
|
|
39
|
-
them over the raw generated creates.
|
|
74
|
+
### getOptions
|
|
40
75
|
|
|
41
|
-
|
|
76
|
+
```ts
|
|
77
|
+
getOptions(): PayoutModuleOptions
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Returns the module options merged over `PAYOUT_MODULE_OPTION_DEFAULTS`. Core reads none of the timing options, so use them in your own payout trigger. See [The payout pipeline](/platform/payout/concepts/payout-pipeline).
|
|
81
|
+
|
|
82
|
+
## Idempotency keys
|
|
83
|
+
|
|
84
|
+
Each provider-backed method sets `context.idempotency_key` before it calls the provider, unless you pass one:
|
|
85
|
+
|
|
86
|
+
| Method | Default key |
|
|
42
87
|
| --- | --- |
|
|
43
|
-
| `createPayoutAccount
|
|
44
|
-
| `createOnboarding
|
|
45
|
-
| `createPayouts
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<Warning>
|
|
50
|
-
Prefer [workflows](/platform/payout/reference/workflows) for anything that
|
|
51
|
-
touches the provider or links records. The generated `updatePayouts` /
|
|
52
|
-
`updatePayoutAccounts` write status directly and do **not** call the provider.
|
|
53
|
-
</Warning>
|
|
88
|
+
| `createPayoutAccount` | The new `pacc` id |
|
|
89
|
+
| `createOnboarding` | The `account_id` |
|
|
90
|
+
| `createPayouts` | The new `pout` id |
|
|
91
|
+
|
|
92
|
+
`createPayoutWorkflow` passes the order id, which replaces the `pout` default. Stripe Connect forwards the key to Stripe on account and transfer creation.
|