Overview
Start hereChatAxon supports full feature parity across all e-commerce platforms — not just WooCommerce. The integration is split into two layers:
Product Catalog
Feed URL or webhook — point ChatAxon at your product catalog. Supports Google Merchant XML, Shopify JSON, or a custom endpoint.
Transactional
Add to cart, apply discounts, and track orders — via JavaScript hooks (client-side) and a server endpoint you expose.
| Feature | WooCommerce | Other platforms |
|---|---|---|
| Product search & AI chat | ✅ Auto | ✅ Feed sync |
| Add to cart | ✅ Native | ✅ JS Hook |
| Apply discount code | ✅ Native | ✅ JS Hook |
| Order tracking (WIMO) | ✅ Native | ✅ Server endpoint |
| Real-time stock updates | ✅ Webhook | ✅ Webhook |
Feed URL Setup
DashboardIn the ChatAxon dashboard, open Store Settings → Product Feed Integration and paste your feed URL. Select a format or leave it on Auto-detect.
Paste your feed URL
Accepts any publicly accessible URL. The feed must return XML or JSON. No authentication on the feed URL is supported yet.
Click "Test Feed"
We fetch the first 5 products and show them in a preview table. Confirm the format is correct.
Click "Sync Now"
A background job fetches all products, generates AI embeddings, and indexes them. Large catalogs may take a few minutes.
Embed the widget
Copy your chataxon_ API key and follow the instructions below.
Google Merchant Center XML
RecommendedThe most widely supported format. If you already run Google Shopping ads, you already have this feed. Both RSS 2.0 (<rss><channel><item>) and Atom (<feed><entry>) are supported.
Platforms with built-in export
- PrestaShop — built-in Google Shopping module
- Magento / Adobe Commerce — native data feed
- Wix eCommerce — Marketing → Google Shopping
- BigCommerce — Channel Manager → Google Shopping
- WooCommerce — plugins: Product Feed PRO, WOOSEA
Minimal example
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>My Store</title>
<item>
<g:id>SKU-001</g:id>
<g:title>Nike Air Max 90</g:title>
<g:description>Classic everyday sneaker.</g:description>
<g:price>129.99 USD</g:price>
<g:image_link>https://mystore.com/img/nike.jpg</g:image_link>
<g:link>https://mystore.com/products/nike-air-max-90</g:link>
<g:product_type>Sneakers</g:product_type>
<g:availability>in stock</g:availability>
</item>
</channel>
</rss>Recognized fields
| Field | Required | Description |
|---|---|---|
| g:id | required | Unique product identifier |
| g:title | required | Product name shown in chat |
| g:description | optional | Long text used for AI search |
| g:price | optional | Numeric price with currency code (e.g. 29.99 USD) |
| g:image_link | optional | Primary product image URL |
| g:link | optional | Product page URL |
| g:product_type | optional | Category label |
| g:availability | optional | "in stock" or "out of stock" |
ChatAxon JSON
For custom platformsThe simplest option if your developer is building a custom endpoint. Serve a JSON response at any URL — we handle the rest.
Content-Type: application/json.Format
{
"products": [
{
"id": "123",
"name": "Nike Air Max 90",
"description": "Classic everyday sneaker, available in 5 colors.",
"price": 129.99,
"image": "https://mystore.com/img/nike.jpg",
"url": "https://mystore.com/products/nike-air-max-90",
"category": "Sneakers",
"in_stock": true,
"variant_id": "123-42"
}
]
}| Field | Required | Description |
|---|---|---|
| id | required | Unique product identifier (string or number) |
| name | required | Product name |
| description | optional | Product description (HTML stripped automatically) |
| price | optional | Numeric price (no currency symbol) |
| image | optional | Primary image URL |
| url | optional | Product page URL |
| category | optional | Category string |
| in_stock | optional | Boolean or "in stock" / "out of stock" |
| variant_id | optional | Variant identifier passed to addToCart hook (size, color, etc.) |
// GET /chataxon-feed.json
app.get('/chataxon-feed.json', async (req, res) => {
const products = await db.query(
'SELECT id, name, description, price, image_url, slug FROM products WHERE active = 1'
);
res.json({
products: products.map(p => ({
id: String(p.id),
name: p.name,
description: p.description,
price: parseFloat(p.price),
image: p.image_url,
url: `https://mystore.com/products/${p.slug}`,
in_stock: true,
}))
});
});Shopify — Product Feed
Zero configEvery Shopify store exposes a public /products.json endpoint. No plugin or app install required.
Enter your store URL
Paste https://your-store.myshopify.com — or your custom domain — into the Feed URL field. Select Auto-detect or Shopify.
That's it
ChatAxon automatically calls /products.json?limit=250&page=N, paginates through all pages (up to 5 000 products), and indexes everything including variant IDs.
/products.json is public by default. If you have a password-protected store (development mode), the endpoint will return 401 and the sync will fail.For add-to-cart, discounts, and order tracking on Shopify, see
Cart Integration
JS HooksThe ChatAxon widget can add products directly to the cart on any platform by calling a JavaScript function you register on the page. If the hook is not registered, the widget falls back to showing a View Product button.
window.ChatAxonHooks before the ChatAxon widget script executes, or pass hooks inline via window.ChatAxonConfig.hooks.Hook interface
window.ChatAxonHooks = {
/**
* Add a product to the cart.
* productId — your product ID from the feed
* variantId — variant ID if applicable (size, color…); undefined for simple products
* quantity — always ≥ 1
* name — product name (for optimistic UI feedback)
*/
addToCart: async ({ productId, variantId, quantity, name }) => {
// Your implementation here
return {
success: true, // required
cartCount: 3, // optional — total items in cart after add
cartTotal: 259.97, // optional — new cart total
message: 'Added!', // optional — shown briefly in the widget
};
// On failure:
// return { success: false, message: 'Item is out of stock' };
},
// Optional: remove a line item by its cart ID.
// NOTE: the AI does NOT trigger removeFromCart — this hook is only called
// if your own widget UI exposes a remove button inside the chat window.
removeFromCart: async ({ lineItemId }) => ({ success: true }),
// Optional: return current cart so the widget shows an item count badge
getCart: async () => ({
count: 2,
total: 129.98,
items: [{ id: '123', name: 'Nike Air Max', quantity: 1, price: 129.99 }],
}),
};Implementation examples
// Use when your store has a custom /api/cart/add endpoint
window.ChatAxonHooks = {
addToCart: async ({ productId, variantId, quantity }) => {
const res = await fetch('/api/cart/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product_id: productId, variant_id: variantId, qty: quantity }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
return { success: false, message: err.message || 'Could not add to cart' };
}
const data = await res.json();
return { success: true, cartCount: data.cart_count, cartTotal: data.cart_total };
},
};Inline via ChatAxonConfig
<script>
window.ChatAxonConfig = {
apiKey: 'chataxon_YOUR_API_KEY',
apiUrl: 'https://api.chataxon.com',
hooks: {
addToCart: async ({ productId, quantity }) => {
// your implementation
return { success: true };
},
},
};
</script>variantId passed to addToCart comes directly from your product feed. Include variant_id in your feed records if your store sells products with variants (size, color, etc.). For simple products variantId will be undefined.Discount Codes
JS Hooks[COUPON:CODE] discount mechanism requires WooCommerce API keys to be configured. The AI fetches active coupons live from your WooCommerce admin (/wp-json/wc/v3/coupons) and only offers codes it finds there. For custom e-shops using the feed + JS API, the applyDiscount hook interface is available but the AI will not proactively offer codes — there is no mechanism to configure coupon lists for non-WooCommerce stores yet.When the AI decides to offer a discount (WooCommerce stores only), it embeds a special tag in its response: [COUPON:CODE] (e.g. [COUPON:SUMMER20]). The ChatAxon widget intercepts this tag, hides it from the chat UI, and calls ChatAxonHooks.applyDiscount({ code: 'SUMMER20' }). You decide how the code is applied — pass it to your cart API, validate it server-side, or use a platform-native redirect.
Hook interface
window.ChatAxonHooks = {
applyDiscount: async ({ code }) => {
return {
success: true, // required
message: '10% off applied!', // required — shown in chat
discountAmount: 12.99, // optional — absolute value
discountPercent: 10, // optional — percentage
};
// On failure:
// return { success: false, message: 'Code expired or invalid' };
},
};// Frontend: call your own validation endpoint
window.ChatAxonHooks = {
applyDiscount: async ({ code }) => {
const res = await fetch('/api/coupon/apply', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code }),
});
return res.json(); // Must match the interface above
},
};Order Tracking API
Server-side endpointWhen a customer asks “Where is my order?” or “What's the status of order #1234?”, the ChatAxon AI calls an order lookup endpoint on your server. You implement this endpoint — ChatAxon sends the request, formats the result into natural language, and delivers it in chat.
Add your Order Lookup URL in the dashboard
Go to Dashboard → Store Settings → Order Tracking and paste your endpoint URL, e.g. https://mystore.com/chataxon/orders.
Implement the endpoint on your server
Accept a GET request with email and/or order_id query params. Verify the X-ChatAxon-Secret header. Return the order as JSON.
Test it
Use the “Test” button in the dashboard to send a sample request and verify your response.
Request — what ChatAxon sends to your server
GET https://your-store.com/chataxon/orders?email=customer@email.com&order_id=12345
Headers:
X-ChatAxon-Secret: <your_webhook_secret> # same value as GET /api/store/feed/webhook-secret
Accept: application/json| Field | Required | Description |
|---|---|---|
| optional | Customer email (present when known from the conversation) | |
| order_id | optional | Order ID or reference number (present when provided by the customer) |
email or order_id will always be present. Handle all three cases: lookup by email only (return latest order), by order_id only, and by both together.Response — order found
{
"found": true,
"order": {
"id": "12345",
"status": "shipped",
"status_label": "Shipped",
"date": "2026-06-08T14:30:00Z",
"total": 129.99,
"currency": "USD",
"items": [
{ "name": "Nike Air Max 90", "quantity": 1, "price": 129.99 }
],
"tracking_number": "1Z999AA10123456784",
"tracking_url": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
"estimated_delivery": "2026-06-15",
"shipping_address": {
"city": "New York",
"country": "US"
},
"notes": "Left at front door"
}
}Response — order not found
{ "found": false, "message": "No order found for this email / ID combination." }| Field | Required | Description |
|---|---|---|
| found | required | Boolean — whether an order was found |
| order.id | required | Order identifier shown to the customer |
| order.status | required | Machine-readable: pending | processing | shipped | delivered | cancelled | refunded |
| order.status_label | optional | Human-readable label in the store's language |
| order.date | optional | ISO 8601 order date |
| order.total | optional | Order total (numeric) |
| order.currency | optional | ISO 4217 currency code (USD, EUR, GBP…) |
| order.items | optional | Array of line items — name, quantity, price |
| order.tracking_number | optional | Carrier tracking number |
| order.tracking_url | optional | Carrier tracking page URL |
| order.estimated_delivery | optional | ISO 8601 estimated delivery date |
| order.shipping_address | optional | Partial address — city + country is enough |
| order.notes | optional | Any extra note to surface to the customer |
Always verify the secret
ChatAxon sends an X-ChatAxon-Secret header with every order lookup request. It contains the same webhook secret value returned by GET /api/store/feed/webhook-secret (also visible in Dashboard → Store Settings → Product Feed Integration). Store it as CHATAXON_WEBHOOK_SECRETin your environment and reject any request where the header doesn't match.
Implementation examples
// GET /chataxon/orders
app.get('/chataxon/orders', async (req, res) => {
// 1. Verify secret
if (req.headers['x-chataxon-secret'] !== process.env.CHATAXON_WEBHOOK_SECRET) {
return res.status(401).json({ found: false, message: 'Unauthorized' });
}
const { email, order_id } = req.query;
// 2. Query your DB
const order = await db.orders.findOne({
where: {
...(order_id && { id: order_id }),
...(email && { customer_email: email }),
},
include: ['items', 'shipment'],
order: [['created_at', 'DESC']],
});
if (!order) return res.json({ found: false, message: 'No order found.' });
const shipment = order.shipment;
res.json({
found: true,
order: {
id: String(order.id),
status: order.status,
status_label: order.status_label,
date: order.created_at.toISOString(),
total: parseFloat(order.total),
currency: order.currency,
items: order.items.map(i => ({
name: i.product_name,
quantity: i.qty,
price: parseFloat(i.unit_price),
})),
tracking_number: shipment?.tracking_number ?? null,
tracking_url: shipment?.tracking_url ?? null,
estimated_delivery: shipment?.estimated_delivery ?? null,
shipping_address: { city: order.shipping_city, country: order.shipping_country },
},
});
});Shopify: Cart & Orders
Native APISince the ChatAxon widget loads on the same domain as your Shopify store, it can call Shopify's first-party Ajax Cart API directly — no app install or admin token needed for cart operations.
Add to cart — Shopify Ajax Cart API
Paste this snippet in your Shopify theme (theme.liquid) before the ChatAxon widget script.
window.ChatAxonHooks = {
addToCart: async ({ variantId, quantity }) => {
// variantId = Shopify numeric variant ID (auto-extracted from /products.json feed)
const res = await fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: Number(variantId), quantity }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
return { success: false, message: err.description || 'Could not add to cart' };
}
// Fetch updated cart totals
const cart = await fetch('/cart.js').then(r => r.json());
return {
success: true,
cartCount: cart.item_count,
cartTotal: cart.total_price / 100, // Shopify stores prices in cents
};
},
getCart: async () => {
const cart = await fetch('/cart.js').then(r => r.json());
return {
count: cart.item_count,
total: cart.total_price / 100,
items: cart.items.map(i => ({
id: String(i.variant_id),
name: i.title,
quantity: i.quantity,
price: i.final_price / 100,
})),
};
},
};Discount codes — two approaches
Shopify does not expose a same-domain AJAX endpoint to apply discount codes to a cart. The standard workaround is a redirect to /discount/{code} which sets the code via a cookie for checkout.
// Simple and reliable. Shopify stores the discount code in a cookie.
// It will automatically apply at checkout.
window.ChatAxonHooks = {
// ...addToCart above...
applyDiscount: async ({ code }) => {
window.location.href =
`/discount/${encodeURIComponent(code)}?redirect=${encodeURIComponent(window.location.pathname)}`;
// Return success optimistically — the redirect confirms the code
return { success: true, message: `Applying code ${code}…` };
},
};Order tracking on Shopify
A — Order status page link
No server-side code. The AI links customers to Shopify's native order status page. Customer must be logged in or have the order confirmation URL.
Zero setup
B — Admin API proxy endpoint
A server function queries the Shopify Admin API and exposes a /chataxon/orders endpoint for ChatAxon to call. Full order data in chat, no customer login required.
Recommended
Option B — Shopify Admin API proxy (Node.js / Vercel Function)
// /api/chataxon-orders.js (Vercel, Netlify, or any Node server)
// Register this URL in Dashboard → Store Settings → Order Tracking
export default async function handler(req, res) {
// 1. Verify ChatAxon secret
if (req.headers['x-chataxon-secret'] !== process.env.CHATAXON_WEBHOOK_SECRET) {
return res.status(401).json({ found: false });
}
const { email, order_id } = req.query;
// 2. Query Shopify Admin API (REST)
const query = order_id
? `name=%23${order_id}` // search by order name e.g. #1234
: `email=${encodeURIComponent(email)}&status=any&limit=1`;
const sfRes = await fetch(
`https://${process.env.SHOPIFY_SHOP_DOMAIN}/admin/api/2024-01/orders.json?${query}`,
{
headers: {
'X-Shopify-Access-Token': process.env.SHOPIFY_ADMIN_TOKEN,
'Content-Type': 'application/json',
},
}
);
const { orders } = await sfRes.json();
const order = orders?.[0];
if (!order) return res.json({ found: false, message: 'No order found.' });
const fulfillment = order.fulfillments?.[0];
return res.json({
found: true,
order: {
id: String(order.order_number),
status: order.fulfillment_status ?? order.financial_status ?? 'pending',
status_label: (order.fulfillment_status ?? order.financial_status ?? 'pending')
.replace(/_/g, ' '),
date: order.created_at,
total: parseFloat(order.total_price),
currency: order.currency,
items: order.line_items.map(i => ({
name: i.name,
quantity: i.quantity,
price: parseFloat(i.price),
})),
tracking_number: fulfillment?.tracking_number ?? null,
tracking_url: fulfillment?.tracking_url ?? null,
estimated_delivery: null,
shipping_address: {
city: order.shipping_address?.city,
country: order.shipping_address?.country_code,
},
},
});
}SHOPIFY_ADMIN_TOKEN is a private Admin API access token — never expose it in client-side code. This endpoint runs server-side only. Your CHATAXON_WEBHOOK_SECRET ensures only ChatAxon can call it.Real-time Webhook
Instant syncWhen products change on your platform, fire a POST to our webhook endpoint. ChatAxon immediately re-fetches your feed and re-indexes it — your AI assistant stays up to date within seconds.
Endpoint
POST https://api.chataxon.com/api/store/feed/webhook
Headers:
x-api-key: chataxon_YOUR_API_KEY
Content-Type: application/json
X-ChatAxon-Signature: <your_webhook_secret> # optional but strongly recommended
Body (all fields optional):
{
"event": "product.updated" // product.created | product.deleted | catalog.updated
}X-ChatAxon-Signature header is optional — if omitted, the request is still accepted when the API key is valid. If included, it must be the pre-computed HMAC-SHA256 hex value tied to your store. Retrieve it once from GET https://api.chataxon.com/api/store/feed/webhook-secret (authenticated with your API key) and store it as an environment variable on your server. Do not compute it per-request — just send the static value you retrieved.Get your webhook secret (one-time setup)
# Run once. Store the returned webhook_secret in your server's environment variables.
curl -s https://api.chataxon.com/api/store/feed/webhook-secret \
-H "x-api-key: chataxon_YOUR_API_KEY"
# Response:
# { "webhook_secret": "a3f1c8...64 hex chars..." }Accepted
Sync job queued successfully
Unauthorized
Invalid API key or signature
Unprocessable
No feed URL configured for this store
Rate limit
Max 20 calls per hour per API key. For catalogs that change frequently, batching is fine — the queue deduplicates rapid calls. If you exceed the limit, you receive a 429 Too Many Requests response.
Code examples
Replace chataxon_YOUR_API_KEY with your actual API key and CHATAXON_WEBHOOK_SECRET with the value returned by the /webhook-secret endpoint above.
# Set these in your environment first:
# CHATAXON_API_KEY=chataxon_YOUR_API_KEY
# CHATAXON_WEBHOOK_SECRET=<value from /api/store/feed/webhook-secret>
curl -X POST https://api.chataxon.com/api/store/feed/webhook \
-H "x-api-key: $CHATAXON_API_KEY" \
-H "X-ChatAxon-Signature: $CHATAXON_WEBHOOK_SECRET" \
-H "Content-Type: application/json" \
-d '{"event": "catalog.updated"}'CSAT Rating
OptionalShow a satisfaction prompt at the end of a conversation (👍 / 👎) and send the result to ChatAxon. The rating appears in your analytics dashboard under CSAT Score.
Fire the event from your widget UI (after the user clicks 👍 or 👎) using the POST /api/store/track endpoint:
Endpoint
POST https://api.chataxon.com/api/store/track
x-api-key: chataxon_YOUR_API_KEY
x-session-id: <current chat session UUID>
Content-Type: application/json
{
"event_type": "csat",
"metadata": {
"rating": "positive" // "positive" | "negative"
}
}JavaScript widget example
// Call this after showing the thumbs-up / thumbs-down prompt
async function sendCSAT(rating) {
await fetch('https://api.chataxon.com/api/store/track', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': window.ChatAxonConfig.apiKey,
'x-session-id': window.ChatAxon.getSessionId(), // exposed by the widget
},
body: JSON.stringify({
event_type: 'csat',
metadata: { rating }, // 'positive' | 'negative'
}),
});
}
// Wire up your buttons
document.getElementById('thumbs-up').addEventListener('click', () => sendCSAT('positive'));
document.getElementById('thumbs-down').addEventListener('click', () => sendCSAT('negative'));| Field | Required | Description |
|---|---|---|
| event_type | required | Must be exactly "csat" |
| metadata.rating | required | "positive" or "negative" |
x-session-id will be recorded but may skew averages — gate the prompt so it appears only once.Widget Embed
Non-WordPressAdd the ChatAxon chat widget to any website — no CMS required. Include the script tag before </body>.
Minimal embed
<!-- ChatAxon Widget -->
<div id="chataxon-root"></div>
<script>
window.ChatAxonConfig = {
apiKey: 'chataxon_YOUR_API_KEY',
apiUrl: 'https://api.chataxon.com',
};
</script>
<script
src="https://cdn.chataxon.com/widget.js"
data-cfasync="false"
data-no-defer="1"
defer
></script>Full configuration
<script>
window.ChatAxonConfig = {
// Required
apiKey: 'chataxon_YOUR_API_KEY',
apiUrl: 'https://api.chataxon.com',
// Appearance
themeColor: '#1E364B', // hex color for buttons and accents
widgetPosition: 'bottom-right', // 'bottom-right' | 'bottom-left'
offsetBottom: 24, // pixels from bottom edge
offsetSide: 24, // pixels from side edge
// Mobile overrides (null = inherit from desktop)
mobileWidgetPosition: null,
mobileOffsetBottom: null,
mobileOffsetSide: null,
// Behaviour
defaultOpen: false, // open chat on page load
bubbleText: 'Need help?', // speech bubble above widget
welcomeMessage: 'Hi! How can I help you today?',
// Internationalisation
currency: '€', // symbol passed to price display
// Transactional hooks (optional — enables add-to-cart, discounts)
hooks: {
addToCart: async ({ productId, variantId, quantity }) => { /* ... */ return { success: true }; },
applyDiscount: async ({ code }) => { /* ... */ return { success: true, message: 'Applied!' }; },
getCart: async () => ({ count: 0, total: 0, items: [] }),
},
};
</script>| Field | Required | Description |
|---|---|---|
| apiKey | required | Your chataxon_ store key (from the dashboard) |
| apiUrl | required | Always https://api.chataxon.com |
| themeColor | optional | Hex color for the widget accent (#1E364B default) |
| widgetPosition | optional | "bottom-right" (default) or "bottom-left" |
| offsetBottom | optional | Pixels from bottom edge (default 24) |
| offsetSide | optional | Pixels from side edge (default 24) |
| mobileWidgetPosition | optional | Override position on mobile. null = use desktop setting |
| defaultOpen | optional | Open chat automatically on page load (default false) |
| bubbleText | optional | Short text in the speech bubble shown above the button |
| welcomeMessage | optional | First message shown in the chat window |
| currency | optional | Currency symbol used by the widget for price display only (default $). Not stored server-side — prices in the feed are used as-is. |
| hooks.addToCart | optional | JS Hook — called when AI adds product to cart |
| hooks.applyDiscount | optional | JS Hook — called when AI applies a discount code |
| hooks.getCart | optional | JS Hook — widget calls this to show cart count badge |
apiKey is safe to include in client-side code. It is scoped to your store and only permits reading product data and sending chat messages — no write access.