The WooCommerce dual API landed in version 10.9 as an experimental, opt-in feature, and my answer for most stores is: don’t build on it yet. It needs PHP 8.1 or newer, it carries no backward compatibility promise, and the core API inside it (products and coupons only) is labeled a proof of concept in the announcement on the WooCommerce developer blog.
Read about it anyway. The GraphQL endpoint is the headline, but the machinery that generates it is what plugin developers should care about, because any WooCommerce plugin can borrow it and get a generated API of its own.
What the WooCommerce dual API is
You write plain PHP classes and decorate them with attributes. A class with an execute() method is a command, and a class full of typed public properties is a data transfer object. A build script, run at development time, reads those classes and generates the GraphQL half: commands become queries and mutations, data objects become input and output types.
#[Name( 'coupon' )]
#[Description( 'Retrieve a single coupon by ID or code.' )]
#[RequiredCapability( 'read_private_shop_coupons' )]
class GetCoupon {
public function execute(
?int $id = null,
?string $code = null,
): ?Coupon {
// Fetch and return the coupon
}
}
Names and types come from conventions, and attributes fill the gaps. A #[Name(‘coupon’)] attribute turns a GetCoupon class into a coupon query, a #[Description] adds the documentation text, and #[RequiredCapability(‘read_private_shop_coupons’)] is the authorization check. That last one is a nicer default than the capability checks you scatter by hand through REST permission callbacks.
Plugins can use the same infrastructure. You define your classes, run the build script that ships inside WooCommerce, hook rest_api_init, and register your GraphQL endpoint with a utility method they provide. Class resolution goes through WooCommerce’s dependency injection container by default, authentication goes through a Principal (a WordPress user), and both are replaceable. The woocommerce-simple-events example plugin shows the whole loop. If you have ever hand-rolled a REST namespace and a schema, start there.
How it compares to the APIs you already use
WooCommerce now has three API surfaces, and they answer different questions. The wc/v3 REST API is key-based, covers almost every object type, and is what ERPs, shipping tools and mobile apps already speak. Its responses have fixed shapes, so you ask for a product and receive the entire product, which is wasteful but predictable. If you maintain client integrations, this is still the default, and it is the surface where version changes break code, as stores found with the Orders API change in 10.8.
The Store API is the customer-facing surface: cart, checkout and product data, unauthenticated because it powers the blocks on the storefront. When a client wants a custom front end over WooCommerce, this is the API to query, and the lazy-loading work in 10.4 made it cheaper to hit. It does not expose orders or coupons, since those are not customer-facing data.
The dual API sits somewhere new. GraphQL lets a consumer request exactly the fields it needs, in one call instead of five, and the types are real PHP types, enums included, instead of the loosely typed arrays wc/v3 hands back. Coverage in 10.9 is two object types, and there is no REST fallback story: you get the code classes and the generated GraphQL, and either half can change between releases without notice.
What I would do right now
On a live store, nothing. Enable it on staging, query the coupon endpoint, and post what you find in the GitHub discussion the team opened for feedback; the docs cover the rest. The one case where I would build with it today is a plugin that owns its own data and wants a typed, queryable API for other developers. Generated GraphQL beats writing a schema by hand, and if the infrastructure shifts, the blast radius is one plugin. If a client needs stable GraphQL on a store this quarter, WPGraphQL is still the mature choice until this leaves experimental.
One version caveat for plugin authors. Sites on PHP 7.4 or 8.0 will not throw errors even if someone flips the feature on; the classes never run and the endpoint stays dead. But the classes in src/Api are PHP 8.1 code, so calling them from code that still supports 7.4 will throw a fatal error. If your plugin still runs on old PHP, the code API is out of reach for now, though WooCommerce already recommends 8.1 or newer and has said support for 7.4 and 8.0 will eventually end.
If you are deciding which of these APIs a new integration should sit on, or you want the new API exercised on a staging copy of your store before it stabilizes, that is work I take on. Tell me what the integration needs to read and write, and I will tell you which surface fits.
The open question for me is whether the dual API grows into the primary way we talk to a WooCommerce store, or stays a parallel track beside REST and the Store API. I can’t tell from the announcement, and the answer decides how much of what integrators know today becomes legacy.