docs: add documentation for v1.8 (#3669)

This commit is contained in:
Shahed Nasser authored and GitHub committed 2023-04-03 13:50:59 +02:00
1 parent 0cca13779d
commit c6bfad14d8
123 files changed
+7610 -2697

No files matched your search

@@ -1,158 +1,167 @@
---
description: 'Learn how to create a payment provider in the Medusa backend. This guide explains the different methods available in a fulfillment provider.'
description: 'Learn how to create a payment processor in the Medusa. This guide explains the different methods available in a payment processor.'
addHowToData: true
---
# How to Create a Payment Provider
# How to Create a Payment Processor
In this document, you’ll learn how to add a Payment Provider to your Medusa backend. If you’re unfamiliar with the Payment architecture in Medusa, make sure to check out the [overview](../payment.md) first.
## Overview
A Payment Provider is the payment method used to authorize, capture, and refund payment, among other actions. An example of a Payment Provider is Stripe.
By default, Medusa has a [manual payment provider](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-manual) that has minimal implementation. It can be synonymous with a Cash on Delivery payment method. It allows store operators to manage the payment themselves but still keep track of its different stages on Medusa.
Adding a Payment Provider is as simple as creating a [service](../../../development/services/create-service.md) file in `src/services`. A Payment Provider is essentially a service that extends `AbstractPaymentService` from the core Medusa package `@medusajs/medusa`.
Payment Provider Services must have a static property `identifier`. It's the name that will be used to install and refer to the Payment Provider in the Medusa backend.
:::tip
Payment Providers are loaded and installed at the backend startup.
:::
The Payment Provider service is also required to implement the following methods:
1. `createPayment`: Called when a Payment Session for the Payment Provider is to be created.
2. `retrievePayment`: Used to retrieve payment data from the third-party provider, if there’s any.
3. `getStatus`: Used to get the status of a Payment or Payment Session.
4. `updatePayment`: Used to update the Payment Session whenever the cart and its related data are updated.
5. `updatePaymentData`: Used to update the `data` field of Payment Sessions. Specifically called when a request is sent to the [Update Payment Session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessionUpdate) endpoint.
6. `deletePayment`: Used to perform any action necessary before a Payment Session is deleted.
7. `authorizePayment`: Used to authorize the payment amount of the cart before the order or swap is created.
8. `getPaymentData`: Used to retrieve the data that should be stored in the `data` field of a new Payment instance after the payment amount has been authorized.
9. `capturePayment`: Used to capture the payment amount of an order or swap.
10. `refundPayment`: Used to refund a payment amount of an order or swap.
11. `cancelPayment`: Used to perform any necessary action with the third-party payment provider when an order or swap is canceled.
In this document, you’ll learn how to create a Payment Processor in your Medusa backend. If you’re unfamiliar with the Payment architecture in Medusa, make sure to check out the [overview](../payment.md) first.
:::note
All these methods must be declared async in the Payment Provider Service.
Before v1.8 of Medusa, this guide explained how to create a payment provider. Payment Providers are now considered legacy and are deprecated. Moving forward, it's recommended to create a Payment Processor that implements the Payment Processor API.
:::
## Overview
A Payment Processor is the payment method used to authorize, capture, and refund payment, among other actions. An example of a Payment Processor is Stripe.
By default, Medusa has a [manual payment provider](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-manual) that has minimal implementation. It can be synonymous with a Cash on Delivery payment method. It allows store operators to manage the payment themselves but still keep track of its different stages on Medusa.
Adding a Payment Processor is as simple as creating a [service](../../../development/services/create-service.md) file in `src/services`. A Payment Processor is essentially a service that extends `AbstractPaymentProcessor` from the core Medusa package `@medusajs/medusa`.
Payment Processor Services must have a static property `identifier`. It's the name that will be used to install and refer to the Payment Processor in the Medusa backend.
:::tip
Payment Processors are loaded and installed at the server startup. If not already saved, they're saved in the database and are represented by the `PaymentProvider` entity.
:::
The Payment Processor is also required to implement the following methods:
1. `initiatePayment`: Called when a Payment Session for the Payment Provider is to be created.
2. `retrievePayment`: Used to retrieve payment session data, which can be retrieved from a third-party provider.
3. `getPaymentStatus`: Used to get the status of a Payment or Payment Session.
4. `updatePayment`: Used to update the Payment Session whenever the cart and its related data are updated.
5. `deletePayment`: Used to perform any action necessary before a Payment Session is deleted. For example, you can cancel the payment with the third-party provider.
6. `authorizePayment`: Used to authorize the payment amount of the cart before the order or swap is created.
7. `capturePayment`: Used to capture the payment amount of an order or swap.
8. `refundPayment`: Used to refund a payment amount of an order or swap.
9. `cancelPayment`: Used to perform any necessary action with the third-party payment provider when an order or swap is canceled.
:::note
All these methods must be declared async in the Payment Processor.
:::
These methods are used at different points in the Checkout flow as well as when processing the order after it’s placed.
![Checkout Flow - Payment](https://res.cloudinary.com/dza7lstvk/image/upload/v1677770739/Medusa%20Docs/Diagrams/checkout-payment_rouet2.png)
![Checkout Flow - Payment](https://res.cloudinary.com/dza7lstvk/image/upload/v1680177820/Medusa%20Docs/Diagrams/checkout-payment_cy9efp.jpg)
---
## Create a Payment Provider
## Create a Payment Processor
The first step to create a payment provider is to create a JavaScript or TypeScript file in `src/services`. The file's name should be the name of the payment provider.
The first step to create a payment processor is to create a JavaScript or TypeScript file in `src/services`. The file's name should be the name of the payment processor, and it should be in snake case.
For example, create the file `src/services/my-payment.ts` with the following content:
For example, create the file `src/services/my-payment-processor.ts` with the following content:
```ts title=src/services/my-payment.ts
```ts title=src/services/my-payment-processor.ts
import {
AbstractPaymentService, PaymentContext, Data,
Payment, PaymentSession, PaymentSessionStatus,
PaymentSessionData, Cart, PaymentData,
PaymentSessionResponse } from "@medusajs/medusa"
AbstractPaymentProcessor,
PaymentProcessorContext,
PaymentProcessorError,
PaymentProcessorSessionResponse,
PaymentSessionStatus,
} from "@medusajs/medusa"
import { EntityManager } from "typeorm"
class MyPaymentProcessor extends AbstractPaymentProcessor {
static identifier = "my-payment"
class MyPaymentService extends AbstractPaymentService {
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
async getPaymentData(
paymentSession: PaymentSession
): Promise<Data> {
throw new Error("Method not implemented.")
}
async updatePaymentData(
paymentSessionData: PaymentSessionData,
data: Data
): Promise<PaymentSessionData> {
throw new Error("Method not implemented.")
}
async createPayment(
context: Cart & PaymentContext
): Promise<PaymentSessionResponse> {
throw new Error("Method not implemented.")
}
async retrievePayment(paymentData: Data): Promise<Data> {
throw new Error("Method not implemented.")
}
async updatePayment(
paymentSessionData: PaymentSessionData,
cart: Cart
): Promise<PaymentSessionData> {
async capturePayment(
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
throw new Error("Method not implemented.")
}
async authorizePayment(
paymentSession: PaymentSession,
context: Data
): Promise<{
data: PaymentSessionData;
status: PaymentSessionStatus
}> {
paymentSessionData: Record<string, unknown>,
context: Record<string, unknown>
): Promise<
PaymentProcessorError |
{
status: PaymentSessionStatus;
data: Record<string, unknown>;
}
> {
throw new Error("Method not implemented.")
}
async capturePayment(payment: Payment): Promise<PaymentData> {
async cancelPayment(
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
throw new Error("Method not implemented.")
}
async refundPayment(
payment: Payment,
refundAmount: number
): Promise<PaymentData> {
throw new Error("Method not implemented.")
}
async cancelPayment(payment: Payment): Promise<PaymentData> {
async initiatePayment(
context: PaymentProcessorContext
): Promise<
PaymentProcessorError | PaymentProcessorSessionResponse
> {
throw new Error("Method not implemented.")
}
async deletePayment(
paymentSession: PaymentSession
): Promise<void> {
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
throw new Error("Method not implemented.")
}
async getStatus(data: Data): Promise<PaymentSessionStatus> {
async getPaymentStatus(
paymentSessionData: Record<string, unknown>
): Promise<PaymentSessionStatus> {
throw new Error("Method not implemented.")
}
async refundPayment(
paymentSessionData: Record<string, unknown>,
refundAmount: number
): Promise<Record<string, unknown> | PaymentProcessorError> {
throw new Error("Method not implemented.")
}
async retrievePayment(
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
throw new Error("Method not implemented.")
}
async updatePayment(
context: PaymentProcessorContext
): Promise<
void |
PaymentProcessorError |
PaymentProcessorSessionResponse
> {
throw new Error("Method not implemented.")
}
}
export default MyPaymentService
export default MyPaymentProcessor
```
Where `MyPaymentService` is the name of your Payment Provider service. For example, Stripe’s Payment Provider Service is called `StripeProviderService`.
Where `MyPaymentProcessor` is the name of your Payment Processor service.
Payment Providers must extend `AbstractPaymentService` from the core Medusa package `@medusajs/medusa`.
Payment Processors must extend `AbstractPaymentProcessor` from the core Medusa package `@medusajs/medusa`.
:::tip
Following the naming convention of Services, the name of the file should be the slug name of the Payment Provider, and the name of the class should be the camel case name of the Payment Provider suffixed with “Service”. In the example above, the name of the file should be `my-payment.js`. You can learn more in the [service documentation](../../../development/services/create-service.md).
Following the naming convention of Services, the name of the file should be the slug name of the Payment Processor, and the name of the class should be the camel case name of the Payment Processors suffixed with “Service”. In the example above, the name of the file should be `my-payment.ts`. You can learn more in the [service documentation](../../../development/services/create-service.md).
:::
### Identifier
### identifier
As mentioned in the overview, Payment Providers should have a static `identifier` property.
As mentioned in the overview, Payment Processors should have a static `identifier` property.
The `PaymentProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the class will be used when the Payment Provider is created in the database.
The `PaymentProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the class will be used when the Payment Processor is created in the database.
The value of this property will also be used to reference the Payment Provider throughout the Medusa backend. For example, the identifier is used when a [Payment Session in a cart is selected on checkout](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession).
The value of this property will also be used to reference the Payment Processor throughout the Medusa backend. For example, the identifier is used when a [Payment Session in a cart is selected on checkout](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession).
The identifier can be retrieved using the `getIdentifier` method, which is defined in `AbstractPaymentProcessor`.
### constructor
You can use the `constructor` of your Payment Provider to have access to different services in Medusa through dependency injection.
You can use the `constructor` of your Payment Processor to have access to different services in Medusa through [dependency injection](../../../development/fundamentals/dependency-injection.md).
You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the service.
Additionally, if you’re creating your Payment Provider as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, you can access it in the constructor. The options are passed as a second parameter:
Additionally, if you’re creating your Payment Processor as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, you can access it in the constructor. The options are passed as a second parameter:
```ts
class MyPaymentService extends AbstractPaymentService {
@@ -165,42 +174,86 @@ class MyPaymentService extends AbstractPaymentService {
}
```
### createPayment
### PaymentProcessorError
This method is called during checkout when [Payment Sessions are initialized](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessions) to present payment options to the customer. It is used to allow you to make any necessary calls to the third-party provider to initialize the payment.
For example, in Stripe this method is used to initialize a Payment Intent for the customer.
The method receives a context object as a first parameter. This object is of type `PaymentContext` and has the following properties:
Before diving into the methods you'll need to implement, you'll notice that part of the expected return signature of these method includes `PaymentProcessorError`. This is an interface of the following definition:
```ts
type PaymentContext = {
cart: {
context: Record<string, unknown>
id: string
email: string
shipping_address: Address | null
shipping_methods: ShippingMethod[]
}
currency_code: string
amount: number
resource_id?: string
customer?: Customer
interface PaymentProcessorError {
error: string
code?: string
detail?: any
}
```
:::note
While implementing the following methods, if you need to inform the Medusa core that an error occurred at a certain stage, return an object having the attributes defined in the `PaymentProcessorError` interface.
Before v1.7.2, the first parameter was of type `Cart`. This method remains backwards compatible, but will be changed in the future. So, it's recommended to change the type of the first parameter to `PaymentContext`.
:::
This method must return an object of type `PaymentSessionResponse`. It should have the following properties:
For example, the Stripe payment processor has the following method to create the error object, which is used within other methods:
```ts
type PaymentSessionResponse = {
update_requests: {
customer_metadata: Record<string, unknown>
abstract class StripeBase extends AbstractPaymentProcessor {
// ...
protected buildError(
message: string,
e: Stripe.StripeRawError | PaymentProcessorError | Error
): PaymentProcessorError {
return {
error: message,
code: "code" in e ? e.code : "",
detail: isPaymentProcessorError(e)
? `${e.error}${EOL}${e.detail ?? ""}`
: "detail" in e
? e.detail
: e.message ?? "",
}
}
// used in other methods
async retrievePayment(
paymentSessionData: Record<string, unknown>
): Promise<
PaymentProcessorError |
PaymentProcessorSessionResponse["session_data"]
> {
try {
// ...
} catch (e) {
return this.buildError(
"An error occurred in retrievePayment",
e
)
}
}
}
```
### initiatePayment
This method is called either if a region has only one payment provider enabled or when [a Payment Session is selected](/api/store#tag/Cart/operation/PostCartsCartPaymentSession), which occurs when the customer selects their preferred payment method during checkout. It is used to allow you to make any necessary calls to the third-party provider to initialize the payment.
For example, in Stripe this method is used to create a Payment Intent for the customer.
The method receives a context object as a first parameter. This object is of type `PaymentProcessorContext` and has the following properties:
```ts
type PaymentProcessorContext = {
billing_address?: Address | null
email: string
currency_code: string
amount: number
resource_id: string
customer?: Customer
context: Record<string, unknown>
paymentSessionData: Record<string, unknown>
}
```
This method must return an object of type `PaymentProcessorSessionResponse`. It should have the following properties:
```ts
type PaymentProcessorSessionResponse = {
update_requests?: {
customer_metadata?: Record<string, unknown>
}
session_data: Record<string, unknown>
}
@@ -209,21 +262,23 @@ type PaymentSessionResponse = {
Where:
- `session_data` is the data that is going to be stored in the `data` field of the Payment Session to be created. As mentioned in the [Architecture Overview](../payment.md), the `data` field is useful to hold any data required by the third-party provider to process the payment or retrieve its details at a later point.
- `update_requests` is an object that can be used to pass data from the payment provider plugin to the core to update internal resources. Currently, it only has one attribute `customer_metadata` which allows updating the `metadata` field of the customer.
- `update_requests` is an object that can be used to pass data from the Payment Processor plugin to the core to update internal resources. Currently, it only has one attribute `customer_metadata` which allows updating the `metadata` field of the customer.
An example of a minimal implementation of `createPayment`:
An example of a minimal implementation of `initiatePayment`:
```ts
import {
PaymentContext,
import {
PaymentContext,
PaymentSessionResponse,
} from "@medusajs/medusa"
class MyPaymentService extends AbstractPaymentService {
// ...
async createPayment(
context: Cart & PaymentContext
): Promise<PaymentSessionResponse> {
async initiatePayment(
context: PaymentProcessorContext
): Promise<
PaymentProcessorError | PaymentProcessorSessionResponse
> {
// prepare data
return {
session_data,
@@ -235,9 +290,9 @@ class MyPaymentService extends AbstractPaymentService {
### retrievePayment
This method is used to provide a uniform way of retrieving the payment information from the third-party provider. For example, in Stripe’s Payment Provider Service this method is used to retrieve the payment intent details from Stripe.
This method is used to provide a uniform way of retrieving the payment information from the third-party provider. For example, in Stripe’s Payment Processor this method is used to retrieve the payment intent details from Stripe.
This method accepts the `data` field of a Payment Session or a Payment. So, you should make sure to store in the `data` field any necessary data that would allow you to retrieve the payment data from the third-party provider.
This method accepts the `data` field of a Payment Session. So, you should make sure to store in the `data` field any necessary data that would allow you to retrieve the payment data from the third-party provider.
This method must return an object containing the data from the third-party provider.
@@ -249,21 +304,23 @@ import { Data } from "@medusajs/medusa"
class MyPaymentService extends AbstractPaymentService {
// ...
async retrievePayment(paymentData: Data): Promise<Data> {
async retrievePayment(
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
return {}
}
}
```
### getStatus
### getPaymentStatus
This method is used to get the status of a Payment or a Payment Session.
Its main usage is in the place order workflow. If the status returned is not `authorized`, then the payment is considered failed, an error will be thrown, and the order will not be placed.
Its main usage is in the place order and create swap workflows. If the status returned is not `authorized`, then the payment is considered failed and an error will be thrown, stopping the task from completion.
This method accepts the `data` field of the Payment or Payment Session as a parameter. You can use this data to interact with the third-party provider to check the status of the payment if necessary.
This method accepts the `data` field of a Payment as a parameter. You can use this data to interact with the third-party provider to check the status of the payment if necessary.
This method returns a string that represents the status. The status must be one of the following values:
This method returns a string that represents the status. This string can be from the enum `PaymentSessionStatus` which can be imported from `@medusajs/medusa`. The status must be one of the following values:
1. `authorized`: The payment was successfully authorized.
2. `pending`: The payment is still pending. This is the default status of a Payment Session.
@@ -271,7 +328,7 @@ This method returns a string that represents the status. The status must be one
4. `error`: If an error occurred with the payment.
5. `canceled`: If the payment was canceled.
An example of a minimal implementation of `getStatus` where you don’t need to interact with the third-party provider:
An example of a minimal implementation of `getPaymentStatus` where you don’t need to interact with the third-party provider:
```ts
import { Data, PaymentSessionStatus } from "@medusajs/medusa"
@@ -279,18 +336,14 @@ import { Data, PaymentSessionStatus } from "@medusajs/medusa"
class MyPaymentService extends AbstractPaymentService {
// ...
async getStatus(data: Data): Promise<PaymentSessionStatus> {
async getPaymentStatus(
paymentSessionData: Record<string, unknown>
): Promise<PaymentSessionStatus> {
return PaymentSessionStatus.AUTHORIZED
}
}
```
:::note
This code block assumes the status is stored in the `data` field as demonstrated in the `createPayment` method.
:::
### updatePayment
This method is used to perform any necessary updates on the payment. This method is called whenever the cart or any of its related data is updated. For example, when a [line item is added to the cart](/api/store/#tag/Cart/operation/PostCartsCartLineItems) or when a [shipping method is selected](/api/store/#tag/Cart/operation/PostCartsCartShippingMethod).
@@ -301,47 +354,35 @@ A line item refers to a product in the cart.
:::
It accepts the `data` field of the Payment Session as the first parameter and a context object as a second parameter. This object is of type `PaymentContext` and has the following properties:
It accepts the `data` field of the Payment Session as the first parameter and a context object as a second parameter. This object is of type `PaymentProcessorContext` and has the following properties:
```ts
type PaymentContext = {
cart: {
context: Record<string, unknown>
id: string
email: string
shipping_address: Address | null
shipping_methods: ShippingMethod[]
}
type PaymentProcessorContext = {
billing_address?: Address | null
email: string
currency_code: string
amount: number
resource_id?: string
resource_id: string
customer?: Customer
context: Record<string, unknown>
paymentSessionData: Record<string, unknown>
}
```
:::note
Before v1.7.2, the second parameter was of type `Cart`. This method remains backwards compatible, but will be changed in the future. So, it's recommended to change the type of the first parameter to `PaymentContext`.
:::
You can utilize this method to interact with the third-party provider and update any details regarding the payment if necessary.
This method must return an object of type `PaymentSessionResponse`. It should have the following properties:
```ts
type PaymentSessionResponse = {
update_requests: {
customer_metadata: Record<string, unknown>
type PaymentProcessorSessionResponse = {
update_requests?: {
customer_metadata?: Record<string, unknown>
}
session_data: Record<string, unknown>
}
```
Where:
- `session_data` is the data that is going to be stored in the `data` field of the Payment Session to be created. As mentioned in the [Architecture Overview](../payment.md), the `data` field is useful to hold any data required by the third-party provider to process the payment or retrieve its details at a later point.
- `update_requests` is an object that can be used to request from the Medusa core to update internal resources. Currently, it only has one attribute `customer_metadata` which allows updating the `metadata` field of the customer.
These are the same fields explained in the [initiatePayment](#initiatepayment) section.
An example of a minimal implementation of `updatePayment`:
@@ -357,9 +398,12 @@ import {
class MyPaymentService extends AbstractPaymentService {
// ...
async updatePayment(
paymentSessionData: PaymentSessionData,
cart: Cart
): Promise<PaymentSessionData> {
context: PaymentProcessorContext
): Promise<
void |
PaymentProcessorError |
PaymentProcessorSessionResponse
> {
// prepare data
return {
session_data,
@@ -369,43 +413,16 @@ class MyPaymentService extends AbstractPaymentService {
}
```
### updatePaymentData
This method is used to update the `data` field of a Payment Session. Particularly, it is called when a request is sent to the [Update Payment Session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessionUpdate) endpoint. This endpoint receives a `data` object in the body of the request that should be used to update the existing `data` field of the Payment Session.
This method accepts the current `data` field of the Payment Session as the first parameter, and the new `data` field sent in the body request as the second parameter.
You can utilize this method to interact with the third-party provider and make any necessary updates based on the `data` field passed in the body of the request.
This method must return an object that will be stored in the `data` field of the Payment Session.
An example of a minimal implementation of `updatePaymentData` that returns the `updatedData` passed in the body of the request as-is to update the `data` field of the Payment Session.
```ts
import { Data, PaymentSessionData } from "@medusajs/medusa"
// ...
class MyPaymentService extends AbstractPaymentService {
// ...
async updatePaymentData(
paymentSessionData: PaymentSessionData,
data: Data
): Promise<PaymentSessionData> {
return updatedData
}
}
```
### deletePayment
This method is used to perform any actions necessary before a Payment Session is deleted. The Payment Session is deleted in one of the following cases:
1. When a request is sent to [delete the Payment Session](/api/store/#tag/Cart/operation/DeleteCartsCartPaymentSessionsSession).
2. When the [Payment Session is refreshed](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessionsSession). The Payment Session is deleted so that a newer one is initialized instead.
3. When the Payment Provider is no longer available. This generally happens when the store operator removes it from the available Payment Provider in the admin.
4. When the region of the store is changed based on the cart information and the Payment Provider is not available in the new region.
3. When the Payment Processor is no longer available. This generally happens when the store operator removes it from the available Payment Processor in the admin.
4. When the region of the store is changed based on the cart information and the Payment Processor is not available in the new region.
It accepts the Payment Session as an object for its first parameter.
It accepts the `data` field of the payment session for its first parameter.
You can use this method to interact with the third-party provider to delete data related to the Payment Session if necessary.
@@ -418,18 +435,18 @@ import { PaymentSession } from "@medusajs/medusa"
class MyPaymentService extends AbstractPaymentService {
// ...
async deletePayment(
paymentSession: PaymentSession
): Promise<void> {
return
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
return paymentSessionData
}
}
```
### authorizePayment
This method is used to authorize payment using the Payment Session for an order. This is called when the [cart is completed](/api/store/#tag/Cart/operation/PostCartsCartComplete) and before the order is created.
This method is used to authorize payment using the Payment Session of an order. This is called when the [cart is completed](/api/store/#tag/Cart/operation/PostCartsCartComplete) and before the order is created.
This method is also used for authorizing payments of a swap of an order.
This method is also used for authorizing payments of a swap of an order and when authorizing sessions in a payment collection.
The payment authorization might require additional action from the customer before it is declared authorized. Once that additional action is performed, the `authorizePayment` method will be called again to validate that the payment is now fully authorized. So, you should make sure to implement it for this case as well, if necessary.
@@ -439,16 +456,20 @@ If the payment authorization fails, then an error will be thrown and the order w
:::note
The payment authorization status is determined using the `getStatus` method as mentioned earlier. If the status is `requires_more` then it means additional actions are required from the customer. If the workflow process reaches the “Start Create Order” step and the status is not `authorized`, then the payment is considered failed.
The payment authorization status is determined using the `getPaymentStatus` method as mentioned earlier. If the status is `requires_more` then it means additional actions are required from the customer. If the workflow process reaches the “Start Create Order” step and the status is not `authorized`, then the payment is considered failed.
:::
This method accepts the Payment Session as an object for its first parameter, and a `context` object as a second parameter. The `context` object contains the following properties:
This method accepts the `data` field of a payment session for its first parameter, and a `context` object as a second parameter. The `context` object may contain the following properties:
1. `ip`: The customer’s IP.
2. `idempotency_key`: The [Idempotency Key](../payment.md#idempotency-key) that is associated with the current cart. It is useful when retrying payments, retrying checkout at a failed point, or for payments that require additional actions from the customer.
3. `cart_id`: The ID of a cart. This is only during operations like placing an order or creating a swap.
This method must return an object containing the property `status` which is a string that indicates the current status of the payment, and the property `data` which is an object containing any additional information required to perform additional payment processing such as capturing the payment. The values of both of these properties are stored in the Payment Session’s `status` and `data` fields respectively.
This method must return an object containing the following properties:
- `status` which is a string that indicates the current status of the payment.
- `data` which is an object containing any additional information required to perform additional payment processing such as capturing the payment. The values of both of these properties are stored in the Payment Session’s `status` and `data` fields respectively.
You can utilize this method to interact with the third-party provider and perform any actions necessary to authorize the payment.
@@ -466,12 +487,15 @@ import {
class MyPaymentService extends AbstractPaymentService {
// ...
async authorizePayment(
paymentSession: PaymentSession,
context: Data
): Promise<{
data: PaymentSessionData;
status: PaymentSessionStatus
}> {
paymentSessionData: Record<string, unknown>,
context: Record<string, unknown>
): Promise<
PaymentProcessorError |
{
status: PaymentSessionStatus;
data: Record<string, unknown>;
}
> {
return {
status: PaymentSessionStatus.AUTHORIZED,
data: {
@@ -482,39 +506,15 @@ class MyPaymentService extends AbstractPaymentService {
}
```
### getPaymentData
After the payment is authorized using `authorizePayment`, a Payment instance will be created. The `data` field of the Payment instance will be set to the value returned from the `getPaymentData` method in the Payment Provider.
This method accepts the Payment Session as an object for its first parameter.
This method must return an object to be stored in the `data` field of the Payment instance. You can either use it as-is or make any changes to it if necessary.
An example of a minimal implementation of `getPaymentData`:
```ts
import { Data, PaymentSession } from "@medusajs/medusa"
// ...
class MyPaymentService extends AbstractPaymentService {
// ...
async getPaymentData(
paymentSession: PaymentSession
): Promise<Data> {
return paymentSession.data
}
}
```
### capturePayment
This method is used to capture the payment amount of an order. This is typically triggered manually by the store operator from the admin.
This method is also used for capturing payments of a swap of an order.
This method is also used for capturing payments of a swap of an order, or when the [Capture Payment](/api/admin#tag/Payment/operation/PostPaymentsPaymentCapture) endpoint is called.
You can utilize this method to interact with the third-party provider and perform any actions necessary to capture the payment.
This method accepts the Payment as an object for its first parameter.
This method accepts the `data` field of the Payment for its first parameter.
This method must return an object that will be stored in the `data` field of the Payment.
@@ -538,11 +538,11 @@ class MyPaymentService extends AbstractPaymentService {
This method is used to refund an order’s payment. This is typically triggered manually by the store operator from the admin. The refund amount might be the total order amount or part of it.
This method is also used for refunding payments of a swap of an order.
This method is also used for refunding payments of a swap or a claim of an order, or when the [Refund Payment](/api/admin#tag/Payment/operation/PostPaymentsPaymentRefunds) endpoint is called.
You can utilize this method to interact with the third-party provider and perform any actions necessary to refund the payment.
This method accepts the Payment as an object for its first parameter, and the amount to refund as a second parameter.
This method accepts the `data` field of a Payment for its first parameter, and the amount to refund as a second parameter.
This method must return an object that is stored in the `data` field of the Payment.
@@ -555,9 +555,9 @@ import { Data, Payment } from "@medusajs/medusa"
class MyPaymentService extends AbstractPaymentService {
// ...
async refundPayment(
payment: Payment,
paymentSessionData: Record<string, unknown>,
refundAmount: number
): Promise<Data> {
): Promise<Record<string, unknown> | PaymentProcessorError> {
return {
id: "test",
}
@@ -571,14 +571,11 @@ This method is used to cancel an order’s payment. This method is typically tri
1. Before an order is placed and after the payment is authorized, an inventory check is done on products to ensure that products are still available for purchase. If the inventory check fails for any of the products, the payment is canceled.
2. If the store operator cancels the order from the admin.
This method is also used for canceling payments of a swap of an order.
3. When the payment of an order's swap is canceled.
You can utilize this method to interact with the third-party provider and perform any actions necessary to cancel the payment.
This method accepts the Payment as an object for its first parameter.
This method must return an object that is stored in the `data` field of the Payment.
This method accepts the `data` field of the Payment for its first parameter.
An example of a minimal implementation of `cancelPayment` that doesn’t need to interact with a third-party provider:
@@ -588,7 +585,9 @@ import { Data, Payment } from "@medusajs/medusa"
class MyPaymentService extends AbstractPaymentService {
// ...
async cancelPayment(payment: Payment): Promise<Data> {
async cancelPayment(
paymentSessionData: Record<string, unknown>
): Promise<Record<string, unknown> | PaymentProcessorError> {
return {
id: "test",
}
@@ -598,57 +597,7 @@ class MyPaymentService extends AbstractPaymentService {
---
## Optional Methods
### retrieveSavedMethods
This method can be added to your Payment Provider service if your third-party provider supports saving the customer’s payment methods. Please note that in Medusa there is no way to save payment methods.
This method is called when a request is sent to [Retrieve Saved Payment Methods](/api/store/#tag/Customer/operation/GetCustomersCustomerPaymentMethods).
This method accepts the customer as an object for its first parameter.
This method returns an array of saved payment methods retrieved from the third-party provider. You have the freedom to shape the items in the array as you see fit since they will be returned as-is for the response to the request.
:::note
If you’re using Medusa’s [Next.js](../../../starters/nextjs-medusa-starter.mdx) storefront starter, note that the presentation of this method is not implemented. You’ll need to implement the UI and pages for this method based on your implementation and the provider you are using.
:::
An example of the implementation of `retrieveSavedMethods` taken from Stripe’s Payment Provider:
```ts
import { Customer, Data } from "@medusajs/medusa"
// ...
class MyPaymentService extends AbstractPaymentService {
// ...
/**
* Fetches a customers saved payment methods
* if they're saved in Stripe.
* @param {object} customer - customer to fetch saved cards for
* @return {Promise<Array<object>>} saved payments methods
*/
async retrieveSavedMethods(
customer: Customer
): Promise<Data[]> {
if (customer.metadata && customer.metadata.stripe_id) {
const methods = await this.stripe_.paymentMethods.list({
customer: customer.metadata.stripe_id,
type: "card",
})
return methods.data
}
return Promise.resolve([])
}
}
```
---
## See Also
- Implementation Examples: [Stripe](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-stripe) and [PayPal](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-paypal) payment providers.
- Implementation Examples: [Stripe](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-stripe) and [PayPal](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-paypal) Payment Processors.
- [Implement checkout flow on the storefront](../storefront/implement-checkout-flow.mdx).
@@ -40,7 +40,7 @@ Customers can manage their cart including adding, updating, and removing items f
Developers can integrate any third-party provider or custom logic to offer shipping and payment options for customers during checkout. They can integrate them using existing plugins or by creating their own.
Admins can specify available shipping and payment providers during checkout for customers based on their [Region](../regions-and-currencies/overview.mdx).
Admins can specify available shipping and payment processors during checkout for customers based on their [Region](../regions-and-currencies/overview.mdx).
<DocCardList colSize={4} items={[
{
@@ -55,10 +55,10 @@ Admins can specify available shipping and payment providers during checkout for
{
type: 'link',
href: '/modules/carts-and-checkout/backend/add-payment-provider',
label: 'Backend: Create Payment Provider',
label: 'Backend: Create Payment Processor',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a fulfillment provider in the backend.'
description: 'Learn how to create a payment processor in the backend.'
}
},
{
@@ -8,51 +8,63 @@ In this document, you’ll learn about the payment architecture in Medusa, speci
## Introduction
The payment architecture refers to all operations in an ecommerce store related to processing a customer’s payment. It includes the checkout flow and order handling including refunds and swaps.
The payment architecture refers to all operations in a commerce application related to processing a customer’s payment. It includes the checkout flow and order handling including refunds and swaps.
In Medusa, there are 3 main components in the payment architecture: Payment Provider, Payment Session, and Payment.
In Medusa, there are 3 main components in the payment architecture: Payment Processor, Payment Session, and Payment.
1. A **Payment Provider** is a service or method used to capture, authorize, and refund payments, among other functionalities.
2. A **Payment Session** is a session associated with a cart and created during a customer’s checkout flow. It is controlled by the **Payment Provider** to authorize the payment and is used eventually to create a **Payment**.
:::note
Payment Processors were previously named Payment Provider. With the roll-out of the Payment Processor API following v1.8 of the core Medusa package, Payment Provider is considered a legacy now. However, there are certain entities and services that still use the name Payment Provider as they still don't follow this change.
:::
1. A **Payment Processor** is a service or method used to capture, authorize, and refund payments, among other functionalities.
2. A **Payment Session** is a session associated with a cart and created during a customer’s checkout flow. It is controlled by the **Payment Processor** to authorize the payment and is used eventually to create a **Payment**.
3. A **Payment** is associated with an order and it represents the amount authorized for the purchase. It is used later for further payment operations such as capturing or refunding payments.
An important part in the Payment architecture to understand is the **Idempotency Key**. It’s a unique value that’s generated for a cart and is used to retry payments during checkout if they fail.
---
## Payment Provider
## Payment Processor
A Payment Provider in Medusa is a method to handle payments in selected regions. It is not associated with a cart, customer, or order in particular. It provides the necessary implementation to create Payment Sessions and Payments, as well as authorize and capture payments, among other functionalities.
A Payment Processor in Medusa is a method to handle payments in selected regions. It is not associated with a cart, customer, or order in particular. It provides the necessary implementation to create Payment Sessions and Payments, as well as authorize and capture payments, among other functionalities.
Payment Providers can be integrated with third-party services that handle payment operations such as capturing a payment. An example of a Payment Provider is Stripe.
Payment Processors can be integrated with third-party services that handle payment operations such as capturing a payment. An example of a Payment Processor is Stripe.
Payment Providers can also be related to a custom way of handling payment operations. An example of that is Cash on Delivery (COD) payment methods or Medusa’s [manual payment provider plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-manual) which provides a minimal implementation of a payment provider and allows store operators to manually handle order payments.
Payment Processors can also be related to a custom way of handling payment operations. An example of that is Cash on Delivery (COD) payment methods or Medusa’s [manual payment provider plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-manual) which provides a minimal implementation of a payment provider and allows store operators to manually handle order payments.
### How Payment Provider is Created
:::tip
A Payment Provider is essentially a Medusa [service](../../development/services/create-service.md) with a unique identifier, and it extends the ``AbstractPaymentService` from the core Medusa package `@medusajs/medusa`. It can be created as part of a [plugin](../../development/plugins/overview.mdx), or it can be created just as a service file in your Medusa backend.
The manual payment plugin is still considered a payment provider since it does not follow the Payment Processor API introduced in v1.8 of the core Medusa package.
As a developer, you will mainly work with the Payment Provider when integrating a payment method in Medusa.
:::
When you run your Medusa backend, the Payment Provider will be registered on your backend if it hasn’t been already.
### How Payment Processor is Created
Once the Payment Provider is added to the backend, the store operator will be able to choose on the [Medusa Admin](../../admin/quickstart.mdx) the payment providers available in a region. These payment providers are shown to the customer at checkout to choose from and use.
A Payment Processor is essentially a Medusa [service](../../development/services/create-service.md) with a unique identifier, and it extends the `AbstractPaymentProcessor` from the core Medusa package `@medusajs/medusa`. You can create it as part of a [plugin](../../development/plugins/overview.mdx), or just as a service file in your Medusa backend.
As a developer, you will mainly work with the Payment Processor when integrating a payment method in Medusa.
When you run your Medusa backend, the Payment Processor will be registered on your backend if it hasn’t been already.
Once the Payment Processor is added to the backend, the store operator will be able to choose using the [admin dashboard](../../admin/quickstart.mdx) the payment processors available in a region. You can alternatively do that using the [admin APIs](/api/admin). These payment processors are shown to the customer at checkout as payment methods to choose from and use.
:::caution
It’s important to choose a payment provider in the list of payment providers in a region, or else the payment provider cannot be used by customers on checkout.
It’s important to enable a payment processor in a region, or else the payment processor cannot be used by customers on checkout.
:::
### PaymentProvider Entity Overview
The [`PaymentProvider`](../../references/entities/classes/PaymentProvider.md) entity only has 2 attributes: `is_installed` to indicate if the payment provider is installed and its value is a boolean; and `id` which is the unique identifier that you define in the Payment Provider service.
The [`PaymentProvider`](../../references/entities/classes/PaymentProvider.md) entity only has 2 attributes: `is_installed` which is a boolean value indicating whether the Payment Processor is installed; and `id` which is the unique identifier that you define in the Payment Processor service.
---
## Payment Session
Payment Sessions are linked to a customer’s cart. Each Payment Session is associated with a payment provider that is available in the customer cart’s region.
Payment Sessions are linked to a customer’s cart. Each Payment Session is associated with a payment processor that is available in the customer cart’s region.
They hold the status of the payment flow throughout the checkout process which can be used to indicate different statuses such as an authorized payment or payment that requires more actions from the customer.
@@ -60,30 +72,30 @@ After the checkout process is completed and the Payment Session has been authori
### How Payment Session is Created
After the customer adds products to the cart, proceeds with the checkout flow, and reaches the payment method section, Payment Sessions are created for each Payment Provider available in that region.
After the customer adds products to the cart, proceeds with the checkout flow, and reaches the payment method section, Payment Sessions are created for each Payment Processor available in that region.
During the creation of the Payment Session, the Payment Provider can interact with third-party services for any initialization necessary on their side. For example, when a Payment Session for Stripe is being created, a payment intent associated with the customer can be created with Stripe as well.
During the creation of the Payment Session, the Payment Processor can interact with third-party services for any initialization necessary on their side. For example, when a Payment Session for Stripe is being created, a payment intent associated with the customer is created with Stripe as well.
Payment Sessions can hold data that is necessary for the customer to complete their payment.
Among the Payment Sessions available only one will be selected based on the customer’s payment provider choice. For example, if the customer sees that they can pay with Stripe or PayPal and chooses Stripe, Stripe’s Payment Session will be the selected Payment Session of that cart.
Among the Payment Sessions available only one will be selected based on the customer’s payment processor of choice. For example, if the customer sees that they can pay with Stripe or PayPal and chooses Stripe, Stripe’s Payment Session will be the selected Payment Session of that cart.
### PaymentSession Entity Overview
The [`PaymentSession`](../../references/entities/classes/PaymentSession.md) entity belongs to a `Cart`. This is the customer‘s cart that was used for checkout which lead to the creation of the Payment Session.
The `PaymentSession` also belongs to a `PaymentProvider`. This is the Payment Provider that was used to create the Payment Session and that controls it for further actions like authorizing the payment.
The `PaymentSession` instance also belongs to a `PaymentProvider` instance. This is the Payment Processor that was used to create the Payment Session and that controls it for further actions like authorizing the payment.
The `data` attribute is an object that holds any data required for the Payment Provider to perform payment operations like authorizing or capturing payment. For example, when a Stripe payment session is initialized, the `data` object will hold the payment intent among other data necessary to authorize the payment.
The `data` attribute is an object that holds any data required for the Payment Processor to perform payment operations like authorizing or capturing payment. For example, when a Stripe payment session is initialized, the `data` object will hold the payment intent among other data necessary to authorize the payment.
The `is_selected` attribute in the `PaymentSession` entity is a boolean value that indicates whether this Payment Session was selected by the customer to pay for their purchase. Going back to the previous example of having Stripe and PayPal as the available Payment Providers, when the customer chooses Stripe, Stripe’s Payment Session will have `is_selected` set to true whereas PayPal’s Payment Session will have `is_selected` set to false.
The `is_selected` attribute in the `PaymentSession` entity is a boolean value that indicates whether this Payment Session was selected by the customer to pay for their purchase. Going back to the previous example of having Stripe and PayPal as the available Payment Processors, when the customer chooses Stripe, Stripe’s Payment Session will have `is_selected` set to true whereas PayPal’s Payment Session will have `is_selected` set to false.
The `status` attributes indicates the current status of the Payment Session. It can be one of the following values:
- `authorized`: The payment has been authorized which means the order can be placed successfully.
- `pending`: The payment is still pending further actions. This is usually used when the payment session is initialized.
- `requires_more`: The payment requires additional actions from the customer before the payment can be authorized successfully and the order can be placed. An example of this is payment methods that require 3-D Secure checks.
- `error`: An error was encountered when an authorization was attempted. This status is usually used when an error has been encountered when authorizing the payment with a third-party payment provider.
- `error`: An error was encountered when an authorization was attempted. This status is usually used when an error has been encountered when authorizing the payment with a third-party payment processor.
- `canceled`: The payment has been canceled.
These statuses are important in the checkout flow to determine the current step the customer is at and which action should come next. For example, if there is an attempt to place the order but the status of the Payment Session is not `authorized`, an error will be thrown.
@@ -100,11 +112,11 @@ Payments are generally created using data from the Payment Session and it holds
Once the customer completes their purchase and the payment has been authorized, a Payment instance will be created from the Payment Session. The Payment is associated first with the cart and then with the order once it’s created and placed.
When the store operator then chooses to capture the order from the Medusa Admin, the Payment is used by the Payment Provider to capture the payment. This is the same case for refunding the amount, canceling the order, or creating a swap.
When the store operator then chooses to capture the order from the Medusa Admin, the Payment is used by the Payment Processor to capture the payment. This is the same case for refunding the amount, canceling the order, or creating a swap.
### Payment Entity Overview
The [`Payment`](../../references/entities/classes/Payment.md) entity belongs to the `Cart` that it was originally created from when the customer’s payment was authorized. It also belongs to an `Order` once it’s placed. Additionally, it belongs to a `PaymentProvider` which is the payment provider that the customer chose on checkout.
The [`Payment`](../../references/entities/classes/Payment.md) entity belongs to the `Cart` that it was originally created from when the customer’s payment was authorized. It also belongs to an `Order` once it’s placed. Additionally, it belongs to a `PaymentProvider` which is the payment processor that the customer chose on checkout.
In case a `Swap` is created for an order, `Payment` will be associated with that swap to handle payment operations related to it.
@@ -135,4 +147,4 @@ This prevents any payment issues from occurring with the customers and allows fo
## See Also
- [Available Payment Plugins](../../plugins/payment/index.mdx)
- [Create a Payment Provider](./backend/add-payment-provider.md)
- [Create a Payment Processor](./backend/add-payment-provider.md)
@@ -8,13 +8,13 @@ import TabItem from '@theme/TabItem';
# How to Implement Checkout Flow
This document will guide you through the steps needed to implement the checkout flow in a Medusa storefront, including steps related to adding a custom payment provider.
This document will guide you through the steps needed to implement the checkout flow in a Medusa storefront, including steps related to adding a custom payment processor.
## Overview
A checkout flow is composed of the necessary steps to allow a customer to perform a successful checkout. It’s generally made up of two primary steps: the shipping and payment steps.
This document will take you through the general process of a checkout flow. You should follow along with this document if you’re creating a custom storefront, if you’re adding a custom payment provider, or if you’re just interested in learning more about how checkout works in Medusa.
This document will take you through the general process of a checkout flow. You should follow along with this document if you’re creating a custom storefront, if you’re adding a custom payment processor, or if you’re just interested in learning more about how checkout works in Medusa.
:::note
@@ -88,7 +88,7 @@ medusa.carts.update(cartId, {
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
```ts
import { useCart } from "medusa-react"
const Cart = () => {
@@ -252,7 +252,7 @@ medusa.carts.addShippingMethod(cartId, {
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
```ts
import { useAddShippingMethodToCart } from "medusa-react"
// ...
@@ -303,11 +303,11 @@ It returns the updated cart, with the created shipping method available in the a
## Payment Step
In this step, the customer generally chooses a payment method to complete their purchase. The implementation of payment providers is done differently for each provider, so this section will just show the general steps you should follow when implementing this step.
In this step, the customer generally chooses a payment method to complete their purchase. The implementation of payment processors is done differently for each processor, so this section will just show the general steps you should follow when implementing this step.
### Initialize Payment Sessions
### Display Payment Methods
When the page opens and before the payment providers are displayed to the customer to choose from, you must initialize the [payment sessions](../payment.md#payment-session) for the current cart. Each payment provider will have a payment session associated with it. These payment sessions will be used later when the customer chooses the payment provider they want to complete their purchase with.
When the page opens and before the payment providers are displayed to the customer to choose from, you must create the [payment sessions](../payment.md#payment-session) for the current cart. Each payment provider will have a payment session associated with it. These payment sessions will be used later when the customer chooses the payment provider they want to complete their purchase with.
To initialize the payment sessions, send a `POST` request to the [Initialize Payment Sessions](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessions) API endpoint:
@@ -339,7 +339,7 @@ const PaymentProviders = () => {
return (
<div>
{!cart?.payment_sessions.length && (
<span>No payment providers</span>
<span>No payment processors</span>
)}
<ul>
{cart?.payment_sessions.map(
@@ -378,7 +378,7 @@ This endpoint accepts the ID of the cart as a path parameter. It returns the upd
### Select Payment Session
When the customer chooses the payment provider they want to complete purchase with, you should select the payment session associated with that payment provider. To do that, send a `POST` request to the [Select a Payment Session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession) API endpoint:
When the customer chooses the payment processor they want to complete purchase with, you should select the payment session associated with that payment processor. To do that, send a `POST` request to the [Select a Payment Session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession) API endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
@@ -396,7 +396,7 @@ medusa.carts.setPaymentSession(cartId, {
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
```ts
import { useCart } from "medusa-react"
const PaymentProviders = () => {
@@ -439,19 +439,19 @@ fetch(`<BACKEND_URL>/store/carts/${cartId}/payment-session`, {
</TabItem>
</Tabs>
The request accepts the ID of the cart as a path parameter, and the ID of the payment provider in the request's body.
The request accepts the ID of the cart as a path parameter, and the ID of the payment processor in the request's body.
It returns the updated cart, with the selected payment session available under `cart.payment_session`.
:::tip
If you have one payment provider or if only one payment provider is available for the current cart, its payment session will be automatically selected in the “[Initialize Payment Session](#initialize-payment-sessions)” step and this step becomes unnecessary. You can check whether there is a payment session selected or not by checking whether `cart.payment_session` is `null` or not.
If you have one payment processor or if only one payment processor is available for the current cart, its payment session will be automatically selected in the “[Initialize Payment Session](#initialize-payment-sessions)” step and this step becomes unnecessary. You can check whether there is a payment session selected or not by checking whether `cart.payment_session` is `null` or not.
:::
### Update Payment Session
This step is optional and is only necessary for some payment providers. As mentioned in the [Payment Architecture](../payment.md#overview) documentation, the `PaymentSession` model has a `data` attribute that holds any data required for the Payment Provider to perform payment operations such as capturing payment.
This step is optional and is only necessary for some payment processors. As mentioned in the [Payment Architecture](../payment.md#overview) documentation, the `PaymentSession` model has a `data` attribute that holds any data required for the Payment Processor to perform payment operations such as capturing payment.
If you need to update that data at any point before the purchase is made, send a request to [Update a Payment Session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessionUpdate) API endpoint:
@@ -474,7 +474,7 @@ medusa.carts.updatePaymentSession(cartId, paymentProviderId, {
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
```ts
import { useUpdatePaymentSession, useCart } from "medusa-react"
// ...
@@ -531,13 +531,13 @@ fetch(
</TabItem>
</Tabs>
This request accepts the ID of the cart and the ID of the payment session's payment provider as path parameters. In the request's body, it accepts a `data` object where you can pass any data relevant for the payment provider.
This request accepts the ID of the cart and the ID of the payment session's payment processor as path parameters. In the request's body, it accepts a `data` object where you can pass any data relevant for the payment processor.
It returns the updated cart. You can access the payment session's data on `cart.payment_session.data`.
### Complete Cart
The last step is to place the order by completing the cart. When you complete the cart, your Medusa backend will try to authorize the payment first, then place the order if the authorization is successful. So, you should perform any necessary action with your payment provider first to make sure the authorization is successful when you send the request to complete the cart.
The last step is to place the order by completing the cart. When you complete the cart, your Medusa backend will try to authorize the payment first, then place the order if the authorization is successful. So, you should perform any necessary action with your payment processor first to make sure the authorization is successful when you send the request to complete the cart.
To complete a cart, send a `POST` request to the [Complete a Cart](/api/store/#tag/Cart/operation/PostCartsCartComplete) API endpoint:
@@ -554,7 +554,7 @@ medusa.carts.complete(cartId)
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
```ts
import { useCart } from "medusa-react"
// ...