Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
alinaqi avatar

Woocommerce

  • 4 installs
  • 706 repo stars
  • Updated July 14, 2026
  • alinaqi/maggy

woocommerce is a Claude Code skill for integrating with WooCommerce stores via the REST API for products, orders, customers, and webhooks.

About

This skill provides patterns for integrating with WooCommerce stores through the WooCommerce REST API. It covers store prerequisites, API key generation, Node.js and Python client setup, authentication, and CRUD for products, orders, customers, and webhooks. A developer uses it when connecting an app to a WooCommerce store.

  • Integrates WooCommerce stores via the REST API for products, orders, customers, and webhooks
  • Includes Node.js and Python client setup, auth, and product CRUD (including variable products)
  • Covers prerequisites, API key generation, and query-string auth fallback

Woocommerce by the numbers

  • 4 all-time installs (skills.sh)
  • Ranked #3,711 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

woocommerce capabilities & compatibility

Free skill; requires a WooCommerce store and WC_CONSUMER_KEY/WC_CONSUMER_SECRET.

Capabilities
api development · ecommerce integration · database
Use cases
api development
Runs
Runs locally
Pricing
Bring your own API key
From the docs

What woocommerce says it does

WooCommerce REST API - products, orders, customers, webhooks
SKILL.md
For integrating with WooCommerce stores via REST API - products, orders, customers, webhooks, and custom extensions.
SKILL.md
npx skills add https://github.com/alinaqi/maggy --skill woocommerce

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs4
repo stars706
Last updatedJuly 14, 2026
Repositoryalinaqi/maggy

What it does

Integrate an app with a WooCommerce store via its REST API for products, orders, customers, and webhooks.

Who is it for?

Integrating an app with a WooCommerce store's REST API.

When should I use this skill?

When integrating with WooCommerce stores.

What you get

A working WooCommerce REST API integration for products, orders, customers, and webhooks.

  • WooCommerce client setup
  • product CRUD functions
  • variable product handling

By the numbers

  • Uses WooCommerce REST API v3 (wc/v3)
  • Provides both Node.js and Python client setups

Files

SKILL.mdMarkdownGitHub ↗

WooCommerce Development Skill

For integrating with WooCommerce stores via REST API - products, orders, customers, webhooks, and custom extensions.

Sources: WooCommerce REST API | Developer Docs

---

Prerequisites

Store Requirements

# WooCommerce store must have:
# 1. WordPress with WooCommerce plugin installed
# 2. HTTPS enabled (required for API auth)
# 3. Permalinks set to anything except "Plain"
#    WordPress Admin → Settings → Permalinks → Post name (recommended)

Generate API Keys

1. Go to WooCommerce → Settings → Advanced → REST API 2. Click Add key 3. Set Description, User (admin), and Permissions (Read/Write) 4. Click Generate API key 5. Copy Consumer Key and Consumer Secret (shown only once)

---

API Basics

Base URL

https://your-store.com/wp-json/wc/v3/

Authentication

// Node.js - Basic Auth (recommended)
const WooCommerceRestApi = require("@woocommerce/woocommerce-rest-api").default;

const api = new WooCommerceRestApi({
  url: "https://your-store.com",
  consumerKey: process.env.WC_CONSUMER_KEY,
  consumerSecret: process.env.WC_CONSUMER_SECRET,
  version: "wc/v3"
});
# Python
from woocommerce import API

wcapi = API(
    url="https://your-store.com",
    consumer_key=os.environ["WC_CONSUMER_KEY"],
    consumer_secret=os.environ["WC_CONSUMER_SECRET"],
    version="wc/v3"
)

Query String Auth (Fallback)

# Only use if Basic Auth fails (some hosting configurations)
curl https://your-store.com/wp-json/wc/v3/products \
  ?consumer_key=ck_xxx&consumer_secret=cs_xxx

---

Installation

Node.js

npm install @woocommerce/woocommerce-rest-api
// lib/woocommerce.ts
import WooCommerceRestApi from "@woocommerce/woocommerce-rest-api";

const api = new WooCommerceRestApi({
  url: process.env.WC_STORE_URL!,
  consumerKey: process.env.WC_CONSUMER_KEY!,
  consumerSecret: process.env.WC_CONSUMER_SECRET!,
  version: "wc/v3",
  queryStringAuth: false, // Set true for HTTP (dev only)
});

export default api;

Python

pip install woocommerce
# lib/woocommerce.py
import os
from woocommerce import API

wcapi = API(
    url=os.environ["WC_STORE_URL"],
    consumer_key=os.environ["WC_CONSUMER_KEY"],
    consumer_secret=os.environ["WC_CONSUMER_SECRET"],
    version="wc/v3",
    timeout=30
)

---

Products

List Products

// Node.js
async function getProducts(page = 1, perPage = 20) {
  const response = await api.get("products", {
    page,
    per_page: perPage,
    status: "publish",
  });
  return response.data;
}

// With filters
async function searchProducts(search: string, category?: number) {
  const response = await api.get("products", {
    search,
    category: category || undefined,
    orderby: "popularity",
    order: "desc",
  });
  return response.data;
}
# Python
def get_products(page=1, per_page=20):
    response = wcapi.get("products", params={
        "page": page,
        "per_page": per_page,
        "status": "publish"
    })
    return response.json()

Get Single Product

async function getProduct(productId: number) {
  const response = await api.get(`products/${productId}`);
  return response.data;
}

Create Product

async function createProduct(data: ProductInput) {
  const response = await api.post("products", {
    name: data.name,
    type: "simple", // simple, variable, grouped, external
    regular_price: data.price.toString(),
    description: data.description,
    short_description: data.shortDescription,
    categories: data.categoryIds.map(id => ({ id })),
    images: data.images.map(url => ({ src: url })),
    manage_stock: true,
    stock_quantity: data.stockQuantity,
    status: "publish",
  });
  return response.data;
}

Update Product

async function updateProduct(productId: number, data: Partial<ProductInput>) {
  const response = await api.put(`products/${productId}`, data);
  return response.data;
}

// Update stock only
async function updateStock(productId: number, quantity: number) {
  const response = await api.put(`products/${productId}`, {
    stock_quantity: quantity,
  });
  return response.data;
}

Delete Product

async function deleteProduct(productId: number, force = false) {
  // force: true = permanent delete, false = move to trash
  const response = await api.delete(`products/${productId}`, {
    force,
  });
  return response.data;
}

Variable Products

// Create variable product
async function createVariableProduct(data: VariableProductInput) {
  // 1. Create product with type "variable"
  const product = await api.post("products", {
    name: data.name,
    type: "variable",
    attributes: [
      {
        name: "Size",
        visible: true,
        variation: true,
        options: ["Small", "Medium", "Large"],
      },
      {
        name: "Color",
        visible: true,
        variation: true,
        options: ["Red", "Blue"],
      },
    ],
  });

  // 2. Create variations
  for (const variant of data.variants) {
    await api.post(`products/${product.data.id}/variations`, {
      regular_price: variant.price.toString(),
      stock_quantity: variant.stock,
      attributes: [
        { name: "Size", option: variant.size },
        { name: "Color", option: variant.color },
      ],
    });
  }

  return product.data;
}

// Get variations
async function getVariations(productId: number) {
  const response = await api.get(`products/${productId}/variations`);
  return response.data;
}

---

Orders

List Orders

async function getOrders(params: OrderQueryParams = {}) {
  const response = await api.get("orders", {
    page: params.page || 1,
    per_page: params.perPage || 20,
    status: params.status || "any", // pending, processing, completed, etc.
    after: params.after, // ISO date string
    before: params.before,
  });
  return response.data;
}

// Get recent orders
async function getRecentOrders(days = 7) {
  const after = new Date();
  after.setDate(after.getDate() - days);

  const response = await api.get("orders", {
    after: after.toISOString(),
    orderby: "date",
    order: "desc",
  });
  return response.data;
}

Get Single Order

async function getOrder(orderId: number) {
  const response = await api.get(`orders/${orderId}`);
  return response.data;
}

Create Order

async function createOrder(data: OrderInput) {
  const response = await api.post("orders", {
    payment_method: "stripe",
    payment_method_title: "Credit Card",
    set_paid: false,
    billing: {
      first_name: data.customer.firstName,
      last_name: data.customer.lastName,
      email: data.customer.email,
      phone: data.customer.phone,
      address_1: data.billing.address1,
      city: data.billing.city,
      state: data.billing.state,
      postcode: data.billing.postcode,
      country: data.billing.country,
    },
    shipping: {
      first_name: data.customer.firstName,
      last_name: data.customer.lastName,
      address_1: data.shipping.address1,
      city: data.shipping.city,
      state: data.shipping.state,
      postcode: data.shipping.postcode,
      country: data.shipping.country,
    },
    line_items: data.items.map(item => ({
      product_id: item.productId,
      variation_id: item.variationId,
      quantity: item.quantity,
    })),
    shipping_lines: [
      {
        method_id: "flat_rate",
        method_title: "Flat Rate",
        total: data.shippingCost.toString(),
      },
    ],
  });
  return response.data;
}

Update Order Status

async function updateOrderStatus(orderId: number, status: OrderStatus) {
  const response = await api.put(`orders/${orderId}`, {
    status, // pending, processing, on-hold, completed, cancelled, refunded, failed
  });
  return response.data;
}

// Add order note
async function addOrderNote(orderId: number, note: string, customerNote = false) {
  const response = await api.post(`orders/${orderId}/notes`, {
    note,
    customer_note: customerNote, // true = visible to customer
  });
  return response.data;
}

Order Statuses

StatusDescription
pendingAwaiting payment
processingPayment received, awaiting fulfillment
on-holdAwaiting action (stock, payment confirmation)
completedOrder fulfilled
cancelledCancelled by admin or customer
refundedRefunded
failedPayment failed

---

Customers

List Customers

async function getCustomers(params: CustomerQueryParams = {}) {
  const response = await api.get("customers", {
    page: params.page || 1,
    per_page: params.perPage || 20,
    role: "customer",
    orderby: "registered_date",
    order: "desc",
  });
  return response.data;
}

// Search customers
async function searchCustomers(email: string) {
  const response = await api.get("customers", {
    email,
  });
  return response.data;
}

Create Customer

async function createCustomer(data: CustomerInput) {
  const response = await api.post("customers", {
    email: data.email,
    first_name: data.firstName,
    last_name: data.lastName,
    username: data.email.split("@")[0],
    billing: {
      first_name: data.firstName,
      last_name: data.lastName,
      email: data.email,
      phone: data.phone,
      address_1: data.address1,
      city: data.city,
      state: data.state,
      postcode: data.postcode,
      country: data.country,
    },
    shipping: {
      // Same as billing or different
    },
  });
  return response.data;
}

Update Customer

async function updateCustomer(customerId: number, data: Partial<CustomerInput>) {
  const response = await api.put(`customers/${customerId}`, data);
  return response.data;
}

---

Webhooks

Create Webhook

async function createWebhook(topic: string, deliveryUrl: string) {
  const response = await api.post("webhooks", {
    name: `Webhook for ${topic}`,
    topic, // order.created, order.updated, product.created, etc.
    delivery_url: deliveryUrl,
    status: "active",
    secret: process.env.WC_WEBHOOK_SECRET,
  });
  return response.data;
}

Webhook Topics

TopicTrigger
order.createdNew order placed
order.updatedOrder status/details changed
order.deletedOrder deleted
product.createdNew product created
product.updatedProduct updated
product.deletedProduct deleted
customer.createdNew customer registered
customer.updatedCustomer updated
coupon.createdNew coupon created

Verify Webhook Signature

// Express.js webhook handler
import crypto from "crypto";

function verifyWooCommerceWebhook(req: Request): boolean {
  const signature = req.headers["x-wc-webhook-signature"] as string;
  const payload = JSON.stringify(req.body);

  const expectedSignature = crypto
    .createHmac("sha256", process.env.WC_WEBHOOK_SECRET!)
    .update(payload)
    .digest("base64");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Route handler
app.post("/webhooks/woocommerce", (req, res) => {
  if (!verifyWooCommerceWebhook(req)) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const topic = req.headers["x-wc-webhook-topic"];
  const payload = req.body;

  switch (topic) {
    case "order.created":
      handleNewOrder(payload);
      break;
    case "order.updated":
      handleOrderUpdate(payload);
      break;
    // ... other topics
  }

  res.status(200).json({ received: true });
});
# Python/Flask webhook handler
import hmac
import hashlib
import base64

@app.route("/webhooks/woocommerce", methods=["POST"])
def woocommerce_webhook():
    signature = request.headers.get("X-WC-Webhook-Signature")
    payload = request.get_data()

    expected = base64.b64encode(
        hmac.new(
            os.environ["WC_WEBHOOK_SECRET"].encode(),
            payload,
            hashlib.sha256
        ).digest()
    ).decode()

    if not hmac.compare_digest(signature, expected):
        return {"error": "Invalid signature"}, 401

    topic = request.headers.get("X-WC-Webhook-Topic")
    data = request.json

    if topic == "order.created":
        handle_new_order(data)
    elif topic == "order.updated":
        handle_order_update(data)

    return {"received": True}, 200

---

Categories & Tags

List Categories

async function getCategories() {
  const response = await api.get("products/categories", {
    per_page: 100,
    orderby: "name",
  });
  return response.data;
}

// Create category
async function createCategory(name: string, parentId?: number) {
  const response = await api.post("products/categories", {
    name,
    parent: parentId || 0,
  });
  return response.data;
}

List Tags

async function getTags() {
  const response = await api.get("products/tags", {
    per_page: 100,
  });
  return response.data;
}

---

Coupons

Create Coupon

async function createCoupon(data: CouponInput) {
  const response = await api.post("coupons", {
    code: data.code,
    discount_type: data.type, // percent, fixed_cart, fixed_product
    amount: data.amount.toString(),
    individual_use: true,
    exclude_sale_items: false,
    minimum_amount: data.minimumAmount?.toString(),
    maximum_amount: data.maximumAmount?.toString(),
    usage_limit: data.usageLimit,
    usage_limit_per_user: 1,
    date_expires: data.expiresAt, // ISO date string
  });
  return response.data;
}

---

Reports

Sales Report

async function getSalesReport(period = "month") {
  const response = await api.get("reports/sales", {
    period, // day, week, month, year
  });
  return response.data;
}

// Top sellers
async function getTopSellers(period = "month") {
  const response = await api.get("reports/top_sellers", {
    period,
  });
  return response.data;
}

---

Pagination

Handle Large Datasets

async function getAllProducts() {
  const allProducts = [];
  let page = 1;
  const perPage = 100;

  while (true) {
    const response = await api.get("products", {
      page,
      per_page: perPage,
    });

    allProducts.push(...response.data);

    // Check headers for total pages
    const totalPages = parseInt(response.headers["x-wp-totalpages"]);
    if (page >= totalPages) break;

    page++;
  }

  return allProducts;
}

Pagination Headers

HeaderDescription
X-WP-TotalTotal number of items
X-WP-TotalPagesTotal number of pages

---

Error Handling

import WooCommerceRestApi from "@woocommerce/woocommerce-rest-api";

async function safeApiCall<T>(
  operation: () => Promise<{ data: T }>
): Promise<T> {
  try {
    const response = await operation();
    return response.data;
  } catch (error: any) {
    if (error.response) {
      // API returned an error
      const { status, data } = error.response;

      switch (status) {
        case 400:
          throw new Error(`Bad request: ${data.message}`);
        case 401:
          throw new Error("Invalid API credentials");
        case 404:
          throw new Error("Resource not found");
        case 429:
          // Rate limited - wait and retry
          await new Promise(r => setTimeout(r, 5000));
          return safeApiCall(operation);
        default:
          throw new Error(`API error: ${data.message}`);
      }
    }
    throw error;
  }
}

// Usage
const products = await safeApiCall(() => api.get("products"));

---

Environment Variables

# .env
WC_STORE_URL=https://your-store.com
WC_CONSUMER_KEY=ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WC_CONSUMER_SECRET=cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WC_WEBHOOK_SECRET=your_webhook_secret

Add to credentials.md:

'WC_CONSUMER_KEY': r'ck_[a-f0-9]{40}',
'WC_CONSUMER_SECRET': r'cs_[a-f0-9]{40}',

---

Checklist

Before Integration

  • [ ] WooCommerce plugin installed and activated
  • [ ] HTTPS enabled on store
  • [ ] Permalinks set to non-Plain setting
  • [ ] API keys generated with appropriate permissions
  • [ ] Webhook secret configured

Security

  • [ ] API keys stored in environment variables
  • [ ] Webhook signatures verified
  • [ ] HTTPS used for all API calls
  • [ ] Rate limiting handled

Testing

  • [ ] Test API connection
  • [ ] Test product CRUD operations
  • [ ] Test order creation/updates
  • [ ] Test webhook delivery
  • [ ] Test pagination for large datasets

---

Anti-Patterns

  • Plain permalinks - API won't work without pretty permalinks
  • HTTP in production - Always use HTTPS
  • Ignoring rate limits - WooCommerce may throttle requests
  • Large single requests - Use pagination for bulk operations
  • Storing keys in code - Use environment variables
  • Skipping webhook verification - Always verify signatures

Related skills

FAQ

What can woocommerce manage via the API?

Products, orders, customers, webhooks, and custom extensions through the WooCommerce REST API.

What auth does it use?

Consumer key and secret via Basic Auth, with a query-string auth fallback for some hosting configurations.

Backend & APIsecommercepayments

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.