# How to Integrate Replit with WooCommerce

- Tool: Replit
- Difficulty: Intermediate
- Time required: 40 minutes
- Last updated: March 2026

## TL;DR

To integrate Replit with WooCommerce, generate a REST API consumer key and secret from your WordPress admin (WooCommerce > Settings > Advanced > REST API), store them in Replit Secrets (lock icon 🔒), and use Python or Node.js to manage products, orders, and customers. Deploy on Autoscale for on-demand store management automation.

## Why Connect Replit to the WooCommerce REST API?

WooCommerce powers over 30% of all online stores worldwide. The WooCommerce REST API (v3) provides programmatic access to products, orders, customers, coupons, and reports, enabling automation tools, inventory sync, fulfillment integrations, and multi-channel dashboards.

WooCommerce API authentication for HTTPS stores uses consumer key and secret as HTTP Basic auth credentials. For non-HTTPS stores, OAuth 1.0a is required, but all production stores should run HTTPS.

WooCommerce webhooks let your Replit server receive real-time notifications for order status changes, new customers, and product updates. Combined with the REST API, you can build fully automated store management workflows entirely from Replit.

## Before you start

- A Replit account with a Python or Node.js project created
- A WordPress site with WooCommerce installed and running on HTTPS
- Administrator access to the WordPress admin dashboard to generate API keys
- WooCommerce REST API enabled (it is enabled by default) under WooCommerce > Settings > Advanced > REST API
- Basic understanding of REST API concepts and HTTP authentication

## Step-by-step guide

### 1. Generate WooCommerce REST API Keys

Log into your WordPress admin dashboard and navigate to WooCommerce > Settings > Advanced > REST API. Click 'Add Key'.

Fill in the key details:
- Description: give the key a descriptive name (e.g., 'Replit Integration')
- User: select the WordPress user the key will act as (use an administrator account for full access)
- Permissions: choose Read/Write for full API access

Click 'Generate API Key'. WordPress will display your Consumer Key and Consumer Secret exactly once — copy both values immediately. The consumer secret is hashed and stored in the database; you cannot retrieve it again after leaving the page.

If you lose the consumer secret, you must revoke the key and create a new one. The Consumer Key format is ck_xxxx and the Consumer Secret format is cs_xxxx. Both are long alphanumeric strings.

Important: WooCommerce REST API only allows Basic auth authentication over HTTPS. If your store does not have an SSL certificate (unlikely in production but possible in local development), you must use OAuth 1.0a or the WooCommerce API will reject Basic auth requests with a 401 error. Always test on a HTTPS-enabled store.

**Expected result:** You have a WooCommerce Consumer Key (ck_xxxx) and Consumer Secret (cs_xxxx) from the WordPress REST API settings page.

### 2. Store Credentials in Replit Secrets

Click the lock icon 🔒 in the Replit sidebar to open the Secrets pane. Add three secrets:

- Key: WC_CONSUMER_KEY — Value: your consumer key (ck_xxxx)
- Key: WC_CONSUMER_SECRET — Value: your consumer secret (cs_xxxx)
- Key: WC_STORE_URL — Value: your WordPress store URL (e.g., https://mystore.com)

Storing the store URL as a secret (rather than hardcoding it) makes the integration portable and easy to update if your store URL changes. Access the values in Python with os.environ['WC_CONSUMER_KEY'] and in Node.js with process.env.WC_CONSUMER_KEY.

WooCommerce consumer keys have the permissions you configured during creation (Read or Read/Write). A Read/Write key can create, update, and delete any store data — treat it as a privileged credential. Never include these values in client-facing code.

**Expected result:** WC_CONSUMER_KEY, WC_CONSUMER_SECRET, and WC_STORE_URL appear in the Replit Secrets pane with values hidden.

### 3. Manage Products and Orders with Python

Install the WooCommerce Python client with 'pip install woocommerce flask'. The woocommerce library handles Basic auth and request signing automatically, so you don't need to manage authentication headers manually.

The Flask server below provides endpoints for listing products, creating products, retrieving orders, and updating order status. The woocommerce library's API class wraps all HTTP operations with proper authentication. Use the get(), post(), put(), and delete() methods for CRUD operations.

WooCommerce pagination uses 'per_page' (max 100) and 'page' parameters. For retrieving all products or orders beyond 100 items, you must paginate through multiple requests. The API returns the total number of pages in the X-WP-TotalPages response header.

```
import os
from flask import Flask, request, jsonify
from woocommerce import API

app = Flask(__name__)

# Initialize WooCommerce API client
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
)


@app.route("/products")
def list_products():
    """List products with optional filtering."""
    page = request.args.get("page", 1)
    per_page = min(int(request.args.get("per_page", 20)), 100)
    status = request.args.get("status", "publish")

    response = wcapi.get("products", params={
        "page": page,
        "per_page": per_page,
        "status": status
    })
    if response.status_code != 200:
        return jsonify({"error": response.json()}), response.status_code
    return jsonify({
        "total_pages": response.headers.get("X-WP-TotalPages"),
        "total": response.headers.get("X-WP-Total"),
        "products": response.json()
    })


@app.route("/products", methods=["POST"])
def create_product():
    """Create a new product."""
    data = request.get_json()
    response = wcapi.post("products", data)
    return jsonify(response.json()), response.status_code


@app.route("/products/batch", methods=["POST"])
def batch_update_products():
    """Batch update multiple products."""
    data = request.get_json()
    # data format: {"update": [{"id": 1, "regular_price": "19.99"}, ...]}
    response = wcapi.post("products/batch", data)
    return jsonify(response.json()), response.status_code


@app.route("/orders")
def list_orders():
    """List orders with optional status filter."""
    page = request.args.get("page", 1)
    per_page = min(int(request.args.get("per_page", 20)), 100)
    status = request.args.get("status", "any")

    response = wcapi.get("orders", params={
        "page": page,
        "per_page": per_page,
        "status": status
    })
    if response.status_code != 200:
        return jsonify({"error": response.json()}), response.status_code
    return jsonify({
        "total_pages": response.headers.get("X-WP-TotalPages"),
        "orders": response.json()
    })


@app.route("/orders/<int:order_id>")
def get_order(order_id):
    """Get a single order by ID."""
    response = wcapi.get(f"orders/{order_id}")
    return jsonify(response.json()), response.status_code


@app.route("/orders/<int:order_id>/status", methods=["PUT"])
def update_order_status(order_id):
    """Update order status."""
    data = request.get_json()
    new_status = data.get("status")
    if not new_status:
        return jsonify({"error": "status is required"}), 400
    # Valid statuses: pending, processing, on-hold, completed, cancelled, refunded, failed
    response = wcapi.put(f"orders/{order_id}", {"status": new_status})
    return jsonify(response.json()), response.status_code


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=3000, debug=True)
```

**Expected result:** GET /products returns a list of WooCommerce products from your store, and GET /orders returns recent orders with their line items and customer data.

### 4. Handle WooCommerce Webhooks in Node.js

Install dependencies with 'npm install express @woocommerce/woocommerce-rest-api'. The Node.js WooCommerce library provides the same API interface as the Python version.

The server below implements both REST API calls and a webhook receiver. WooCommerce webhooks include a secret (configured in WordPress) that is used to generate an HMAC-SHA256 signature in the X-WC-Webhook-Signature header. Verifying this signature in your Replit server confirms the webhook came from your actual WooCommerce store and prevents spoofed requests.

To configure webhooks in WooCommerce, go to WooCommerce > Settings > Advanced > Webhooks and add a new webhook with your Replit deployment URL and your chosen webhook secret.

```
const express = require('express');
const crypto = require('crypto');
const WooCommerceRestApi = require('@woocommerce/woocommerce-rest-api').default;

const app = express();

const WC_STORE_URL = process.env.WC_STORE_URL;
const WC_CONSUMER_KEY = process.env.WC_CONSUMER_KEY;
const WC_CONSUMER_SECRET = process.env.WC_CONSUMER_SECRET;
const WC_WEBHOOK_SECRET = process.env.WC_WEBHOOK_SECRET || '';

const api = new WooCommerceRestApi({
  url: WC_STORE_URL,
  consumerKey: WC_CONSUMER_KEY,
  consumerSecret: WC_CONSUMER_SECRET,
  version: 'wc/v3'
});

// Webhook handler — use raw body for signature verification
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  // Verify webhook signature if secret is configured
  if (WC_WEBHOOK_SECRET) {
    const signature = req.headers['x-wc-webhook-signature'];
    const expected = crypto
      .createHmac('sha256', WC_WEBHOOK_SECRET)
      .update(req.body)
      .digest('base64');
    if (signature !== expected) {
      return res.status(401).json({ error: 'Invalid webhook signature' });
    }
  }

  const event = JSON.parse(req.body);
  const topic = req.headers['x-wc-webhook-topic'];

  console.log(`WooCommerce webhook: ${topic}`);

  switch (topic) {
    case 'order.created':
    case 'order.updated':
      console.log(`Order ${event.id} status: ${event.status}, total: ${event.total}`);
      // Add downstream logic: notify fulfillment, update CRM, etc.
      break;
    case 'product.created':
    case 'product.updated':
      console.log(`Product ${event.id}: ${event.name} — stock: ${event.stock_quantity}`);
      break;
    case 'customer.created':
      console.log(`New customer: ${event.email}`);
      break;
    default:
      console.log(`Unhandled topic: ${topic}`);
  }

  res.json({ received: true });
});

// Use JSON parser for non-webhook routes
app.use(express.json());

// List products
app.get('/products', async (req, res) => {
  try {
    const response = await api.get('products', {
      per_page: Number(req.query.per_page) || 20,
      page: Number(req.query.page) || 1,
      status: req.query.status || 'publish'
    });
    res.json({
      total: response.headers['x-wp-total'],
      total_pages: response.headers['x-wp-totalpages'],
      products: response.data
    });
  } catch (err) {
    res.status(err.response?.status || 500).json({ error: err.message });
  }
});

// Get order by ID
app.get('/orders/:id', async (req, res) => {
  try {
    const response = await api.get(`orders/${req.params.id}`);
    res.json(response.data);
  } catch (err) {
    res.status(err.response?.status || 500).json({ error: err.message });
  }
});

// Update order status
app.put('/orders/:id/status', async (req, res) => {
  const { status } = req.body;
  if (!status) return res.status(400).json({ error: 'status is required' });
  try {
    const response = await api.put(`orders/${req.params.id}`, { status });
    res.json(response.data);
  } catch (err) {
    res.status(err.response?.status || 500).json({ error: err.message });
  }
});

app.listen(3000, '0.0.0.0', () => {
  console.log('WooCommerce integration server running on port 3000');
});
```

**Expected result:** POST /webhook correctly receives WooCommerce order events with signature verification, and GET /products returns product data from your store.

### 5. Deploy and Configure WooCommerce Webhooks

Deploy your Replit app by clicking the Deploy button. For a WooCommerce integration that receives order webhooks, choose a Reserved VM deployment to ensure the webhook endpoint is always available. Order processing automation should never miss events due to a cold start.

After deployment, go to WooCommerce > Settings > Advanced > Webhooks in your WordPress admin. Click 'Add Webhook':

- Name: Replit Integration
- Status: Active
- Topic: Order Created (or whichever events you need)
- Delivery URL: your Replit deployment URL + /webhook (e.g., https://your-app.yourusername.repl.co/webhook)
- Secret: create a random string and add it as WC_WEBHOOK_SECRET in Replit Secrets

Save the webhook. WooCommerce will send a test ping to your endpoint — check your Replit deployment logs to confirm receipt. Repeat for each event topic you need (Order Updated, Customer Created, Product Updated, etc.).

```
[[ports]]
internalPort = 3000
externalPort = 80

[deployment]
run = ["node", "server.js"]
deploymentTarget = "cloudrun"
```

**Expected result:** Your deployed Replit server receives WooCommerce webhook events and your webhook appears as 'Active' in the WooCommerce Webhooks settings page.

## Best practices

- Store WC_CONSUMER_KEY, WC_CONSUMER_SECRET, and WC_STORE_URL in Replit Secrets (lock icon 🔒) — never hardcode them in server files.
- Always use HTTPS for your WooCommerce store URL — WooCommerce REST API Basic auth is only secure over encrypted connections.
- Set a WooCommerce webhook secret and verify the HMAC-SHA256 signature on every incoming webhook to prevent spoofed order events.
- Use the batch API endpoint (products/batch, orders/batch) for bulk operations instead of individual API calls — this reduces request count significantly.
- Use Reserved VM deployment for WooCommerce webhook receivers to avoid missing order events during Autoscale cold starts.
- Always paginate through large product or order lists — the WooCommerce API returns a maximum of 100 items per request, and stores with thousands of products require multiple paginated calls.
- Create separate API keys for different integrations (analytics vs fulfillment vs inventory) so you can revoke specific access without disrupting other tools.
- Log WooCommerce webhook payloads to a database before processing so you can replay events if downstream processing fails.

## Use cases

### Automated Order Fulfillment Notifications

A Replit webhook receiver listens for WooCommerce order.created events, extracts the order details and customer information, and triggers downstream actions: sending a custom order confirmation email with branding beyond WooCommerce's default templates, updating a Google Sheet with order data for the fulfillment team, and posting a Slack notification to the warehouse channel.

Prompt example:

```
Build a Flask webhook server that receives WooCommerce new order events, extracts product line items, sends a formatted fulfillment notification to a Slack channel, and logs the order to a database.
```

### Bulk Product Price and Inventory Updater

A Replit script reads a CSV of product IDs, new prices, and stock quantities, then uses the WooCommerce Batch Update API to update hundreds of products in a single API call. This is far more efficient than editing products individually in the WordPress admin and enables regular pricing updates from a spreadsheet-based workflow.

Prompt example:

```
Create a Python script that reads a CSV with WooCommerce product IDs and new prices, batches the updates into groups of 100, and sends batch update requests to the WooCommerce API.
```

### Customer Segment Export for Email Marketing

A Replit endpoint queries WooCommerce for customers who have placed more than two orders in the past 90 days, formats their email addresses and purchase history, and exports the data to a Mailchimp audience segment. This creates a high-value customer cohort for loyalty marketing campaigns without any manual data export from WordPress.

Prompt example:

```
Write a Node.js script that fetches WooCommerce customers with repeat purchases, filters by order count and recency, and adds them to a specific Mailchimp audience segment.
```

## Troubleshooting

### HTTP 401 Unauthorized when calling the WooCommerce REST API

Cause: The most common cause is calling the API over HTTP (not HTTPS). WooCommerce Basic auth only works over HTTPS. Another cause is incorrect consumer key or secret values in Replit Secrets.

Solution: Verify your WC_STORE_URL in Replit Secrets starts with https:// not http://. Confirm the consumer key (ck_xxxx) and consumer secret (cs_xxxx) in Secrets match exactly what is shown in WordPress WooCommerce > Settings > Advanced > REST API.

```
# Verify the store URL uses HTTPS
store_url = os.environ['WC_STORE_URL']
if not store_url.startswith('https://'):
    raise ValueError(f'WooCommerce store URL must use HTTPS: {store_url}')
```

### WooCommerce webhook not arriving at Replit server

Cause: The webhook delivery URL points to the Replit editor preview URL instead of the deployed app URL, or the deployment is on Autoscale and the server is cold-starting when the webhook arrives.

Solution: Use the Replit deployment URL (from the Deploy tab) not the editor preview URL. For reliable webhook delivery, use Reserved VM deployment to avoid cold starts. Check the WooCommerce Webhook log (in WooCommerce > Status > Logs) for delivery errors.

### Webhook signature verification fails with 401

Cause: The raw body is being parsed as JSON before the HMAC signature is computed, or the webhook secret in Replit Secrets does not match the secret configured in WooCommerce.

Solution: Ensure the /webhook route uses express.raw() or an equivalent raw body parser BEFORE any json middleware runs on that route. Verify WC_WEBHOOK_SECRET in Replit Secrets exactly matches the secret entered in the WooCommerce Webhook settings.

```
// Correct: raw body for webhook route BEFORE express.json()
app.post('/webhook', express.raw({ type: 'application/json' }), handler);
// Wrong: express.json() consumes the body first
// app.use(express.json()); // Don't put this before webhook route
```

### 403 Forbidden when trying to create or update resources

Cause: The WooCommerce API consumer key was generated with Read-only permissions instead of Read/Write.

Solution: Go to WooCommerce > Settings > Advanced > REST API, find your API key, and check its permissions. If it is set to Read, revoke it and create a new key with Read/Write permissions. Update WC_CONSUMER_KEY and WC_CONSUMER_SECRET in Replit Secrets with the new credentials.

## Frequently asked questions

### How do I generate WooCommerce REST API keys?

Log into WordPress admin and go to WooCommerce > Settings > Advanced > REST API. Click 'Add Key', set permissions to Read/Write, and click 'Generate API Key'. Copy the Consumer Key and Consumer Secret immediately — the secret cannot be retrieved after leaving the page.

### Why does the WooCommerce API return 401 Unauthorized from Replit?

The most common cause is using HTTP instead of HTTPS for your store URL — WooCommerce Basic auth only works over HTTPS. Check that WC_STORE_URL in Replit Secrets starts with https://. Also verify the consumer key and secret values are correct and the key has the right permissions (Read/Write).

### Can I receive real-time order notifications in Replit from WooCommerce?

Yes, using WooCommerce webhooks. Configure a webhook in WooCommerce > Settings > Advanced > Webhooks pointing to your Replit deployment URL. Set the topic to 'Order Created' or other events. Your Replit server receives a POST request with the full order data whenever a matching event occurs. Use a Reserved VM deployment to ensure the endpoint is always available.

### Is there a WooCommerce client library for Python and Node.js?

Yes. For Python, install the 'woocommerce' package (pip install woocommerce). For Node.js, install '@woocommerce/woocommerce-rest-api' (npm install @woocommerce/woocommerce-rest-api). Both libraries handle Basic auth and OAuth 1.0a automatically based on your store URL being HTTPS or HTTP.

### How many WooCommerce records can I retrieve per API request?

The WooCommerce REST API returns a maximum of 100 records per request (using per_page=100). For stores with thousands of products or orders, you need to paginate through results using the page parameter. The total number of pages is returned in the X-WP-TotalPages response header so you know when to stop.

---

Source: https://www.rapidevelopers.com/replit-integration/woocommerce
© RapidDev — https://www.rapidevelopers.com/replit-integration/woocommerce
