The WooCommerce REST API is the backbone of every headless WooCommerce implementation. While WPGraphQL gets attention for its flexibility, the REST API remains the most battle-tested, well-documented, and widely-supported option. Here’s everything you need to know to build a production headless store on it.
Authentication
WooCommerce REST API supports three authentication methods:
Consumer Key/Secret (Server-to-Server)
Best for server-side rendering and backend operations. Generate keys in WooCommerce > Settings > REST API.
import WooCommerceRestApi from "@woocommerce/woocommerce-rest-api";
const api = new WooCommerceRestApi({
url: "https://your-store.com",
consumerKey: process.env.WC_CONSUMER_KEY,
consumerSecret: process.env.WC_CONSUMER_SECRET,
version: "wc/v3"
});
JWT Authentication (Client-Side)
For customer-facing operations (viewing orders, managing account), use JWT. Install the JWT Authentication plugin on WordPress.
// Login and get token
const auth = await fetch('https://your-store.com/wp-json/jwt-auth/v1/token', {
method: 'POST',
body: JSON.stringify({ username, password })
});
const { token } = await auth.json();
// Use token for authenticated requests
const orders = await fetch('https://your-store.com/wp-json/wc/v3/orders', {
headers: { 'Authorization': Bearer ${token} }
});
Application Passwords (WordPress 5.6+)
Built into WordPress core. Simple but less suitable for public-facing apps.
Essential Endpoints for Headless Stores
Products
GET /wp-json/wc/v3/products # List products
GET /wp-json/wc/v3/products/{id} # Single product
GET /wp-json/wc/v3/products/{id}/variations # Product variations
GET /wp-json/wc/v3/products/categories # Categories
GET /wp-json/wc/v3/products/tags # Tags
GET /wp-json/wc/v3/products/attributes # Attributes (Size, Color, etc.)
Key query parameters:
per_page(max 100),page— paginationcategory— filter by category IDtag— filter by tag IDsearch— keyword searchorderby— date, title, price, popularity, ratingmin_price,max_price— price range filterstock_status— instock, outofstock, onbackorder
Cart (via CoCart or Store API)
WooCommerce’s native REST API doesn’t include cart endpoints. Use one of these:
WooCommerce Store API (Block-based):
GET /wp-json/wc/store/v1/cart
POST /wp-json/wc/store/v1/cart/add-item
POST /wp-json/wc/store/v1/cart/remove-item
POST /wp-json/wc/store/v1/cart/update-item
POST /wp-json/wc/store/v1/cart/apply-coupon
CoCart Plugin:
GET /wp-json/cocart/v2/cart
POST /wp-json/cocart/v2/cart/add-item
DELETE /wp-json/cocart/v2/cart/item/{item_key}
Orders
POST /wp-json/wc/v3/orders # Create order (checkout)
GET /wp-json/wc/v3/orders/{id} # Order details
PUT /wp-json/wc/v3/orders/{id} # Update order
Customers
POST /wp-json/wc/v3/customers # Register
GET /wp-json/wc/v3/customers/{id} # Profile
PUT /wp-json/wc/v3/customers/{id} # Update profile
Building the Checkout Flow
The headless checkout is the most complex part. Here’s the typical flow:
1. Cart (Store API) → Collect items
- Shipping zones → Calculate shipping
- Payment → Process via gateway
- Create order → POST /orders with all data
- Confirmation → Display order details
Creating an order with payment:
const order = await api.post('orders', {
payment_method: 'stripe',
payment_method_title: 'Credit Card',
set_paid: false, // Payment gateway handles this
billing: {
first_name: 'John', last_name: 'Doe',
address_1: '123 Main St', city: 'New York',
state: 'NY', postcode: '10001', country: 'US',
email: '[email protected]', phone: '555-0123'
},
shipping: { / same structure / },
line_items: [
{ product_id: 93, quantity: 2 },
{ variation_id: 1234, quantity: 1 }
],
shipping_lines: [
{ method_id: 'flat_rate', method_title: 'Standard', total: '5.00' }
]
});
Performance Optimization
1. Field Filtering
Don’t fetch entire product objects when you only need title, price, and image:
GET /wp-json/wc/v3/products?_fields=id,name,price,images
2. Batch Requests
Update multiple products in one call:
await api.post('products/batch', {
update: [
{ id: 1, stock_quantity: 50 },
{ id: 2, stock_quantity: 30 }
]
});
3. Caching Strategy
- Product listings: Cache for 5-10 minutes (ISR in Next.js)
- Single products: Cache for 1-5 minutes
- Cart: Never cache
- Stock levels: Cache for 60 seconds max
4. Pagination
Always paginate. Never fetch all products at once. The response header X-WP-TotalPages tells you how many pages exist.
Common Pitfalls
CORS: WordPress doesn’t enable CORS by default. Add to your theme’s functions.php or use a plugin:
add_action('init', function() {
header('Access-Control-Allow-Origin: https://your-frontend.com');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
});
Rate Limiting: WooCommerce doesn’t have built-in rate limiting, but your hosting provider might. Test under load.
Image URLs: Product images return full WordPress URLs. If your frontend is on a different domain, consider proxying images through your CDN.
Conclusion
The WooCommerce REST API is comprehensive enough to power a full headless storefront. The key gaps — cart management and real-time features — are filled by the Store API and CoCart. Focus on field filtering and caching for performance, and plan your checkout flow carefully. The API is stable, well-documented, and ready for production headless commerce.
Last modified: April 3, 2026
United States / English
Slovensko / Slovenčina
Canada / Français
Türkiye / Türkçe