Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

The REST API

The REST API is a way to work with the shop over HTTP: an external program sends a request to a site address and receives JSON. This is how an accounting system updates stock, a warehouse collects orders and a mobile app shows the catalog. The API is built into WooCommerce and does not need enabling.

Access keys

Requests are signed with a key. Create one in WooCommerce → Settings → Advanced → REST API → Add key: give a description, a user and permissions — Read, Write or Read/Write. The panel shows two strings once: ck_... (the key) and cs_... (the secret) — save them.

The first request

curl "https://shop.example.com/wp-json/wc/v3/products?per_page=5" \
    -u ck_your_key:cs_your_secret

The key and the secret are passed as a user name and a password. The response is a JSON array of five products with the fields id, name, price, stock_quantity and others. Passing keys this way is acceptable only over HTTPS.

Endpoints

AddressWhat it is
/wp-json/wc/v3/productsProducts
/wp-json/wc/v3/products/12One product
/wp-json/wc/v3/products/15/variationsA product's variations
/wp-json/wc/v3/products/categoriesCategories
/wp-json/wc/v3/ordersOrders
/wp-json/wc/v3/customersCustomers
/wp-json/wc/v3/couponsCoupons

The methods are the usual ones: GET reads, POST creates, PUT changes, DELETE deletes.

List parameters

ParameterWhat it does
per_page, pagePage size and number, at most 100 records
searchSearch by name
statusFilter by status
modified_afterOnly records changed after a date
_fieldsOnly the listed fields: _fields=id,status,total

The total number of records and pages comes in the X-WP-Total and X-WP-TotalPages response headers.

Changing data

curl -X PUT "https://shop.example.com/wp-json/wc/v3/products/12" \
    -u ck_your_key:cs_your_secret \
    -H "Content-Type: application/json" \
    -d '{"stock_quantity": 15, "regular_price": "11.90"}'

The request changes the stock and price of product 12 and returns the updated product. The key needs write permission. Many products are updated in one request through /products/batch with the create, update and delete fields.

Your own field in a response

Create the includes/rest.php file and include it in acme-shop.php:

// wp-content/plugins/acme-shop/includes/rest.php
add_filter('woocommerce_rest_prepare_product_object', function (WP_REST_Response $response, WC_Product $product) {
    $response->data['lead_time'] = (int) $product->get_meta('_acme_lead_time');
 
    return $response;
}, 10, 2);

The filter fires before each product is sent. Repeat the first request: every product now has a lead_time field. Orders have the same kind of filter, woocommerce_rest_prepare_shop_order_object.

A custom route

When the ready-made endpoints are not enough, you register your own:

// wp-content/plugins/acme-shop/includes/rest.php
add_action('rest_api_init', function () {
    register_rest_route('acme/v1', '/low-stock', [
        'methods' => 'GET',
        'permission_callback' => fn () => current_user_can('manage_woocommerce'),
        'callback' => function () {
            $products = wc_get_products(['manage_stock' => true, 'limit' => 100]);
            $low = array_filter($products, fn ($product) => (int) $product->get_stock_quantity() < 5);
 
            return array_map(
                fn ($product) => ['id' => $product->get_id(), 'name' => $product->get_name()],
                array_values($low)
            );
        },
    ]);
});

The address /wp-json/acme/v1/low-stock returns products with fewer than five left. permission_callback lets in only users allowed to manage the shop. The ck_ and cs_ keys work only for wc/... addresses: your own route is called with a WordPress application password, created in Users → Profile → Application Passwords.

Common mistake

An integration polls /orders every minute and fetches all orders in full. On a large shop such requests load the database noticeably. Request only what has changed — with modified_after — and only the fields you need through _fields. Better still, receive orders with a webhook at the moment of checkout — that is the next lesson.

Thanks for reading!

Donate to the site — we work hard for you.