Commerce Ingestion
Sync orders and refunds server-side from Shopify, WooCommerce, BigCommerce or any commerce platform — no tracking script changes needed.
Commerce ingestion lets you send order and refund data from your backend (Shopify webhooks, WooCommerce webhooks, or any custom integration) straight into BuddyStat. Orders become purchase events, refunds become refund events — the same events your e-commerce tracking script sends, so all product, funnel, order and attribution analytics light up with zero client-side changes.
Only product IDs/SKUs, quantities and money amounts are stored. No customer names, emails, addresses or other PII ever reaches BuddyStat.
How it works
- Create a webhook in Commerce (in your site's sidebar).
- BuddyStat gives you a webhook URL and you set a secret.
- Your platform calls the webhook when an order is placed or refunded.
- BuddyStat verifies the signature and writes the event.
Shopify
- Open Commerce for your site, choose Shopify, and enter:
- Webhook secret — your Shopify Admin API access token is not used; use the Shopify API secret for HMAC verification (create an app or use an existing one to get
API secret). - Shop domain — e.g.
mystore.myshopify.com.
- Webhook secret — your Shopify Admin API access token is not used; use the Shopify API secret for HMAC verification (create an app or use an existing one to get
- Copy the displayed webhook URL.
- In your Shopify admin: Settings → Notifications → Webhooks → Create webhook and add two webhooks:
- Event:
Order created→ URL: your webhook URL - Event:
Refund created→ URL: your webhook URL
- Event:
- Save. Shopify signs every request with
X-Shopify-Hmac-Sha256; BuddyStat verifies it with your secret.
Shopify payload mapping
| Shopify field | BuddyStat event |
|---|---|
total_price | purchase revenue |
total_discounts | purchase discount |
total_tax | purchase tax |
shipping_lines[].price (sum) | purchase shipping |
discount_codes[0].code | purchase coupon |
line_items[] (variant_id, product_id, title, price, quantity, variant_title) | purchase items[] — the variant id is used as the item id so each variant tracks as its own product |
customer.id | purchase buyerId (SHA-256 hashed) — repeat purchases by the same customer count as Returning Buyers |
refunds/create (transactions[] sum, refund_line_items[]) | refund event |
Official Shopify app
The BuddyStat Shopify app installs the tracking script automatically via ScriptTag. In the app's Settings you can optionally enable Track checkout field funnel (adds data-track-checkout-funnel to the script, capturing per-field checkout analytics — field names only, values masked). Order/refund webhooks are consumed server-side as described above; configure them once in the Commerce card.
Generic commerce webhook (WooCommerce, BigCommerce, custom)
For any other platform, choose Generic Commerce (or WooCommerce to label the connection) and set a webhook secret. Then POST to:
{BACKEND_URL}/v1/ingest/commerce/{SITE_ID}/webhookwith the header:
X-Commerce-Webhook-Secret: your-secretWooCommerce (official WordPress plugin)
If your store runs on WordPress + WooCommerce, the official BuddyStat plugin handles this automatically — no functions.php edits:
- Install BuddyStat Analytics and open BuddyStat → Settings.
- Enter your Site ID and Dashboard Path.
- In the WooCommerce (Server-Side Orders) section: enable the toggle, paste the Webhook URL from the app's Commerce card, and the Webhook Secret.
- Optionally tick Checkout Funnel to also capture per-field checkout analytics.
The plugin fires order.created on new orders and order.refunded on refunds (from WC_Order line items) and POSTs them with the X-Commerce-Webhook-Secret header. A Send Test Webhook button shows the live server response.
Order created
{
"event": "order.created",
"order": {
"orderId": "ORD-12345",
"revenue": 129.98,
"currency": "EUR",
"coupon": "SAVE10",
"tax": 20.0,
"shipping": 5.99,
"discount": 10.0,
"buyerId": "a1b2c3...",
"items": [
{ "id": "sku-123", "name": "Canvas Tote", "price": 49.99, "quantity": 2, "category": "Bags", "variant": "Black" }
]
}
}Refund created
{
"event": "order.refunded",
"refund": {
"orderId": "ORD-12345",
"revenue": 49.99,
"currency": "EUR",
"items": [{ "id": "sku-123", "price": 49.99, "quantity": 1 }]
}
}Supported events: order.created, order.paid, order.refunded, refund.created.
Custom webhook integration (for developers)
For any platform that can send JSON — BigCommerce, PrestaShop, headless backends, custom carts — POST order/refund payloads to the generic endpoint:
POST {BACKEND_URL}/v1/ingest/commerce/{SITE_ID}/webhook
X-Commerce-Webhook-Secret: <your-secret>
Content-Type: application/jsonAuthentication. The X-Commerce-Webhook-Secret header must match the secret saved for that site + platform. A mismatch returns 401 {"error":"Invalid webhook secret"}; a missing or disabled config returns 200 {"status":"ignored"} (no error, no data — make sure the Commerce card is saved and enabled).
Events
| Event | Payload key | Meaning |
|---|---|---|
order.created | order | Order placed |
order.paid | order | Order paid — use either order.created or order.paid, not both, to avoid double-counting |
order.refunded | refund | Full / partial refund |
refund.created | refund | Refund created |
Order fields (order)
| Field | Type | Notes |
|---|---|---|
orderId | string | Your order number — unique per order |
revenue | number | Gross order value (incl. tax/shipping) |
currency | string | ISO 4217, e.g. EUR |
coupon | string? | Coupon code |
tax | number? | Total tax |
shipping | number? | Shipping total |
discount | number? | Total discount |
items[] | array | Line items: id (SKU / variant), name, price (unit), quantity, category?, variant? |
buyerId | string? | Optional non-PII buyer identity (e.g. SHA-256 of your customer id). Repeat purchases from the same buyerId count as Returning Buyers. Never send raw emails/phones. |
createdAt | string? | Optional — must be YYYY-MM-DD HH:MM:SS (UTC). ISO-8601 timestamps with milliseconds are rejected by ClickHouse. Omit to use the current time. |
curl — order
curl -X POST "https://app.buddystat.com/api/v1/ingest/commerce/6/webhook" \
-H "Content-Type: application/json" \
-H "X-Commerce-Webhook-Secret: your-secret" \
-d '{"event":"order.created","platform":"woocommerce","order":{"orderId":"ORD-12345","revenue":129.98,"currency":"EUR","tax":20,"shipping":5.99,"discount":10,"buyerId":"a1b2c3...","items":[{"id":"sku-123","name":"Canvas Tote","price":49.99,"quantity":2,"category":"Bags","variant":"Black"}]}}'curl — refund
curl -X POST "https://app.buddystat.com/api/v1/ingest/commerce/6/webhook" \
-H "Content-Type: application/json" \
-H "X-Commerce-Webhook-Secret: your-secret" \
-d '{"event":"order.refunded","platform":"woocommerce","refund":{"orderId":"ORD-12345","revenue":49.99,"currency":"EUR","items":[{"id":"sku-123","price":49.99,"quantity":1}]}}'Notes
- Products are grouped by
items[].id— for variable products send the variant / SKU id so each variant shows as its own product (the official plugins do this automatically). - Revenue is always recorded even without
items[]; product, orders and bought-together analytics needitems[]. - Only IDs, quantities and money amounts are stored — no customer PII ever reaches BuddyStat.
What lights up
Once orders flow in, the following all work without the tracking script on your storefront:
- Products — views/ATC/checkouts/purchases/revenue/AOV per product
- Revenue — order metrics, net vs gross, refunds, repeat-purchase rate
- Orders — the order browser with line-item drill-down
- Attribution — coupon-attributed revenue (promo tracking)