WooCommerce API – how to start?
CHALLENGE: configure the development environment for Woo REST API
SOLUTION: set up API keys, example API route endpoint and Postman GET requests
Woo REST API version 3 is the way to connect to the popular ecommerce WordPress plugin. By configuring API keys you can easily share your shop orders with external services, such as shipping providers. Follow these easy steps to set up WooCommerce API credentials.
Configure WooCommerce API keys
To give somebody “access” to our API, we need to generate 2 random strings: ‘Customer Key’ and ‘Customer secret’. Each pair of keys is connected to a particular WordPress user. You can give permission to Read data only, or also to Write. If an external service is using only ‘GET’ requests, ‘Read’ will be enough. To set up the keys:
- register a new WordPress user (only for the purpose of API access )
- generate a pair of keys ( wp-admin / WooCommerce / Settings / Advanced – REST API – Add key )
Sharing API credentials: ‘Customer secret’ should be kept private. You can use the privnote.com service for sharing credentials with third-party. After receiving it, the note will self-destruct.
Testing route with Postman
Postman is a convenient tool for connecting to API and performing tests. We will try GET request /wp-json/wc/v3/orders that will fetch all shop orders. If we have a shop with an https connection, we will use: Auth 1.0 Authorization, signature Method HMAC-SHA1. Now, fill in the 2 fields for ‘Consumer Key’ and ‘Consumer Secret’. After clicking ‘Send’ in Postman, we will see all orders in json format.
Using endpoint parameters
The built in WooCommerce Routes often offer parameters that can be used to filter the request data. To get all orders with status processing, we can add a param to the url: /wp-json/wc/v3/orders?status=processing
Postman on localhost
When working with WordPress in the development environment on localhost, a website often uses the http:// protocol, which might be a problem when doing authorization using Auth 1.0. The solution will be to change the Type of Authorization to: Basic Auth. As Username and Password just use wp_user credentials. This is recommended only for local development, on production servers proper authorization protocol type should be used.
Custom Woo Endpoint
Let’s say we would like to create our custom endpoint that will return order details, but with additional shipping data added to the GET request. We will register a custom API route. There are 2 help methods: add_data_to_order() and filter_order_data(), one will be adding extra data, the other one will strip unnecessary data from array. Instead of quering order data ourselves – we will just use the WooCommerce built-in endpoint: /wc/v3/orders/[order_id] and call it internally.
// functions.php class WC_REST_CUSTOM_1_Orders_Controller { public function get_extra_order_details(WP_REST_Request $request_params ){ $order_number = $request_params['order_number']; if(empty($request_params['order_number'])){ return new WP_Error( 'incorrect_data', 'order_number param required' ); } // Internal Woocommerce API call $api_route_name = '/wc/v3/orders/'.$order_number; $request = new WP_REST_Request( 'GET', $api_route_name ); $response = rest_do_request( $request ); $server = rest_get_server(); $order_data = $server->response_to_data( $response, false ); if(isset($order_data['code'])){ return new WP_REST_Response( $order_data, 401 ); } if(empty($order_data)){ return new WP_Error( 'incorrect_data', 'order does not exist' ); } // make single order - as array element $temp_array = array(); $temp_array[] = $order_data; $temp_array = $this->add_data_to_order($temp_array); if(!isset($request_params['full'])){ $temp_array = $this->filter_order_data($temp_array); } return $temp_array; } /** * @param $orders * Add extra data to woocommerce order */ private function add_data_to_order($orders){ foreach($orders as $mainkey => $order) { $additionalShippingData = array(); $shipping_type = 'address'; foreach($order['shipping_lines'][0]['meta_data'] as $shipping_row_item){ if($shipping_row_item['key'] == 'wcus_city_ref'){ $additionalShippingData['RecipientCityRef'] = $shipping_row_item['value']; if(!empty($additionalShippingData['RecipientCityRef'])){ $shipping_type = 'warehouse'; } } if($shipping_row_item['key'] == 'wcus_warehouse_ref'){ $additionalShippingData['RecipientWarehouseRef'] = $shipping_row_item['value']; } if($shipping_row_item['key'] == 'wcus_settlement_name'){ $additionalShippingData['RecipientCityName'] = $shipping_row_item['value']; } } if(isset($order['billing']['phone'])){ $additionalShippingData['RecipientsPhone'] = $order['billing']['phone']; $additionalShippingData['RecipientsPhone'] = kirillbdev\WCUkrShipping\Helpers\WCUSHelper::preparePhone($additionalShippingData['RecipientsPhone']); } $additionalShippingData['RecipientType'] = 'PrivatePerson'; if($shipping_type == 'address') { $additionalShippingData['ServiceType'] = 'WarehouseDoors'; } elseif ($shipping_type == 'warehouse'){ $additionalShippingData['ServiceType'] = 'WarehouseWarehouse'; } if($order['payment_method'] == 'cod'){ $additionalShippingData['AfterpaymentOnGoodsCost'] = $order['total'];; } // assign value $orders[$mainkey]['additional_shipping_data'] = $additionalShippingData; } return $orders; } private function filter_order_data($orders){ foreach($orders as $mainkey => $order){ unset($orders[$mainkey]['billing']); // unset not-needed keys unset($orders[$mainkey]['id']); unset($orders[$mainkey]['parent_id']); unset($orders[$mainkey]['version']); unset($orders[$mainkey]['prices_include_tax']); unset($orders[$mainkey]['date_modified']); unset($orders[$mainkey]['discount_tax']); unset($orders[$mainkey]['shipping_tax']); unset($orders[$mainkey]['cart_tax']); unset($orders[$mainkey]['order_key']); unset($orders[$mainkey]['total_tax']); unset($orders[$mainkey]['customer_id']); // more unset($orders[$mainkey]['customer_ip_address']); unset($orders[$mainkey]['customer_user_agent']); unset($orders[$mainkey]['created_via']); unset($orders[$mainkey]['cart_hash']); // remove not needed meta_data unset($orders[$mainkey]['meta_data']); // clean up line_items foreach($orders[$mainkey]['line_items'] as $line_items_key => $line_items_data){ $orders[$mainkey]['line_items'][ $line_items_key] = array(); $orders[$mainkey]['line_items'][ $line_items_key]['name'] = $line_items_data['name']; $orders[$mainkey]['line_items'][ $line_items_key]['quantity'] = $line_items_data['quantity']; $orders[$mainkey]['line_items'][ $line_items_key]['sku'] = $line_items_data['sku']; } // clean up more details unset($orders[$mainkey]['tax_lines']); unset($orders[$mainkey]['fee_lines']); unset($orders[$mainkey]['coupon_lines']); unset($orders[$mainkey]['refunds']); unset($orders[$mainkey]['date_created_gmt']); unset($orders[$mainkey]['date_modified_gmt']); unset($orders[$mainkey]['date_completed_gmt']); unset($orders[$mainkey]['date_paid_gmt']); unset($orders[$mainkey]['currency_symbol']); unset($orders[$mainkey]['_links']); // unset shipping lines unset($orders[$mainkey]['shipping_lines']); } return $orders; } public function register_routes() { /** * Define custom WooCommerce routes */ register_rest_route( 'wc/v3', '/get_extra_order_details', array( 'methods' => 'GET', 'callback' => array( $this, 'get_extra_order_details' ), 'permission_callback' => function($request){ return true; }, 'args' => array( 'order_number' => array( 'required' => true, 'type' => 'string', 'description' => 'Shop order number', ), 'full' => array( 'required' => false, 'type' => 'string', 'description' => 'Display all order details, use value: 1', ), ) ) ); } } /** * Register endpoints */ add_filter( 'woocommerce_rest_api_get_rest_namespaces', 'ct_custom_api' ); function ct_custom_api( $controllers ) { $controllers['wc/v3']['ct-my-endpoints-123'] = 'WC_REST_CUSTOM_1_Orders_Controller'; return $controllers; }
Usage and example response
Our custom route is ready. We can test the GET request using:
/wp-json/wc/v3/get_extra_order_details?order_number=565 . This will show order details with some data stripped. The full data in json format is available using: /wp-json/wc/v3/get_extra_order_details?order_number=565&full=1
Example API response:
[ { "status": "completed", "currency": "USD", "date_created": "2021-09-02T09:56:55", "discount_total": "0", "shipping_total": "50", "total": "1503", "shipping": { "first_name": "test", "last_name": "test", "company": "", "address_1": "abc", "address_2": "", "city": "testing", "state": "", "postcode": "", "country": "USA" }, "payment_method": "cod", "transaction_id": "", "customer_note": "", "date_completed": "2021-09-16T11:19:01", "date_paid": "2021-09-16T11:19:01", "number": "565", "line_items": [ { "name": "Product1", "quantity": 2, "sku": "3145" }, { "name": "Product2", "quantity": 4, "sku": "3144" }, ], "additional_shipping_data": { "RecipientCityRef": "abc1", "RecipientWarehouseRef": "abc2", "RecipientsPhone": "321321321", "RecipientType": "PrivatePerson", "ServiceType": "WarehouseWarehouse", "AfterpaymentOnGoodsCost": "1503" } } ]
WooCommerce API documentation
We would like to share the details about WooCommerce API documentation, route parameters, and enable the ability to make API requests in the browser. This will be automatically handled by the WP API SwaggerUI plugin. After plugin activation and simple config in Settings / Swagger, the entire API documentation will be visible using the following url: /rest-api/docs/
Next steps
It’s important to remember that a third party company that received API Keys for our WooCommerce shop will have access to all built-in woo endpoints. For example, the list of all customers ( /wp-json/wc/v3/customers ) is available for every authorized API user. If we would like to restrict access to only some routes or blacklist particular endpoints, WooCommerce provides filters for this: ‘rest_endpoints’ and ‘rest_authentication_errors’.
We hope you find these solutions useful. Make sure to follow us for more tips and guidelines.