docs: improve payment related guides (#12502)

* improve guide

* update guides

* small change
This commit is contained in:
Shahed Nasser
2025-05-15 18:40:21 +03:00
committed by GitHub
parent b312a7e077
commit 22cdcedddc
26 changed files with 15844 additions and 15704 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,44 @@
export const metadata = {
title: `Payment Steps in Checkout Flow`,
}
# {metadata.title}
In this guide, you'll learn about Medusa's accept payment flow that's used in checkout.
## Overview of the Payment Flow in Checkout
The Medusa application has a built-in payment flow that allows you to accept payments from customers, typically during checkout.
This flow is designed to be flexible and extensible, allowing you to integrate with various payment providers.
The payment flow consists of the following steps:
![A diagram showcasing the payment flow's steps](https://res.cloudinary.com/dza7lstvk/image/upload/v1711566781/Medusa%20Resources/payment-flow_jblrvw.jpg)
- [Create Payment Collection](!api!/store#payment-collections_postpaymentcollections): Create a payment collection associated with a cart.
- This payment collection will hold all details related to the payment operations.
- [Show Payment Providers](!api!/store#payment-providers_getpaymentproviders): Show the customer the available payment providers to choose from.
- You can integrate any [payment provider](../payment-provider/page.mdx), and you can enable them per region.
- [Create and Initialize Payment Session](!api!/store#payment-collections_postpaymentcollectionsidpaymentsessions): Create a payment session for the selected payment provider in the Medusa application, and initialize the session in the third-party payment provider.
- [Complete Cart](!api!/store#carts_postcartsidcomplete): Once the customer places the order, complete the cart, which involves:
- Authorizing the payment session with the third-party payment provider.
- If the third-party payment provider requires performing additional actions, show them to the customer, then retry cart completion.
---
## Implement Payment Checkout Step in Storefront
If you're using the [Next.js Starter Storefront](../../../nextjs-starter/page.mdx), the checkout flow is already implemented with the payment step.
If you're building a custom storefront, or you want to customize the checkout flow, you can follow the [Checkout in Storefront](../../../storefront-development/checkout/page.mdx) guide to learn how to build the checkout flow in the storefront, including the payment step.
---
{/* TODO add section on customizng the payment flow */}
## Build a Custom Payment Flow
You can also build a custom payment flow using workflows or the Payment Module's main service.
Refer to the [Accept Payment Flow](../payment-flow/page.mdx) guide to learn more.
@@ -1,18 +1,26 @@
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Accept Payment Flow`,
title: `Accept Payment in Checkout Flow`,
}
# {metadata.title}
In this document, youll learn how to implement an accept-payment flow using workflows or the Payment Module's main service.
In this guide, you'll learn how to implement it using workflows or the Payment Module.
<Note>
## Why Implement the Payment Flow?
It's highly recommended to use Medusa's workflows to implement this flow. Use the Payment Module's main service for more complex cases.
Medusa already provides a built-in payment flow that allows you to accept payments from customers, which you can learn about in the [Accept Payment Flow in Checkout](../payment-checkout-flow/page.mdx) guide.
</Note>
You may need to implement a custom payment flow if you have a different use case, or you're using the Payment Module separately from the Medusa application.
This guide will help you understand how to implement a payment flow using the Payment Module's main service or workflows.
You can also follow this guide to get a general understanding of how the payment flow works in the Medusa application.
---
## How to Implement the Accept Payment Flow?
<Note title="Tip">
@@ -20,16 +28,18 @@ For a guide on how to implement this flow in the storefront, check out [this gui
</Note>
## Flow Overview
<Note>
![A diagram showcasing the payment flow's steps](https://res.cloudinary.com/dza7lstvk/image/upload/v1711566781/Medusa%20Resources/payment-flow_jblrvw.jpg)
It's highly recommended to use Medusa's workflows to implement this flow. Use the Payment Module's main service for more complex cases.
---
</Note>
## 1. Create a Payment Collection
### 1. Create a Payment Collection
A payment collection holds all details related to a resources payment operations. So, you start off by creating a payment collection.
In the Medusa application, you associate the payment collection with a cart, which is the resource that the customer is trying to pay for.
For example:
<CodeTabs group="workflow-service">
@@ -40,7 +50,7 @@ import { createPaymentCollectionForCartWorkflow } from "@medusajs/medusa/core-fl
// ...
await createPaymentCollectionForCartWorkflow(req.scope)
await createPaymentCollectionForCartWorkflow(container)
.run({
input: {
cart_id: "cart_123",
@@ -62,13 +72,50 @@ const paymentCollection =
</CodeTab>
</CodeTabs>
---
### 2. Show Payment Providers
## 2. Create Payment Sessions
Next, you'll show the customer the available payment providers to choose from.
In the Medusa application, you need to use [Query](!docs!/learn/fundamentals/module-links/query) to retrieve the available payment providers in a region.
<CodeTabs group="query-service">
<CodeTab label="Using Query" value="query">
```ts
const query = container.resolve("query")
const { data: regionPaymentProviders } = await query.graph({
entryPoint: "region_payment_provider",
variables: {
filters: {
region_id: "reg_123",
},
},
fields: ["payment_providers.*"],
})
const paymentProviders = regionPaymentProviders.map(
(relation) => relation.payment_providers
)
```
</CodeTab>
<CodeTab label="Using Service" value="service">
```ts
const paymentProviders = await paymentModuleService.listPaymentProviders()
```
</CodeTab>
</CodeTabs>
### 3. Create Payment Sessions
The payment collection has one or more payment sessions, each being a payment amount to be authorized by a payment provider.
So, after creating the payment collection, create at least one payment session for a provider.
So, once the customer selects a payment provider, create a payment session for the selected payment provider.
This will also initialize the payment session in the third-party payment provider.
For example:
@@ -80,11 +127,11 @@ import { createPaymentSessionsWorkflow } from "@medusajs/medusa/core-flows"
// ...
const { result: paymentSesion } = await createPaymentSessionsWorkflow(req.scope)
const { result: paymentSesion } = await createPaymentSessionsWorkflow(container)
.run({
input: {
payment_collection_id: "paycol_123",
provider_id: "stripe",
provider_id: "pp_stripe_stripe",
},
})
```
@@ -97,7 +144,7 @@ const paymentSession =
await paymentModuleService.createPaymentSession(
paymentCollection.id,
{
provider_id: "stripe",
provider_id: "pp_stripe_stripe",
currency_code: "usd",
amount: 5000,
data: {
@@ -111,11 +158,9 @@ const paymentSession =
</CodeTab>
</CodeTabs>
---
### 4. Authorize Payment Session
## 3. Authorize Payment Session
Once the customer chooses a payment session, start the authorization process. This may involve some action performed by the third-party payment provider, such as entering a 3DS code.
Once the customer places the order, you need to authorize the payment session with the third-party payment provider.
For example:
@@ -148,7 +193,7 @@ const payment = authorizePaymentSessionStep({
When the payment authorization is successful, a payment is created and returned.
### Handling Additional Action
#### Handling Additional Action
<Note>
@@ -184,14 +229,13 @@ try {
}
```
---
## 4. Payment Flow Complete
### 5. Payment Flow Complete
The payment flow is complete once the payment session is authorized and the payment is created.
You can then:
- Complete the cart using the [completeCartWorkflow](/references/medusa-workflows/completeCartWorkflow) if you're using the Medusa application.
- Capture the payment either using the [capturePaymentWorkflow](/references/medusa-workflows/capturePaymentWorkflow) or [capturePayment method](/references/payment/capturePayment).
- Refund captured amounts using the [refundPaymentWorkflow](/references/medusa-workflows/refundPaymentWorkflow) or [refundPayment method](/references/payment/refundPayment).
@@ -18,9 +18,23 @@ A payment collection can have multiple payment sessions. Using this feature, you
## data Property
Payment providers may need additional data to process the payment later. The `PaymentSession` data model has a `data` property used to store that data.
Payment providers may need additional data to process the payment later. For example, the ID of the session in the third-party provider.
For example, the customer's ID in Stripe is stored in the `data` property.
The `PaymentSession` data model has a `data` property used to store that data. It's set by the [payment provider in Medusa](../payment-provider/page.mdx) when the payment is initialized.
Then, when the payment session is authorized, the `data` property is used by the payment provider in Medusa to process the payment with the third-party provider.
<Note title="Tip">
If you're building a custom payment provider, learn more about initializing the payment session and setting the `data` property in the [Create Payment Provider](/references/payment/provider) guide.
</Note>
### data Property in the Storefront
This `data` property is accessible in the storefront as well. So, only store in it data that can be publicly shared, and data that is useful in the storefront.
For example, you can also store the client token used to initialize the payment session in the storefront with the third-party provider.
---
@@ -35,3 +35,19 @@ When a payment is refunded, a refund, represented by the [Refund data model](/re
A payment can be refunded multiple times, and each time a refund record is created.
![A diagram showcasing how a payment's multiple refunds are stored](https://res.cloudinary.com/dza7lstvk/image/upload/v1711565555/Medusa%20Resources/payment-refund_lgfvyy.jpg)
---
## data Property
Payment providers may need additional data to process the payment later. For example, the ID of the associated payment in the third-party provider.
The `Payment` data model has a `data` property used to store that data. The first time it's set is when the [payment provider in Medusa](../payment-provider/page.mdx) authorizes the payment.
Then, the `data` property is passed to the Medusa payment provider when the payment is captured or refunded, allowing the payment provider to utilize the data to process the payment with the third-party provider.
<Note title="Tip">
If you're building a custom payment provider, learn more about authorizing and capturing the payments and setting the `data` property in the [Create Payment Provider](/references/payment/provider) guide.
</Note>
@@ -1,38 +1,58 @@
export const metadata = {
title: `Webhook Events`,
title: `Payment Webhook Events`,
}
# {metadata.title}
In this document, youll learn how the Payment Module supports listening to webhook events.
In this guide, youll learn how you can handle payment webhook events in your Medusa application and using the Payment Module.
## What's a Webhook Event?
## What's a Payment Webhook Event?
A webhook event is sent from a third-party payment provider to your application. It indicates a change in a payments status.
A payment webhook event is a request sent from a third-party payment provider to your application. It indicates a change in a payments status.
This is useful in many cases such as when a payment is being processed asynchronously or when a request is interrupted and the payment provider is sending details on the process later.
This is useful in many cases such as:
- When a payment is processed (authorized or captured) asynchronously.
- When a payment is managed on the third-party payment provider's side.
- When a payment action on the frontend was interrupted, leading the payment to be processed without an order being created in the Medusa application.
So, it's essential to handle webhook events to ensure that your application is aware of updated payment statuses and can take appropriate actions.
---
## getWebhookActionAndData Method
## How to Handle Payment Webhook Events
The Payment Modules main service has a [getWebhookActionAndData method](/references/payment/getWebhookActionAndData) used to handle incoming webhook events from third-party payment services. The method delegates the handling to the associated payment provider, which returns the event's details.
### Webhook Listener API Route
Medusa implements a webhook listener route at the `/hooks/payment/[identifier]_[provider]` API route, where:
The Medusa application has a `/hooks/payment/[identifier]_[provider]` API route out-of-the-box that allows you to listen to webhook events from third-party payment providers, where:
- `[identifier]` is the `identifier` static property defined in the payment provider. For example, `stripe`.
- `[provider]` is the ID of the provider. For example, `stripe`.
For example, when integrating basic Stripe payments with the [Stripe Module Provider](../payment-provider/stripe/page.mdx), the webhook listener route is `/hooks/payment/stripe_stripe`. If you're integrating Stripe's Bancontact payments, the webhook listener route is `/hooks/payment/stripe-bancontact_stripe`.
For example, when integrating basic Stripe payments with the [Stripe Module Provider](../payment-provider/stripe/page.mdx), the webhook listener route is `/hooks/payment/stripe_stripe`.
Use that webhook listener in your third-party payment provider's configurations.
You can use this webhook listener when configuring webhook events in your third-party payment provider.
### getWebhookActionAndData Method
The webhook listener API route executes the [getWebhookActionAndData method](/references/payment/getWebhookActionAndData) of the Payment Module's main service. This method delegates handling of incoming webhook events to the relevant payment provider.
<Note title="Tip">
Payment providers have a similar [getWebhookActionAndData method](/references/payment/provider) to process the webhook event. So, if you're implementing a custom payment provider, make sure to implement it to handle webhook events.
</Note>
![A diagram showcasing the steps of how the getWebhookActionAndData method words](https://res.cloudinary.com/dza7lstvk/image/upload/v1711567415/Medusa%20Resources/payment-webhook_seaocg.jpg)
If the event's details indicate that the payment should be authorized, then the [authorizePaymentSession method of the main service](/references/payment/authorizePaymentSession) is executed on the specified payment session.
If the `getWebhookActionAndData` method returns an `authorized` or `captured` action, the Medusa application will perform one of the following actions:
If the event's details indicate that the payment should be captured, then the [capturePayment method of the main service](/references/payment/capturePayment) is executed on the payment of the specified payment session.
<Note>
### Actions After Webhook Payment Processing
View the full flow of the webhook event processing in the [processPaymentWorkflow](/references/medusa-workflows/processPaymentWorkflow) reference.
After the payment webhook actions are processed and the payment is authorized or captured, the Medusa application completes the cart associated with the payment's collection if it's not completed yet.
</Note>
- If the method returns an `authorized` action, Medusa will set the associated payment session to `authorized`.
- If the method returns a `captured` action, Medusa will set the associated payment session to `captured`.
- In either cases, if the cart associated with the payment session is not completed yet, Medusa will complete the cart.
+6 -5
View File
@@ -45,13 +45,13 @@ export const generatedEditDates = {
"app/commerce-modules/payment/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/payment/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/payment/module-options/page.mdx": "2024-10-15T12:51:40.574Z",
"app/commerce-modules/payment/payment/page.mdx": "2024-10-09T10:59:08.463Z",
"app/commerce-modules/payment/payment/page.mdx": "2025-05-15T15:13:47.920Z",
"app/commerce-modules/payment/payment-collection/page.mdx": "2024-10-09T10:56:49.510Z",
"app/commerce-modules/payment/payment-flow/page.mdx": "2025-01-16T10:43:25.958Z",
"app/commerce-modules/payment/payment-flow/page.mdx": "2025-05-15T15:00:46.800Z",
"app/commerce-modules/payment/payment-provider/stripe/page.mdx": "2025-04-25T12:43:03.674Z",
"app/commerce-modules/payment/payment-provider/page.mdx": "2025-05-09T11:29:10.212Z",
"app/commerce-modules/payment/payment-session/page.mdx": "2024-10-09T10:58:00.960Z",
"app/commerce-modules/payment/webhook-events/page.mdx": "2024-11-19T11:45:02.167Z",
"app/commerce-modules/payment/payment-session/page.mdx": "2025-05-15T15:11:33.262Z",
"app/commerce-modules/payment/webhook-events/page.mdx": "2025-05-15T13:18:09.356Z",
"app/commerce-modules/payment/page.mdx": "2025-04-17T08:48:11.702Z",
"app/commerce-modules/pricing/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/pricing/_events/page.mdx": "2024-07-03T19:27:13+03:00",
@@ -6480,5 +6480,6 @@ export const generatedEditDates = {
"references/core_flows/Product/Steps_Product/functions/core_flows.Product.Steps_Product.normalizeCsvStep/page.mdx": "2025-05-15T08:05:21.388Z",
"references/core_flows/Product/Steps_Product/variables/core_flows.Product.Steps_Product.normalizeCsvStepId/page.mdx": "2025-05-15T08:05:21.385Z",
"references/core_flows/types/core_flows.NormalizeProductCsvStepInput/page.mdx": "2025-05-15T08:05:23.806Z",
"references/utils/ProductUtils/classes/utils.ProductUtils.CSVNormalizer/page.mdx": "2025-05-15T08:05:33.996Z"
"references/utils/ProductUtils/classes/utils.ProductUtils.CSVNormalizer/page.mdx": "2025-05-15T08:05:33.996Z",
"app/commerce-modules/payment/payment-checkout-flow/page.mdx": "2025-05-15T15:06:08.891Z"
}
+4 -32
View File
@@ -359,6 +359,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/payment/payment/page.mdx",
"pathname": "/commerce-modules/payment/payment"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/payment/payment-checkout-flow/page.mdx",
"pathname": "/commerce-modules/payment/payment-checkout-flow"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/payment/payment-collection/page.mdx",
"pathname": "/commerce-modules/payment/payment-collection"
@@ -13571,26 +13575,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/references/medusa/types/medusa.SubscriberConfig/page.mdx",
"pathname": "/references/medusa/types/medusa.SubscriberConfig"
},
{
"filePath": "/www/apps/resources/references/medusa_config/interfaces/medusa_config.AdminOptions/page.mdx",
"pathname": "/references/medusa_config/interfaces/medusa_config.AdminOptions"
},
{
"filePath": "/www/apps/resources/references/medusa_config/interfaces/medusa_config.ConfigModule/page.mdx",
"pathname": "/references/medusa_config/interfaces/medusa_config.ConfigModule"
},
{
"filePath": "/www/apps/resources/references/medusa_config/interfaces/medusa_config.HttpCompressionOptions/page.mdx",
"pathname": "/references/medusa_config/interfaces/medusa_config.HttpCompressionOptions"
},
{
"filePath": "/www/apps/resources/references/medusa_config/interfaces/medusa_config.ProjectConfigOptions/page.mdx",
"pathname": "/references/medusa_config/interfaces/medusa_config.ProjectConfigOptions"
},
{
"filePath": "/www/apps/resources/references/medusa_config/types/medusa_config.PluginDetails/page.mdx",
"pathname": "/references/medusa_config/types/medusa_config.PluginDetails"
},
{
"filePath": "/www/apps/resources/references/module_events/module_events.Auth/page.mdx",
"pathname": "/references/module_events/module_events.Auth"
@@ -13735,10 +13719,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/references/modules/medusa/page.mdx",
"pathname": "/references/modules/medusa"
},
{
"filePath": "/www/apps/resources/references/modules/medusa_config/page.mdx",
"pathname": "/references/modules/medusa_config"
},
{
"filePath": "/www/apps/resources/references/modules/module_events/page.mdx",
"pathname": "/references/modules/module_events"
@@ -13815,10 +13795,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/references/modules/sales_channel_models/page.mdx",
"pathname": "/references/modules/sales_channel_models"
},
{
"filePath": "/www/apps/resources/references/modules/search/page.mdx",
"pathname": "/references/modules/search"
},
{
"filePath": "/www/apps/resources/references/modules/stock_location_next/page.mdx",
"pathname": "/references/modules/stock_location_next"
@@ -17783,10 +17759,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/references/sales_channel_models/variables/sales_channel_models.SalesChannel/page.mdx",
"pathname": "/references/sales_channel_models/variables/sales_channel_models.SalesChannel"
},
{
"filePath": "/www/apps/resources/references/search/classes/search.AbstractSearchService/page.mdx",
"pathname": "/references/search/classes/search.AbstractSearchService"
},
{
"filePath": "/www/apps/resources/references/stock_location_next/IMessageAggregator/methods/stock_location_next.IMessageAggregator.clearMessages/page.mdx",
"pathname": "/references/stock_location_next/IMessageAggregator/methods/stock_location_next.IMessageAggregator.clearMessages"
@@ -9081,6 +9081,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"title": "Payment Module Provider",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/commerce-modules/payment/payment-checkout-flow",
"title": "Payment in Checkout",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -4874,11 +4874,6 @@ export const slugChanges = [
"newSlug": "/references/locking-module-provider",
"filePath": "/www/apps/resources/references/locking/interfaces/locking.ILockingProvider/page.mdx"
},
{
"origSlug": "/references/medusa_config/interfaces/medusa_config.ConfigModule",
"newSlug": "/references/medusa-config",
"filePath": "/www/apps/resources/references/medusa_config/interfaces/medusa_config.ConfigModule/page.mdx"
},
{
"origSlug": "/references/module_events/module_events.Auth",
"newSlug": "/references/auth/events",
@@ -7064,11 +7059,6 @@ export const slugChanges = [
"newSlug": "/references/sales-channel/models/SalesChannel",
"filePath": "/www/apps/resources/references/sales_channel_models/variables/sales_channel_models.SalesChannel/page.mdx"
},
{
"origSlug": "/references/search/classes/search.AbstractSearchService",
"newSlug": "/references/search-service",
"filePath": "/www/apps/resources/references/search/classes/search.AbstractSearchService/page.mdx"
},
{
"origSlug": "/references/stock_location_next/IStockLocationService/methods/stock_location_next.IStockLocationService.createStockLocations",
"newSlug": "/references/stock-location-next/createStockLocations",
@@ -76,6 +76,8 @@ export default MyPaymentProviderService
The constructor allows you to access resources from the [module's container](https://docs.medusajs.com/learn/fundamentals/modules/container)
using the first parameter, and the module's options using the second parameter.
If you're creating a client or establishing a connection with a third-party service, do it in the constructor.
:::note
A module's options are passed when you register it in the Medusa application.
@@ -125,7 +127,7 @@ export default MyPaymentProviderService
#### Parameters
<TypeList types={[{"name":"cradle","type":"`Record<string, unknown>`","description":"The module's container cradle used to resolve resources.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="AbstractPaymentProvider"/>
<TypeList types={[{"name":"cradle","type":"`Record<string, unknown>`","description":"The module's container used to resolve resources.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="AbstractPaymentProvider"/>
### identifier
@@ -146,13 +148,30 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### authorizePayment
This method authorizes a payment session. When authorized successfully, a payment is created by the Payment
Module which can be later captured using the [capturePayment](page.mdx#capturepayment) method.
This method authorizes a payment session using the third-party payment provider.
Refer to [this guide](https://docs.medusajs.com/resources/commerce-modules/payment/payment-flow#3-authorize-payment-session)
to learn more about how this fits into the payment flow and how to handle required actions.
During checkout, the customer may need to perform actions required by the payment provider,
such as entering their card details or confirming the payment. Once that is done,
the customer can place their order.
To automatically capture the payment after authorization, return the status `captured`.
During cart-completion before placing the order, this method is used to authorize the cart's payment session with the
third-party payment provider. The payment can later be captured
using the [capturePayment](page.mdx#capturepayment) method.
![Diagram showcasing authorize payment flow](https://res.cloudinary.com/dza7lstvk/image/upload/v1747307795/Medusa%20Resources/authorize-payment\_qzpy6e.jpg)
When authorized successfully, a `Payment` is created by the Payment
Module, and it's associated with the order.
#### Understanding `data` property
The `data` property of the method's parameter contains the `PaymentSession` record's `data` property, which was
returned by the [initiatePayment](page.mdx#initiatepayment) method.
The `data` property returned by this method is then stored in the created `Payment` record. You can store data relevant to later capture or process the payment.
For example, you can store the ID of the payment in the third-party provider to reference it later.
![Diagram showcasing data flow between methods](https://res.cloudinary.com/dza7lstvk/image/upload/v1747309278/Medusa%20Resources/authorize-data\_erjg7r.jpg)
#### Example
@@ -195,7 +214,18 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### cancelPayment
This method cancels a payment.
This method cancels a payment in the third-party payment provider. It's used when
the admin user cancels an order. The order can only be canceled if the payment
is not captured yet.
#### Understanding `data` property
The `data` property of the method's parameter contains the `Payment` record's `data` property, which was
returned by the [authorizePayment](page.mdx#authorizepayment) method.
The `data` property returned by this method is then stored in the `Payment` record. You can store data relevant for any further processing of the payment.
![Diagram showcasing data flow between methods](https://res.cloudinary.com/dza7lstvk/image/upload/v1747310189/Medusa%20Resources/cancel-data\_gzcgbc.jpg)
#### Example
@@ -233,13 +263,24 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### capturePayment
This method is used to capture a payment. The payment is captured in one of the following scenarios:
This method captures a payment using the third-party provider. In this method, use the third-party provider to capture the payment.
- The [authorizePayment](page.mdx#authorizepayment) method returns the status `captured`, which automatically executed this method after authorization.
- The merchant requests to capture the payment after its associated payment session was authorized.
- A webhook event occurred that instructs the payment provider to capture the payment session. Learn more about handing webhook events in [this guide](https://docs.medusajs.com/resources/commerce-modules/payment/webhook-events).
When an order is placed, the payment is authorized using the [authorizePayment](page.mdx#authorizepayment) method. Then, the admin
user can capture the payment, which triggers this method.
In this method, use the third-party provider to capture the payment.
![Diagram showcasing capture payment flow](https://res.cloudinary.com/dza7lstvk/image/upload/v1747307414/Medusa%20Resources/Klarna\_Payment\_Graphic\_2025\_1\_lii7bw.jpg)
This method can also be triggered by a webhook event if the [getWebhookActionAndData](page.mdx#getwebhookactionanddata) method returns the action `captured`.
#### Understanding `data` property
The `data` property of the input parameter contains data that was previously stored in the Payment record's `data` property, which was
returned by the [authorizePayment](page.mdx#authorizepayment) method.
The `data` property returned by this method is then stored in the `Payment` record. You can store data relevant to later refund or process the payment.
For example, you can store the ID of the payment in the third-party provider to reference it later.
![Diagram showcasing data flow between methods](https://res.cloudinary.com/dza7lstvk/image/upload/v1747309870/Medusa%20Resources/capture-data\_acgdhf.jpg)
#### Example
@@ -260,7 +301,12 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
// assuming you have a client that captures the payment
const newData = await this.client.capturePayment(externalId)
return {data: newData}
return {
data: {
...newData,
id: externalId,
}
}
}
// ...
}
@@ -398,9 +444,22 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### deletePayment
This method is used when a payment session is deleted, which can only happen if it isn't authorized, yet.
This method deletes a payment session in the third-party payment provider.
Use this to delete or cancel the payment in the third-party service.
When a customer chooses a payment method during checkout, then chooses a different one,
this method is triggered to delete the previous payment session.
If your provider doesn't support deleting a payment session, you can just return an empty object or
an object that contains the same received `data` property.
![Diagram showcasing delete payment flow](https://res.cloudinary.com/dza7lstvk/image/upload/v1747311084/Medusa%20Resources/delete-payment\_smxsiq.jpg)
#### Understanding `data` property
The `data` property of the method's parameter contains the `PaymentSession` record's `data` property, which was
returned by the [initiatePayment](page.mdx#initiatepayment) method.
![Diagram showcasing data flow between methods](https://res.cloudinary.com/dza7lstvk/image/upload/v1747311084/Medusa%20Resources/delete-data\_xg65ck.jpg)
#### Example
@@ -421,7 +480,9 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
// assuming you have a client that cancels the payment
await this.client.cancelPayment(externalId)
return {}
return {
data: input.data
}
}
// ...
@@ -487,10 +548,11 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### getWebhookActionAndData
This method is executed when a webhook event is received from the third-party payment provider. Use it
to process the action of the payment provider.
This method is executed when a webhook event is received from the third-party payment provider. Medusa uses
the data returned by this method to perform actions in the Medusa application, such as completing the associated cart
if the payment was authorized successfully.
Learn more in [this documentation](https://docs.medusajs.com/resources/commerce-modules/payment/webhook-events)
Learn more in the [Webhook Events](https://docs.medusajs.com/resources/commerce-modules/payment/webhook-events) documentation.
#### Example
@@ -522,6 +584,8 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
return {
action: "authorized",
data: {
// assuming the session_id is stored in the metadata of the payment
// in the third-party provider
session_id: (data.metadata as Record<string, any>).session_id,
amount: new BigNumber(data.amount as number)
}
@@ -530,19 +594,27 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
return {
action: "captured",
data: {
// assuming the session_id is stored in the metadata of the payment
// in the third-party provider
session_id: (data.metadata as Record<string, any>).session_id,
amount: new BigNumber(data.amount as number)
}
}
default:
return {
action: "not_supported"
action: "not_supported",
data: {
session_id: "",
amount: new BigNumber(0)
}
}
}
} catch (e) {
return {
action: "failed",
data: {
// assuming the session_id is stored in the metadata of the payment
// in the third-party provider
session_id: (data.metadata as Record<string, any>).session_id,
amount: new BigNumber(data.amount as number)
}
@@ -560,12 +632,32 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
#### Returns
<TypeList types={[{"name":"Promise","type":"Promise&#60;[WebhookActionResult](../../../types/interfaces/types.WebhookActionResult/page.mdx)&#62;","optional":false,"defaultValue":"","description":"The webhook result. If the `action`'s value is `captured`, the payment is captured within Medusa as well.\nIf the `action`'s value is `authorized`, the associated payment session is authorized within Medusa.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="getWebhookActionAndData"/>
<TypeList types={[{"name":"Promise","type":"Promise&#60;[WebhookActionResult](../../../types/interfaces/types.WebhookActionResult/page.mdx)&#62;","optional":false,"defaultValue":"","description":"The webhook result. If the `action`'s value is `captured`, the payment is captured within Medusa as well.\nIf the `action`'s value is `authorized`, the associated payment session is authorized within Medusa and the associated cart\nwill be completed to create an order.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="getWebhookActionAndData"/>
### initiatePayment
This method is used when a payment session is created. It can be used to initiate the payment
in the third-party session, before authorizing or capturing the payment later.
This method initializes a payment session with the third-party payment provider.
When a customer chooses a payment method during checkout, this method is triggered to
perform any initialization action with the third-party provider, such as creating a payment session.
![Diagram showcasing initiate payment flow](https://res.cloudinary.com/dza7lstvk/image/upload/v1747310624/Medusa%20Resources/initiate-payment\_dpoa2g.jpg)
#### Understanding `data` property
The `data` property returned by this method will be stored in the created `PaymentSession` record. You can store data relevant to later authorize or process the payment.
For example, you can store the ID of the payment session in the third-party provider to reference it later.
The `data` property is also available to storefronts, allowing you to store data necessary for the storefront to integrate
the payment provider in the checkout flow. For example, you can store the client token to use with the payment provider's SDK.
:::note
This also means you shouldn't store sensitive data and tokens in the `data` property, as it's publicly accessible.
:::
![Diagram showcasing data flow between methods](https://res.cloudinary.com/dza7lstvk/image/upload/v1747310699/Medusa%20Resources/initiate-data\_ikc05t.jpg)
#### Example
@@ -672,7 +764,25 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### refundPayment
This method refunds an amount of a payment previously captured.
This method refunds an amount using the third-party payment provider. This method
is triggered when the admin user refunds a payment of an order.
#### Understanding `data` property
The `data` property of the method's parameter contains the `Payment` record's `data` property, which was
returned by the [capturePayment](page.mdx#capturepayment) or [refundPayment](page.mdx#refundpayment) method.
The `data` property returned by this method is then stored in the `Payment` record. You can store data relevant to later refund or process the payment.
For example, you can store the ID of the payment in the third-party provider to reference it later.
:::note
A payment may be refunded multiple times with different amounts. In this case, the `data` property
of the input parameter contains the data from the last refund.
:::
![Diagram showcasing data flow between methods](https://res.cloudinary.com/dza7lstvk/image/upload/v1747311296/Medusa%20Resources/refund-data\_plcjl0.jpg)
#### Example
@@ -697,7 +807,9 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
input.amount
)
return {data: newData}
return {
data: input.data,
}
}
// ...
}
@@ -713,7 +825,7 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### retrievePayment
Retrieves the payment's data from the third-party service.
This method retrieves the payment's data from the third-party payment provider.
#### Example
@@ -870,7 +982,7 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### updatePayment
Update a payment in the third-party service that was previously initiated with the [initiatePayment](page.mdx#initiatepayment) method.
This method updates a payment in the third-party service that was previously initiated with the [initiatePayment](page.mdx#initiatepayment) method.
#### Example
@@ -923,7 +1035,8 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
### validateOptions
This method validates the options of the provider set in `medusa-config.ts`.
Implementing this method is optional. It's useful if your provider requires custom validation.
Implementing this method is optional, but it's useful to ensure that the required
options are passed to the provider, or if you have any custom validation logic.
If the options aren't valid, throw an error.
@@ -944,7 +1057,7 @@ class MyPaymentProviderService extends AbstractPaymentProvider<Options> {
#### Parameters
<TypeList types={[{"name":"options","type":"`Record<any, any>`","description":"The provider's options.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="validateOptions"/>
<TypeList types={[{"name":"options","type":"`Record<any, any>`","description":"The provider's options passed in `medusa-config.ts`.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="validateOptions"/>
---
+5
View File
@@ -42,6 +42,11 @@ export const paymentSidebar = [
path: "/commerce-modules/payment/payment-provider",
title: "Payment Module Provider",
},
{
type: "link",
path: "/commerce-modules/payment/payment-checkout-flow",
title: "Payment in Checkout",
},
{
type: "link",
path: "/commerce-modules/payment/account-holder",