WooCommerce extends the WordPress REST API with its own namespace at /wp-json/wc/v3/, exposing products, orders, customers, coupons, shipping zones, payment gateways, and more as REST resources. Unlike the standard WordPress REST API which is read-mostly public, WooCommerce REST API endpoints require authentication for all requests — reads and writes alike. The recommended authentication method for server-to-server integrations is HTTP Basic Auth using Consumer Key and Consumer Secret credentials generated in WooCommerce → Settings → Advanced → REST API. For local development and testing, Basic Auth over HTTPS is straightforward; for production integrations between systems you control, it is the standard approach. The API supports all standard REST operations: GET for retrieval, POST for creation, PUT for update, and DELETE for deletion, with consistent response shapes across resource types.
Problem: An external ERP system needs to sync product stock levels to WooCommerce and retrieve new orders every 15 minutes — without using the WooCommerce admin UI or installing a plugin on the WooCommerce site.
Solution: Use the WooCommerce REST API with Consumer Key / Consumer Secret credentials. Use GET /wp-json/wc/v3/orders with after and status filters to retrieve new orders, and PUT /wp-json/wc/v3/products/{id} to update stock.
<?php
/**
* Minimal WooCommerce REST API client using wp_remote_get / wp_remote_request.
*/
class WC_REST_Client {
private string $base_url;
private string $consumer_key;
private string $consumer_secret;
public function __construct( string $store_url, string $ck, string $cs ) {
$this->base_url = rtrim( $store_url, '/' ) . '/wp-json/wc/v3';
$this->consumer_key = $ck;
$this->consumer_secret = $cs;
}
private function request( string $method, string $endpoint, array $body = [] ): array {
$args = [
'method' => $method,
'headers' => [
'Authorization' => 'Basic ' . base64_encode( $this->consumer_key . ':' . $this->consumer_secret ),
'Content-Type' => 'application/json',
],
'timeout' => 30,
];
if ( ! empty( $body ) ) {
$args['body'] = wp_json_encode( $body );
}
$response = wp_remote_request( $this->base_url . $endpoint, $args );
if ( is_wp_error( $response ) ) {
throw new RuntimeException( $response->get_error_message() );
}
return json_decode( wp_remote_retrieve_body( $response ), true );
}
// Get orders placed after a specific date with a specific status
public function get_orders( string $after_date, string $status = 'processing' ): array {
$qs = http_build_query( [ 'after' => $after_date, 'status' => $status, 'per_page' => 100 ] );
return $this->request( 'GET', '/orders?' . $qs );
}
// Update product stock quantity
public function update_stock( int $product_id, int $quantity ): array {
return $this->request( 'PUT', '/products/' . $product_id, [
'stock_quantity' => $quantity,
'manage_stock' => true,
] );
}
// Create a coupon
public function create_coupon( string $code, float $amount, string $type = 'percent' ): array {
return $this->request( 'POST', '/coupons', [
'code' => sanitize_text_field( $code ),
'discount_type' => $type,
'amount' => (string) $amount,
'usage_limit' => 1,
] );
}
}
// Usage:
$client = new WC_REST_Client(
'https://mystore.com',
'ck_xxxxxxxxxxxxxxxxxxxx',
'cs_xxxxxxxxxxxxxxxxxxxx'
);
$new_orders = $client->get_orders( '2020-11-15T00:00:00', 'processing' );
$client->update_stock( 42, 150 );
NOTE: Consumer Key / Consumer Secret credentials use HTTP Basic Auth. Always use HTTPS — sending these credentials over plain HTTP exposes them in every request. For public-facing or browser-based integrations, use OAuth 1.0a instead (WooCommerce supports it), which signs requests without transmitting the secret. The per_page parameter maxes out at 100 — for large datasets, paginate using the page parameter and the X-WP-TotalPages response header (the WooCommerce REST API returns the same pagination headers as the core WordPress REST API).