docs: publish restructure (#3496)
* docs: added features and guides overview page * added image * added version 2 * added version 3 * added version 4 * docs: implemented new color scheme * docs: redesigned sidebar (#3193) * docs: redesigned navbar for restructure (#3199) * docs: redesigned footer (#3209) * docs: redesigned cards (#3230) * docs: redesigned admonitions (#3231) * docs: redesign announcement bar (#3236) * docs: redesigned large cards (#3239) * docs: redesigned code blocks (#3253) * docs: redesigned search modal and page (#3264) * docs: redesigned doc footer (#3268) * docs: added new sidebars + refactored css and assets (#3279) * docs: redesigned api reference sidebar * docs: refactored css * docs: added code tabs transition * docs: added new sidebars * removed unused assets * remove unusued assets * Fix deploy errors * fix incorrect link * docs: fixed code responsivity + missing icons (#3283) * docs: changed icons (#3296) * docs: design fixes to the sidebar (#3297) * redesign fixes * docs: small design fixes * docs: several design fixes after restructure (#3299) * docs: bordered icon fixes * docs: desgin fixes * fixes to code blocks and sidebar scroll * design adjustments * docs: restructured homepage (#3305) * docs: restructured homepage * design fixes * fixed core concepts icon * docs: added core concepts page (#3318) * docs: restructured homepage * design fixes * docs: added core concepts page * changed text of different components * docs: added architecture link * added missing prop for user guide * docs: added regions overview page (#3327) * docs: added regions overview * moved region pages to new structure * docs: fixed description of regions architecture page * small changes * small fix * docs: added customers overview page (#3331) * docs: added regions overview * moved region pages to new structure * docs: fixed description of regions architecture page * small changes * small fix * docs: added customers overview page * fix link * resolve link issues * docs: updated regions architecture image * docs: second-iteration fixes (#3347) * docs: redesigned document * design fixes * docs: added products overview page (#3354) * docs: added carts overview page (#3363) * docs: added orders overview (#3364) * docs: added orders overview * added links in overview * docs: added vercel redirects * docs: added soon badge for cards (#3389) * docs: resolved feedback changes + organized troubleshooting pages (#3409) * docs: resolved feedback changes * added extra line * docs: changed icons for restructure (#3421) * docs: added taxes overview page (#3422) * docs: added taxes overview page * docs: fix sidebar label * added link to taxes overview page * fixed link * docs: fixed sidebar scroll (#3429) * docs: added discounts overview (#3432) * docs: added discounts overview * fixed links * docs: added gift cards overview (#3433) * docs: added price lists overview page (#3440) * docs: added price lists overview page * fixed links * docs: added sales channels overview page (#3441) * docs: added sales overview page * fixed links * docs: added users overview (#3443) * docs: fixed sidebar border height (#3444) * docs: fixed sidebar border height * fixed svg markup * docs: added possible solutions to feedback component (#3449) * docs: added several overview pages + restructured files (#3463) * docs: added several overview pages * fixed links * docs: added feature flags + PAK overview pages (#3464) * docs: added feature flags + PAK overview pages * fixed links * fix link * fix link * fixed links colors * docs: added strategies overview page (#3468) * docs: automated upgrade guide (#3470) * docs: automated upgrade guide * fixed vercel redirect * docs: restructured files in docs codebase (#3475) * docs: restructured files * docs: fixed eslint exception * docs: finished restructure loose-ends (#3493) * fixed uses of backend * docs: finished loose ends * eslint fixes * fixed links * merged master * added update instructions for v1.7.12
This commit is contained in:
5
docs/content/plugins/payment/index.mdx
Normal file
5
docs/content/plugins/payment/index.mdx
Normal file
@@ -0,0 +1,5 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
# Payment Plugins
|
||||
|
||||
<DocCardList />
|
||||
93
docs/content/plugins/payment/klarna.md
Normal file
93
docs/content/plugins/payment/klarna.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
description: 'Learn how to integrate Klarna as a payment provider with the Medusa backend. Learn how to install Klarna and enable the payment provider in a region.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# Klarna
|
||||
|
||||
In this document, you’ll learn how to integrate Klarna as a payment provider in Medusa.
|
||||
|
||||
## Introduction
|
||||
|
||||
[Klarna](https://www.klarna.com/) is a payment provider that allows customers to pay in different ways including direct payment, installment payments, payment after delivery, and more.
|
||||
|
||||
You can integrate Klarna into Medusa using the [official plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-klarna).
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../development/backend/install.mdx).
|
||||
|
||||
In addition, you’ll need to use the [Medusa Admin](../../admin/quickstart.mdx) to enable the payment provider in later steps. You can alternatively use the [REST APIs](/api/admin/#tag/Region/operation/PostRegionsRegionPaymentProviders).
|
||||
|
||||
### Needed Accounts
|
||||
|
||||
- A [Klarna business account](https://portal.klarna.com/)
|
||||
|
||||
---
|
||||
|
||||
## Install Plugin
|
||||
|
||||
On your Medusa backend, run the following command to install the plugin:
|
||||
|
||||
```bash
|
||||
npm install medusa-payment-klarna
|
||||
```
|
||||
|
||||
Then, add the following environment variables:
|
||||
|
||||
```bash
|
||||
KLARNA_BACKEND_URL=<YOUR_KLARNA_BACKEND_URL>
|
||||
KLARNA_URL=<YOUR_KLARNA_URL>
|
||||
KLARNA_USER=<YOUR_KLARNA_USER>
|
||||
KLARNA_PASSWORD=<YOUR_KLARNA_PASSWORD>
|
||||
KLARNA_TERMS_URL=<YOUR_KLARNA_TERMS_URL>
|
||||
KLARNA_CHECKOUT_URL=<YOUR_KLARNA_CHECKOUT_URL>
|
||||
KLARNA_CONFIRMATION_URL=<YOUR_KLARNA_CONFIRMATION_URL>
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `<YOUR_KLARNA_BACKEND_URL>` is your Klarna URL.
|
||||
- `<YOUR_KLARNA_URL>` is the [base Klarna URL based on your environment](https://docs.klarna.com/api/api-urls/).
|
||||
- `<YOUR_KLARNA_USER>` and `<YOUR_KLARNA_PASSWORD>` are your [API credentials](https://docs.klarna.com/api/authentication/).
|
||||
- `<YOUR_KLARNA_TERMS_URL>`, `<YOUR_KLARNA_CHECKOUT_URL>`, and `<YOUR_KLARNA_CONFIRMATION_URL>` are the terms, checkout, and confirmation URL of your Klarna account.
|
||||
|
||||
Finally, in `medusa-config.js`, add the Klarna plugin to the `plugins` array with the necessary configurations:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
// other plugins...
|
||||
{
|
||||
resolve: `medusa-payment-klarnal`,
|
||||
options: {
|
||||
backend_url: process.env.KLARNA_BACKEND_URL,
|
||||
url: process.env.KLARNA_URL,
|
||||
user: process.env.KLARNA_USER,
|
||||
password: process.env.KLARNA_PASSWORD,
|
||||
merchant_urls: {
|
||||
terms: process.env.KLARNA_TERMS_URL,
|
||||
checkout: process.env.KLARNA_CHECKOUT_URL,
|
||||
confirmation: process.env.KLARNA_CONFIRMATION_URL,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enable Klarna in Regions
|
||||
|
||||
To use Klarna in your store, you must enable it in at least one region.
|
||||
|
||||
You can follow [this user guide to learn how to enable a payment provider in a region](../../user-guide/regions/providers#manage-payment-providers). You can alternatively use the [REST APIs](/api/admin/#tag/Region/operation/PostRegionsRegionPaymentProviders).
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- Check out [more plugins](../overview.mdx) you can add to your store.
|
||||
438
docs/content/plugins/payment/paypal.md
Normal file
438
docs/content/plugins/payment/paypal.md
Normal file
@@ -0,0 +1,438 @@
|
||||
---
|
||||
description: 'Learn how to integrate PayPal with the Medusa backend. Learn how to install the PayPal plugin on the Medusa backend and integrate into a storefront.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# PayPal
|
||||
|
||||
This document guides you through setting up PayPal as a payment provider in your Medusa backend, admin, and storefront using the [PayPal plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-paypal).
|
||||
|
||||
## Overview
|
||||
|
||||
[PayPal](https://www.paypal.com) is a payment provider used by millions around the world. It allows customers to purchase orders from your website using their PayPal account rather than the need to enter their card details.
|
||||
|
||||
As a developer, you can use PayPal’s SDKs and APIs to integrate PayPal as a payment method into your ecommerce store. You can test out the payment method in sandbox mode before going live with it as a payment method.
|
||||
|
||||
Using the `medusa-payment-paypal` plugin, this guide shows you how to set up your Medusa backend with PayPal as a payment provider.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you proceed with this guide, make sure you create a [PayPal account](https://www.paypal.com). You also need a PayPal Developer account and retrieve the Client ID and Client Secret. You can learn more about how to do that in [PayPal’s documentation](https://developer.paypal.com/api/rest/).
|
||||
|
||||
In addition, you need to configure a webhook listener on your PayPal Developer Dashboard and obtain the webhook ID. This is necessary for Webhooks to work.
|
||||
|
||||
Webhooks are used in scenarios where the customer might leave the page during the authorization and before the checkout flow is fully complete. It will then create the order or swap after the payment is authorized if they weren’t created
|
||||
|
||||
Additionally, you need a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../development/backend/install.mdx) to get started.
|
||||
|
||||
You also need [Medusa Admin](../../admin/quickstart.mdx) installed to enable PayPal as a payment provider. You can alternatively use the [REST APIs](/api/admin).
|
||||
|
||||
---
|
||||
|
||||
## Medusa Backend
|
||||
|
||||
### Install the PayPal Plugin
|
||||
|
||||
In the root of your Medusa backend, run the following command to install the PayPal plugin:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install medusa-payment-paypal
|
||||
```
|
||||
|
||||
### Configure the PayPal Plugin
|
||||
|
||||
Next, you need to add configurations for your PayPal plugin.
|
||||
|
||||
In the `.env` file add the following new environment variables:
|
||||
|
||||
```bash
|
||||
PAYPAL_SANDBOX=true
|
||||
PAYPAL_CLIENT_ID=<CLIENT_ID>
|
||||
PAYPAL_CLIENT_SECRET=<CLIENT_SECRET>
|
||||
PAYPAL_AUTH_WEBHOOK_ID=<WEBHOOK_ID>
|
||||
```
|
||||
|
||||
Where `<CLIENT_ID>`, `<CLIENT_SECRET>`, and `<WEBHOOK_ID>` are the keys you retrieved from the PayPal Developer dashboard as explained in the [Prerequisites](#prerequisites) section.
|
||||
|
||||
Notice that during development it’s highly recommended to set `PAYPAL_SANDBOX` to `true` and ensure you have [sandbox accounts set up in PayPal](https://developer.paypal.com/api/rest/sandbox/).
|
||||
|
||||
Then, in `medusa-config.js`, add the PayPal plugin to the `plugins` array with the configurations necessary:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
// other plugins...
|
||||
{
|
||||
resolve: `medusa-payment-paypal`,
|
||||
options: {
|
||||
sandbox: process.env.PAYPAL_SANDBOX,
|
||||
client_id: process.env.PAYPAL_CLIENT_ID,
|
||||
client_secret: process.env.PAYPAL_CLIENT_SECRET,
|
||||
auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
That’s all you need to install PayPal on your Medusa backend!
|
||||
|
||||
---
|
||||
|
||||
## Admin Setup
|
||||
|
||||
This section will guide you through adding PayPal as a payment provider in a region using your Medusa admin dashboard.
|
||||
|
||||
This step is required for you to be able to use PayPal as a payment provider in your storefront.
|
||||
|
||||
### Admin Prerequisites
|
||||
|
||||
If you don’t have a Medusa admin installed, make sure to follow along with [the guide on how to install it](../../admin/quickstart.mdx) before continuing with this section.
|
||||
|
||||
### Add PayPal to Regions
|
||||
|
||||
You can refer to [this documentation in the user guide](../../user-guide/regions/providers.mdx#manage-payment-providers) to learn how to add a payment provider like PayPal to a region.
|
||||
|
||||
---
|
||||
|
||||
## Storefront Setup
|
||||
|
||||
This section will take you through the steps to add PayPal as a payment method on the storefront. It includes the steps necessary when using one of Medusa’s official storefronts as well as your own custom React-based storefront.
|
||||
|
||||
### Storefront Prerequisites
|
||||
|
||||
All storefronts require that you obtain your PayPal Client ID. You can retrieve it from your PayPal developer dashboard.
|
||||
|
||||
### Process Overview
|
||||
|
||||
Aside from the Next.js Storefront, you need to add the implementation with PayPal manually.
|
||||
|
||||
:::note
|
||||
|
||||
It is recommended to read through the [Frontend Checkout Flow](../../modules/carts-and-checkout/storefront/implement-checkout-flow.mdx) first to fully understand how payment is implemented on the storefront.
|
||||
|
||||
:::
|
||||
|
||||
Although the next sections have different implementations to add PayPal into your storefront, they essentially follow the same process:
|
||||
|
||||
1. Show PayPal’s button if the PayPal provider is available for the current cart.
|
||||
2. When the button is clicked, open PayPal’s payment portal and wait for the customer to authorize the payment.
|
||||
3. If the payment is authorized successfully, set PayPal’s [Payment Session](../../modules/carts-and-checkout/payment.md#payment-session) as the session used to perform the payment for the current cart, then update the Payment Session on the backend with the data received from PayPal’s payment portal. This data is essential to the backend to verify the authorization and perform additional payment processing later such as capturing payment.
|
||||
4. Complete the cart to create the order.
|
||||
|
||||
:::info
|
||||
|
||||
In Medusa, by default, payments are authorized during checkout, but the payment is not captured right away. The payment should be manually [captured from the Medusa Admin](#capture-payment).
|
||||
|
||||
:::
|
||||
|
||||
### Add to Next.js Storefront
|
||||
|
||||
Medusa has a Next.js storefront that you can easily use with your Medusa backend. If you don’t have the storefront installed, you can follow [this quickstart guide](../../starters/nextjs-medusa-starter.mdx).
|
||||
|
||||
In your `.env.local` file (or the file you’re using for your environment variables), add the following variable:
|
||||
|
||||
```bash title=.env.local
|
||||
NEXT_PUBLIC_PAYPAL_CLIENT_ID=<YOUR_CLIENT_ID>
|
||||
```
|
||||
|
||||
Make sure to replace `<YOUR_CLIENT_ID>` with your PayPal Client ID.
|
||||
|
||||
Now, if you run your Medusa backend and your storefront, on checkout you’ll be able to use PayPal].
|
||||
|
||||

|
||||
|
||||
You can test out the payment with PayPal using your sandbox account.
|
||||
|
||||
### Add to Gatsby Storefront
|
||||
|
||||
Medusa also has a Gatsby storefront that you can use as your ecommerce storefront. If you don’t have the storefront installed, you can follow [this quickstart guide](../../starters/gatsby-medusa-starter.mdx).
|
||||
|
||||
In your `.env.development` file (or the file you’re using for your environment variables) add the following variable with its value set to the Client ID:
|
||||
|
||||
```bash title=.env.development
|
||||
GATSBY_PAYPAL_CLIENT_ID=<CLIENT_ID>
|
||||
```
|
||||
|
||||
Then, install [PayPal’s React components](https://www.npmjs.com/package/@paypal/react-paypal-js) library:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @paypal/react-paypal-js
|
||||
```
|
||||
|
||||
Next, create a new file `src/components/payment/paypal-payment/index.jsx` with the following content:
|
||||
|
||||
```jsx title=src/components/payment/paypal-payment/index.jsx
|
||||
import {
|
||||
PayPalButtons,
|
||||
PayPalScriptProvider,
|
||||
} from "@paypal/react-paypal-js"
|
||||
import React, { useMemo, useState } from "react"
|
||||
|
||||
import { navigate } from "gatsby"
|
||||
import { useCart } from "../../../hooks/use-cart"
|
||||
import { useMedusa } from "../../../hooks/use-medusa"
|
||||
|
||||
const paypalClientId = process.env.GATSBY_PAYPAL_CLIENT_ID || ""
|
||||
|
||||
const PaypalPayment = () => {
|
||||
const {
|
||||
cart,
|
||||
actions: { completeCart, setPaymentSession },
|
||||
} = useCart()
|
||||
const [errorMessage, setErrorMessage] = useState(undefined)
|
||||
const [processing, setProcessing] = useState(false)
|
||||
|
||||
const client = useMedusa()
|
||||
|
||||
const paypalSession = useMemo(() => {
|
||||
if (cart.payment_sessions) {
|
||||
return cart.payment_sessions.find(
|
||||
(s) => s.provider_id === "paypal"
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}, [cart.payment_sessions])
|
||||
|
||||
if (!paypalSession) {
|
||||
return null
|
||||
}
|
||||
|
||||
const completeOrder = async (authorizationOrder) => {
|
||||
const cart = await setPaymentSession("paypal")
|
||||
|
||||
if (!cart) {
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
await client.carts.updatePaymentSession(cart.id, "paypal", {
|
||||
data: {
|
||||
data: {
|
||||
...authorizationOrder,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const order = await completeCart(cart.id)
|
||||
|
||||
if (!order || order.object !== "order") {
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
setProcessing(false)
|
||||
navigate("/order-confirmed", { state: { order } })
|
||||
}
|
||||
|
||||
const handlePayment = (data, actions) => {
|
||||
actions.order.authorize().then((authorization) => {
|
||||
if (authorization.status !== "COMPLETED") {
|
||||
setErrorMessage(
|
||||
`An error occurred, status: ${authorization.status}`
|
||||
)
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
completeOrder(authorization)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<PayPalScriptProvider options={{
|
||||
"client-id": paypalClientId,
|
||||
"currency": cart.region.currency_code.toUpperCase(),
|
||||
"intent": "authorize",
|
||||
}}>
|
||||
{errorMessage && (
|
||||
<span className="text-rose-500 mt-4">
|
||||
{errorMessage}
|
||||
</span>
|
||||
)}
|
||||
<PayPalButtons
|
||||
style={{ layout: "horizontal" }}
|
||||
onApprove={handlePayment}
|
||||
disabled={processing}
|
||||
/>
|
||||
</PayPalScriptProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaypalPayment
|
||||
```
|
||||
|
||||
Here’s briefly what this code snippet does:
|
||||
|
||||
1. This component renders a PayPal button to initialize the payment using PayPal. You use the components from the PayPal React components library to render the button and you pass the `PayPalScriptProvider` component the Client ID.
|
||||
2. When the button is clicked, the `handlePayment` function is executed. In this method, you initialize the payment authorization using `actions.order.authorize()`. It takes the customer to another page to log in with PayPal and authorize the payment.
|
||||
3. After the payment is authorized successfully on PayPal’s portal, the fulfillment function passed to `actions.order.authorize().then` will be executed which calls the `completeOrder` function.
|
||||
4. In `completeOrder`, you first ensure that the payment session for the PayPal payment provider is set as the [selected Payment Session in the cart](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession). Then, you send a request to the backend to [update the payment session](/api/store#tag/Cart/operation/PostCartsCartPaymentSessionUpdate) data with the authorization data received from PayPal.
|
||||
5. You then [complete the cart and place the order](/api/store/#tag/Cart/operation/PostCartsCartComplete). If that is done successfully, you navigate to the `/order-confirmed` page.
|
||||
|
||||
The last step is to add this component as the component to render when PayPal is available as a payment provider.
|
||||
|
||||
In `src/components/payment/index.js` you’ll find in the return statement a switch statement that checks the payment provider for each payment session and renders the component based on the ID. Add before the `default` case a case for `paypal`:
|
||||
|
||||
```jsx title=src/components/payment/index.js
|
||||
switch (ps.provider_id) {
|
||||
case "stripe":
|
||||
// ...
|
||||
break
|
||||
case "manual":
|
||||
// ...
|
||||
break
|
||||
case "paypal":
|
||||
return <PaypalPayment />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
```
|
||||
|
||||
Make sure to also import the `PayPalPayment` component at the top of the file:
|
||||
|
||||
```jsx
|
||||
import PaypalPayment from "./paypal-payment"
|
||||
```
|
||||
|
||||
That’s all you need to integrate PayPal into the Gatsby storefront.
|
||||
|
||||
Now, start the Medusa backend and the Gatsby storefront backend. Try adding an item into the cart and proceeding to checkout. When you reach the payment step, you should see the PayPal button.
|
||||
|
||||

|
||||
|
||||
You can test out the payment with PayPal using your sandbox account.
|
||||
|
||||
### Add to Custom Storefront
|
||||
|
||||
This section guides you to add PayPal into a React-based framework. The instructions are general instructions that you can use in your storefront.
|
||||
|
||||
In your storefront, you need to install the [PayPal React components library](https://www.npmjs.com/package/@paypal/react-paypal-js) and the [Medusa JS Client library](https://www.npmjs.com/package/@medusajs/medusa-js):
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @paypal/react-paypal-js @medusajs/medusa-js
|
||||
```
|
||||
|
||||
Then, add the Client ID as an environment variable based on the framework you’re using.
|
||||
|
||||
Next, create the file that will hold the PayPal component with the following content:
|
||||
|
||||
```jsx
|
||||
import {
|
||||
PayPalButtons,
|
||||
PayPalScriptProvider,
|
||||
} from "@paypal/react-paypal-js"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
function Paypal() {
|
||||
const client = new Medusa()
|
||||
const [errorMessage, setErrorMessage] = useState(undefined)
|
||||
const [processing, setProcessing] = useState(false)
|
||||
const cart = "..." // TODO retrieve the cart here
|
||||
|
||||
const handlePayment = (data, actions) => {
|
||||
actions.order.authorize().then(async (authorization) => {
|
||||
if (authorization.status !== "COMPLETED") {
|
||||
setErrorMessage(
|
||||
`An error occurred, status: ${authorization.status}`
|
||||
)
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
const response = await client
|
||||
.carts
|
||||
.setPaymentSession(cart.id, {
|
||||
"provider_id": "paypal",
|
||||
})
|
||||
|
||||
if (!response.cart) {
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
await client
|
||||
.carts
|
||||
.updatePaymentSession(cart.id, "paypal", {
|
||||
data: {
|
||||
data: {
|
||||
...authorization,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const { data } = await client.carts.complete(cart.id)
|
||||
|
||||
if (!data || data.object !== "order") {
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
// order successful
|
||||
alert("success")
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "10px", marginLeft: "10px" }}>
|
||||
{cart !== undefined && (
|
||||
<PayPalScriptProvider options={{
|
||||
"client-id": "<CLIENT_ID>",
|
||||
"currency": "EUR",
|
||||
"intent": "authorize",
|
||||
}}>
|
||||
{errorMessage && (
|
||||
<span className="text-rose-500 mt-4">
|
||||
{errorMessage}
|
||||
</span>
|
||||
)}
|
||||
<PayPalButtons
|
||||
style={{ layout: "horizontal" }}
|
||||
onApprove={handlePayment}
|
||||
disabled={processing}
|
||||
/>
|
||||
</PayPalScriptProvider>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Paypal
|
||||
```
|
||||
|
||||
Here’s briefly what this code snippet does:
|
||||
|
||||
1. At the beginning of the component, the Medusa client is initialized using the JS Client you installed.
|
||||
2. You also need to retrieve the cart. Ideally, the cart should be managed through a context. So, every time the cart has been updated the cart should be updated in the context to be accessed from all components.
|
||||
3. This component renders a PayPal button to initialize the payment using PayPal. You use the components from the PayPal React components library to render the button and you pass the `PayPalScriptProvider` component the Client ID. Make sure to replace `<CLIENT_ID>` with the environment variable you added.
|
||||
4. When the button is clicked, the `handlePayment` function is executed. In this method, you initialize the payment authorization using `actions.order.authorize()`. It takes the customer to another page to log in with PayPal and authorize the payment.
|
||||
5. After the payment is authorized successfully on PayPal’s portal, the fulfillment function passed to `actions.order.authorize().then` will be executed.
|
||||
6. In the fulfillment function, you first ensure that the payment session for the PayPal payment provider is set as the [selected Payment Session in the cart](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession). Then, you send a request to the backend to [update the payment session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessionUpdate) data with the authorization data received from PayPal.
|
||||
7. You then [complete the cart and place the order](/api/store/#tag/Cart/operation/PostCartsCartComplete). If that is done successfully, you just show a success alert. You can change this based on the behavior you want in your storefront.
|
||||
|
||||
You can then import this component where you want to show it in your storefront.
|
||||
|
||||
If you run the Medusa backend and the storefront backend, you should see the PayPal button on checkout.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Capture Payments
|
||||
|
||||
After the customer places an order, you can see the order on the admin panel. In the payment information under the “Payment” section, you should see a “Capture” button.
|
||||
|
||||

|
||||
|
||||
Clicking this button lets you capture the payment for an order. You can also refund payments if an order has captured payments.
|
||||
|
||||
Refunding or Capturing payments is reflected in your PayPal dashboard as well.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- Check out [more plugins](../overview.mdx) you can add to your store.
|
||||
388
docs/content/plugins/payment/stripe.md
Normal file
388
docs/content/plugins/payment/stripe.md
Normal file
@@ -0,0 +1,388 @@
|
||||
---
|
||||
description: 'Learn how to integrate Stripe with the Medusa backend. Learn how to install the Stripe plugin on the Medusa backend and integrate it into a storefront.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# Stripe
|
||||
|
||||
This document guides you through setting up Stripe payments in your Medusa backend, admin, and storefront using the [Stripe Plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-stripe).
|
||||
|
||||
## Video Guide
|
||||
|
||||
You can also follow this video guide to learn how the setup works:
|
||||
|
||||
<div>
|
||||
<video width="100%" height="100%" playsinline autoplay muted controls>
|
||||
<source src="https://user-images.githubusercontent.com/59018053/154807206-6fbda0a6-bf3e-4e39-9fc2-f11710afe0b9.mp4" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
|
||||
## Overview
|
||||
|
||||
[Stripe](https://stripe.com/) is a battle-tested and unified platform for transaction handling. Stripe supplies you with the technical components needed to handle transactions safely and all the analytical features necessary to gain insight into your sales. These features are also available in a safe test environment which allows for a concern-free development process.
|
||||
|
||||
Using the `medusa-payment-stripe` plugin, this guide shows you how to set up your Medusa project with Stripe as a payment provider.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you proceed with this guide, make sure you create a [Stripe account](https://stripe.com). You’ll later retrieve the API Keys and secrets from your account to connect Medusa to your Stripe account.
|
||||
|
||||
---
|
||||
|
||||
## Medusa Backend
|
||||
|
||||
This section guides you over the steps necessary to add Stripe as a payment provider to your Medusa backend.
|
||||
|
||||
If you don’t have a Medusa backend installed yet, you must follow the [quickstart guide](../../development/backend/install.mdx) first.
|
||||
|
||||
### Install the Stripe Plugin
|
||||
|
||||
In the root of your Medusa backend, run the following command to install the stripe plugin:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install medusa-payment-stripe
|
||||
```
|
||||
|
||||
### Configure the Stripe Plugin
|
||||
|
||||
Next, you need to add configurations for your stripe plugin.
|
||||
|
||||
In `medusa-config.js` add the following at the end of the `plugins` array:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-payment-stripe`,
|
||||
options: {
|
||||
api_key: process.env.STRIPE_API_KEY,
|
||||
webhook_secret: process.env.STRIPE_WEBHOOK_SECRET,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
You might find that this code is already available but commented out. You can proceed with removing the comments instead of adding the code again, but make sure to replace `STRIPE_API_KEY` and `STRIPE_WEBHOOK_SECRET` with `process.env.STRIPE_API_KEY` and `process.env.STRIPE_WEBHOOK_SECRET` respectively.
|
||||
|
||||
:::
|
||||
|
||||
The Stripe plugin uses two configuration options. The `api_key` is essential to both your development and production environments. As for the `webhook_secret`, it’s essential for your production environment. So, if you’re only using Stripe for development you can skip adding the value for this option at the moment.
|
||||
|
||||
### Retrieve Stripe's Keys
|
||||
|
||||
On the [dashboard](https://dashboard.stripe.com) of your Stripe account click on the Developers link at the top right. This will take you to the developer dashboard.
|
||||
|
||||
You’ll first retrieve the API key. You can find it by choosing API Keys from the sidebar and copying the Secret key.
|
||||
|
||||
Next, you need to add the key to your environment variables. In your Medusa backend, create `.env` if it doesn’t already exist and add the Stripe key:
|
||||
|
||||
```bash
|
||||
STRIPE_API_KEY=sk_...
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
If you store environment variables differently on your backend, for example, using the hosting provider’s UI, then you don’t need to add it in `.env`. Add the environment variables in a way relevant to your backend.
|
||||
|
||||
:::
|
||||
|
||||
Next, if you’re installing this plugin for production use, you need to retrieve the Webhook secret. Webhooks allows you to track different events on your Medusa backend, such as failed payments.
|
||||
|
||||
Go to Webhooks on Stripe’s developer dashboard. Then, choose the Add an Endpoint button.
|
||||
|
||||
The endpoint for Stripe’s webhook on your Medusa backend is `{BACKEND_URL}/stripe/hooks`. So, add that endpoint in its field. Make sure to replace `{BACKEND_URL}` with the URL to your backend.
|
||||
|
||||
Then, you can add a description. You must select at least one event to listen to. Once you’re done, click “Add endpoint”.
|
||||
|
||||
After the Webhook is created, you’ll see "Signing secret" in the Webhook details. Click on "Reveal" to reveal the secret key. Copy that key and in your Medusa backend add the Webhook secret environment variable:
|
||||
|
||||
```bash
|
||||
STRIPE_WEBHOOK_SECRET=whsec_...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Admin Setup
|
||||
|
||||
This section will guide you through adding Stripe as a payment provider in a region using your Medusa admin dashboard.
|
||||
|
||||
This step is required for you to be able to use Stripe as a payment provider in your storefront.
|
||||
|
||||
### Admin Prerequisites
|
||||
|
||||
If you don’t have a Medusa admin installed, make sure to follow along with [the guide on how to install it](https://github.com/medusajs/admin#-quickstart) before continuing with this section.
|
||||
|
||||
### Add Stripe to Regions
|
||||
|
||||
You can refer to [this documentation in the user guide](../../user-guide/regions/providers.mdx#manage-payment-providers) to learn how to add a payment provider like Stripe to a region.
|
||||
|
||||
---
|
||||
|
||||
## Storefront Setup
|
||||
|
||||
This guide will take you through how to set up Stripe payments in your Medusa storefront. It includes the steps necessary when using one of Medusa’s official storefronts as well as your own custom React-based storefront.
|
||||
|
||||
### Storefront Prerequisites
|
||||
|
||||
All storefronts require that you obtain your Stripe’s Publishable Key. You can retrieve it from your Stripe’s developer dashboard by choosing API Keys and then copying the Publishable Key.
|
||||
|
||||
### Add to Next.js Storefront
|
||||
|
||||
Medusa has a Next.js storefront that you can easily use with your Medusa backend. If you don’t have the storefront installed, you can follow [this quickstart guide](../../starters/nextjs-medusa-starter).
|
||||
|
||||
In your `.env.local` file (or the file you’re using for your environment variables), add the following variable:
|
||||
|
||||
```bash title=.env.local
|
||||
NEXT_PUBLIC_STRIPE_KEY=<YOUR_PUBLISHABLE_KEY>
|
||||
```
|
||||
|
||||
Make sure to replace `<YOUR_PUBLISHABLE_KEY>` with your Stripe Publishable Key.
|
||||
|
||||
Now, if you run your Medusa backend and your storefront, on checkout you’ll be able to use Stripe.
|
||||
|
||||

|
||||
|
||||
### Add to Gatsby Storefront
|
||||
|
||||
Medusa also has a Gatsby storefront that you can use as your ecommerce store. If you don’t have the storefront installed, you can follow [this quickstart guide](../../starters/gatsby-medusa-starter).
|
||||
|
||||
In your `.env.development` file (or the file you’re using for your environment variables) add the following variable with the value set to the Publishable Key:
|
||||
|
||||
```jsx title=.env.development
|
||||
GATSBY_STRIPE_KEY=pk_
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
You might find this environment variable already available so you can just replace its value with your Publishable Key.
|
||||
|
||||
:::
|
||||
|
||||
Now, if you run your Medusa backend and your storefront, on checkout you’ll be able to use Stripe.
|
||||
|
||||

|
||||
|
||||
### Add to Custom Storefront
|
||||
|
||||
This section will go over how to add Stripe into a React-based framework. The instructions are general instructions that you can use in your storefront.
|
||||
|
||||
#### Workflow Overview
|
||||
|
||||
The integration with stripe must have the following workflow:
|
||||
|
||||
1. During checkout when the user reaches the payment section, you should [create payment sessions](/api/store/#tag/Cart/operation/PostCartsCartPaymentSessions). This will initialize the `payment_sessions` array in the `cart` object received. The `payment_sessions` is an array of available payment providers.
|
||||
2. If Stripe is available as a payment provider, you should select Stripe as [the payment session](/api/store/#tag/Cart/operation/PostCartsCartPaymentSession) for the current cart. This will initialize the `payment_session` object in the `cart` object to include data related to Stripe and the current payment session. This includes the payment intent and client secret.
|
||||
3. After the user enters their card details and submits the form, confirm the payment with Stripe.
|
||||
4. If the payment is confirmed successfully, [complete the order](/api/store/#tag/Cart/operation/PostCartsCartComplete) in Medusa. Otherwise show an error.
|
||||
|
||||
#### Install Dependencies
|
||||
|
||||
Before you start the implementations you need to install the necessary dependencies. You’ll be using Stripe’s React libraries to show the UI and handle the payment confirmation:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @stripe/react-stripe-js @stripe/stripe-js
|
||||
```
|
||||
|
||||
You’ll also use Medusa’s JS Client to easily call Medusa’s REST APIs:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/medusa-js
|
||||
```
|
||||
|
||||
#### Initialize Stripe
|
||||
|
||||
In this section, you’ll initialize Stripe without Medusa’s checkout workflow. Please note that this is one approach to add Stripe into your React project. You can check out [Stripe’s React documentation](https://stripe.com/docs/stripe-js/react) for other methods or components.
|
||||
|
||||
Create a container component that will hold the payment card component:
|
||||
|
||||
```jsx
|
||||
import { useState } from "react"
|
||||
|
||||
import { Elements } from "@stripe/react-stripe-js"
|
||||
import Form from "./Form"
|
||||
import { loadStripe } from "@stripe/stripe-js"
|
||||
|
||||
const stripePromise = loadStripe("pk_...")
|
||||
|
||||
export default function Container() {
|
||||
const [clientSecret, setClientSecret] = useState()
|
||||
|
||||
// TODO set clientSecret
|
||||
|
||||
return (
|
||||
<div>
|
||||
{clientSecret && (
|
||||
<Elements stripe={stripePromise} options={{
|
||||
clientSecret,
|
||||
}}>
|
||||
<Form clientSecret={clientSecret} cartId={cartId} />
|
||||
</Elements>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
In this component, you need to use Stripe’s `loadStripe` function outside of the component’s implementation to ensure that Stripe doesn’t re-load with every change. The function accepts the Publishable Key.
|
||||
|
||||
:::note
|
||||
|
||||
You’ll probably store this Publishable Key in an environment variable depending on your framework. It’s hard-coded here for simplicity.
|
||||
|
||||
:::
|
||||
|
||||
Then, inside the component’s implementation, you add a state variable `clientSecret` which you’ll retrieve in the next section.
|
||||
|
||||
Once the clientSecret is set, the `Elements` Stripe component will wrap a `Form` component you’ll create next. This is necessary because the `Elements` component allows child elements to get access to the card’s inputs and their data using Stripe’s `useElements` hook.
|
||||
|
||||
Create a new file for the `Form` component with the following content:
|
||||
|
||||
```jsx
|
||||
import {
|
||||
CardElement,
|
||||
useElements,
|
||||
useStripe,
|
||||
} from "@stripe/react-stripe-js"
|
||||
|
||||
export default function Form({ clientSecret, cartId }) {
|
||||
const stripe = useStripe()
|
||||
const elements = useElements()
|
||||
|
||||
async function handlePayment(e) {
|
||||
e.preventDefault()
|
||||
// TODO handle payment
|
||||
}
|
||||
|
||||
return (
|
||||
<form>
|
||||
<CardElement />
|
||||
<button onClick={handlePayment}>Submit</button>
|
||||
</form>
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
This component shows a CardElement component from Stripe’s React library. You can use `stripe` to be able to confirm the payment later. The `elements` variable will be used to retrieve the entered card details safely.
|
||||
|
||||
#### Implement the Workflow
|
||||
|
||||
You’ll now implement the workflow explained earlier. You’ll use Medusa’s JS Client, so make sure to import it and initialize it in your `Container` component:
|
||||
|
||||
```jsx
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
export default function Container() {
|
||||
const client = new Medusa()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
In your storefront, you’ll probably be managing the Medusa client through a context for better performance.
|
||||
|
||||
:::
|
||||
|
||||
Then, in the place of the `//TODO` inside the `Container` element, initialize the payment sessions and create a payment session if Stripe is available:
|
||||
|
||||
```tsx
|
||||
client.carts.createPaymentSessions(cart.id)
|
||||
.then(({ cart }) => {
|
||||
// check if stripe is selected
|
||||
const isStripeAvailable = cart.payment_sessions?.some(
|
||||
(session) => (
|
||||
session.provider_id === "stripe"
|
||||
)
|
||||
)
|
||||
if (!isStripeAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
// select stripe payment session
|
||||
client.carts.setPaymentSession(cart.id, {
|
||||
provider_id: "stripe",
|
||||
}).then(({ cart }) => {
|
||||
setClientSecret(cart.payment_session.data.client_secret)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Notice that here it’s assumed you have access to the `cart` object throughout your storefront. Ideally, the `cart` should be managed through a context. So, every time the cart is updated, for example, when the `createPaymentSessions` or `setPaymentSession` are called, the cart should be updated in the context to be accessed from other elements. In this case, you probably wouldn’t need a `clientSecret` state variable as you can use the client secret directly from the `cart` object.
|
||||
|
||||
:::
|
||||
|
||||
Once the client secret is set, the form will be shown to the user.
|
||||
|
||||
The last step in the workflow is confirming the payment with Stripe and if it’s done successfully, completing the user’s order. This part is done in the `Form` component.
|
||||
|
||||
As you’ll use Medusa’s client again make sure to import it and initialize it:
|
||||
|
||||
```jsx
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
export default function Form() {
|
||||
const client = new Medusa()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Then, replace the `//TODO` in the `handlePayment` function with the following content:
|
||||
|
||||
```jsx
|
||||
return stripe.confirmCardPayment(clientSecret, {
|
||||
payment_method: {
|
||||
card: elements.getElement(CardElement),
|
||||
billing_details: {
|
||||
name,
|
||||
email,
|
||||
phone,
|
||||
address: {
|
||||
city,
|
||||
country,
|
||||
line1,
|
||||
line2,
|
||||
postal_code,
|
||||
},
|
||||
},
|
||||
},
|
||||
}).then(({ error, paymentIntent }) => {
|
||||
// TODO handle errors
|
||||
client.carts.complete(cartId).then(
|
||||
(resp) => console.log(resp)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
You use the `confirmCardPayment` method in the `stripe` object. You’ll need to pass it the client secret, which you can have access to from the cart object if it’s available through the context.
|
||||
|
||||
This method also requires the customer’s information like `name`, `email`, and their address. Make sure to place the values for each based on your implementation.
|
||||
|
||||
Once the promise resolves you can handle the errors, if there are any. If not, you can complete the customer’s order using `complete` from Medusa’s client. This request expects the cart ID which you should have access to as well.
|
||||
|
||||
If you run your backend and storefront now, you’ll see the Stripe UI element and you’ll be able to make orders.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Capture Payments
|
||||
|
||||
After the customer places an order, you’ll be able to see the order on the admin panel. In the payment information under the “Payment” section, you should see a “Capture” button.
|
||||
|
||||

|
||||
|
||||
Clicking this button allows you to capture the payment for an order. You can also refund payments if an order has captured payments.
|
||||
|
||||
Refunding or Capturing payments is reflected in your Stripe’s dashboard as well. This gives you access to all of Stripe’s analytical capabilities.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- Check out [more plugins](../overview.mdx) you can add to your store.
|
||||
Reference in New Issue
Block a user