Building an e-commerce storefront requires implementing a robust checkout flow that handles cart management, shipping, and payment processing. Medusa.js provides a comprehensive set of Store APIs that make this process straightforward. In this article, we'll explore the complete Medusa checkout flow by walking through each API endpoint required to take a customer from an empty cart to a completed order.
Understanding the Medusa Checkout Process
The Medusa checkout flow consists of seven essential steps:
- Cart Creation - Initialize a new shopping cart
- Add Items - Add products to the cart
- Set Shipping Address - Configure delivery information
- Select Shipping Method - Choose delivery options
- Payment Collection - Initialize payment processing
- Payment Session - Set up payment provider
- Complete Order - Finalize the purchase
Each step builds upon the previous one, creating a seamless user experience while maintaining data integrity throughout the process.
Prerequisites and Setup
Before diving into the implementation, ensure you have:
- A running Medusa v2 application
- Valid publishable API key
- Product variants, regions, and shipping options configured
- Payment provider set up (we'll use the system default)
-
curl
andjq
installed for making API requests and parsing JSON responses
curl
and jq
Installation
# macOS (using Homebrew)
brew install curl jq
# Ubuntu/Debian
sudo apt update
sudo apt install curl jq
# Windows (using Chocolatey)
choco install curl jq
Environment Variables
Set the following variables before running the checkout flow:
export BASE_URL="<http://localhost:9000>"
export PUBLISHABLE_KEY="pk_<your_publishable_key_here>"
export REGION_ID="reg_<your_region_id>"
export PRODUCT_VARIANT_ID="variant_<your_variant_id>"
export SHIPPING_OPTION_ID="so_<your_shipping_option_id>"
export PAYMENT_PROVIDER_ID="pp_system_default"
Note: The CART_ID
and PAYMENT_COLLECTION_ID
variables should be set during the checkout process after cart creation and payment collection initialization.
Step-by-Step Implementation
1. Create a New Cart
The checkout journey begins with creating a new cart associated with a specific region:
curl -X POST "$BASE_URL/store/carts" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "region_id": "'$REGION_ID'" }'
Key Points:
- Each cart gets a unique identifier used in subsequent API calls
- Regions define currency, tax rates, and fulfillment settings
2. Add Products to Cart
Once the cart exists, add product variants with specified quantities:
curl -X POST "$BASE_URL/store/carts/$CART_ID/line-items" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "variant_id": "'$PRODUCT_VARIANT_ID'", "quantity": 1 }'
Key Points:
- Use
variant_id
rather thanproduct_id
for specific product configurations - Quantities can be updated by calling this endpoint again
- Inventory levels are automatically checked during this step
3. Set Shipping Address and Customer Information
Configure the delivery address and customer contact details:
curl -X POST "$BASE_URL/store/carts/$CART_ID" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{
"shipping_address": {
"first_name": "John",
"last_name": "Doe",
"address_1": "Nordmarksvej 9",
"city": "Billund",
"country_code": "dk",
"postal_code": "7190",
"phone": "1234567890"
},
"email": "john.doe@example.com"
}'
Key Points:
-
country_code
must match the region's available countries - Email is required for order confirmation and customer account association
- Billing address can be set separately if different from shipping address
4. Select Shipping Method
Choose from available shipping options for the cart's region and address:
curl -X POST "$BASE_URL/store/carts/$CART_ID/shipping-methods" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "option_id": "'$SHIPPING_OPTION_ID'" }'
5. Create Payment Collection
Initialize the payment processing system for the cart:
curl -X POST "$BASE_URL/store/payment-collections" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "cart_id": "'$CART_ID'" }'
6. Initialize Payment Session
Set up the payment provider session for processing:
curl -X POST "$BASE_URL/store/payment-collections/$PAYMENT_COLLECTION_ID/payment-sessions" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "provider_id": "'$PAYMENT_PROVIDER_ID'" }'
Key Points:
- Payment providers (Stripe, PayPal, etc.) require specific session initialization
- Provider ID must match configured payment providers in your Medusa setup
- Session contains payment intent or equivalent for the provider
7. Complete the Order
Finalize the checkout process and create the order:
curl -X POST "$BASE_URL/store/carts/$CART_ID/complete" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY"
Key Points:
- This step validates all cart information and processes payment
- Inventory is reserved and order confirmation is triggered
- The cart is converted to an immutable order record
Complete Implementation Example
Here's a complete shell script implementing the entire checkout flow:
#!/bin/bash
# Configuration
BASE_URL="<http://localhost:9000>"
PUBLISHABLE_KEY="pk_"
REGION_ID="reg_"
PRODUCT_VARIANT_ID="variant_"
SHIPPING_OPTION_ID="so_"
PAYMENT_PROVIDER_ID="pp_system_default"
# 1. Create cart
echo "Creating cart..."
CART_RESPONSE=$(curl -s -X POST "$BASE_URL/store/carts" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "region_id": "'$REGION_ID'" }')
CART_ID=$(echo $CART_RESPONSE | jq -r '.cart.id')
echo "Cart created with ID: $CART_ID"
# 2. Add item to cart
echo "Adding item to cart..."
curl -s -X POST "$BASE_URL/store/carts/$CART_ID/line-items" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "variant_id": "'$PRODUCT_VARIANT_ID'", "quantity": 1 }' > /dev/null
# 3. Set shipping address and email
echo "Setting shipping address..."
curl -s -X POST "$BASE_URL/store/carts/$CART_ID" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{
"shipping_address": {
"first_name": "John",
"last_name": "Doe",
"address_1": "Nordmarksvej 9",
"city": "Billund",
"country_code": "dk",
"postal_code": "7190",
"phone": "1234567890"
},
"email": "john.doe@example.com"
}' > /dev/null
# 4. Set shipping method
echo "Setting shipping method..."
curl -s -X POST "$BASE_URL/store/carts/$CART_ID/shipping-methods" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "option_id": "'$SHIPPING_OPTION_ID'" }' > /dev/null
# 5. Create payment collection
echo "Creating payment collection..."
PAYMENT_COLLECTION_RESPONSE=$(curl -s -X POST "$BASE_URL/store/payment-collections" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "cart_id": "'$CART_ID'" }')
PAYMENT_COLLECTION_ID=$(echo $PAYMENT_COLLECTION_RESPONSE | jq -r '.payment_collection.id')
echo "Payment collection created with ID: $PAYMENT_COLLECTION_ID"
# 6. Initialize payment session
echo "Initializing payment session..."
curl -s -X POST "$BASE_URL/store/payment-collections/$PAYMENT_COLLECTION_ID/payment-sessions" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY" \
-d '{ "provider_id": "'$PAYMENT_PROVIDER_ID'" }' > /dev/null
# 7. Complete the cart
echo "Completing order..."
ORDER_RESPONSE=$(curl -s -X POST "$BASE_URL/store/carts/$CART_ID/complete" \
-H "Content-Type: application/json" \
-H "x-publishable-api-key: $PUBLISHABLE_KEY")
ORDER_ID=$(echo $ORDER_RESPONSE | jq -r '.order.id')
echo "Order completed successfully: $ORDER_ID"
Troubleshooting
-
Check Service Health: Test if the service is responding by visiting
http://localhost:9000/store/products
in your browser. You should see a JSON response with available products. - Validate API Key: Confirm your publishable API key is correct and has proper permissions for store operations.
-
No Products Available: Verify products exist in your store by checking the
/store/products
endpoint. Ensure products are published and have available variants. -
Invalid Shipping Address:
- Validate address format matches the expected country standards
- Ensure the
country_code
is listed under the region's allowed countries - Check
/store/regions/{region_id}
to see available countries for your region
-
Shipping Option Not Available: Verify the shipping option is enabled for the selected region and address. Check
/store/shipping-options
for available options in your region. - Insufficient Inventory: Check stock levels before adding items. The API will return inventory errors if requested quantities exceed available stock.
-
Payment Provider Issues:
- Ensure the payment provider is properly configured in your Medusa setup
- Handle payment failures gracefully with appropriate error messaging
- Verify payment provider credentials are valid
Conclusion
The Medusa checkout flow provides a robust foundation for e-commerce applications with its well-structured API endpoints. By following this seven-step process, you can build reliable checkout experiences that handle modern e-commerce requirements.
Key takeaways:
- Each step depends on the previous one's completion
- Implement proper validation and retry logic
- Track cart state throughout the process
- Provide user feedback at each step
This approach supports various checkout scenarios including guest flows, multiple payment methods, and subscription purchases.
Top comments (0)