docs: improve payment related guides (#12502)
* improve guide * update guides * small change
This commit is contained in:
@@ -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:
|
||||
|
||||

|
||||
|
||||
- [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, you’ll 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>
|
||||
|
||||

|
||||
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 resource’s 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.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 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, you’ll learn how the Payment Module supports listening to webhook events.
|
||||
In this guide, you’ll 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 payment’s status.
|
||||
A payment webhook event is a request sent from a third-party payment provider to your application. It indicates a change in a payment’s 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 Module’s 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>
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user