Cart API
The Cart API allows you to create, update, delete carts and manage line items in your Flutter application using the Reachu SDK.
Overview
The cart module provides methods to:
- 🛒 Create carts - Initialize new shopping carts for customers
- ➕ Add items - Add products to existing carts
- ✏️ Update items - Modify quantities and variants
- 🗑️ Remove items - Delete products from carts
- 📊 Get cart data - Retrieve cart details and totals
Create Cart
Create a new shopping cart for a customer session.
Method
Create Cart
Future<Cart> create({
required String customer_session_id,
required String currency,
})
Example
lib/services/cart_service.dart
import 'package:your_app/services/sdk_service.dart';
import 'package:uuid/uuid.dart';
class CartService {
static Future<Cart> createCart({String currency = 'USD'}) async {
try {
// Generate unique session ID
final uuid = const Uuid().v4();
final cart = await SdkService().sdk.cart.create(
customer_session_id: uuid,
currency: currency,
);
print('Cart created successfully!');
print('Cart ID: ${cart.cartId}');
print('Currency: ${cart.currency}');
return cart;
} catch (e) {
print('Error creating cart: $e');
rethrow;
}
}
}
Response
Cart Model
class Cart {
final String cartId;
final String customerSessionId;
final String currency;
final double totalAmount;
final List<LineItem> lineItems;
final ShippingInfo? shippingInfo;
final DateTime createdAt;
final DateTime updatedAt;
// Convert to JSON
Map<String, dynamic> toJson();
}
Get Cart by ID
Retrieve an existing cart by its ID.
Method
Get Cart
Future<Cart> getById({required String cart_id})
Example
Get Cart Example
Future<Cart?> fetchCart(String cartId) async {
try {
final cart = await SdkService().sdk.cart.getById(cart_id: cartId);
print('Cart loaded: ${cart.cartId}');
print('Items in cart: ${cart.lineItems.length}');
print('Total: ${cart.currency} ${cart.totalAmount}');
return cart;
} catch (e) {
print('Error fetching cart: $e');
return null;
}
}
Add Item to Cart
Add a product to an existing shopping cart.
Method
Add Item
Future<Cart> addItem({
required String cart_id,
required Map<String, dynamic> line_items,
})
Example
lib/services/cart_service.dart
class CartService {
static Future<Cart?> addProductToCart({
required String cartId,
required int productId,
required int variantId,
int quantity = 1,
}) async {
try {
final updatedCart = await SdkService().sdk.cart.addItem(
cart_id: cartId,
line_items: {
'product_id': productId,
'variant_id': variantId,
'quantity': quantity,
},
);
print('Item added successfully!');
print('New cart total: ${updatedCart.totalAmount}');
print('Items in cart: ${updatedCart.lineItems.length}');
return updatedCart;
} catch (e) {
print('Error adding item to cart: $e');
return null;
}
}
}
Add Multiple Items
Add Multiple Items
Future<Cart?> addMultipleItems({
required String cartId,
required List<Map<String, dynamic>> items,
}) async {
try {
Cart? currentCart;
for (final item in items) {
currentCart = await SdkService().sdk.cart.addItem(
cart_id: cartId,
line_items: item,
);
}
return currentCart;
} catch (e) {
print('Error adding multiple items: $e');
return null;
}
}
// Usage
final items = [
{'product_id': 123, 'variant_id': 456, 'quantity': 2},
{'product_id': 789, 'variant_id': 101, 'quantity': 1},
];
final cart = await addMultipleItems(cartId: 'cart-123', items: items);
Update Cart Item
Update the quantity or variant of an existing cart item.
Method
Update Item
Future<Cart> updateItem({
required String cart_id,
required String line_item_id,
Map<String, dynamic>? updates,
})
Example
Update Cart Item
Future<Cart?> updateCartItemQuantity({
required String cartId,
required String lineItemId,
required int newQuantity,
}) async {
try {
final updatedCart = await SdkService().sdk.cart.updateItem(
cart_id: cartId,
line_item_id: lineItemId,
updates: {'quantity': newQuantity},
);
print('Item quantity updated to $newQuantity');
print('New cart total: ${updatedCart.totalAmount}');
return updatedCart;
} catch (e) {
print('Error updating cart item: $e');
return null;
}
}
Remove Item from Cart
Remove a specific item from the shopping cart.
Method
Remove Item
Future<Cart> removeItem({
required String cart_id,
required String line_item_id,
})
Example
Remove Cart Item
Future<Cart?> removeCartItem({
required String cartId,
required String lineItemId,
}) async {
try {
final updatedCart = await SdkService().sdk.cart.removeItem(
cart_id: cartId,
line_item_id: lineItemId,
);
print('Item removed successfully!');
print('Remaining items: ${updatedCart.lineItems.length}');
return updatedCart;
} catch (e) {
print('Error removing cart item: $e');
return null;
}
}
Cart Widget Example
Here's a complete cart widget implementation:
lib/widgets/shopping_cart.dart
import 'package:flutter/material.dart';
class ShoppingCartWidget extends StatefulWidget {
final String cartId;
const ShoppingCartWidget({super.key, required this.cartId});
_ShoppingCartWidgetState createState() => _ShoppingCartWidgetState();
}
class _ShoppingCartWidgetState extends State<ShoppingCartWidget> {
Cart? _cart;
bool _isLoading = true;
void initState() {
super.initState();
_loadCart();
}
Future<void> _loadCart() async {
try {
final cart = await SdkService().sdk.cart.getById(cart_id: widget.cartId);
setState(() {
_cart = cart;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
});
print('Error loading cart: $e');
}
}
Future<void> _updateQuantity(String lineItemId, int newQuantity) async {
if (newQuantity <= 0) {
await _removeItem(lineItemId);
return;
}
try {
final updatedCart = await SdkService().sdk.cart.updateItem(
cart_id: widget.cartId,
line_item_id: lineItemId,
updates: {'quantity': newQuantity},
);
setState(() {
_cart = updatedCart;
});
} catch (e) {
print('Error updating quantity: $e');
}
}
Future<void> _removeItem(String lineItemId) async {
try {
final updatedCart = await SdkService().sdk.cart.removeItem(
cart_id: widget.cartId,
line_item_id: lineItemId,
);
setState(() {
_cart = updatedCart;
});
} catch (e) {
print('Error removing item: $e');
}
}
Widget build(BuildContext context) {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (_cart == null || _cart!.lineItems.isEmpty) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.shopping_cart_outlined, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('Your cart is empty', style: TextStyle(fontSize: 18)),
],
),
);
}
return Column(
children: [
// Cart Items
Expanded(
child: ListView.builder(
itemCount: _cart!.lineItems.length,
itemBuilder: (context, index) {
final item = _cart!.lineItems[index];
return CartItemTile(
item: item,
onQuantityChanged: (newQuantity) => _updateQuantity(item.id, newQuantity),
onRemove: () => _removeItem(item.id),
);
},
),
),
// Cart Summary
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
border: Border(top: BorderSide(color: Colors.grey[300]!)),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Total:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text(
'${_cart!.currency} ${_cart!.totalAmount.toStringAsFixed(2)}',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
// Navigate to checkout
Navigator.pushNamed(context, '/checkout', arguments: _cart!.cartId);
},
child: const Text('Proceed to Checkout'),
),
),
],
),
),
],
);
}
}
class CartItemTile extends StatelessWidget {
final LineItem item;
final Function(int) onQuantityChanged;
final VoidCallback onRemove;
const CartItemTile({
super.key,
required this.item,
required this.onQuantityChanged,
required this.onRemove,
});
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
// Product Image
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
item.image ?? 'https://via.placeholder.com/60',
width: 60,
height: 60,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 60,
height: 60,
color: Colors.grey[300],
child: const Icon(Icons.image_not_supported),
);
},
),
),
const SizedBox(width: 12),
// Product Details
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.productTitle,
style: const TextStyle(fontWeight: FontWeight.bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
if (item.variantTitle != null)
Text(
item.variantTitle!,
style: TextStyle(color: Colors.grey[600], fontSize: 12),
),
const SizedBox(height: 4),
Text(
'${item.currency} ${item.price.toStringAsFixed(2)}',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.w600,
),
),
],
),
),
// Quantity Controls
Column(
children: [
Row(
children: [
IconButton(
onPressed: () => onQuantityChanged(item.quantity - 1),
icon: const Icon(Icons.remove_circle_outline),
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
),
Text(
'${item.quantity}',
style: const TextStyle(fontWeight: FontWeight.bold),
),
IconButton(
onPressed: () => onQuantityChanged(item.quantity + 1),
icon: const Icon(Icons.add_circle_outline),
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
),
],
),
IconButton(
onPressed: onRemove,
icon: const Icon(Icons.delete_outline, color: Colors.red),
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
),
],
),
],
),
),
);
}
}
Line Item Model
Line Item Model
class LineItem {
final String id;
final int productId;
final String productTitle;
final int? variantId;
final String? variantTitle;
final int quantity;
final double price;
final String currency;
final String? image;
final String supplier;
final Map<String, dynamic> attributes;
double get totalPrice => price * quantity;
Map<String, dynamic> toJson();
}
Error Handling
Handle common cart-related errors:
Cart Error Handling
Future<void> handleCartErrors() async {
try {
final cart = await SdkService().sdk.cart.getById(cart_id: 'cart-123');
// Process cart...
} on CartException catch (e) {
switch (e.type) {
case CartErrorType.cartNotFound:
print('Cart not found - creating new cart');
// Create new cart
break;
case CartErrorType.productNotAvailable:
print('Product is no longer available');
break;
case CartErrorType.insufficientStock:
print('Not enough stock for this quantity');
break;
case CartErrorType.invalidCurrency:
print('Invalid currency for this market');
break;
default:
print('Cart error: ${e.message}');
}
} catch (e) {
print('General error: $e');
}
}
Best Practices
1. Cart Persistence
Cart Persistence
import 'package:shared_preferences/shared_preferences.dart';
class CartPersistence {
static const String _cartIdKey = 'current_cart_id';
static Future<void> saveCartId(String cartId) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_cartIdKey, cartId);
}
static Future<String?> getCartId() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(_cartIdKey);
}
static Future<void> clearCartId() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_cartIdKey);
}
}
2. Cart State Management
Cart Provider
import 'package:flutter/material.dart';
class CartProvider extends ChangeNotifier {
Cart? _cart;
bool _isLoading = false;
Cart? get cart => _cart;
bool get isLoading => _isLoading;
int get itemCount => _cart?.lineItems.length ?? 0;
double get totalAmount => _cart?.totalAmount ?? 0.0;
Future<void> loadCart(String cartId) async {
_isLoading = true;
notifyListeners();
try {
_cart = await SdkService().sdk.cart.getById(cart_id: cartId);
} catch (e) {
print('Error loading cart: $e');
} finally {
_isLoading = false;
notifyListeners();
}
}
Future<void> addItem(int productId, int variantId, {int quantity = 1}) async {
if (_cart == null) return;
try {
_cart = await SdkService().sdk.cart.addItem(
cart_id: _cart!.cartId,
line_items: {
'product_id': productId,
'variant_id': variantId,
'quantity': quantity,
},
);
notifyListeners();
} catch (e) {
print('Error adding item: $e');
}
}
}
Related APIs
- Checkout API - Convert carts to checkouts
- Payment API - Process cart payments
- Channel API - Get products to add to cart
Troubleshooting
Common Issues
-
"Cart not found"
- Check if cart ID is valid
- Cart might have expired
- Create a new cart for the session
-
"Product not available"
- Product might be out of stock
- Check product availability before adding
- Handle gracefully in UI
-
"Invalid line item"
- Verify product and variant IDs exist
- Check required fields are provided
- Ensure quantities are positive numbers
-
"Currency mismatch"
- Ensure all products use the same currency
- Create separate carts for different currencies
- Check market-specific pricing