Files
medusa-store/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx
Danijel Predojevic b78171b80c docs: update api urls (#2074)
* Update homepage.md

* Update add-fulfillment-provider.md

* Update gatsby-medusa-starter.md

* Update how-to-create-notification-provider.md

* Update how-to-create-payment-provider.md

* Update how-to-implement-checkout-flow.mdx

* Update nextjs-medusa-starter.md

* Update paypal.md

* Update quick-start.md

* Update stripe.md

* Update docs/content/advanced/backend/shipping/add-fulfillment-provider.md

Co-authored-by: Shahed Nasser <shahednasser@gmail.com>

* Update docs/content/quickstart/quick-start.md

Co-authored-by: Shahed Nasser <shahednasser@gmail.com>

* Update docs/content/advanced/backend/shipping/add-fulfillment-provider.md

Co-authored-by: Shahed Nasser <shahednasser@gmail.com>

Co-authored-by: Danijel Predojevic <danijel@vivant.eco>
Co-authored-by: Shahed Nasser <shahednasser@gmail.com>
2022-08-22 14:35:58 +03:00

333 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. Its 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 youre creating a custom storefront, if youre adding a custom payment provider, or if youre just interested in learning more about how checkout works in Medusa.
:::note
Its 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 Medusas architecture.
:::
## Prerequisites
This document assumes youve already taken care of the add-to-cart flow. So, you should have a [cart created](https://docs.medusajs.com/api/store/#tag/Cart/operation/PostCart) for the customer with at least [one product in it](https://docs.medusajs.com/api/store/#tag/Cart/operation/PostCartsCartLineItems).
You can learn how to implement the cart flow using [this documentation](../../guides/carts-in-medusa.mdx).
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
```
Theres also an alternative approach in this document using [JavaScripts Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) in case youre unable to use Medusas JS Client. Make sure to replace `<SERVER_URL>` 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/#tag/Cart/operation/PostCartsCart) API endpoint passing it the new shipping address:
<Tabs groupId="request-tyoe">
<TabItem value="client" label="Medusa JS Client" default>
```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
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/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
})
```
</TabItem>
</Tabs>
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 customers 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/#tag/Shipping-Option/operation/GetShippingOptionsCartId) endpoint:
<Tabs groupId="request-tyoe">
<TabItem value="client" label="Medusa JS Client" default>
```jsx
medusa.shippingOptions.listCartOptions(cart.id)
.then((response) => {
//shipping options available in response.shipping_options
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/store/shipping-options/${cart.id}`)
.then((response) => response.json())
.then((response) => {
//shipping options available in response.shipping_options
})
```
</TabItem>
</Tabs>
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/#tag/Shipping-Option/operation/GetShippingOptions). 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/#tag/Cart/operation/PostCartsCartShippingMethod) 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 customers cart:
<Tabs groupId="request-type">
<TabItem value="client" label="Medusa JS Client" default>
```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
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/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
})
```
</TabItem>
</Tabs>
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/#tag/Cart/operation/PostCartsCartPaymentSessions) API endpoint:
<Tabs groupId="request-tyoe">
<TabItem value="client" label="Medusa JS Client" default>
```jsx
medusa.carts.createPaymentSessions(cart.id)
.then((response) => {
//updated cart is in response.cart
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/store/carts/${cart.id}/payment-sessions`, {
method: 'POST'
}).then((response) => response.json())
.then((response) => {
//updated cart is in response.cart
})
```
</TabItem>
</Tabs>
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/#tag/Cart/operation/PostCartsCartPaymentSession) API endpoint:
<Tabs groupId="request-tyoe">
<TabItem value="client" label="Medusa JS Client" default>
```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
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/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
})
```
</TabItem>
</Tabs>
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/#tag/Cart/operation/PostCartsCartPaymentSessionUpdate) API endpoint passing it the updated data object:
<Tabs groupId="request-tyoe">
<TabItem value="client" label="Medusa JS Client" default>
```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
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/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
})
```
</TabItem>
</Tabs>
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/#tag/Cart/operation/PostCartsCartComplete) API endpoint:
<Tabs groupId="request-tyoe">
<TabItem value="client" label="Medusa JS Client" default>
```jsx
medusa.carts.complete(cart.id)
.then((response) => {
//order details is in response.data
})
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx
fetch(`<SERVER_URL>/store/carts/${cart.id}/complete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}).then((response) => response.json())
.then((response) => {
//order details is in response.data
})
```
</TabItem>
</Tabs>
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`.
## Whats Next 🚀
- Learn more about the [JS Client and how to use it](../../js-client/overview.md).
- 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.