How to Connect WooCommerce to WaveAccounting (Automated Data Sync)
📊 Integration Overview This blueprint outlines a robust, real-time integration pipeline designed to synchronize sales order data from WooCommerce to WaveAccounting. Upon the creation or successful completion of an order in WooCommerce, this system automatically triggers the creation of corresponding sales invoices or customer records in WaveAccounting. The integration ensures accurate and timely financial record-keeping, minimizes manual data entry, and provides a consolidated view of sales performance and revenue without delay. The data flow begins with a webhook trigger from WooCommerce, followed by secure payload transformation, and finally, idempotent API calls to WaveAccounting, complete with comprehensive error handling and retry mechanisms.
Available integrations in directory: ["shopify-to-freshbooks","shopify-to-hubspot","shopify-to-klaviyo","shopify-to-mailchimp","shopify-to-netsuite","shopify-to-quickbooks","shopify-to-salesforce","shopify-to-waveaccounting","shopify-to-xero","shopify-to-zohocrm","stripe-to-hubspot","woocommerce-to-hubspot","woocommerce-to-quickbooks","woocommerce-to-salesforce","woocommerce-to-xero"]. For other e-commerce or accounting integrations, consider WooCommerce to HubSpot for CRM sync, WooCommerce to QuickBooks for alternative accounting, or explore Shopify to WaveAccounting if you're using a different e-commerce platform. Similarly, other WooCommerce-related integrations include WooCommerce to Salesforce and WooCommerce to Xero.
🛠️ Core Connection Requirements
Primary Key: order_id
Trigger Event: Order Created in WooCommerce
Action Event: Create Sales Invoice and Create Customer (if not exists) in WaveAccounting
📋 The 5-Step Execution Blueprint
Step 1: Authentication & Scope Configuration Secure access to both WooCommerce and WaveAccounting is paramount. For WooCommerce, REST API authentication requires a Consumer Key and Consumer Secret. For WaveAccounting, OAuth2 is used, demanding a Client ID, Client Secret, and handling of access/refresh tokens.
WooCommerce API Key Generation:
- Log into your WordPress admin panel.
- Navigate to WooCommerce > Settings > Advanced > REST API.
- Click "Add key" and provide a description.
- Set permissions to "Read/Write" for order synchronization.
- Generate and securely store the Consumer Key and Consumer Secret.
WaveAccounting OAuth2 Setup:
- Register your application with WaveAccounting Developer portal to obtain a Client ID and Client Secret.
- Configure a
redirect_urifor your authorization callback. - The integration will manage the OAuth2 flow to obtain an initial authorization code, exchange it for an access token and refresh token, and subsequently use the refresh token to renew expired access tokens.
Sample .env Setup:
# WooCommerce Credentials
WOOCOMMERCE_CONSUMER_KEY="ck_**************************************"
WOOCOMMERCE_CONSUMER_SECRET="cs_**************************************"
WOOCOMMERCE_STORE_URL="https://yourstore.com"
# WaveAccounting OAuth2 Credentials
WAVE_CLIENT_ID="****************************"
WAVE_CLIENT_SECRET="****************************"
WAVE_REDIRECT_URI="https://yourintegration.com/auth/wave/callback"
# Initial access and refresh tokens (will be dynamically managed)
WAVE_ACCESS_TOKEN=""
WAVE_REFRESH_TOKEN=""
# Webhook Secret for HMAC validation
WEBHOOK_SECRET="your_strong_webhook_secret_for_woocommerce"
Step 2: Webhook Trigger Setup
The integration listens for Order Created events from WooCommerce via a webhook. This requires registering a webhook endpoint on your integration service and securing it using HMAC-SHA256 signature validation.
WooCommerce Webhook Registration (via API or Admin UI): Configure a webhook in WooCommerce (WooCommerce > Settings > Advanced > Webhooks) or programmatically via the API:
- Topic:
order.created - Delivery URL:
https://yourintegration.com/webhooks/woocommerce - Secret:
your_strong_webhook_secret_for_woocommerce(matchesWEBHOOK_SECRETfrom.env) - API version:
WP REST API integration v3
Webhook Endpoint Verification with Signature Validation (TypeScript/Node.js):
import express from 'express';
import crypto from 'crypto';
import { Buffer } from 'buffer';
const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!; // Load from .env
app.post('/webhooks/woocommerce', express.json({
verify: (req, res, buf) => {
// Store the raw body for signature verification
(req as any).rawBody = buf.toString();
}
}), (req, res) => {
const signature = req.headers['x-wc-webhook-signature'] as string;
const timestamp = req.headers['x-wc-webhook-topic'] as string; // Not strictly timestamp, but often used for unique nonce
const topic = req.headers['x-wc-webhook-topic'] as string;
if (!signature || !(req as any).rawBody) {
console.warn('Missing WooCommerce webhook signature or raw body.');
return res.status(400).send('Webhook signature missing.');
}
// Reconstruct the message for HMAC. WooCommerce signs the raw JSON body.
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update((req as any).rawBody);
const expectedSignature = Buffer.from(hmac.digest('base64'));
const receivedSignature = Buffer.from(signature);
if (!crypto.timingSafeEqual(expectedSignature, receivedSignature)) {
console.error('WooCommerce webhook signature mismatch. Request blocked.');
return res.status(401).send('Webhook signature mismatch.');
}
console.log(`Received WooCommerce webhook for topic: ${topic}`);
const orderData = req.body;
// Enqueue orderData for processing to avoid blocking the webhook
processWooCommerceOrder(orderData); // Asynchronous processing function
res.status(202).send('Webhook received and queued for processing.');
});
async function processWooCommerceOrder(order: any) {
// This function would typically push the order to a message queue (e.g., Redis, RabbitMQ)
// for asynchronous processing to prevent webhook timeouts.
console.log(`Processing order: ${order.id}`);
// Example: await queue.add('processOrder', order);
}
// Start the server
// app.listen(3000, () => console.log('Webhook receiver listening on port 3000'));
Step 3: Payload Transformation & Mapping Once a validated webhook payload is received, the WooCommerce order data must be transformed into a format suitable for WaveAccounting's Customer and Invoice APIs. This involves mapping fields like customer details, line items, taxes, and totals.
Sample WooCommerce Order (Input):
{
"id": 12345,
"status": "processing",
"currency": "USD",
"total": "120.00",
"prices_include_tax": true,
"customer_id": 101,
"billing": {
"first_name": "John",
"last_name": "Doe",
"company": "Acme Corp",
"address_1": "123 Main St",
"city": "Anytown",
"state": "CA",
"postcode": "90210",
"country": "US",
"email": "john.doe@example.com",
"phone": "555-123-4567"
},
"line_items": [
{
"id": 1,
"name": "Product A",
"product_id": 10,
"quantity": 1,
"total": "100.00",
"price": "100.00",
"tax_class": "",
"subtotal_tax": "0.00",
"total_tax": "0.00"
}
],
"shipping_lines": [
{
"id": 2,
"method_title": "Flat rate",
"method_id": "flat_rate",
"total": "20.00",
"total_tax": "0.00"
}
],
"tax_lines": [],
"fee_lines": [],
"coupon_lines": []
}
Mapped WaveAccounting Invoice & Customer Data (Output): First, check for customer existence, then create or update.
// WaveAccounting Customer Payload (if customer needs to be created)
{
"businessId": "YOUR_WAVE_BUSINESS_ID",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "555-123-4567",
"address": {
"addressLine1": "123 Main St",
"city": "Anytown",
"provinceCode": "CA",
"countryCode": "US",
"postalCode": "90210"
},
"externalId": "woocommerce_customer_101" // To track original customer ID
}
// WaveAccounting Invoice Payload
{
"businessId": "YOUR_WAVE_BUSINESS_ID",
"customerId": "WAVE_CUSTOMER_ID_FROM_PREVIOUS_STEP", // Or looked up
"invoiceDate": "YYYY-MM-DD", // Current date
"dueDate": "YYYY-MM-DD", // E.g., invoiceDate + 30 days
"invoiceNumber": "WC-ORDER-12345", // Map from WooCommerce order ID
"memo": "WooCommerce Order #12345",
"items": [
{
"productId": "YOUR_WAVE_PRODUCT_ID_FOR_PRODUCT_A", // Map to existing Wave product or create generic service product
"description": "Product A",
"quantity": 1,
"unitPrice": 100.00,
"subtotal": 100.00
},
{
"productId": "YOUR_WAVE_PRODUCT_ID_FOR_SHIPPING", // Map to existing Wave shipping product
"description": "Shipping: Flat rate",
"quantity": 1,
"unitPrice": 20.00,
"subtotal": 20.00
}
],
"total": 120.00,
"currency": "USD",
"externalId": "woocommerce_order_12345" // Critical for idempotency
}
Step 4: Endpoint Despatch & Error Guarding API requests to WaveAccounting must be handled robustly, addressing potential network issues, API-specific errors, and rate limits.
Core Logic Flow:
- Retrieve or Create Customer:
- Search WaveAccounting for a customer using the
billing.emailfrom WooCommerce. - If found, use the existing
customerId. - If not found, create a new customer using the mapped data.
- Search WaveAccounting for a customer using the
- Create Invoice:
- Before creating, search for an invoice with
externalIdmatchingwoocommerce_order_12345to prevent duplicates. - If no matching invoice is found, create the new invoice with the mapped data.
- Before creating, search for an invoice with
Error Handling Strategies:
-
HTTP 401 Unauthorized (Token Expiry):
- Action: Trigger an OAuth2 token refresh flow using the stored
refresh_token. Update theaccess_tokenandrefresh_tokenin your secure storage (e.g., database, encrypted.envif single instance). - Retry: Re-attempt the original API request with the new
access_token. - Instruction: Implement a token management class that transparently refreshes tokens on 401 errors.
- Action: Trigger an OAuth2 token refresh flow using the stored
-
HTTP 400 Bad Request (Invalid Data):
- Action: Log the full error response from WaveAccounting, which typically includes validation messages. Analyze the payload transformation logic for discrepancies.
- Retry: Generally, do NOT retry automatically as the request itself is malformed. Requires manual intervention or code fix.
- Instruction: Implement detailed logging for API requests and responses to quickly diagnose data mapping issues.
-
HTTP 429 Too Many Requests (Rate Limiting):
- Action: Implement an asynchronous processing queue (e.g., using BullMQ with Redis) to buffer incoming webhook events. When a 429 is encountered, pause processing for a short duration, then retry the failed request using an exponential backoff strategy (e.g., 2s, 4s, 8s, 16s).
- Retry: Yes, with exponential backoff and potentially moving the task to a delayed queue.
- Instruction: Maintain a dedicated queue for WaveAccounting API calls, implementing retry logic with a maximum number of retries and a dead-letter queue for persistent failures.
-
HTTP 5xx Server Errors (Internal Server Error, Gateway Timeout):
- Action: These are usually transient issues on WaveAccounting's side. Implement a robust retry mechanism with exponential backoff.
- Retry: Yes, with exponential backoff and potentially circuit breaker patterns to avoid overloading a failing service.
- Instruction: Configure a maximum number of retries (e.g., 5-7 times) before moving the task to a dead-letter queue for manual investigation.
Step 5: Live Loop Validation Thorough testing in a sandbox environment is crucial before deploying to production.
- Sandbox Setup: Configure both WooCommerce and WaveAccounting to their respective sandbox or development environments. Ensure your integration is pointing to these sandbox URLs and using sandbox API keys/tokens.
- Test Order Creation: Create a series of test orders in WooCommerce with varying complexities (single product, multiple products, shipping, discounts, taxes).
- Webhook Monitoring: Monitor your webhook endpoint logs to confirm that the
order.createdwebhook is received, validated, and processed successfully without errors. - WaveAccounting Validation:
- Customer Verification: Log into your WaveAccounting sandbox account. Navigate to Customers and verify that new customers are created (if they didn't exist) with correct details, especially email, name, and address.
- Invoice Verification: Navigate to Sales > Invoices. Verify that invoices are created for each WooCommerce order, with the correct
invoiceNumber(e.g.,WC-ORDER-12345), accuratetotalamounts, correct line items, and linked to the correct customer. - Data Integrity Check: Cross-reference individual invoice line items and totals against the original WooCommerce order. Ensure no data truncation (e.g., long descriptions) or duplication has occurred.
- Idempotency Test: Process the same WooCommerce order (if possible, by manually re-sending a webhook payload) multiple times. Verify that only one invoice is created in WaveAccounting due to the
externalIdcheck.
- Error Scenario Testing: Simulate authentication expiry (by manually invalidating tokens), send malformed webhook payloads, or temporarily block outbound requests to test the error guarding and retry mechanisms. Verify that errors are logged, retries are attempted, and ultimately, persistent failures are handled gracefully (e.g., moved to a dead-letter queue).
❓ Integration Frequently Asked Questions
Q: How does this pipeline handle duplicate data entries?
A: The pipeline prevents duplicate data entries through a two-fold idempotency strategy. First, when processing a WooCommerce order, the system attempts to find an existing customer in WaveAccounting using the customer's email address. If a customer is found, their existing customerId is used; otherwise, a new customer record is created. Second, and crucially for invoices, before creating a new sales invoice in WaveAccounting, the system performs a query to check for an existing invoice that uses a unique externalId (e.g., woocommerce_order_12345). By leveraging the order_id from WooCommerce as the externalId in WaveAccounting, the integration can confidently identify and skip the creation of invoices for orders that have already been processed, ensuring that each unique WooCommerce order maps to exactly one WaveAccounting invoice.
Q: What happens if the API rate limit is exceeded during high volume? A: To manage high-volume scenarios and adhere to WaveAccounting's API rate limits, this pipeline incorporates an asynchronous queuing system, typically built with a message broker like Redis (e.g., using a library like BullMQ). When a WooCommerce webhook event is received, instead of immediately making direct API calls to WaveAccounting, the event payload is pushed onto this queue. A separate worker process then consumes messages from this queue. If the worker encounters an HTTP 429 "Too Many Requests" error from WaveAccounting, it implements an exponential backoff strategy, which means it will retry the failed API call after progressively longer intervals (e.g., 2 seconds, then 4 seconds, 8 seconds, etc.). Messages can also be moved to a delayed queue for a specified duration before being re-processed. This buffer and intelligent retry mechanism ensures that the integration gracefully handles spikes in order volume without losing data, preventing API exhaustion, and maintaining system stability.