Cart Integration Guide
This guide covers how to integrate VesuvioPay's cart functionality into your e-commerce application, enabling customers to build shopping carts and proceed to checkout.
Overview​
The VesuvioPay Cart API provides:
- Multi-store cart management
- Add, update, and remove cart items
- Bulk operations for better performance
- Product availability checking
- Back-in-stock subscription management
- Checkout flow integration
Authentication​
Cart API endpoints support dual authentication:
- JWT Token (Required): Customer authentication via Bearer token
- API Key (Optional): Store identification via
X-Api-Keyheader
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
X-Api-Key: your-api-key (optional)
Authentication Policies​
- Customer with Verified Phone: Required for all cart operations
- Public API Key: Required for availability checking without customer auth
- Private API Key: Optional for enhanced security and store validation
Cart Lifecycle​
graph LR
A[Customer Login] --> B[Get/Create Cart]
B --> C[Add Items]
C --> D[Update Quantities]
D --> E[Remove Items]
E --> F[Finish Cart]
F --> G[Checkout & Payment]
G --> H[Order Created]
Getting Started​
Step 1: Authenticate Customer​
Before accessing the cart, authenticate your customer to get a JWT token:
const response = await fetch('https://api.vesuviopay.com/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
phoneNumber: '+1234567890',
verificationCode: '123456'
})
});
const { token } = await response.json();
Step 2: Get Customer's Cart​
Retrieve the current cart for a specific store:
Endpoint: GET /api/v1/sdk/cart/{storeId}
const storeId = 'a3f2b1c0-1234-5678-90ab-cdef12345678';
const response = await fetch(`https://api.vesuviopay.com/api/v1/sdk/cart/${storeId}`, {
headers: {
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
}
});
const cart = await response.json();
Response:
{
"success": true,
"data": {
"storeId": "a3f2b1c0-1234-5678-90ab-cdef12345678",
"storeName": "My Store",
"items": [
{
"id": "b4e3c2d1-2345-6789-01bc-def123456789",
"productVariantId": "c5f4d3e2-3456-7890-12cd-ef1234567890",
"externalId": "shopify_12345",
"externalVariantId": "shopify_variant_001",
"productTitle": "Premium T-Shirt",
"variantTitle": "Small / Red",
"sku": "TSHIRT-S-RED",
"quantity": 2,
"originalUnitPrice": 39.99,
"unitPrice": 29.99,
"originalTotalPrice": 79.98,
"totalPrice": 59.98,
"hasDiscount": true,
"discountPercentage": 25,
"discountAmount": 19.98,
"addedAt": "2025-10-08T10:00:00Z",
"updatedAt": "2025-10-08T10:15:00Z"
}
],
"summary": {
"itemCount": 1,
"totalQuantity": 2,
"subtotal": 59.98,
"estimatedTax": 4.80,
"estimatedShipping": 5.00,
"estimatedTotal": 69.78
}
}
}
Cart Operations​
Add Item to Cart​
Endpoint: POST /api/v1/sdk/cart/store/{storeId}/item
Add a product variant to the cart. If the item already exists, the quantity will be incremented.
async function addToCart(storeId, externalProductId, externalVariantId, quantity) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/item`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({
externalProductId: externalProductId,
externalVariantId: externalVariantId,
quantity: quantity
})
}
);
return await response.json();
}
// Usage
await addToCart(
'a3f2b1c0-1234-5678-90ab-cdef12345678',
'shopify_12345',
'shopify_variant_001',
2
);
Request Body:
{
"externalProductId": "shopify_12345",
"externalVariantId": "shopify_variant_001",
"quantity": 2
}
Update Cart Item Quantity​
Endpoint: PUT /api/v1/sdk/cart/store/{storeId}/item
Update the quantity of an existing cart item.
async function updateCartItem(storeId, cartItemId, newQuantity) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/item`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({
cartItemId: cartItemId,
quantity: newQuantity
})
}
);
return await response.json();
}
// Usage
await updateCartItem(
'a3f2b1c0-1234-5678-90ab-cdef12345678',
'b4e3c2d1-2345-6789-01bc-def123456789',
5
);
Remove Item from Cart​
Endpoint: DELETE /api/v1/sdk/cart/store/{storeId}/item/{cartItemId}
async function removeFromCart(storeId, cartItemId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/item/${cartItemId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
}
}
);
return await response.json();
}
Clear Entire Cart​
Endpoint: DELETE /api/v1/sdk/cart/store/{storeId}
Remove all items from the cart for a specific store.
async function clearCart(storeId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
}
}
);
return await response.json();
}
Bulk Operations​
For better performance when adding or updating multiple items, use bulk endpoints.
Bulk Add Items​
Endpoint: POST /api/v1/sdk/cart/store/{storeId}/items/bulk
async function bulkAddToCart(storeId, items) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/items/bulk`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({ items })
}
);
return await response.json();
}
// Usage
await bulkAddToCart('a3f2b1c0-1234-5678-90ab-cdef12345678', [
{
externalProductId: 'shopify_12345',
externalVariantId: 'shopify_variant_001',
quantity: 2
},
{
externalProductId: 'shopify_67890',
externalVariantId: 'shopify_variant_002',
quantity: 1
}
]);
Bulk Update Items​
Endpoint: PUT /api/v1/sdk/cart/store/{storeId}/items/bulk
async function bulkUpdateCartItems(storeId, items) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/items/bulk`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({ items })
}
);
return await response.json();
}
// Usage
await bulkUpdateCartItems('a3f2b1c0-1234-5678-90ab-cdef12345678', [
{ cartItemId: 'item-id-1', quantity: 5 },
{ cartItemId: 'item-id-2', quantity: 3 }
]);
Bulk Remove Items​
Endpoint: DELETE /api/v1/sdk/cart/store/{storeId}/items/bulk
async function bulkRemoveFromCart(storeId, cartItemIds) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/items/bulk`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({ cartItemIds })
}
);
return await response.json();
}
// Usage
await bulkRemoveFromCart('a3f2b1c0-1234-5678-90ab-cdef12345678', [
'item-id-1',
'item-id-2',
'item-id-3'
]);
Product Availability Checking​
Before adding items to cart or during checkout, check product availability.
Check Availability (API Key Only)​
Endpoint: POST /api/v1/sdk/cart/store/{storeId}/availability
Authentication: Public API Key (no customer authentication required)
async function checkAvailability(storeId, externalProductId, externalVariantId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/availability`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'your-public-api-key'
},
body: JSON.stringify({
externalProductId,
externalVariantId
})
}
);
return await response.json();
}
// Usage
const availability = await checkAvailability(
'a3f2b1c0-1234-5678-90ab-cdef12345678',
'shopify_12345',
'shopify_variant_001'
);
Response:
{
"success": true,
"data": {
"available": true,
"inventoryQuantity": 100,
"inventoryTracking": true,
"productTitle": "Premium T-Shirt",
"variantTitle": "Small / Red",
"price": 29.99,
"compareAtPrice": 39.99
}
}
Check Availability with Subscription Status​
Endpoint: POST /api/v1/sdk/cart/store/{storeId}/availability-with-subscription
Authentication: Customer JWT + Optional API Key
This endpoint also returns whether the customer is subscribed to back-in-stock notifications.
async function checkAvailabilityWithSubscription(storeId, externalProductId, externalVariantId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/availability-with-subscription`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({
externalProductId,
externalVariantId
})
}
);
return await response.json();
}
Response:
{
"success": true,
"data": {
"available": false,
"inventoryQuantity": 0,
"inventoryTracking": true,
"productTitle": "Premium T-Shirt",
"variantTitle": "Small / Red",
"price": 29.99,
"compareAtPrice": 39.99,
"isSubscribedToBackInStock": true
}
}
Back-in-Stock Subscriptions​
Allow customers to subscribe to notifications when out-of-stock products become available.
Subscribe to Back-in-Stock Notifications​
Endpoint: POST /api/v1/sdk/cart/store/{storeId}/back-in-stock-subscription
async function subscribeToBackInStock(storeId, externalProductId, externalVariantId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/back-in-stock-subscription`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({
externalProductId,
externalVariantId
})
}
);
return await response.json();
}
Unsubscribe from Back-in-Stock Notifications​
Endpoint: DELETE /api/v1/sdk/cart/store/{storeId}/back-in-stock-subscription
async function unsubscribeFromBackInStock(storeId, externalProductId, externalVariantId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/back-in-stock-subscription`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
},
body: JSON.stringify({
externalProductId,
externalVariantId
})
}
);
return await response.json();
}
Checkout Flow​
Finish Cart and Send Checkout Link​
Endpoint: POST /api/v1/sdk/cart/store/{storeId}/finish
This endpoint completes the cart flow and sends the customer a checkout link via SMS.
async function finishCart(storeId) {
const response = await fetch(
`https://api.vesuviopay.com/api/v1/sdk/cart/store/${storeId}/finish`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'X-Api-Key': 'your-api-key' // optional
}
}
);
return await response.json();
}
// Usage
const result = await finishCart('a3f2b1c0-1234-5678-90ab-cdef12345678');
console.log('Checkout URL:', result.data); // Returns the checkout URL
Response:
{
"success": true,
"data": "https://checkout.vesuviopay.com/c/abc123xyz"
}
The customer will receive an SMS with the checkout link and can complete the purchase on VesuvioPay's secure checkout page.
Complete Cart Integration Example​
Here's a complete React example with cart state management:
import { useState, useEffect } from 'react';
const VESUVIO_API_BASE = 'https://api.vesuviopay.com/api/v1';
const STORE_ID = 'a3f2b1c0-1234-5678-90ab-cdef12345678';
const API_KEY = process.env.VESUVIO_API_KEY;
class VesuvioCartService {
constructor(token, apiKey) {
this.token = token;
this.apiKey = apiKey;
}
async getCart(storeId) {
const response = await fetch(`${VESUVIO_API_BASE}/sdk/cart/${storeId}`, {
headers: {
'Authorization': `Bearer ${this.token}`,
'X-Api-Key': this.apiKey
}
});
if (!response.ok) throw new Error('Failed to fetch cart');
return await response.json();
}
async addItem(storeId, externalProductId, externalVariantId, quantity) {
const response = await fetch(`${VESUVIO_API_BASE}/sdk/cart/store/${storeId}/item`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.token}`,
'X-Api-Key': this.apiKey
},
body: JSON.stringify({
externalProductId,
externalVariantId,
quantity
})
});
if (!response.ok) throw new Error('Failed to add item');
return await response.json();
}
async updateItem(storeId, cartItemId, quantity) {
const response = await fetch(`${VESUVIO_API_BASE}/sdk/cart/store/${storeId}/item`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.token}`,
'X-Api-Key': this.apiKey
},
body: JSON.stringify({ cartItemId, quantity })
});
if (!response.ok) throw new Error('Failed to update item');
return await response.json();
}
async removeItem(storeId, cartItemId) {
const response = await fetch(
`${VESUVIO_API_BASE}/sdk/cart/store/${storeId}/item/${cartItemId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${this.token}`,
'X-Api-Key': this.apiKey
}
}
);
if (!response.ok) throw new Error('Failed to remove item');
return await response.json();
}
async finishCart(storeId) {
const response = await fetch(`${VESUVIO_API_BASE}/sdk/cart/store/${storeId}/finish`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'X-Api-Key': this.apiKey
}
});
if (!response.ok) throw new Error('Failed to finish cart');
return await response.json();
}
}
// React Hook for Cart Management
function useVesuvioCart(token) {
const [cart, setCart] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const cartService = new VesuvioCartService(token, API_KEY);
const loadCart = async () => {
setLoading(true);
try {
const result = await cartService.getCart(STORE_ID);
setCart(result.data);
setError(null);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const addToCart = async (externalProductId, externalVariantId, quantity = 1) => {
setLoading(true);
try {
await cartService.addItem(STORE_ID, externalProductId, externalVariantId, quantity);
await loadCart(); // Refresh cart
setError(null);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const updateQuantity = async (cartItemId, quantity) => {
setLoading(true);
try {
await cartService.updateItem(STORE_ID, cartItemId, quantity);
await loadCart(); // Refresh cart
setError(null);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const removeItem = async (cartItemId) => {
setLoading(true);
try {
await cartService.removeItem(STORE_ID, cartItemId);
await loadCart(); // Refresh cart
setError(null);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const checkout = async () => {
setLoading(true);
try {
const result = await cartService.finishCart(STORE_ID);
// Redirect to checkout URL
window.location.href = result.data;
} catch (err) {
setError(err.message);
setLoading(false);
}
};
useEffect(() => {
if (token) loadCart();
}, [token]);
return {
cart,
loading,
error,
addToCart,
updateQuantity,
removeItem,
checkout,
refresh: loadCart
};
}
// Cart Component
function CartPage({ token }) {
const { cart, loading, addToCart, updateQuantity, removeItem, checkout } = useVesuvioCart(token);
if (loading && !cart) return <div>Loading cart...</div>;
if (!cart) return <div>Your cart is empty</div>;
return (
<div className="cart-page">
<h1>Shopping Cart</h1>
<div className="cart-items">
{cart.items.map(item => (
<div key={item.id} className="cart-item">
<h3>{item.productTitle}</h3>
{item.variantTitle && <p>{item.variantTitle}</p>}
<div className="quantity-controls">
<button onClick={() => updateQuantity(item.id, item.quantity - 1)}>-</button>
<span>{item.quantity}</span>
<button onClick={() => updateQuantity(item.id, item.quantity + 1)}>+</button>
</div>
<div className="price">
{item.hasDiscount && (
<span className="original-price">${item.originalUnitPrice}</span>
)}
<span className="current-price">${item.unitPrice}</span>
</div>
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
))}
</div>
<div className="cart-summary">
<p>Subtotal: ${cart.summary.subtotal.toFixed(2)}</p>
<p>Tax (estimated): ${cart.summary.estimatedTax.toFixed(2)}</p>
<p>Shipping (estimated): ${cart.summary.estimatedShipping.toFixed(2)}</p>
<h2>Total: ${cart.summary.estimatedTotal.toFixed(2)}</h2>
<button onClick={checkout} disabled={loading}>
Proceed to Checkout
</button>
</div>
</div>
);
}
Error Handling​
Common Error Responses​
400 Bad Request - Invalid Item​
{
"success": false,
"message": "Product variant not found or unavailable",
"errorCode": "PRODUCT_NOT_FOUND"
}
400 Bad Request - Insufficient Inventory​
{
"success": false,
"message": "Insufficient inventory. Only 5 items available",
"errorCode": "INSUFFICIENT_INVENTORY"
}
401 Unauthorized​
{
"success": false,
"message": "Unauthorized. Valid JWT token required"
}
403 Forbidden - API Key Mismatch​
{
"success": false,
"message": "API key does not have access to this store",
"errorCode": "NO_STORE_ACCESS"
}
Best Practices​
1. Handle Inventory Validation​
Always check availability before adding items:
const availability = await checkAvailability(storeId, productId, variantId);
if (availability.data.available) {
await addToCart(storeId, productId, variantId, quantity);
} else {
alert('Product is out of stock');
}
2. Use Bulk Operations​
For better performance when modifying multiple items:
// Instead of multiple individual calls
for (const item of items) {
await addToCart(storeId, item.productId, item.variantId, item.quantity);
}
// Use bulk operation
await bulkAddToCart(storeId, items);
3. Implement Optimistic Updates​
Update UI immediately, then sync with server:
function optimisticUpdateQuantity(cartItemId, newQuantity) {
// Update local state immediately
setCart(prev => ({
...prev,
items: prev.items.map(item =>
item.id === cartItemId ? { ...item, quantity: newQuantity } : item
)
}));
// Then sync with server
updateQuantity(cartItemId, newQuantity).catch(() => {
// Revert on error
loadCart();
});
}
4. Monitor Cart State​
Listen for cart-related webhook events to keep cart in sync:
cart.item_addedcart.item_updatedcart.item_removedcart.cleared
See Webhook Integration Guide for details.
Next Steps​
- Implement Webhook Integration to receive real-time cart updates
- Set up Product Sync to ensure product availability
- Review Order Management for post-checkout handling