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 a JSON endpoint you expose and configure in the widget.
| Feature | WooCommerce | Other platforms |
|---|---|---|
| Product search & AI chat | ✅ Auto | ✅ Feed sync |
| Add to cart | ✅ Native | ✅ JSON endpoint |
| Apply discount code | ✅ Native | ⚠️ Copy code (or JSON endpoint) |
| 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
JSON endpointThe ChatAxon widget can add products directly to your cart on any platform by calling a JSON endpoint you host. If cart.addToCartUrl isn't configured, the widget falls back to WooCommerce's own ajax cart (?wc-ajax=add_to_cart), so WordPress stores need no configuration here at all.
window.ChatAxonConfig.cart before the ChatAxon widget script executes.Config shape
window.ChatAxonConfig.cart = {
// Required to activate the cart adapter at all.
addToCartUrl: 'https://yourstore.com/api/cart/add',
// Extra headers merged into every request — this is where you pass your
// platform's own session id / CSRF token. Read them fresh at page-load
// time (e.g. from a cookie) since the config is built once per page load.
headers: { 'X-Session-ID': '...' },
};What the widget sends
POST https://yourstore.com/api/cart/add
Content-Type: application/json
<...your configured headers>
{ "product_id": "123", "quantity": 1 }A 2xxresponse is treated as success (the widget shows “Added!” and does not need any particular response body). Any other status is treated as a failure.
Implementation example
// Read whatever your framework already uses for session/CSRF at page-load
// time, then wire it into the widget config before the script tag loads.
window.ChatAxonConfig = {
apiKey: 'chataxon_YOUR_API_KEY',
apiUrl: 'https://api.chataxon.com',
cart: {
addToCartUrl: '/api/cart/add',
headers: { 'X-Session-ID': getMySessionId() },
},
};fetch()call, it does not read cookies or inject CSRF tokens for you the way a framework's HTTP client might.Discount Codes
WooCommerce[COUPON:CODE] mechanism requires WooCommerce API keys — the AI fetches active coupons live from your WooCommerce admin (/wp-json/wc/v3/coupons) and only offers codes it finds there. There is currently no way to configure a coupon list for non-WooCommerce stores, so the AI will not proactively offer discounts on custom/feed-based integrations.When the AI offers a discount, it embeds a tag in its response: [COUPON:CODE] (e.g. [COUPON:SUMMER20]). The widget intercepts this tag and renders a code card instead of showing it as plain text. What happens when the shopper clicks it depends on whether you've configured cart.applyCouponUrl (see ):
- Not configured (default for non-WooCommerce): clicking the code copies it to the clipboard. This covers most custom storefronts, which usually have their own promo field at checkout rather than a live-apply endpoint.
- WooCommerce: applied directly to the live WooCommerce cart via the plugin's own ajax handler — no configuration needed.
cart.applyCouponUrlconfigured: the widget POSTs{ code }as JSON to your endpoint instead of copying.
applyCouponUrl config
window.ChatAxonConfig.cart = {
addToCartUrl: '/api/cart/add', // required for the cart adapter to activate
applyCouponUrl: '/api/cart/coupon', // optional — omit to use copy-to-clipboard instead
headers: { 'X-Session-ID': getMySessionId() },
};Your endpoint receives POST { code: "SUMMER20" } and should return a 2xx for a successfully applied code, any other status otherwise. The widget does not require a specific response body — it does not parse discount amounts back out today.
Order Tracking API
WooCommerce-shapedWhen a customer asks “Where is my order?”, the AI collects an order ID and email in chat, then calls the same store endpoint used for real-time product sync — there is no separate order-tracking URL to configure. It requests GET {store_url}/wp-json/wc/v3/orders/{orderId}, authenticated with HTTP Basic Auth using the same consumer key/secret pair from your Connect Store step.
store_url + consumer key/secret setup (the same one that powers real-time single-product sync) — a catalog synced purely via feed_url has no order-tracking endpoint to call yet.Expose one endpoint per order
GET {store_url}/wp-json/wc/v3/orders/{orderId} — the exact path WooCommerce itself uses. orderId is whatever the customer typed (their order number), not necessarily numeric.
Authenticate the same way as product sync
HTTP Basic Auth: Authorization: Basic base64(consumer_key:consumer_secret).
Return billing.email — it's the security check
ChatAxon compares the email the customer typed in chat against billing.emailin your response (case-insensitive). A mismatch is treated as “not your order” and nothing is disclosed.
Request
GET https://your-store.com/wp-json/wc/v3/orders/ORD-12345
Authorization: Basic base64(consumer_key:consumer_secret)Response — order found
{
"id": 12345,
"status": "shipped",
"billing": { "email": "customer@email.com" },
// Everything below is optional. A plain WooCommerce order never has
// these fields — the AI only mentions tracking info when present.
"tracking_number": "1Z999AA10123456784",
"carrier": "ups",
"status_description": "In Transit",
"shipped_at": "2026-06-08T14:30:00Z",
"estimated_delivery": "2026-06-15T18:00:00Z"
}Response — order not found
Return an HTTP 404 — there is no found: false body to construct.
| Field | Required | Description |
|---|---|---|
| id | required | Order identifier (echoed back, not otherwise used) |
| status | required | Any string — combined with your store's configured status-message mapping in the ChatAxon dashboard |
| billing.email | required | Used for the security check against what the customer typed in chat |
| tracking_number | optional | Carrier tracking number |
| carrier | optional | e.g. "ups", "fedex" — shown uppercased next to the tracking number |
| status_description | optional | Human-readable carrier status ("In Transit", "Delivered"…) |
| shipped_at | optional | ISO 8601 — when the AI mentions a ship date |
| estimated_delivery | optional | ISO 8601 — when the AI mentions an ETA |
Implementation examples
// GET /wp-json/wc/v3/orders/:orderId
app.get('/wp-json/wc/v3/orders/:orderId', requireBasicAuth, async (req, res) => {
const order = await db.orders.findOne({ where: { number: req.params.orderId } });
if (!order) return res.status(404).json({});
res.json({
id: order.id,
status: order.status,
billing: { email: order.customerEmail },
// Optional — only include what you actually have:
tracking_number: order.trackingNumber ?? undefined,
carrier: order.carrier ?? undefined,
status_description: order.carrierStatusText ?? undefined,
shipped_at: order.shippedAt?.toISOString(),
estimated_delivery: order.estimatedDelivery?.toISOString(),
});
});Shopify: Cart & Orders
Proxy requiredShopify's Ajax Cart API (/cart/add.js) expects { id: variantId, quantity }, but the ChatAxon widget always POSTs { product_id, quantity } to whatever URL you configure — the field name doesn't match, so you need a small proxy function rather than pointing addToCartUrl straight at Shopify.
Add to cart — proxy function
Deploy this as a small serverless function (Vercel/Netlify/Cloudflare Worker) on your own domain, then set cart.addToCartUrl to it. It forwards to Shopify's storefront using the customer's own session — the widget request must run through the shopper's browser (so it needs credentials: 'include', which the widget already sends).
// /api/shopify-cart-add.js — deployed on your own domain, proxied to Shopify
export default async function handler(req, res) {
const { product_id, quantity } = req.body; // product_id = Shopify variant ID
// (set this as the feed's product id for Shopify stores)
const shopifyRes = await fetch(`https://${process.env.SHOPIFY_SHOP_DOMAIN}/cart/add.js`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Cookie': req.headers.cookie ?? '' },
body: JSON.stringify({ id: Number(product_id), quantity }),
});
res.status(shopifyRes.ok ? 200 : 422).json({});
}window.ChatAxonConfig.cart = {
addToCartUrl: 'https://yourdomain.com/api/shopify-cart-add',
};Discount codes
Shopify has no same-domain endpoint to apply a code without a redirect. The simplest reliable option: leave cart.applyCouponUrl unconfigured so the widget copies the code to the clipboard, and tell shoppers to paste it at checkout — or redirect via /discount/{code}, which sets the code as a cookie Shopify auto-applies at checkout.
Order tracking on Shopify
Same contract as — a GET {store_url}/wp-json/wc/v3/orders/{orderId} endpoint with Basic Auth. For Shopify, that endpoint is a proxy function that queries the Shopify Admin API server-side:
// GET /wp-json/wc/v3/orders/:orderId (route this path on your own domain/proxy)
export default async function handler(req, res) {
// 1. Basic Auth check (same consumer key/secret as Connect Store)
const auth = Buffer.from((req.headers.authorization || '').split(' ')[1] || '', 'base64').toString();
if (auth !== `${process.env.CHATAXON_CONSUMER_KEY}:${process.env.CHATAXON_CONSUMER_SECRET}`) {
return res.status(401).end();
}
// 2. Query Shopify Admin API — order name e.g. "#1234"
const sfRes = await fetch(
`https://${process.env.SHOPIFY_SHOP_DOMAIN}/admin/api/2024-01/orders.json?name=%23${req.query.orderId}`,
{ headers: { 'X-Shopify-Access-Token': process.env.SHOPIFY_ADMIN_TOKEN } }
);
const { orders } = await sfRes.json();
const order = orders?.[0];
if (!order) return res.status(404).end();
const fulfillment = order.fulfillments?.[0];
res.json({
id: order.order_number,
status: order.fulfillment_status ?? order.financial_status ?? 'pending',
billing: { email: order.email },
tracking_number: fulfillment?.tracking_number,
carrier: fulfillment?.tracking_company,
});
}SHOPIFY_ADMIN_TOKEN is a private Admin API access token — it stays server-side in this function, never in the widget config.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>.
<div id="chataxon-root"> must already be in the DOM before widget.js runs — it looks the element up once, synchronously, at load time (it does not wait for DOMContentLoaded). Placing the div and scripts together right before </body>, in this order, satisfies that.Minimal embed
<!-- ChatAxon Widget -->
<div id="chataxon-root"></div>
<script>
window.ChatAxonConfig = {
apiKey: 'chataxon_YOUR_API_KEY',
apiUrl: 'https://api.chataxon.com',
};
</script>
<link rel="stylesheet" href="https://api.chataxon.com/widget.css">
<script src="https://api.chataxon.com/widget.js" 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
// Cart adapter (optional) — see Cart Integration. Omit entirely on
// WordPress; the widget falls back to WooCommerce's own ajax cart.
cart: {
addToCartUrl: '/api/cart/add',
applyCouponUrl: '/api/cart/coupon', // optional
headers: { 'X-Session-ID': '...' },
},
};
</script>| Field | Required | Description |
|---|---|---|
| apiKey | required | Your chataxon_ store key (from the dashboard) |
| apiUrl | required | Always https://api.chataxon.com — also where /widget.js and /widget.css are served from |
| 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. |
| cart.addToCartUrl | optional | See Cart Integration — enables non-WooCommerce add-to-cart |
| cart.applyCouponUrl | optional | See Discount Codes — omit to copy codes to clipboard instead |
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.