API Integration Guide
This guide explains how the app communicates with the Botble E-commerce backend API.

API Overview
The app uses the Botble E-commerce REST API for all data operations. The API documentation is available at https://ecommerce-api.botble.com/docs.
Configuration
Base URL
Set your API base URL in the .env file:
API_BASE_URL=https://your-website.com
API_KEY=your-api-keyNote: The app automatically appends /api/v1 to API_BASE_URL for API calls.
API Client
The app uses a centralized API client at src/services/apiClient.ts with these features:
- Automatic headers —
X-LANGUAGE,X-CURRENCY,X-API-KEY, andAuthorizationheaders are injected automatically - In-memory cache — Language, currency, and auth token are cached in memory (synced from AsyncStorage on startup)
- 30-second timeout — All requests abort after 30s via
AbortController - Error extraction — Parses API error responses to extract validation messages (e.g.,
{errors: {qty: ["Max qty is 2"]}}) - App status monitoring — 503 responses trigger maintenance mode UI; 500/502/504 trigger server error state
import { api } from '@/services/apiClient';
// GET request (auth token auto-injected if user is logged in)
const products = await api.get('/ecommerce/products');
// POST request
const result = await api.post('/ecommerce/cart/add', { product_id: 123, quantity: 1 });
// With explicit token override
const data = await api.get('/ecommerce/profile', customToken);Authentication
Login
POST /api/v1/ecommerce/loginRequest:
{
"email": "[email protected]",
"password": "password123"
}Response:
{
"error": false,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"name": "John Doe",
"email": "[email protected]"
}
}
}Register
POST /api/v1/ecommerce/registerRequest:
{
"name": "John Doe",
"email": "[email protected]",
"password": "password123",
"password_confirmation": "password123"
}Token Storage
Tokens are stored securely using Expo Secure Store:
import * as SecureStore from 'expo-secure-store';
// Store token
await SecureStore.setItemAsync('auth_token', token);
// Retrieve token
const token = await SecureStore.getItemAsync('auth_token');
// Remove token
await SecureStore.deleteItemAsync('auth_token');Products
Get Products
GET /api/v1/ecommerce/productsQuery Parameters:
page- Page numberper_page- Items per pagecategories[]- Filter by category IDsbrands[]- Filter by brand IDsmin_price- Minimum pricemax_price- Maximum pricesort_by- Sort field (name, price, created_at)order_by- Sort order (asc, desc)
Get Product Detail
GET /api/v1/ecommerce/products/{slug}Get Categories
GET /api/v1/ecommerce/categoriesGet Brands
GET /api/v1/ecommerce/brandsSearch Products
GET /api/v1/ecommerce/products?keyword={query}Cart
Get Cart
GET /api/v1/ecommerce/cartAdd to Cart
POST /api/v1/ecommerce/cart/addRequest:
{
"product_id": 123,
"quantity": 1,
"options": {
"attribute_color": "Red",
"attribute_size": "M"
}
}Update Cart Item
PUT /api/v1/ecommerce/cart/updateRemove from Cart
DELETE /api/v1/ecommerce/cart/remove/{rowId}Apply Coupon
POST /api/v1/ecommerce/coupon/applyRequest:
{
"coupon_code": "DISCOUNT10",
"cart_id": "abc123"
}Note: The cart_id is always required when applying or removing coupons — both for guest and authenticated users.
Remove Coupon
POST /api/v1/ecommerce/coupon/removeRequest:
{
"cart_id": "abc123"
}Wishlist
Get Wishlist
GET /api/v1/ecommerce/wishlistAdd to Wishlist
POST /api/v1/ecommerce/wishlistRequest:
{
"product_id": 123
}Remove from Wishlist
DELETE /api/v1/ecommerce/wishlist/{product_id}Orders
Get Orders
GET /api/v1/ecommerce/ordersGet Order Detail
GET /api/v1/ecommerce/orders/{id}Cancel Order
POST /api/v1/ecommerce/orders/{id}/cancelAddresses
Get Addresses
GET /api/addressesCreate Address
POST /api/addressesRequest:
{
"name": "John Doe",
"phone": "+1234567890",
"email": "[email protected]",
"country": "United States",
"state": "California",
"city": "Los Angeles",
"address": "123 Main St",
"zip_code": "90001",
"is_default": true
}Update Address
PUT /api/addresses/{id}Delete Address
DELETE /api/addresses/{id}Get Countries
GET /api/countriesCheckout
WebView Checkout
The app uses a WebView-based checkout for payment processing:
GET /checkout/cart/{cartId}?token={authToken}This opens the website's checkout page with the user's cart and authentication.
Error Handling
Standard Error Response
{
"error": true,
"message": "Error description",
"errors": {
"field_name": ["Validation error message"]
}
}Error Codes
| Code | Meaning | App Behavior |
|---|---|---|
| 400 | Bad Request - Invalid data | Shows error message |
| 401 | Unauthorized - Invalid/expired token | Redirects to login |
| 403 | Forbidden - Access denied | Shows error message |
| 404 | Not Found - Resource doesn't exist | Shows error message |
| 422 | Validation Error | Extracts first validation message |
| 500 | Server Error | Triggers server_error app status |
| 503 | Service Unavailable | Triggers maintenance mode UI |
Error Message Extraction
The API client automatically extracts user-friendly messages from error responses. It checks in order:
errorsobject → first validation message (e.g.,{errors: {qty: ["Max qty is 2"]}}→"Max qty is 2")messagefield → generic API message- Fallback →
"API request failed: {status} {statusText}"
Handling Errors in Code
import { ApiError } from '@/services/apiClient';
try {
const data = await api.get('/ecommerce/products');
} catch (error) {
if (error instanceof ApiError) {
// error.message contains the extracted user-friendly message
// error.status contains the HTTP status code
if (error.status === 401) {
logout();
} else {
showToast(error.message);
}
}
}React Query Integration
Query Example
import { useQuery } from '@tanstack/react-query';
import { fetchProducts } from '@/services/api';
function ProductList() {
const { data, isLoading, error, refetch } = useQuery({
queryKey: ['products'],
queryFn: fetchProducts,
staleTime: 5 * 60 * 1000, // 5 minutes
});
if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage onRetry={refetch} />;
return <ProductGrid products={data} />;
}Mutation Example
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { addToCart } from '@/services/api';
function AddToCartButton({ productId }) {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: addToCart,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['cart'] });
showToast('Added to cart!');
},
onError: (error) => {
showToast(error.message);
},
});
return (
<Button
onPress={() => mutation.mutate({ productId, quantity: 1 })}
loading={mutation.isPending}
>
Add to Cart
</Button>
);
}Testing API Connections
Check API Health
curl https://your-website.com/api/v1/ecommerce/productsTest Authentication
curl -X POST https://your-website.com/api/v1/ecommerce/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password"}'Need Help?
- Check API Documentation
- Read the Troubleshooting Guide
- Contact support for assistance
