Skip to main content
RapidDev - Software Development Agency
API AutomationsWordPressBasic Auth

How to Automate WordPress Ecommerce Orders using the API

Automate WooCommerce order processing by verifying HMAC-SHA256 signatures on order.created webhooks, fetching order details with GET /wp-json/wc/v3/orders/{id}, and updating fulfillment status with PUT /wp-json/wc/v3/orders/{id}. WooCommerce uses consumer key/secret auth (not Application Passwords). Rate limit: 25 requests per 10-second window. The Checkout endpoint is capped at just 3 requests per 60 seconds.

Need help automating? Talk to an expert
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate6 min read30-60 minutesWordPressMay 2026RapidDev Engineering Team
TL;DR

Automate WooCommerce order processing by verifying HMAC-SHA256 signatures on order.created webhooks, fetching order details with GET /wp-json/wc/v3/orders/{id}, and updating fulfillment status with PUT /wp-json/wc/v3/orders/{id}. WooCommerce uses consumer key/secret auth (not Application Passwords). Rate limit: 25 requests per 10-second window. The Checkout endpoint is capped at just 3 requests per 60 seconds.

API Quick Reference

Auth

HTTP Basic Auth (Consumer Key/Secret)

Rate limit

25 requests per 10 seconds (Store API)

Format

JSON

SDK

REST only

Understanding the WooCommerce REST API

WooCommerce adds its own REST API to WordPress at /wp-json/wc/v3/. Unlike the WordPress core REST API which uses Application Passwords, WooCommerce uses consumer key and consumer secret pairs (generated at WooCommerce > Settings > Advanced > REST API). Authentication is HTTP Basic Auth over HTTPS with consumer_key as the username and consumer_secret as the password.

For order automation, WooCommerce provides a first-class webhook system — the only first-party webhook source in WordPress. Webhooks are configured at WooCommerce > Settings > Advanced > Webhooks and fire for order.created, order.updated, and other events. Each delivery includes an X-WC-Webhook-Signature header containing HMAC-SHA256 of the raw payload body, base64-encoded, keyed by the webhook secret.

WooCommerce's Store API has a documented rate limit: 25 requests per 10-second window, with the Checkout endpoint capped at 3 requests per 60 seconds. The REST API (wc/v3) shares the WordPress host's WAF policies. Official documentation: woocommerce.com/document/woocommerce-rest-api/.

Base URLhttps://yourwordpresssite.com/wp-json

Setting Up WooCommerce API Authentication

WooCommerce REST API keys are completely separate from WordPress user accounts. Generate a key pair at WooCommerce > Settings > Advanced > REST API. Set permissions to 'Read/Write' for order automation. The consumer_secret is shown only once at generation time — copy it immediately.

  1. 1Log into wp-admin and go to WooCommerce > Settings
  2. 2Click the 'Advanced' tab, then 'REST API'
  3. 3Click 'Add Key', enter a description (e.g., 'Order Automation'), set user to an admin, permissions to 'Read/Write'
  4. 4Click 'Generate API Key'
  5. 5Copy both the Consumer Key (ck_...) and Consumer Secret (cs_...) — the secret is shown only once
  6. 6Set environment variables: WC_CONSUMER_KEY and WC_CONSUMER_SECRET
  7. 7Test: curl 'https://yoursite.com/wp-json/wc/v3/orders?status=processing' -u ck_xxx:cs_xxx
auth.py
1import os
2import requests
3
4WP_BASE = os.environ['WP_BASE_URL'] # e.g. https://yoursite.com/wp-json
5WC_KEY = os.environ['WC_CONSUMER_KEY'] # ck_...
6WC_SECRET = os.environ['WC_CONSUMER_SECRET'] # cs_...
7WC_AUTH = (WC_KEY, WC_SECRET)
8
9# Verify connection
10resp = requests.get(f'{WP_BASE}/wc/v3/orders?per_page=1', auth=WC_AUTH)
11print('WooCommerce API connected:', resp.status_code == 200)

Security notes

  • Store consumer key and secret in environment variables, never in source code
  • Consumer secrets are shown only once at generation time — store immediately in your secret manager
  • Always use HTTPS — WooCommerce consumer key auth is only valid over encrypted connections
  • Create a dedicated API key per integration so you can revoke individual keys without disrupting others
  • Validate the X-WC-Webhook-Signature header on every incoming webhook before processing

Key endpoints

GET/wc/v3/orders

List orders with filtering by status, date, customer, and more. Use this for polling or backfill operations. Default returns 10 orders; max per_page is 100.

ParameterTypeRequiredDescription
statusstringoptionalFilter by order status: pending, processing, on-hold, completed, cancelled, refunded, failed.
per_pagenumberoptionalOrders per page, max 100. Default 10.
afterstringoptionalISO 8601 date to filter orders created after this date.
pagenumberoptionalPage number for pagination. Check X-WP-TotalPages header for total pages.

Response

json
1[{"id":1001,"status":"processing","billing":{"first_name":"Jane","last_name":"Doe","email":"jane@example.com"},"line_items":[{"name":"Product A","quantity":2,"total":"49.98"}],"total":"49.98","date_created":"2026-05-07T10:00:00"}]
GET/wc/v3/orders/{id}

Retrieve a single order by ID with full detail including line items, billing/shipping address, payment method, and status.

ParameterTypeRequiredDescription
idnumberrequiredWooCommerce order ID.

Response

json
1{"id":1001,"status":"processing","payment_method":"stripe","billing":{"first_name":"Jane","email":"jane@example.com","address_1":"123 Main St","city":"Boston","state":"MA","postcode":"02101"},"line_items":[{"id":5,"name":"Product A","sku":"PROD-A","quantity":2,"total":"49.98"}],"shipping_lines":[{"method_title":"Flat Rate","total":"5.00"}],"total":"54.98"}
PUT/wc/v3/orders/{id}

Update an order's status, tracking information, or notes. Use this to move orders from 'processing' to 'completed' after shipping.

ParameterTypeRequiredDescription
statusstringoptionalNew order status: pending, processing, on-hold, completed, cancelled, refunded, failed.
customer_notestringoptionalNote visible to the customer.

Request

json
1{"status":"completed"}

Response

json
1{"id":1001,"status":"completed","date_completed":"2026-05-07T12:00:00"}

Step-by-step automation

1

Configure WooCommerce Webhook

Why: WooCommerce webhooks provide real-time order notifications — far more efficient than polling the orders endpoint every minute.

In wp-admin, go to WooCommerce > Settings > Advanced > Webhooks and click 'Add webhook'. Set topic to 'Order created', enter your HTTPS handler URL, and set status to Active. Copy the webhook secret. Alternatively, create programmatically via POST /wc/v3/webhooks. Each delivery includes X-WC-Webhook-Signature (HMAC-SHA256, base64-encoded) using your webhook secret.

request.sh
1# Create webhook via API
2curl -X POST 'https://yoursite.com/wp-json/wc/v3/webhooks' \
3 -u 'ck_YOUR_KEY:cs_YOUR_SECRET' \
4 -H 'Content-Type: application/json' \
5 -d '{
6 "name": "Order Created",
7 "topic": "order.created",
8 "delivery_url": "https://yourapp.com/webhooks/woocommerce",
9 "secret": "YOUR_WEBHOOK_SECRET"
10 }'

Pro tip: WooCommerce signatures use HMAC-SHA256 base64-encoded, not hex-encoded like most webhook systems. If your signature verification fails, check that you are base64-encoding the digest, not hex-encoding it.

Expected result: Your webhook handler receives POST requests for each new WooCommerce order with the full order JSON payload.

2

Extract Order Details and Validate

Why: Validating the order status and line items before processing prevents duplicate fulfillment of already-shipped orders.

Parse the webhook payload to extract order ID, status, billing address, and line items. For critical operations, re-fetch the order from the API to get the authoritative state — webhook payloads can occasionally be slightly stale.

request.sh
1curl -X GET 'https://yoursite.com/wp-json/wc/v3/orders/1001' \
2 -u 'ck_YOUR_KEY:cs_YOUR_SECRET'

Pro tip: WooCommerce order statuses follow a flow: pending → processing → completed (or cancelled/refunded). Only process orders in 'processing' status for fulfillment — 'pending' orders have not yet been paid.

Expected result: Order data is validated and enriched with fresh API data. The order is ready for shipping service integration.

3

Update Order Status to Completed

Why: Marking orders as completed in WooCommerce triggers customer completion emails and removes them from the active orders queue.

After fulfillment, send PUT /wc/v3/orders/{id} with the new status. You can also add a customer_note to the order update to include tracking information.

request.sh
1curl -X PUT 'https://yoursite.com/wp-json/wc/v3/orders/1001' \
2 -u 'ck_YOUR_KEY:cs_YOUR_SECRET' \
3 -H 'Content-Type: application/json' \
4 -d '{"status":"completed","customer_note":"Your order has been shipped. Tracking: 1Z999AA10123456784"}'

Pro tip: WooCommerce order status changes trigger internal hooks that run email notifications. Do not send your own completion email from the automation — WooCommerce handles it. Focus on status updates and tracking notes.

Expected result: The WooCommerce order status updates to 'completed'. WooCommerce automatically sends the order completion email to the customer.

4

Sync Order to External Shipping Service

Why: Most fulfillment automations need to send order data to a shipping API (ShipStation, EasyPost, etc.) before marking the order complete.

Extract the shipping address and line items from the WooCommerce order and POST them to your shipping service API. Receive the tracking number, then update the WooCommerce order with tracking info. The exact shipping API call depends on your provider.

request.sh
1# Example: Create shipment in ShipStation
2curl -X POST 'https://ssapi.shipstation.com/orders/createshipment' \
3 -H 'Authorization: Basic BASE64_SHIPSTATION_CREDS' \
4 -H 'Content-Type: application/json' \
5 -d '{"orderId": 12345, "carrierCode": "fedex", "serviceCode": "fedex_ground"}'

Pro tip: Always update the WooCommerce order status AFTER the shipping API call succeeds, not before. If the shipping API fails, the order should remain in 'processing' so it can be retried.

Expected result: A tracking number is returned from the shipping service and added to the WooCommerce order as a customer note.

Complete working code

Complete WooCommerce order webhook handler: verifies HMAC-SHA256 signature, processes 'processing' orders, re-fetches for fresh data, calls a shipping service, updates order status to 'completed' with tracking note. Handles retries for transient failures.

automate_wc_orders.py
1import os
2import hmac
3import hashlib
4import base64
5import threading
6import requests
7from flask import Flask, request, jsonify
8
9app = Flask(__name__)
10
11WP_BASE = os.environ['WP_BASE_URL']
12WC_AUTH = (os.environ['WC_CONSUMER_KEY'], os.environ['WC_CONSUMER_SECRET'])
13WEBHOOK_SECRET = os.environ['WC_WEBHOOK_SECRET']
14
15def verify_sig(body: bytes, sig: str) -> bool:
16 expected = base64.b64encode(hmac.new(WEBHOOK_SECRET.encode(), body, hashlib.sha256).digest()).decode()
17 return hmac.compare_digest(expected, sig)
18
19def wc_get(path):
20 resp = requests.get(f'{WP_BASE}{path}', auth=WC_AUTH)
21 resp.raise_for_status()
22 return resp.json()
23
24def wc_put(path, payload):
25 resp = requests.put(f'{WP_BASE}{path}', auth=WC_AUTH,
26 headers={'Content-Type': 'application/json'}, json=payload)
27 resp.raise_for_status()
28 return resp.json()
29
30def get_tracking_number(order):
31 # Replace with your shipping API integration
32 return f"TRACK{order['id']:08d}"
33
34def process_order(order_payload):
35 order_id = order_payload['id']
36 if order_payload.get('status') != 'processing':
37 return
38 try:
39 order = wc_get(f'/wc/v3/orders/{order_id}')
40 if order['status'] != 'processing':
41 return
42 tracking = get_tracking_number(order)
43 wc_put(f'/wc/v3/orders/{order_id}', {
44 'status': 'completed',
45 'customer_note': f'Shipped! Tracking: {tracking}'
46 })
47 print(f'Order {order_id} completed, tracking: {tracking}')
48 except Exception as e:
49 print(f'Error processing order {order_id}: {e}')
50
51@app.route('/webhooks/woocommerce', methods=['POST'])
52def webhook():
53 raw = request.get_data()
54 sig = request.headers.get('X-WC-Webhook-Signature', '')
55 if not verify_sig(raw, sig):
56 return jsonify({'error': 'bad sig'}), 401
57 order = request.json
58 threading.Thread(target=process_order, args=(order,), daemon=True).start()
59 return jsonify({'ok': True})
60
61if __name__ == '__main__':
62 app.run(port=3000)

Error handling

401{"code":"woocommerce_rest_cannot_view","message":"Sorry, you cannot list resources.","data":{"status":401}}
Cause

Consumer key or secret is incorrect, or the API key does not have the required permissions.

Fix

Verify consumer key and secret from WooCommerce > Settings > Advanced > REST API. Regenerate if unsure. Ensure permissions are set to 'Read/Write' not 'Read'.

Retry strategy

No retry — fix credentials.

401Webhook signature mismatch
Cause

The X-WC-Webhook-Signature is HMAC-SHA256 base64-encoded, not hex-encoded. Most webhook verification examples use hex — this is a common mistake.

Fix

Ensure you are base64-encoding the HMAC-SHA256 digest, not hex-encoding it: base64.b64encode(hmac.digest()).decode() in Python, .digest('base64') in Node.js.

Retry strategy

No retry — fix the signature verification code.

429Too Many Requests
Cause

Exceeded the WooCommerce Store API rate limit of 25 requests per 10-second window, or the managed host's WAF throttled your IP.

Fix

Add delays between order processing calls. For bulk operations, process at most 2 orders per second. Honor any Retry-After header.

Retry strategy

Exponential backoff: 1s, 2s, 4s, 8s. Check Retry-After header.

404{"code":"woocommerce_rest_order_invalid_id","message":"Invalid ID.","data":{"status":404}}
Cause

The order ID does not exist or was permanently deleted.

Fix

Handle 404 gracefully — log the ID and skip. Orders can be deleted manually in the admin.

Retry strategy

No retry — skip and log.

403{"code":"woocommerce_rest_cannot_edit","message":"Sorry, you are not allowed to edit this resource."}
Cause

The WooCommerce API key was created with 'Read' permissions only.

Fix

Regenerate the API key at WooCommerce > Settings > Advanced > REST API with 'Read/Write' permissions.

Retry strategy

No retry — fix permissions.

Rate Limits for WooCommerce REST API

ScopeLimitWindow
WooCommerce Store API (block-based)25 requestsper 10-second window
Checkout endpoint (Store API)3 requestsper 60-second window
WooCommerce REST API (wc/v3)Host WAF dependentNo WordPress core limit; managed hosts vary
retry-handler.ts
1import time
2import requests
3
4def wc_request(method, url, auth, max_retries=5, **kwargs):
5 for attempt in range(max_retries):
6 resp = getattr(requests, method)(url, auth=auth, **kwargs)
7 if resp.status_code == 429:
8 wait = int(resp.headers.get('Retry-After', 2 ** attempt))
9 time.sleep(wait)
10 continue
11 return resp
12 raise Exception('Max retries exceeded')
  • Process webhook events asynchronously — return 200 immediately and process in a background thread
  • Re-fetch orders from the API for authoritative state rather than relying solely on webhook payload data
  • Update order status only AFTER the shipping API succeeds to prevent marking orders complete if shipping fails
  • Add 500ms delays between sequential order processing calls when doing batch backfills
  • Monitor the X-WP-Total header when listing orders to understand pagination requirements

Security checklist

  • Always verify X-WC-Webhook-Signature using HMAC-SHA256 base64-encoded (not hex) before processing webhook payloads
  • Store WC_CONSUMER_KEY, WC_CONSUMER_SECRET, and WC_WEBHOOK_SECRET in environment variables
  • Use HTTPS only — WooCommerce consumer key auth requires encrypted transport
  • Create separate API keys per integration and set minimum required permissions (Read for read-only, Read/Write for updates)
  • Return 200 from webhook handler immediately — process asynchronously to prevent Notion retries
  • Validate order status before processing — skip orders not in 'processing' state to prevent duplicate fulfillment
  • Log all order processing actions with order IDs for audit trail and debugging

Automation use cases

Real-Time Order Fulfillment

intermediate

Process every new WooCommerce order immediately via webhook, submit to a shipping API, and mark complete with tracking within seconds of payment.

Daily Order Sync to Spreadsheet

beginner

Poll GET /wc/v3/orders?after=YESTERDAY for all orders from the past 24 hours and sync them to Google Sheets or Airtable for reporting.

Low Stock Backorder Manager

advanced

Combine GET /wc/v3/orders (for pending orders) with GET /wc/v3/products (for stock levels) to identify and email customers about backorders automatically.

No-code alternatives

Don't want to write code? These platforms can automate the same workflows visually.

Zapier

Free tier available; paid plans from $19.99/month

Zapier's WooCommerce integration supports order.created triggers and can update order status and sync to shipping tools without code.

Pros
  • + No code required
  • + Built-in WooCommerce trigger
  • + Connects to ShipStation, Airtable, Sheets
Cons
  • - Webhook processing delay of a few seconds
  • - Cannot verify webhook signatures natively
  • - Cost scales with order volume

Make

Free tier available; paid plans from $9/month

Make's WooCommerce module supports webhooks, order reading, and status updates with stronger data transformation capabilities than Zapier.

Pros
  • + Better for complex order data transformations
  • + More affordable at high volume
  • + HTTP module handles shipping API calls
Cons
  • - Learning curve higher than Zapier
  • - WooCommerce module may lag updates
  • - Webhook signature verification requires custom setup

n8n

Free self-hosted; cloud from €20/month

n8n has a WooCommerce node for order reading and status updates, plus a Webhook node for real-time order notifications.

Pros
  • + Self-hostable
  • + Full order lifecycle management
  • + Code node for custom shipping API integration
Cons
  • - WooCommerce node may not cover all edge cases
  • - Requires server for webhook reception
  • - More setup than SaaS tools

Best practices

  • Verify X-WC-Webhook-Signature with base64-encoded HMAC-SHA256 on every webhook — this prevents processing forged orders
  • Re-fetch the order via GET /wc/v3/orders/{id} in the webhook handler for the authoritative state
  • Only process orders in 'processing' status — 'pending' orders have not been paid
  • Update order status to 'completed' only after your shipping/fulfillment step succeeds
  • Handle all order statuses: if an order is 'cancelled' in the re-fetch, abort processing
  • Log order_id, shipping tracking numbers, and status changes for support and debugging
  • Test the full webhook flow with a real WooCommerce test order before going live

Ask AI to help

Copy one of these prompts to get a personalized, working implementation.

ChatGPT / Claude Prompt

I'm verifying WooCommerce webhook signatures in Python. The X-WC-Webhook-Signature header contains the signature. The webhook secret is stored as WC_WEBHOOK_SECRET. My verification code is: {paste code}. The verification is failing even though the secret is correct. WooCommerce uses HMAC-SHA256 with base64 encoding. What is the correct Python code to verify the signature?

Lovable / V0 Prompt

Build a Next.js order management dashboard for WooCommerce. The app should: display recent WooCommerce orders fetched from GET /wp-json/wc/v3/orders?per_page=50 with WooCommerce consumer key/secret auth stored in env vars, show order ID, customer email, total, status, and date in a table with color-coded status badges, include a 'Mark Complete' button that calls PUT /wc/v3/orders/{id} with status: 'completed', and a webhook handler at POST /api/webhooks/woocommerce that verifies the X-WC-Webhook-Signature (HMAC-SHA256 base64) and updates a Supabase table with new orders. Use WC_CONSUMER_KEY, WC_CONSUMER_SECRET, and WC_WEBHOOK_SECRET from environment variables.

Frequently asked questions

What is the difference between WooCommerce consumer key/secret and WordPress Application Passwords?

They are completely separate authentication systems. WordPress Application Passwords (Users > Profile > Application Passwords) authenticate against the WordPress REST API at /wp-json/wp/v2/. WooCommerce consumer keys (WooCommerce > Settings > Advanced > REST API) authenticate against the WooCommerce REST API at /wp-json/wc/v3/. You cannot use one for the other.

Why is the X-WC-Webhook-Signature base64-encoded instead of hex like other webhook systems?

WooCommerce generates the signature using PHP's hash_hmac('sha256', $body, $secret, true) — the third parameter (true) returns raw binary output, which WooCommerce then base64-encodes with base64_encode(). Most other webhook systems use the hex representation. Always use base64-encoded HMAC for WooCommerce signature verification.

Can I create WooCommerce webhooks via the API instead of the admin UI?

Yes. Send POST /wp-json/wc/v3/webhooks with {name, topic, delivery_url, secret} using your consumer key/secret auth. Topics include: order.created, order.updated, order.deleted, customer.created, product.created, product.updated. The response includes the webhook ID and generated secret.

Is the WooCommerce REST API free?

Yes. WooCommerce is a free plugin and its REST API is free to use. WooCommerce does not charge for API calls. Your costs are hosting only.

What happens when I hit the WooCommerce Store API rate limit?

The WooCommerce Store API returns HTTP 429 when you exceed 25 requests per 10-second window. The wc/v3 REST API (used for order management) is subject to your host's WAF policies, not the documented Store API limits. Implement exponential backoff and add delays between sequential order processing calls.

How do I paginate through all orders?

Use GET /wc/v3/orders with per_page=100&page=1. The response headers include X-WP-Total (total order count) and X-WP-TotalPages (total pages). Increment the page parameter and continue until page > X-WP-TotalPages.

Can I add custom meta data to WooCommerce orders via the API?

Yes. Include a meta_data array in your PUT or POST payload: {"meta_data": [{"key": "tracking_number", "value": "TRACK123"}]}. Meta data is returned in subsequent GET requests under the meta_data array. This is the best way to store fulfillment data alongside the order.

Can RapidDev build a custom WooCommerce order automation?

Yes. RapidDev has built 600+ apps including WooCommerce fulfillment pipelines, multi-warehouse order routing, and order sync systems. We can build a custom integration connecting WooCommerce to your shipping provider, inventory system, or ERP. Contact us at rapidevelopers.com for a free consultation.

RapidDev

Need this automated?

Our team has built 600+ apps with API automations. We can build this for you.

Book a free consultation

Skip the coding — we'll build it for you

Our experts have built 600+ API automations. From prototype to production in days, not weeks.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.