diff --git a/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md b/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md
deleted file mode 100644
index eeb1ba83a9..0000000000
--- a/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md
+++ /dev/null
@@ -1,117 +0,0 @@
-# Frontend Payment Flow in Checkout
-
-## Introduction
-The purpose of this guide is to describe a checkout flow in Medusa. It is assumed that you've completed our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or [Tutorial](https://docs.medusajs.com/tutorial/set-up-your-development-environment) and are familiar with the technologies we use in our stack. Additionally, having an understanding of the [core API](https://docs.medusajs.com/api/store/auth) would serve as a great foundation for this walkthrough.
-
-:::note
-
-All code snippets in the following guide, use the JS SDK distributed through **npm**. To install it, run:
-
-```bash npm2yarn
-npm install @medusajs/medusa-js
-```
-
-:::
-
-## Glossary
-- **Cart**: The Cart contains all the information needed for customers to complete an Order. In the Cart customers gather the items they wish to purchase, they add shipping and billing details and complete payment information.
-- **LineItem**: Line Items represent an expense added to a Cart. Typically this will be a Product Variant and a certain quantity of the same variant. Line Items hold descriptive fields that help communicate its contents and price.
-- **PaymentSession**: A Payment Session is a Medusa abstraction that unifies the APIs of multiple payment gateways. Payment Sessions are _initialized_ when the customer begins a checkout and are _authorized_ prior to an Order being placed. Payment Sessions are created based on the available Payment Providers configured in a Cart's region.
-- **ShippingOption**: A Shipping Option represents a way in which an Order can be fulfilled. Shipping Options have a price and are associated with a Fulfillment Provider that will handle the shipment later in the Order flow. Once a customer selects a Shipping Option it becomes a Shipping Method.
-- **ShippingMethod**: Shipping Methods are unique to each Cart and can thereby hold either overwrites for fields in a Shipping Option (e.g. price) or additional details (e.g. an id representing a parcel pickup location).
-
-## Checkout flow
-To create an order from a cart, we go through the following flow.
-
-:::note
-
-At this point, it assumed that the customer has created a cart, added items and is now at the initial step of the checkout flow.
-
-:::
-
-### Initializing the checkout
-The first step in the flow is to _initialize_ the configured Payment Sessions for the Cart. If you are using the `medusa-starter-default` starter, this call will result in the `cart.payment_sessions` array being filled with one Payment Session for the manual payment provider.
-
-```javascript
-const { cart } = await medusa.carts.createPaymentSessions("cart_id")
-```
-
-To give a more real life example, it is assumed that `medusa-payment-stripe` is installed in your project in which case the call will result in a [Stripe PaymentIntent](https://stripe.com/docs/api/payment_intents) being created. The unique provider data for each Payment Session can be found in the Payment Session's `data` field; this data can be used in front end implementations e.g. if using Stripe Elements the `client_secret` can be retrieved through `session.data.client_secret`.
-
-### Adding customer information
-After initializing the checkout flow, you would typically have one big step or several smaller steps for gathering user information; email, address, country, and more. To store this data you may update the cart with each of field or all fields at the same time.
-
-```javascript
-const { cart } = await medusa.carts.update("cart_id", {
- email: "lebron@james.com",
- shipping_address: {
- first_name: "",
- last_name: "",
- ...
- }
-})
-```
-
-### Selecting payment provider
-This step is only applicable if you have multiple Payment Sessions installed in your project. In cases where only one Payment Provider is configured the Payment Session will be preselected. In all other cases your implementations should call:
-
-```javascript
-const { cart } = await medusa.carts.setPaymentSession("cart_id", {
- provider_id: "stripe"
-})
-```
-
-### Choosing a shipping method
-Before reaching the payment step, you would typically require the customer to choose a Shipping Method from a number of options. In Medusa you can set rules that must be met for a Shipping Option to be available for a Cart. To get the available shipping options for a Cart you should call:
-```javascript
-const { shipping_options } = await medusa.carts.listCartOptions("cart_id")
-```
-
-Choosing a Shipping Option, will create a Shipping Method and attach it to the Cart. The second argument to the function in the snippet below holds the id of the selected option.
-```javascript=
-const { cart } = await medusa.carts.addShippingMethod("cart_id", { option_id: "option_id"})
-```
-
-### Collecting payment details
-The following snippet shows how we use Stripe to collect payment details from the customer. Note that we are using the `client_secret` from the Stripe PaymentIntent in `data` on the payment session as this is required by Stripe Elements.
-```jsx
-import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
-
-...
-
-const stripe = useStripe();
-const elements = useElements();
-
-
-const handleSubmit = () => {
- ...
- const { paymentIntent, error } = await stripe.confirmCardPayment(
- cart.payment_session.data.client_secret,
- {
- payment_method: {
- card: elements.getElement(CardElement),
- },
- }
- );
- ...
-}
-
-return
-```
-After collecting the payment details, the customer can complete the checkout flow.
-
-### Completing the cart
-When all relevant customer information has been captured, your implementation should proceed to the final step: completing the cart.
-```javascript
-const { order } = await medusa.carts.complete("cart_id")
-```
-If all information is collected correctly throughout the checkout flow, the call will place an Order based on the details gathered in the Cart.
-
-## Summary
-You now have a solid foundation for creating your own checkout flows using Medusa. Throughout this guide, we've used Stripe as a Payment Provider. Stripe is one of the most popular providers and we have an official plugin that you can easily install in your project.
-
-## What's next?
-See the checkout flow, explained in the previous sections, in one of our frontend starters:
-- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa)
-- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa)
-
diff --git a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md
index 8037f3374f..304446068e 100644
--- a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md
+++ b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md
@@ -384,4 +384,4 @@ async retrieveSavedMethods(customer) {
## What’s Next 🚀
- Check out the Payment Providers for [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) for implementation examples.
-- Learn more about the [frontend checkout flow](./frontend-payment-flow-in-checkout.md).
+- Learn more about the [frontend checkout flow](./../../storefront/how-to-implement-checkout-flow.mdx).
diff --git a/docs/content/advanced/backend/payment/overview.md b/docs/content/advanced/backend/payment/overview.md
index a34c19e4e3..2320bc342c 100644
--- a/docs/content/advanced/backend/payment/overview.md
+++ b/docs/content/advanced/backend/payment/overview.md
@@ -126,5 +126,5 @@ This prevents any payment issues from occurring with the customers and allows fo
## What’s Next 🚀
-- [Check out how the checkout flow is implemented on the frontend.](./frontend-payment-flow-in-checkout.md)
+- [Check out how the checkout flow is implemented on the frontend.](./../../storefront/how-to-implement-checkout-flow.mdx)
- Check out payment plugins like [Stripe](../../../add-plugins/stripe.md), [Paypal](/add-plugins/paypal), and [Klarna](../../../add-plugins/klarna.md).
diff --git a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx
new file mode 100644
index 0000000000..724fa3c7bf
--- /dev/null
+++ b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx
@@ -0,0 +1,329 @@
+# 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.
+
+## 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 2 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.
+
+:::note
+
+It’s recommended to go through the [Shipping Architecture Overview](../backend/shipping/overview.md) and [Payment Architecture Overview](../backend/payment/overview.md) first to have a better understanding of Medusa’s architecture.
+
+:::
+
+## Prerequisites
+
+This document assumes you’ve already taken care of the add-to-cart flow. So, you should have a [cart created](https://docs.medusajs.com/api/store/cart/create-a-cart) for the customer with at least [one product in it](https://docs.medusajs.com/api/store/cart/add-a-line-item).
+
+To follow along with this tutorial, you can make use of the [Medusa JS Client](https://www.npmjs.com/package/@medusajs/medusa-js). You can install it with this command:
+
+```bash npm2yarn
+npm install @medusajs/medusa-js
+```
+
+There’s also an alternative approach in this document using [JavaScript’s Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) in case you’re unable to use Medusa’s JS Client. Make sure to replace `` in those examples with your server URL.
+
+## Shipping Step
+
+In this step, the customer generally enters their shipping info, then chooses the available shipping option based on the entered info.
+
+### Add Shipping Address
+
+After the customer enters their shipping address information, you must send a `POST` request to the [Update a Cart](https://docs.medusajs.com/api/store/cart/update-a-cart) API endpoint passing it the new shipping address:
+
+
+
+
+```jsx
+medusa.carts.update(cart.id, {
+ shipping_address: {
+ company,
+ first_name,
+ last_name,
+ address_1,
+ address_2,
+ city,
+ country_code,
+ province,
+ postal_code,
+ phone
+ },
+}).then((response) => {
+ //updated cart is in response.cart
+})
+```
+
+
+
+
+```jsx
+fetch(`/store/carts/${cart.id}`, {
+ method: 'POST',
+ body: JSON.stringify({
+ shipping_address: {
+ company,
+ first_name,
+ last_name,
+ address_1,
+ address_2,
+ city,
+ country_code,
+ province,
+ postal_code,
+ phone
+ },
+ }),
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+}).then((response) => response.json())
+ .then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+You can have access to the updated cart in `response.cart`, which now has the shipping address you added in `response.cart.shipping_address`.
+
+### List Shipping Options
+
+After updating the cart with the customer’s address, the list of available [shipping options](../backend/shipping/overview.md#shipping-option) for that cart might change. So, you should retrieve the updated list of options by sending a `GET` request to the [Retrieve Shipping Options for Cart API](https://docs.medusajs.com/api/store/shipping-option/retrieve-shipping-options-for-cart) endpoint:
+
+
+
+
+```jsx
+medusa.shippingOptions.listCartOptions(cart.id)
+ .then((response) => {
+ //shipping options available in response.shipping_options
+ })
+```
+
+
+
+
+```jsx
+fetch(`/store/shipping-options/${cart.id}`)
+ .then((response) => response.json())
+ .then((response) => {
+ //shipping options available in response.shipping_options
+ })
+```
+
+
+
+
+You can access all shipping options available with their info in `response.shipping_options` which is an array of [shipping options](https://docs.medusajs.com/api/store/shipping-option). Typically you would display those options to the customer to choose from.
+
+### Choose Shipping Option
+
+Once the customer chooses one of the available shipping options, send a `POST` request to the [Add a Shipping Method](https://docs.medusajs.com/api/store/cart/add-a-shipping-method) API endpoint. This will create a [shipping method](../backend/shipping/overview.md#shipping-method) based on the shipping option chosen and will associate it with the customer’s cart:
+
+
+
+
+```jsx
+medusa.carts.addShippingMethod(cart.id, {
+ option_id: shipping_option.id //shipping_option is the select option
+}).then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+```jsx
+fetch(`/store/carts/${cart.id}/shipping-methods`, {
+ method: 'POST',
+ body: JSON.stringify({
+ option_id: shipping_option.id //shipping_option is the select option
+ }),
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+}).then((response) => response.json())
+ .then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+You can have access to the updated cart in `response.cart`, which now has one item in the array value of the property `shipping_methods`.
+
+## 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.
+
+### Initialize Payment Sessions
+
+When the page opens and before the payment providers are displayed to the customer to choose from, you must initialize the [payment sessions](./../backend/payment/overview.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](https://docs.medusajs.com/api/store/cart/initialize-payment-sessions) API endpoint:
+
+
+
+
+```jsx
+medusa.carts.createPaymentSessions(cart.id)
+ .then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+```jsx
+fetch(`/store/carts/${cart.id}/payment-sessions`, {
+ method: 'POST'
+}).then((response) => response.json())
+ .then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+You can then access the initialized payment sessions under the `payment_sessions` array in `response.cart`.
+
+### 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](https://docs.medusajs.com/api/store/cart/select-a-payment-session) API endpoint:
+
+
+
+
+```jsx
+medusa.carts.setPaymentSession(cart.id, {
+ provider_id: payment_session.provider_id //payment_session is the session chosen by the customer
+}).then((response) => {
+ //updated cart is in response.cart
+})
+```
+
+
+
+
+```jsx
+fetch(`/store/carts/${cart.id}/payment-session`, {
+ method: 'POST',
+ body: JSON.stringify({
+ provider_id: payment_session.provider_id //payment_session is the session chosen by the customer
+ }),
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+}).then((response) => response.json())
+ .then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+You can then access the selected payment session in `response.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.
+
+:::
+
+### Update Payment Session
+
+This step is optional and is only necessary for some payment providers. As mentioned in the [Payment Architecture](../backend/payment/overview.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.
+
+If you need to update that data at any point before the purchase is made, send a request to [Update a Payment Session](https://docs.medusajs.com/api/store/cart/update-a-payment-session) API endpoint passing it the updated data object:
+
+
+
+
+```jsx
+medusa.carts.updatePaymentSession(cart.id, cart.payment_session.provider_id, {
+ data: {
+ //pass any data you want to add in the `data` attribute
+ //for example:
+ "test": true
+ }
+}).then((response) => {
+ //updated cart is in response.cart
+})
+```
+
+
+
+
+```jsx
+fetch(`/store/carts/${cart.id}/payment-sessions/${cart.payment_session.provider_id}`, {
+ method: 'POST',
+ body: JSON.stringify({
+ data: {
+ //pass any data you want to add in the `data` attribute
+ //for example:
+ "test": true
+ }
+ }),
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+}).then((response) => response.json())
+ .then((response) => {
+ //updated cart is in response.cart
+ })
+```
+
+
+
+
+You can have access to the updated data in the payment session in `response.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 server 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.
+
+To complete a cart, send a `POST` request to the [Complete a Cart](https://docs.medusajs.com/api/store/cart/complete-a-cart) API endpoint:
+
+
+
+
+```jsx
+medusa.carts.complete(cart.id)
+ .then((response) => {
+ //order details is in response.data
+ })
+```
+
+
+
+
+```jsx
+fetch(`/store/carts/${cart.id}/complete`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+}).then((response) => response.json())
+ .then((response) => {
+ //order details is in response.data
+ })
+```
+
+
+
+
+If the order is placed successfully, you can access the order data in `response.data` and the value for `response.type` is `order`. Otherwise, `response.data` holds the cart details and `response.type` is `cart`.
+
+## What’s Next 🚀
+
+- Check out available plugins for popular payment providers such as [Stripe](../../add-plugins/stripe.md) and [PayPal](/add-plugins/paypal.md).
+- Learn more about the [Payment](../backend/payment/overview.md) and [Shipping](../backend/shipping/overview.md) Architectures.
diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js
index 7e2009c5cc..85783792dd 100644
--- a/www/docs/sidebars.js
+++ b/www/docs/sidebars.js
@@ -174,10 +174,6 @@ module.exports = {
type: "doc",
id: "advanced/backend/payment/how-to-create-payment-provider",
},
- {
- type: "doc",
- id: "advanced/backend/payment/frontend-payment-flow-in-checkout",
- },
]
},
{
@@ -210,6 +206,17 @@ module.exports = {
]
},
]
+ },
+ {
+ type: "category",
+ label: "Storefront",
+ collapsed: true,
+ items: [
+ {
+ type: "doc",
+ id: "advanced/storefront/how-to-implement-checkout-flow",
+ },
+ ]
}
]
},