WooCommerce REST API¶
woocommerce-rest-api
Call the WooCommerce REST API at wc/v3, including authentication, pagination, batch writes, and webhook registration, and keep it separate from the Store API. Use when an external system integrates with a WooCommerce store over HTTP.
Version 0.3.2 · MIT · Source · Rule
Install this skill
Copy the skill and its rule into your project:
The skill goes to .agents/skills/ and the rule to .agents/rules/. See Command line for other directories.
Use this skill for a server-side client of a WooCommerce store. The browser checkout uses a different API. Payment notification handling belongs to the webhook reliability skill.
Which API¶
| API | Namespace | Who calls it |
|---|---|---|
| WooCommerce REST API | /wp-json/wc/v3/ |
Your server, with a consumer key and secret. |
| Store API | /wp-json/wc/store/v1/ |
The storefront, with a cart token and nonce. |
| Legacy REST API | /wc-api/v3/ |
Old clients only. Do not start new work here. |
The current REST API requires WooCommerce 3.5+, WordPress 4.4+, and pretty permalinks. Default permalinks do not serve these routes.
Never put a consumer secret in browser JavaScript, a mobile binary, or a Store API request.
Authentication¶
Create a key at WooCommerce > Settings > Advanced > REST API. The key inherits the WordPress user you bind it to, and the permission you select: Read, Write, or Read/Write. Deleting that user disables the key. The consumer secret is shown once.
Over HTTPS, send HTTP Basic authentication with the consumer key as the username and the consumer secret as the password.
curl --user "$WC_CONSUMER_KEY:$WC_CONSUMER_SECRET" \
"https://shop.example/wp-json/wc/v3/orders?per_page=20"
Some FastCGI hosts drop the Authorization header and WooCommerce then reports that the consumer key is missing. Only then, and only over HTTPS, send consumer_key and consumer_secret as query parameters. Query secrets land in access logs and caches. Prefer fixing the host header.
Over plain HTTP, WooCommerce expects one-legged OAuth 1.0a. For a new integration, use HTTPS instead of adding an OAuth client.
Store the secret in the server environment or a secret manager. Do not commit it.
Reads¶
- Follow pages with
pageandper_page.per_pageabove 100 is rejected. ReadX-WP-TotalandX-WP-TotalPages. - Request only the fields you need when the endpoint supports
_fields. - Compare instants with
date_created_gmtanddate_modified_gmt. The unsuffixed fields are in the site timezone. - Product variations are a child resource:
/wp-json/wc/v3/products/<id>/variations. - Error bodies use the WordPress shape
{ "code", "message", "data": { "status" } }. Branch oncodeand HTTP status, not on the message string.
Endpoint groups and the batch body are in the endpoint notes.
Writes¶
The REST API does not provide a general idempotency key. A retried POST /orders can create a second order.
- Put your own key in meta, for example
meta_data: [{ "key": "_idempotency_key", "value": "<key>" }]. - Before creating, search orders by that meta. Treat a hit as the original result.
- Meta search is not a unique index. Two concurrent creates can still both miss. For payments, dedupe on the provider transaction id as well. See the order and webhook skill.
Batch routes (POST /products/batch, /orders/batch, and the customer and coupon equivalents) accept create, update, and delete. The batch is not one database transaction. Read each item result. A 200 response can still contain per-item errors.
Update orders and products with the resource id. Do not match a later update on SKU alone unless you have already resolved the SKU to one id. SKUs can change.
Webhooks registered over REST¶
POST /wp-json/wc/v3/webhooks with name, topic, delivery_url, and secret. The secret is write-only on later reads. If you omit it, WooCommerce falls back to the API user's consumer secret. Set an explicit secret.
The first save of an active webhook delivers a ping, not a full order or product. Acknowledge that ping with a 2xx response and do not create an order from it.
Topic names look like order.updated and product.created. The delivered resource body matches the REST representation. Verify X-WC-Webhook-Signature against the raw body before trusting it. The signature procedure is in the order and webhook skill.
Gotchas¶
- A Read key cannot create products. A Write key cannot list orders. Check the key permission and the user's capability when you get
401or403. - Order status names in the API omit the
wc-prefix (processing, notwc-processing). - Prices are strings in major currency units, such as
"19.00". Do not send a float. - HPOS does not change the REST shape. Clients should keep using this API rather than reading the database.
- Webhook delivery that returns
301or302can be counted as success whileWC_Webhook::deliver()sends the body with redirects disabled. Serve the JSON handler on the exactdelivery_url.
Verification¶
- A request with the wrong secret returns 401 and creates nothing.
- Listing orders walks every
X-WP-TotalPagespage without duplicating or skipping ids. - Repeating the same create with the same idempotency key returns one order.
- A webhook ping does not create an order. A signed
order.updateddelivery updates the matching local record.
Evaluation¶
Worked examples and the checks they must satisfy are in evals/tasks.json.
References¶
WooCommerce REST API endpoints¶
Base path: /wp-json/wc/v3/. All routes below are relative to that base. Authenticate every call as described in SKILL.md.
Resources¶
| Path | Typical use |
|---|---|
products |
Create and update the parent product. |
products/<id>/variations |
Create and update purchasable variants. |
products/attributes |
Global attributes. Taxonomy name is pa_ plus the slug. |
products/categories |
Product categories. |
products/<id>/reviews |
Product reviews. |
orders |
Order header, line items, shipping lines, fee lines, and coupons. |
orders/<id>/notes |
Customer or private notes. customer_note: true emails the customer. |
orders/<id>/refunds |
Create a refund. This is the REST equivalent of wc_create_refund(). |
customers |
WordPress users who are customers. Guest orders are not customers until an account exists. |
coupons |
Coupon definitions. Applying a coupon still happens in checkout or by editing the order. |
webhooks |
Register, pause, or delete a webhook. secret is write-only. |
taxes, shipping/zones, payment_gateways, settings |
Store configuration. Prefer the admin UI unless you are provisioning stores. |
system_status |
Environment diagnostic. Do not require it on the hot path. |
reports/sales |
Aggregates. For large extracts, page through orders instead of assuming one report call is complete. |
<id> is the integer resource id.
Batch¶
POST products/batch, orders/batch, customers/batch, and coupons/batch.
Inspect create, update, and delete in the response. An item error does not roll back its siblings.
Pagination and filters¶
pagestarts at 1.per_pagedefaults to 10 and cannot exceed 100.- Order list filters include
status,customer,product,after,before,modified_after, andmodified_before. Pass the date filters as ISO-8601 timestamps. - Use
modified_afterfor an incremental sync. A record can change while you are paging. Keep an overlap and dedupe by id plusdate_modified_gmt. If the installed WooCommerce rejectsmodified_after, fall back toafterandbefore.
Status values¶
Order statuses used by core: pending, processing, on-hold, completed, cancelled, refunded, failed, and checkout-draft. Custom statuses registered with woocommerce_register_shop_order_post_statuses also appear. Do not send the wc- internal prefix.
Product status uses WordPress post statuses such as publish, draft, and private. Catalog visibility is catalog_visibility (visible, catalog, search, hidden), which is not the same field.
Webhook topics¶
Common topics: order.created, order.updated, order.deleted, product.created, product.updated, product.deleted, customer.created, customer.updated, coupon.created, coupon.updated. Action topics bind a webhook to a WooCommerce action name. Prefer a resource topic unless you need a specific action.
Headers on delivery:
X-WC-Webhook-SourceX-WC-Webhook-TopicX-WC-Webhook-ResourceX-WC-Webhook-EventX-WC-Webhook-SignatureX-WC-Webhook-IDX-WC-Webhook-Delivery-ID
X-WC-Webhook-Delivery-ID changes on every attempt. Do not use it as the only idempotency key.
Evaluation¶
Fixtures from evals/tasks.json. See evaluation fixtures for how the checks work.
https-basic-auth¶
Authenticate a server-side WooCommerce REST client over HTTPS without putting the secret in the browser.
Must include: /wp-json/wc/v3/, Basic
Must not include: wc-api/v3
Worked example
Call the current REST API from the server.
Send the consumer key and secret as HTTP Basic authentication over HTTPS only.
idempotent-order-create¶
Create an order through the REST API so a retried POST does not create a second order.
Must include: meta_data, _idempotency_key
Must not include: consumer_secret=