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 — pagination
  • category — filter by category ID
  • tag — filter by tag ID
  • search — keyword search
  • orderby — date, title, price, popularity, rating
  • min_price, max_price — price range filter
  • stock_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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Close Search Window