Module 2 · 2.4
What your shop shows publicly
Module 2: Installing and setting up · Reading time: 10 minutes
Learning objective: After this lesson you can explain what WooCommerce's Store API and REST API are, which data should be public and which should not, and how to use API keys and webhooks safely.
Key concepts: API, WordPress REST API, Store API (wc/store/v1), WooCommerce REST API (wc/v3), JSON, public and protected, API key, read and write permissions, least privilege, webhook, webhook secret, X-WP-Total
A shop with two doors
A visitor sees your shop as web pages. But your shop also has "doors" for programs: addresses where a program can request or send data, without the layout of a page. Such a door is called an API (application programming interface). WordPress has one under /wp-json/, the REST API. In lesson 7.3, the WordPress course showed that you can request usernames there, for example, if you do not protect anything.
WooCommerce adds two APIs of its own, each with a very different purpose:
| Store API | WooCommerce REST API | |
|---|---|---|
| Address | /wp-json/wc/store/v1/... | /wp-json/wc/v3/... |
| For whom | A visitor's browser (the cart and checkout blocks, lesson 2.2) | Other programs: accounting, stock management, an app, a link to a marketplace |
| Key needed | No, public | Yes, an API key from an administrator (or a logged-in user with permissions) |
| What it contains | Products, prices, stock status, categories, reviews; the cart and order of the visitor themselves | Everything: everyone's orders, customers, coupons, settings, reports |
So the Store API is the shop-window entrance: whatever appears on a product page in your shop is in there too, just as data. The WooCommerce REST API is the back door to the warehouse: it should be locked.
The Store API: what a visitor (and anyone) can request
Open in your browser:
https://shop.example.com/wp-json/wc/store/v1/productsYou get a list in JSON, a text format for data. For each product you see, among other things, the name, the slug, the type (simple, variable), the address of the product page (permalink), the SKU, the prices, images, categories, whether it is in stock and whether it can be purchased. The response headers include X-WP-Total: the number of products the shop shows to visitors.
A few things to know:
- Prices are in cents. A teapot costing € 34.95 appears as
"price": "3495"with"currency_minor_unit": 2. You divide by 100. Whether that is the price including or excluding VAT depends on your setting under "Display prices in the shop" (lesson 4.1). We use this property in the exercise for lesson 4.1. - Only what is visible. The Store API does not count products that are drafts, private or hidden from the catalogue. That is why
X-WP-Totalcan be lower than the number in your admin. - Anyone may read, but not simply write. Adding something to the cart or checking out via the Store API only works with a one-time code (nonce) from the page, and then only for that visitor's own cart.
Is it a problem that this is public? No: it is the same data that appears on your product pages. A competitor who wants to track your prices can do that with the normal pages too. It is worth realising, though, that anything you put in a product field can end up in the Store API. Never put purchase prices, supplier names or internal notes in the short or long description "because the theme doesn't show that field anyway".
Do not shut down the Store API either. The cart and checkout blocks need it (lesson 2.2). Security plugins that "disable the REST API for visitors" therefore sometimes break checkout. If you want to restrict the REST API, exclude the Store API.
The Store API can be abused, but on the writing side: attackers using stolen card numbers to attempt thousands of small orders. This is called card testing; lesson 6.3 covers it.
The WooCommerce REST API: always behind a key
Now open, without being logged in:
https://shop.example.com/wp-json/wc/v3/ordersThe right response is an error with status 401 (not logged in) and a code such as woocommerce_rest_cannot_view. Your shop is saying: "you are not allowed to see this". That is how it should be. If you get a list of orders here, something is seriously wrong: a plugin that opens up permissions, custom code in the theme, or a key that sits in a public address. In that case you have a possible data breach (WordPress course, lesson 7.5, and knowledge base 6749).
Programs that need access to your orders get an API key. You create it under WooCommerce > Settings > Advanced > REST API. A key consists of two parts (a consumer key and a consumer secret) and belongs to a WordPress user. You choose the permissions:
- Read: the program may request data;
- Write: the program may create and change data;
- Read/Write: both.
Rules you always follow:
- Least privilege. An accounting link that only fetches orders gets read access only. A stock link that updates stock levels needs write access, but a reporting tool does not.
- One key per link, with a clear description ("Accounting, read only, 2026"). If a link stops, you revoke only that key.
- Tie the key to a user with suitable permissions. An administrator's key can do everything an administrator can. Preferably create a separate user with the Shop manager role (lesson 6.2).
- Keep the secret half safe. You only see it once, when you create it. It belongs in the program's settings or in a password manager, not in an email, a shared document or a public code repository.
- Clean up. Under REST API you can see for each key when it was last used. Revoke a key that has not been used for months.
Webhooks: your shop calls another program
An API waits until someone asks. A webhook works the other way round: when something happens in your shop (a new order, a changed product), WooCommerce itself sends a message to an address you specify. That way your shipping program hears about an order straight away, without asking every minute. You set them up under WooCommerce > Settings > Advanced > Webhooks.
Three things to watch out for:
- The message contains personal data. A webhook for a new order sends the name, address and ordered products along with it. Only send that to an address using https and to a party that is listed in your privacy statement and record of processing activities (lesson 5.5).
- The secret. For a webhook you enter a secret. The receiving program uses it to check that the message really comes from your shop and not from someone who guessed the address. Do not leave it empty and share it only with the recipient.
- Failed delivery. If the receiving address is unreachable for a while, WooCommerce may disable the webhook after repeated errors. After an outage, check under Webhooks whether they are still active.
Do not confuse this with your payment provider's webhook (lesson 4.4). That works the other way round: the provider tells your shop that a payment has succeeded.
In practice: this is how it looks in WooCommerce
It works the same at other hosting providers; these are parts of WooCommerce itself.
- In a private window, open
/wp-json/wc/store/v1/productson your (test) shop. Find a product and convert the price. - In the same private window, open
/wp-json/wc/v3/orders. You should see status 401. - Go to WooCommerce > Settings > Advanced > REST API. Check which keys exist, which user they belong to and what permissions they have. Revoke keys you do not recognise (or no longer need).
- Under Webhooks, check which webhooks exist and which address they go to.
- If you have a security plugin that restricts the REST API, check that the Store API is excluded.
Summary
- The Store API (
wc/store/v1) is public and contains what is also on your product pages; the cart and checkout blocks need it. - Do not put internal data in product fields: it can become visible via the Store API.
- Without a key, the WooCommerce REST API (
wc/v3) should return a 401; a list of orders without a key is a possible data breach. - API keys: least privilege, one per link, tied to a suitable user, kept secret, unused ones revoked.
- Webhooks send personal data to another program: only via https, with a secret, to a party from your record of processing activities.
Quiz
Exercise
Exercise A2.4: What does your shop show publicly? Enter the address of your (test) shop and the number of products visible in your shop. The program makes three requests, without cookies and without a key, read only:
/wp-json/wc/store/v1/products?per_page=1(the Store API, via the REST address your site itself provides);/wp-json/wc/v3/orders?per_page=1;/wp-json/wc/v3/customers?per_page=1.
Good means: the Store API responds with status 200 and a JSON list; the X-WP-Total header equals the number you entered; orders and customers return 401, 403 or 404.
Orange: X-WP-Total differs (draft, private or hidden products are not counted); the Store API returns 401 or 403, usually because of a security plugin, which stops the checkout blocks from working.
Red: the Store API cannot be reached even though your site runs WooCommerce; or orders or customers return a list. The latter is serious: close it off immediately, check your API keys and plugins, and assess whether you need to report a data breach. In that case the program stores only the status code, never the content.
Then check REST API and Webhooks yourself: which keys and webhooks are there, and do you know what each one is for?
Further reading
- Free WordPress course 7.3: Logging in: passwords, two-factor authentication and brute force
- Free WordPress course 7.5: Hacked: recognise, recover and prevent
- WordPress xmlrpc.php access not working
- Is this a data breach and do I need to report it?
- The Store API (developer.woocommerce.com): https://developer.woocommerce.com/docs/apis/store-api/
- Rate limiting for the Store API (developer.woocommerce.com): https://developer.woocommerce.com/docs/apis/store-api/rate-limiting/
