From 5e22bee70b5ae8affe7cae709b94023bc94416e6 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 1 Apr 2022 15:58:58 +0300 Subject: [PATCH] modified stripe doc --- docs/content/add-plugins/stripe.md | 401 +++++++++++++++++++++++------ www/docs/sidebars.js | 153 ++++++----- 2 files changed, 419 insertions(+), 135 deletions(-) diff --git a/docs/content/add-plugins/stripe.md b/docs/content/add-plugins/stripe.md index 0fb742204a..f89003a3f9 100644 --- a/docs/content/add-plugins/stripe.md +++ b/docs/content/add-plugins/stripe.md @@ -1,6 +1,10 @@ # Stripe -[View plugin here](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-stripe) +This document guides you through setting up Stripe payments in your Medusa server, admin, and storefront using the [Stripe Plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-stripe). + +## Video Guide + +You can also follow our video guide to learn how the setup works:
+## Overview -### Introduction +[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. -Handling payments is at the core of every commerce system; it allows us to run our businesses. Consequently, a vast landscape of payment providers has developed, each with varying cost models, implementational specifications, and analytical capabilities. +Using the `medusa-payment-stripe` plugin, this guide shows you how to set up your Medusa project with Stripe as a payment provider. -As a consequence, one might ask, which one(s) should I choose? Medusa makes exchanging enabled payment providers easy through its unified payment API. Here, one may select payment provider plugins already existing ([PayPal](https://docs.medusajs.com/add-plugins/paypal), [Klarna](https://docs.medusajs.com/add-plugins/klarna), and Stripe), or develop new ones. +## Prerequisites -Using the `medusa-payment-stripe` plugin, this guide will show you how to set up your Medusa project with Stripe as a payment provider. +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. -[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. +## Medusa Server -### Prerequisites +This section guides you over the steps necessary to add Stripe as a payment provider to your Medusa server. -This guide assumes that you have set up a medusa project (See [this guide](https://docs.medusajs.com/tutorial/creating-your-medusa-server)). Furthermore, this guide will be using the Gatsby starter as our storefront (See [this guide](https://docs.medusajs.com/starters/gatsby-medusa-starter)) and the Admin panel to manage our store (See the github installation guide [here](https://github.com/medusajs/admin)). +If you don’t have a Medusa server installed yet, you must follow our [quickstart guide](../quickstart/quick-start) first. -### Installation +### Plugin Installation -The first step is to install the `medusa-payment-stripe` plugin in your Medusa project using your favorite package manager: +In the root of your Medusa server, run the following command to install the stripe plugin: ```bash -# yarn -yarn add medusa-payment-stripe - - -# npm npm install medusa-payment-stripe ``` -Then in your `medusa-config.js` , add the plugin to your `plugins` array: +### Plugin Configuration -```javascript -module.exports = { - // ... other options - plugins: [ - // ... other plugins - { - resolve: `medusa-payment-stripe`, - options: { - api_key: STRIPE_API_KEY, - webhook_secret: STRIPE_WEBHOOK_SECRET, - }, - }, - ]; +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 +const plugins = [ + ..., + { + resolve: `medusa-payment-stripe`, + options: { + api_key: STRIPE_API_KEY, + webhook_secret: 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. + +::: + +The Stripe plugin uses 2 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. + +### Retrieving The 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 server, create `.env` if it doesn’t already exist and add the Stripe key: + +```jsx +STRIPE_API_KEY=sk_... +``` + +:::note + +If you store environment variables differently on your server, 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 server. + +::: + +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 server, 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 server is `{SERVER_URL}/stripe/hooks`. So, add that endpoint in its field. Make sure to replace `{SERVER_URL}` with the URL to your server. + +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 a key at the top right that starts with `we_...`. Copy that key and in your Medusa server add the Webhook secret environment variable: + +```jsx +STRIPE_WEBHOOK_SECRET=we_... +``` + +## 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. + +### 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. + +### Adding Stripe + +First, make sure that both your Medusa server and Medusa Admin are running. + +Then, in your Medusa Admin, log in and choose Settings from the Sidebar. Then, choose Regions. + +![Settings](https://i.imgur.com/wRkmbLY.png) + +Then, choose the regions you want to add Stripe as a payment provider. In the right-side settings, scroll down to “Payment Providers” and choose Stripe. + +![Choose Stripe](https://i.imgur.com/FH5vgWh.png) + +Once you’re done, click Save. Stripe is now a payment provider in your store in the regions you selected. + +## 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. + +### 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. + +### Next.js Storefront + +Medusa has a Next.js storefront that you can easily use with your Medusa server. If you don’t have the storefront installed, you can follow [this quickstart guide](../starters/nextjs-medusa-starter). + +In your `.env` file, add the following variable with its value set to the Publishable Key: + +```jsx +NEXT_PUBLIC_STRIPE_KEY=pk_... +``` + +:::note + +This variable might be available in your `.env` file but commented out. You can instead remove the comment and change its value. + +::: + +Now, if you run your Medusa server and your storefront, on checkout you’ll be able to use Stripe. + +![Next.js Stripe Form](https://i.imgur.com/1XvW776.png) + +### 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 +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 server and your storefront, on checkout you’ll be able to use Stripe. + +![Gatsby Stripe Form](https://i.imgur.com/1XvW776.png) + +### 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](https://docs.medusajs.com/api/store/cart/initialize-payment-sessions). 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](https://docs.medusajs.com/api/store/cart/select-a-payment-session) 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](https://docs.medusajs.com/api/store/cart/complete-a-cart) in Medusa. Otherwise show an error. + +#### Installing 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 +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 +npm i @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 ( +
+ {clientSecret && ( + +
+ + )} +
+ ); +}; +``` + +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 ( + + + + + ); +}; +``` + +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(); + ... } ``` -Now head over to [Stripe](https://stripe.com/) and create your account. You can then click API Keys on your dashboard, and here you will see two keys. We suggest using the test environment during development, and therefore you should make sure that you are seeing the keys to the test environment (These keys start with `pk_test_` and `sk_test_` respectively). +:::note -Now open your `.env` file for the Medusa project and store your _secret key_ in the `STRIPE_API_KEY` variable: +In your storefront, you’ll probably be managing the Medusa client through a context for better performance. -```bash -# .env -STRIPE_API_KEY= +::: + +Then, in the place of the `//TODO` inside the `Container` element, initialize the payment sessions and create a payment session if Stripe is available: + +```jsx +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: For production you should also create a webhook on Stripe (also available on your dashboard) and store its secret in the `STRIPE_WEBHOOK_SECRET` variable. We will go into detail with this in a later guide. +:::note -Then navigate to your Gatsby starter project and open the `.env.development` file and store your _publishable key_ in the `GATSBY_STRIPE_KEY` variable: +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. -```bash -# .env -GATSBY_STRIPE_KEY= +::: + +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(); + ... +} ``` -### What’s next? +Then, replace the `//TODO` in the `handlePayment` function with the following content: -At this point we have set everything up, and the Stripe payment provider is now enabled in your Medusa project. So, go ahead and start up your medusa project, the gatsby starter, and the admin panel! +```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)) +}) +``` -However, as Medusa allows for different payment providers in different regions (and multiple providers in each) we should first make Stripe a valid payment option in our default region. To do so, open the admin panel (`http://localhost:7000`) login, and navigate to `Settings > Region settings > Edit Default Region`. Here you should now be able to select Stripe as a payment provider: +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. -![Change payment provider](https://i.imgur.com/mVIDYz4.png) +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 server and storefront now, you’ll see the Stripe UI element and you’ll be able to make orders. -After doing this, and clicking save, we are ready to accept payments using Stripe. So, navigate to your storefront (`http://localhost:8000`) and go through the checkout process: +![Stripe Form](https://i.imgur.com/NOi8THw.png) -
+## Capturing Payment -![Checkout process](https://i.imgur.com/qhanISL.gif) +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. -
-After doing so, you should be able to see an uncaptured payment in Stripe. Here, you navigate to the payments tab, where you should see the following (depending on your choices during the checkout process): +![Capture Payment](https://i.imgur.com/Iz55PVZ.png) -
+Clicking this button allows you to capture the payment for an order. You can also refund payments if an order has captured payments. -![Uncaptured payment](https://i.imgur.com/LX6UR40.png) +Refunding or Capturing payments is reflected in your Stripe’s dashboard as well. This gives you access to all of Stripe’s analytical capabilities. -
+## What’s Next 🚀 -To then capture the payment, navigate back to the admin panel (`http://localhost:7000/`), and dig into the relevant order, and capture the payment: - -
- -![Capture payment](https://i.imgur.com/y5UxxpS.gif) - -
- -The capture is then reflected in the payment overview in Stripe as well, giving you access to all of Stripe's analytical capabilities: - -
- -![Captured payment](https://i.imgur.com/edv84Nq.png) - -
- -### Summary - -In this guide we have setup Stripe as a payment provider giving you a fully functioning ecommerce experience! Interested in learning more? Check out the other guides and tutorials or head over to our [Discord channel](https://discord.gg/xpCwq3Kfn8) if you have any questions or want to become part of our community! - -[View plugin here](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-stripe) +- Check out [more plugins](https://github.com/medusajs/medusa/tree/master/packages) you can add to your store. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index a1c194e576..8a6cf0521a 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -175,82 +175,113 @@ module.exports = { items: [ { type: "category", - label: "Gatsby + Contentful + Medusa", + label: "Analytics", items: [ { type: "doc", - id: "how-to/headless-ecommerce-store-with-gatsby-contentful-medusa", - }, - { - type: "doc", - id: "how-to/making-your-store-more-powerful-with-contentful", + id: "add-plugins/segment", + label: "Segment", }, ], }, { - type: "doc", - id: "add-plugins/contentful", - label: "CMS: Contentful", + type: "category", + label: "Bot", + items: [ + { + type: "doc", + id: "add-plugins/slack", + label: "Slack", + }, + ], }, { - type: "doc", - id: "add-plugins/strapi", - label: "CMS: Strapi", + type: "category", + label: "CMS", + items: [ + { + type: "doc", + id: "add-plugins/contentful", + label: "Contentful", + }, + { + type: "doc", + id: "add-plugins/strapi", + label: "Strapi", + }, + { + type: "category", + label: "Gatsby + Contentful + Medusa", + items: [ + { + type: "doc", + id: "how-to/headless-ecommerce-store-with-gatsby-contentful-medusa", + }, + { + type: "doc", + id: "how-to/making-your-store-more-powerful-with-contentful", + }, + ], + }, + ], }, { - type: "doc", - id: "add-plugins/segment", - label: "Analytics: Segment", + type: "category", + label: "Payment", + items: [ + { + type: "doc", + id: "add-plugins/klarna", + label: "Klarna", + }, + { + type: "doc", + id: "add-plugins/paypal", + label: "PayPal", + }, + { + type: "doc", + id: "add-plugins/stripe", + label: "Stripe", + }, + ], }, { - type: "doc", - id: "add-plugins/meilisearch", - label: "Search: MeiliSearch", + type: "category", + label: "Search", + items: [ + { + type: "doc", + id: "add-plugins/algolia", + label: "Algolia", + }, + { + type: "doc", + id: "add-plugins/meilisearch", + label: "MeiliSearch", + }, + ], }, { - type: "doc", - id: "add-plugins/algolia", - label: "Search: Algolia", - }, - { - type: "doc", - id: "add-plugins/spaces", - label: "File: Spaces", - }, - { - type: "doc", - id: "add-plugins/s3", - label: "File: S3", - }, - { - type: "doc", - id: "add-plugins/minio", - label: "File: MinIO", - }, - { - type: "doc", - id: "add-plugins/stripe", - label: "Payment: Stripe", - }, - { - type: "doc", - id: "add-plugins/klarna", - label: "Payment: Klarna", - }, - { - type: "doc", - id: "add-plugins/paypal", - label: "Payment: PayPal", - }, - { - type: "doc", - id: "add-plugins/sendgrid", - label: "Notification: SendGrid", - }, - { - type: "doc", - id: "add-plugins/slack", - label: "Bot: Slack", + type: "category", + label: "Storage", + items: [ + { + type: "doc", + id: "add-plugins/minio", + label: "MinIO", + }, + { + type: "doc", + id: "add-plugins/s3", + label: "S3", + }, + { + type: "doc", + id: "add-plugins/spaces", + label: "Spaces", + }, + ], }, ], },