The WooCommerce Store API is one of the most powerful, and often underutilized, tools available to WooCommerce developers. Introduced as a modern replacement for the legacy WC REST API, the Store API provides a fast, block-friendly set of REST endpoints that power WooCommerce Blocks, the Cart and Checkout Block, and an increasing number of headless and decoupled commerce implementations. If you’re building custom storefronts, integrating third-party services, or extending the WooCommerce checkout experience, understanding the Store API is essential in 2026.
This guide covers everything developers need to know: the architecture of the Store API, how it differs from the WooCommerce REST API, authentication models, available endpoints, extending the API with custom data, error handling, performance optimization, and real-world implementation patterns. Whether you’re building a React-powered storefront, a mobile app, or an internal fulfillment dashboard, this guide will help you work with WooCommerce REST API endpoints confidently and correctly.
What Is the WooCommerce Store API?
The WooCommerce Store API (also called the WooCommerce Blocks API or Cart API in older documentation) is a set of public-facing REST endpoints introduced by the WooCommerce team to power WooCommerce Blocks. It lives at /wp-json/wc/store/v1/ and is distinct from the authenticated WooCommerce REST API at /wp-json/wc/v3/.
The Store API was designed with several goals in mind:
- Performance: Optimized for front-end consumption with minimal overhead
- Blocks compatibility: Powers Cart Block, Checkout Block, and Product Blocks
- Headless commerce: Enables decoupled frontend implementations (Next.js, Nuxt, React Native)
- Extensibility: Exposes extension hooks so plugins can add custom data to API responses
- Nonce-based auth: No need for OAuth or Application Passwords for front-end cart interactions
Unlike the WooCommerce REST API (which requires authentication for most operations), the Store API is designed to be consumed by unauthenticated front-end clients. Cart operations use session-based nonces, making it safe to call from JavaScript without exposing API keys.
Store API vs. WooCommerce REST API: Key Differences

Developers frequently confuse the Store API with the legacy WooCommerce REST API. Understanding the difference is critical before choosing which one to use for your project.
| Feature | Store API (/wc/store/v1/) | WooCommerce REST API (/wc/v3/) |
|---|---|---|
| Authentication | Nonce (front-end sessions) | Basic Auth / OAuth / Application Passwords |
| Primary Use Case | Front-end cart & checkout | Server-to-server admin operations |
| Product Read Access | Public (no auth needed) | Requires auth |
| Order Creation | Via checkout endpoint | Via orders endpoint (auth required) |
| Extensibility | ExtendSchema API | Custom endpoints / filters |
| Block Compatible | Yes (native) | No |
| Rate Limiting | Low (public API) | Higher (authenticated) |
| Stability | Experimental → Stable (2024+) | Stable since WooCommerce 3.x |
As a general rule: use the Store API for customer-facing front-end interactions, and use the WooCommerce REST API for server-side admin operations like order management, product sync, and fulfillment automation. For shipping integrations that bridge both worlds, see our guide on WooCommerce Shipping API Integrations for Multi-Carrier Rate Comparison.
Store API Endpoints: Complete Reference
The Store API exposes endpoints across several resource types. Here is a complete breakdown of the available endpoints as of WooCommerce 9.x:
Products Endpoints
GET /wp-json/wc/store/v1/products
GET /wp-json/wc/store/v1/products/{id}
GET /wp-json/wc/store/v1/products/collection-data
GET /wp-json/wc/store/v1/products/attributes
GET /wp-json/wc/store/v1/products/attributes/{attribute_id}/terms
The products endpoint supports filtering by category, tag, attribute, price range, on-sale status, featured status, and more. Collection data returns aggregated filter counts (stock status totals, attribute term counts, min/max prices), essential for building faceted search interfaces.
Cart Endpoints
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
POST /wp-json/wc/store/v1/cart/remove-coupon
POST /wp-json/wc/store/v1/cart/update-customer
POST /wp-json/wc/store/v1/cart/select-shipping-rate
GET /wp-json/wc/store/v1/cart/extensions
Cart endpoints are session-based. Each request must include either the X-WC-Store-API-Nonce header or the nonce query parameter. The nonce is generated by WordPress and injected into the front-end via wp_localize_script or wp_add_inline_script.
Checkout Endpoint
POST /wp-json/wc/store/v1/checkout
PUT /wp-json/wc/store/v1/checkout/{id}
The checkout endpoint is the most critical in the Store API. It processes the full order: validates the cart, applies taxes, collects payment method data, creates the WooCommerce order, and triggers payment processing. The PUT variant is used for updating an in-progress order (e.g., after 3D Secure redirect).
Other Resource Endpoints
GET /wp-json/wc/store/v1/countries
GET /wp-json/wc/store/v1/countries/{country_code}
GET /wp-json/wc/store/v1/payment-gateways
GET /wp-json/wc/store/v1/batch
The batch endpoint is particularly useful for reducing round trips, you can execute multiple cart operations in a single HTTP request, which significantly improves performance on mobile networks and low-latency-sensitive storefronts.
Authentication and Nonce Handling
Authentication in the Store API is fundamentally different from the WooCommerce REST API. Instead of API keys or OAuth tokens, the Store API uses WordPress nonces tied to the user’s session. This makes it safe for front-end JavaScript consumption without exposing credentials.
Generating and Using Nonces
Generate a nonce in PHP and pass it to JavaScript:
// In your plugin or theme functions.php
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_script( 'my-store-app', get_template_directory_uri() . '/js/app.js', [], '1.0', true );
wp_add_inline_script( 'my-store-app', sprintf(
'var MyStoreConfig = %s;',
wp_json_encode([
'nonce' => wp_create_nonce( 'wc_store_api' ),
'apiUrl' => rest_url( 'wc/store/v1' ),
])
), 'before' );
} );
Then in JavaScript, include the nonce header on all mutating requests:
// Fetch cart contents
const response = await fetch( `${MyStoreConfig.apiUrl}/cart`, {
method: 'GET',
credentials: 'include', // Required for session cookies
headers: {
'X-WC-Store-API-Nonce': MyStoreConfig.nonce,
'Content-Type': 'application/json',
},
} );
const cart = await response.json();
// Add item to cart
const addResponse = await fetch( `${MyStoreConfig.apiUrl}/cart/add-item`, {
method: 'POST',
credentials: 'include',
headers: {
'X-WC-Store-API-Nonce': MyStoreConfig.nonce,
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: 42, // Product ID
quantity: 1,
variation: [], // Variation data if applicable
}),
} );
The credentials: 'include' flag is essential, it ensures session cookies are sent with each request, allowing WooCommerce to identify the cart session. Without it, every request will create a new cart session and your cart will appear empty.
Nonce Expiry and Refresh
WordPress nonces expire after 12 hours by default. For long-lived single-page applications, implement nonce refresh by watching for a 401 response with a woocommerce_rest_cookie_invalid_nonce error code, then refreshing via a lightweight PHP endpoint and retrying the request.
async function storeApiFetch( endpoint, options = {} ) {
const response = await fetch( `${MyStoreConfig.apiUrl}${endpoint}`, {
credentials: 'include',
headers: {
'X-WC-Store-API-Nonce': window.__storeNonce,
'Content-Type': 'application/json'...options.headers,
}...options,
} );
if ( response.status === 401 ) {
const error = await response.json();
if ( error.code === 'woocommerce_rest_cookie_invalid_nonce' ) {
// Refresh nonce and retry once
const newNonce = await refreshNonce();
window.__storeNonce = newNonce;
return storeApiFetch( endpoint, options );
}
}
return response.json();
}
Extending the Store API with Custom Data
One of the most powerful features of the Store API is the ExtendSchema interface, which allows plugins to add custom data to existing Store API responses without modifying core files. This is the official, supported way to extend the Store API.
Adding Custom Data to Cart Items
<?php
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;
use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
// Register your extension
add_action( 'woocommerce_blocks_loaded', function() {
$extend = StoreApi::container()->get( ExtendSchema::class );
$extend->register_endpoint_data( [
'endpoint' => CartItemSchema::IDENTIFIER,
'namespace' => 'my-plugin',
'data_callback' => function( $cart_item ) {
$product_id = $cart_item['data']->get_id();
return [
'custom_message' => get_post_meta( $product_id, '_custom_message', true ),
'delivery_estimate' => get_post_meta( $product_id, '_delivery_estimate', true ),
'loyalty_points' => my_plugin_calculate_points( $cart_item ),
];
},
'schema_callback' => function() {
return [
'custom_message' => [
'description' => 'Custom product message',
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'delivery_estimate' => [
'description' => 'Estimated delivery in days',
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'loyalty_points' => [
'description' => 'Loyalty points this item earns',
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
];
},
] );
} );
Your custom data will appear in the extensions key of each cart item in the API response, namespaced to my-plugin to prevent conflicts with other plugins.
Extending the Checkout Endpoint
You can also add custom fields to the checkout payload and process them during order creation. This is how gift message fields, custom delivery instructions, and loyalty redemption fields are typically implemented:
<?php
use Automattic\WooCommerce\StoreApi\Schemas\V1\CheckoutSchema;
$extend->register_endpoint_data( [
'endpoint' => CheckoutSchema::IDENTIFIER,
'namespace' => 'my-plugin',
'data_callback' => function() {
return [
'gift_message' => WC()->session->get( 'gift_message', '' ),
];
},
'schema_callback' => function() {
return [
'gift_message' => [
'description' => 'Optional gift message for this order',
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => false,
],
];
},
] );
// Process the custom data when the order is placed
add_action( 'woocommerce_store_api_checkout_update_order_from_request', function( $order, $request ) {
$extensions = $request->get_param( 'extensions' );
if ( isset( $extensions['my-plugin']['gift_message'] ) ) {
$order->update_meta_data( '_gift_message', sanitize_text_field( $extensions['my-plugin']['gift_message'] ) );
$order->save();
}
}, 10, 2 );
Error Handling and Response Structure
The Store API returns standard HTTP status codes along with structured JSON error objects. Understanding the error structure is essential for building robust front-end applications.
Standard Error Response Format
{
"code": "woocommerce_rest_product_invalid_id",
"message": "Invalid product ID.",
"data": {
"status": 404,
"details": {}
}
}
Common error codes you’ll encounter:
woocommerce_rest_cookie_invalid_nonce, Nonce expired or invalid (401)woocommerce_cart_product_invalid, Product not found or not purchasable (400)woocommerce_cart_product_no_longer_exists, Product deleted since added to cart (409)woocommerce_checkout_order_error, Generic order processing failure (500)woocommerce_coupon_error, Invalid or expired coupon (400)woocommerce_stock_amount_remaining, Quantity exceeds available stock (400)
Handling Errors in JavaScript
async function addToCart( productId, quantity = 1 ) {
try {
const response = await fetch( `${apiUrl}/cart/add-item`, {
method: 'POST',
credentials: 'include',
headers: {
'X-WC-Store-API-Nonce': getNonce(),
'Content-Type': 'application/json',
},
body: JSON.stringify( { id: productId, quantity } ),
} );
if ( ! response.ok ) {
const error = await response.json();
// Handle specific error types
switch ( error.code ) {
case 'woocommerce_rest_cookie_invalid_nonce':
await refreshNonce();
return addToCart( productId, quantity ); // Retry
case 'woocommerce_stock_amount_remaining':
showNotice( `Only ${error.data.remaining} in stock.` );
break;
default:
showNotice( error.message );
}
return null;
}
return await response.json();
} catch ( networkError ) {
console.error( 'Network error:', networkError );
showNotice( 'Connection error. Please try again.' );
return null;
}
}
Performance Optimization for Store API Calls
The Store API is designed to be fast, but poorly implemented consumers can still generate significant server load. Apply these patterns for optimal performance, and pair them with the broader site-level recommendations in our WooCommerce Performance Checklist.
Use the Batch Endpoint
Instead of making multiple sequential requests, batch them into a single call:
// Instead of 3 separate requests, use batch
const batchResponse = await fetch( `${apiUrl}/batch`, {
method: 'POST',
credentials: 'include',
headers: {
'X-WC-Store-API-Nonce': getNonce(),
'Content-Type': 'application/json',
},
body: JSON.stringify( {
requests: [
{ method: 'POST', path: '/wc/store/v1/cart/apply-coupon', body: { code: 'SAVE10' } },
{ method: 'POST', path: '/wc/store/v1/cart/update-customer', body: { billing_address: { country: 'US', state: 'CA', postcode: '90210', city: 'Beverly Hills' } } },
{ method: 'GET', path: '/wc/store/v1/cart' },
],
} ),
} );
const results = await batchResponse.json();
// results.responses[0] = coupon result
// results.responses[1] = customer update result
// results.responses[2] = updated cart
Client-Side Cart State Management
Avoid fetching the full cart on every page load. Instead, use the cart hash returned by the Store API to determine if a refresh is needed:
// Store cart hash in localStorage
const cachedHash = localStorage.getItem( 'wc_cart_hash' );
// Check if cart changed (WooCommerce updates this hash on cart changes)
const serverHash = document.cookie.match( /woocommerce_cart_hash=([^;]+)/ )?.[1];
if ( cachedHash !== serverHash ) {
const cart = await fetchCart();
localStorage.setItem( 'wc_cart_hash', serverHash );
updateCartUI( cart );
}
Cache Product Responses
Product listing responses (which don’t include session-specific data) are safe to cache on the server side using object caching. Add a transient layer in your custom endpoint handlers, or configure a full-page cache to recognize and cache Store API product requests while bypassing caching for cart and checkout endpoints.
From a security perspective, never expose authenticated WooCommerce REST API keys in front-end code. Keep all admin-level API operations server-side. For a broader perspective on WooCommerce store security, see our Essential WooCommerce Security Checklist.
Building a Headless WooCommerce Storefront with the Store API
The Store API is the recommended API for headless WooCommerce implementations. Whether you’re using Next.js, Nuxt, SvelteKit, or a mobile app, the same endpoints power the entire shopping experience.
Architecture Pattern
A typical headless WooCommerce architecture using the Store API looks like this:
- Product catalog: Store API
/productswith Next.js ISR (Incremental Static Regeneration) for fast page loads - Cart management: Store API
/cart/*endpoints, client-side state with Zustand or Redux - Checkout: Store API
/checkoutfor order creation and payment - Account management: WooCommerce REST API
/customerswith Application Passwords or JWT auth - Order history: WooCommerce REST API
/ordersscoped to authenticated customer
CORS Configuration for Headless Setups
When your frontend is on a different domain from WordPress, you need to configure CORS and handle cross-domain session cookies:
<?php
// Allow CORS for your headless frontend
add_action( 'rest_api_init', function() {
remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
add_filter( 'rest_pre_serve_request', function( $value ) {
$origin = get_http_origin();
$allowed_origins = [ 'https://mystore.com', 'https://staging.mystore.com' ];
if ( in_array( $origin, $allowed_origins, true ) ) {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
header( 'Access-Control-Allow-Credentials: true' );
header( 'Access-Control-Allow-Headers: X-WC-Store-API-Nonce, Content-Type, Authorization' );
header( 'Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS' );
}
return $value;
} );
}, 15 );
Note that cross-domain session cookies require SameSite=None; Secure cookie attributes, which means your WordPress instance must be served over HTTPS. For most production deployments this is already the case, but it’s a common gotcha in local development.
Next.js Integration Example
// lib/woocommerce-store-api.ts
const STORE_API_URL = process.env.NEXT_PUBLIC_WC_STORE_API_URL!;
export async function getProducts( params: ProductQueryParams ) {
const searchParams = new URLSearchParams( {
per_page: String( params.perPage ?? 12 ),
page: String( params.page ?? 1 )...(params.category && { category: String( params.category ) })...(params.orderby && { orderby: params.orderby }),
} );
const response = await fetch(
`${STORE_API_URL}/products?${searchParams}`,
{ next: { revalidate: 300 } } // ISR: revalidate every 5 minutes
);
if ( ! response.ok ) {
throw new Error( `Store API error: ${response.status}` );
}
return response.json() as Promise<StoreApiProduct[]>;
}
Frequently Asked Questions
Is the WooCommerce Store API stable enough for production use?
Yes. The Store API reached stable status in WooCommerce 8.x and has been the foundation for WooCommerce Blocks (which powers millions of stores) since WooCommerce 6.x. The WooCommerce team maintains backward compatibility commitments for the /wc/store/v1/ namespace. However, endpoints marked as “experimental” in the documentation may change, always check the WooCommerce Blocks GitHub changelog before upgrading major versions.
Can I use the Store API without WooCommerce Blocks?
Absolutely. The Store API is part of the WooCommerce core codebase and is available regardless of whether you use WooCommerce Blocks in your theme. You can use it with any frontend technology, React, Vue, vanilla JavaScript, or server-side PHP fetches. The only requirement is WooCommerce 7.x or later.
How do I handle payment processing with the Store API?
Payment processing happens through the POST /checkout endpoint. Your request body includes a payment_method identifier and a payment_data array containing payment gateway-specific data (e.g., Stripe payment intent ID). The gateway must implement the IntegrationInterface to be compatible with the Store API checkout endpoint. Major gateways (Stripe, PayPal, Square) have already updated their WooCommerce plugins to support Store API checkout.
Real-World Use Cases and Implementation Patterns
Beyond the basics, the Store API unlocks a wide range of real-world customizations that would otherwise require complex overrides or legacy shortcode manipulation. Here are several patterns that development teams encounter regularly and how to approach them cleanly with the Store API.
Custom Product Types in Cart
If your store sells custom product types, subscription boxes, configurable bundles, print-on-demand products, you need to ensure the Store API handles them correctly. The key is implementing the WC_Product class properly for your custom type and registering it so WooCommerce Blocks (and therefore the Store API) can display it correctly in the cart.
Custom product types that extend WC_Product work out of the box with cart and checkout endpoints. However, if your product has custom configuration data (like selected engraving text or uploaded artwork), you need to store that data in cart item meta and expose it via ExtendSchema so your frontend can read and display it accurately. Without this, custom configuration options silently disappear from the cart display in block-based checkout.
Dynamic Pricing in Real Time
Many B2B and membership stores display different prices based on who is logged in. The Store API respects WooCommerce’s pricing filters, meaning if you use woocommerce_product_get_price or woocommerce_get_price_html filters to modify prices dynamically, those modifications will be reflected in Store API responses automatically.
This makes it straightforward to build role-based pricing, member discounts, and tier-based pricing that works correctly across both classic WooCommerce templates and Block-based or headless storefronts, as long as the session cookie is present so WooCommerce knows who the customer is. Developers building B2B storefronts should verify that login-gated pricing is correctly reflected in the cart response, as this is a common source of pricing discrepancies in headless implementations.
Integrating Loyalty and Rewards Programs
Loyalty programs are an excellent use case for Store API extensions. Using ExtendSchema, you can expose point balances on the cart endpoint and add a point redemption field to checkout, all without touching core WooCommerce files. The workflow typically looks like this: display available points on the cart page, let the customer choose how many to redeem, POST to checkout with the redemption amount in extensions, then hook into woocommerce_store_api_checkout_update_order_from_request to apply the discount programmatically before payment is charged. This pattern is clean, upgradeable, and works seamlessly with the WooCommerce Checkout Block.
Webhook Integration and Order Automation
After an order is created via the Store API checkout endpoint, WooCommerce fires the same hooks as classic checkout: woocommerce_checkout_order_created, woocommerce_new_order, and status transition hooks as payment is confirmed. This means your existing webhook integrations, ERP connectors, and fulfillment automations work without modification when you migrate to Store API-powered checkout.
For high-volume stores, consider using WooCommerce’s built-in webhook system to push order events to your fulfillment system asynchronously rather than processing synchronously in the order creation hook. This reduces checkout latency and prevents fulfillment system outages from affecting the customer checkout experience, a key resilience pattern for stores processing hundreds of orders per hour.
Testing and Debugging Store API Implementations
Robust testing is essential for any Store API implementation, especially the checkout flow where bugs directly impact revenue. Here are the testing strategies that production WooCommerce development teams rely on to ship with confidence.
Manual Testing with Postman or Bruno
For exploring and manually testing Store API endpoints, Postman and Bruno (an open-source alternative) work well. The key setup steps are: configure a cookie jar and enable “Send cookies” to maintain session state across requests, make an initial GET to /cart to establish a session and capture session cookies, generate a nonce via a WordPress REST helper and include it in subsequent POST headers, then test each cart operation sequentially before testing checkout. Postman’s collection runner is particularly useful for running a scripted end-to-end purchase flow, including edge cases like out-of-stock items and expired coupons.
Debugging Common Issues
The most common Store API issues developers encounter, and how to diagnose them quickly:
- Cart always empty: Missing
credentials: 'include'in fetch calls, or SameSite cookie issues in cross-domain setups. Always verify the session cookie is being sent and received correctly using browser DevTools Network panel. - Nonce invalid errors: Nonce generated before user session was established, or nonce from wrong user context. Generate the nonce server-side after the session is active and pass it to the frontend via
wp_add_inline_script. - Extension data not appearing: Check that the
woocommerce_blocks_loadedhook fires before your registration. Ensure the namespace matches exactly between registration and consumption in JavaScript. - Payment method not showing: The payment gateway plugin needs to declare Store API compatibility via its
supportsarray. Check the gateway plugin’s registration forblocksorstore_apisupport declarations. - CORS errors in headless setups: Missing
Access-Control-Allow-Credentials: trueheader, or the frontend domain not included in the allowed origins list. Remember thatcredentials: 'include'on the client requires explicit origin allowlisting, wildcard*does not work with credentialed requests.
Conclusion
The WooCommerce Store API represents a major step forward in how developers build with WooCommerce. It provides a clean, performant, session-aware API surface designed specifically for front-end consumption, eliminating the security risks of exposing authenticated API keys in JavaScript, reducing round trips through batching, and making extensibility a first-class concern through the ExtendSchema interface.
Whether you’re adding a custom cart field, building a fully headless Next.js storefront, or integrating a loyalty program into the checkout flow, the Store API gives you a stable, documented foundation to build on. Start with the endpoints you need, layer in the ExtendSchema extensions where required, and follow the nonce and CORS patterns outlined in this guide to ensure your implementation is both performant and secure.
The WooCommerce ecosystem continues to evolve rapidly in 2026, with the Store API at the center of that evolution. Investing time to understand these REST endpoints now will pay dividends as WooCommerce continues its transition toward a fully block-based, API-first commerce platform. Developers who master the Store API today are building skills that will be foundational for the next decade of WooCommerce development, as the platform increasingly relies on this modern API layer for everything from simple cart interactions to complex multi-step checkout flows with custom payment integrations, split fulfillment, and real-time inventory validation.
If you are just getting started, begin with the products and cart endpoints, then progress to checkout customization. Once you’re comfortable with the basics, the ExtendSchema API opens up a world of possibilities for adding custom data, custom checkout fields, and deep integrations with third-party services, all in a way that is upgrade-safe, block-compatible, and performance-optimized. The Store API is the right foundation for modern WooCommerce development, and this guide gives you everything you need to build on it with confidence.

