Ecommerce API
The ecommerce API lets you send purchase, cart, and product events, then query revenue metrics, attribution, and cohort data. Event ingestion accepts publishable or secret keys. Query endpoints require a secret key.
Date range parameters
Section titled “Date range parameters”All GET ecommerce query endpoints accept the same date range parameters as the Analytics API:
| Param | Description |
|---|---|
days | Number of days to look back. Defaults to 30. Clamped to your plan’s retention limit. |
start | ISO date (e.g. 2026-01-01). Used with end. |
end | ISO date (e.g. 2026-01-31). Used with start. |
Track a single event
Section titled “Track a single event”Send one ecommerce event.
POST /v1/api/analytics/ecommerce/trackAuth: Any valid API key (publishable or secret)
Request body:
{ "event_type": "purchase", "transaction_id": "order_456", "revenue": 49.99, "currency": "USD", "user_id": "user_123", "coupon_code": "SAVE10", "discount": 5.00, "shipping": 4.99, "tax": 3.75, "items": [ { "item_id": "sku_1", "item_name": "T-Shirt", "item_category": "Apparel", "item_brand": "MyBrand", "item_variant": "Red / L", "price": 24.99, "quantity": 2, "currency": "USD" } ], "properties": { "campaign": "spring-sale", "source": "email" }}Event types
Section titled “Event types”| Event type | Required fields | Description |
|---|---|---|
view_item | items | User views a product page |
add_to_cart | items | Item added to cart |
remove_from_cart | items | Item removed from cart |
add_to_wishlist | items | Item added to wishlist |
view_cart | (none) | User views their cart |
add_payment_info | (none) | Payment method entered |
begin_checkout | (none) | Checkout flow started |
purchase | transaction_id, revenue | Order completed |
refund | transaction_id, revenue | Order refunded |
search | (none) | Product search performed (pass search_term in properties) |
share | (none) | Product shared (pass item_id in properties) |
rate | (none) | Product rated (pass item_id, rating in properties) |
spend_credits | revenue | Loyalty credits redeemed |
Common fields
Section titled “Common fields”| Field | Type | Required | Description |
|---|---|---|---|
event_type | string | Yes | One of the 13 event types above |
transaction_id | string | For purchase/refund | Unique order identifier. Used for deduplication. |
revenue | number | For purchase/refund/spend_credits | Total revenue amount |
currency | string | No | ISO 4217 currency code (e.g. USD, EUR). Defaults to your appspace’s base currency. |
user_id | string | No | Your application’s user ID. Required for attribution. |
cart_id | string | No | Cart session ID. SDKs manage this automatically. |
coupon_code | string | No | Applied coupon or promo code |
discount | number | No | Discount amount |
shipping | number | No | Shipping cost |
tax | number | No | Tax amount |
items | array | For item events | Array of item objects (see below) |
properties | object | No | Additional key-value pairs (string values) |
Item object
Section titled “Item object”| Field | Type | Required | Description |
|---|---|---|---|
item_id | string | Yes | Product SKU or identifier |
item_name | string | No | Product name |
item_category | string | No | Product category |
item_brand | string | No | Brand name |
item_variant | string | No | Variant (e.g. “Red / L”) |
item_list_name | string | No | List or collection name (e.g. “Search Results”) |
item_list_id | string | No | List identifier |
item_image_url | string | No | Product image URL |
price | number | No | Unit price |
quantity | number | No | Quantity (defaults to 1) |
currency | string | No | Item-level currency |
coupon_code | string | No | Item-level coupon |
discount | number | No | Item-level discount |
Response 200:
{ "ok": true }Errors:
| Status | Error |
|---|---|
400 | event_type is required |
400 | Invalid ecommerce event_type |
400 | transaction_id is required for purchase events |
400 | revenue is required for purchase events |
403 | Ecommerce events are not available on the free tier |
429 | Ecommerce event quota exceeded |
Fraud detection
Section titled “Fraud detection”Events are automatically checked against fraud rules (bot detection, impossible revenue, velocity limits, currency restrictions). Flagged events (severity 1) are stored but marked. Blocked events (severity 2) are silently rejected with { "ok": true } to avoid leaking detection signals.
Transaction deduplication
Section titled “Transaction deduplication”Purchase and refund events are deduplicated by transaction_id. If the same transaction ID is sent twice within 24 hours, the second event is silently ignored. This prevents revenue double-counting from network retries.
Batch track events
Section titled “Batch track events”Send up to 100 ecommerce events in a single request. This is the primary endpoint used by SDKs.
POST /v1/api/analytics/ecommerce/batchAuth: Any valid API key (publishable or secret)
Request body:
{ "events": [ { "event_type": "add_to_cart", "items": [{ "item_id": "sku_1", "item_name": "T-Shirt", "price": 24.99 }], "user_id": "user_123" }, { "event_type": "purchase", "transaction_id": "order_456", "revenue": 49.99, "currency": "USD", "user_id": "user_123", "items": [{ "item_id": "sku_1", "price": 24.99, "quantity": 2 }] } ]}Response 200:
{ "ok": true, "accepted": 2}If some events are invalid, they are skipped:
{ "ok": true, "accepted": 1, "errors": [ "events[0]: transaction_id is required for purchase events" ]}Errors:
| Status | Error |
|---|---|
400 | events array is required and must not be empty |
400 | Maximum 100 events per batch |
403 | Ecommerce events are not available on the free tier |
Revenue overview
Section titled “Revenue overview”Get aggregate revenue metrics for the date range.
GET /v1/api/analytics/ecommerce/overviewAuth: Secret key required
Response 200:
{ "total_revenue": 12450.00, "net_revenue": 11200.00, "total_orders": 245, "total_refunds": 12, "refund_amount": 1250.00, "avg_order_value": 50.82, "total_items_sold": 512, "cart_abandonment_rate": 68.5, "add_to_cart_rate": 32.1, "days": 30}Revenue timeseries
Section titled “Revenue timeseries”Get daily revenue grouped by date.
GET /v1/api/analytics/ecommerce/revenue-timeseriesAuth: Secret key required
Response 200:
{ "series": [ { "date": "2026-01-01", "revenue": 450.00, "orders": 8 }, { "date": "2026-01-02", "revenue": 620.00, "orders": 12 } ], "days": 30}Ecommerce funnel
Section titled “Ecommerce funnel”Get step-by-step conversion funnel from product views to purchase.
GET /v1/api/analytics/ecommerce/funnelAuth: Secret key required
Response 200:
{ "steps": [ { "name": "view_item", "count": 5000, "percentage": 100 }, { "name": "add_to_cart", "count": 1600, "percentage": 32.0 }, { "name": "view_cart", "count": 1200, "percentage": 75.0 }, { "name": "begin_checkout", "count": 800, "percentage": 66.7 }, { "name": "add_payment_info", "count": 600, "percentage": 75.0 }, { "name": "purchase", "count": 400, "percentage": 66.7 } ], "days": 30}Each percentage is relative to the previous step (except view_item, which is always 100).
Top products
Section titled “Top products”Get best-selling products by revenue.
GET /v1/api/analytics/ecommerce/top-productsAuth: Secret key required
Query parameters:
| Param | Default | Max | Description |
|---|---|---|---|
limit | 20 | 100 | Number of products to return |
Response 200:
{ "products": [ { "item_id": "sku_1", "item_name": "T-Shirt", "revenue": 2499.00, "quantity": 100, "orders": 85 }, { "item_id": "sku_2", "item_name": "Hoodie", "revenue": 1899.00, "quantity": 38, "orders": 35 } ], "days": 30}Revenue by channel
Section titled “Revenue by channel”Get revenue breakdown by campaign, source, and medium.
GET /v1/api/analytics/ecommerce/revenue-by-channelAuth: Secret key required
Response 200:
{ "channels": [ { "campaign": "spring-sale", "source": "email", "medium": "newsletter", "revenue": 4500.00, "orders": 90, "conversion_rate": 3.2 } ], "days": 30}Revenue by coupon
Section titled “Revenue by coupon”Get revenue and usage stats per coupon code.
GET /v1/api/analytics/ecommerce/revenue-by-couponAuth: Secret key required
Response 200:
{ "coupons": [ { "coupon_code": "SAVE10", "revenue": 1200.00, "orders": 40, "avg_discount": 12.50 } ], "days": 30}Revenue by device
Section titled “Revenue by device”Get revenue breakdown by device type.
GET /v1/api/analytics/ecommerce/revenue-by-deviceAuth: Secret key required
Response 200:
{ "devices": [ { "device_type": "mobile", "revenue": 8200.00, "orders": 165 }, { "device_type": "desktop", "revenue": 4250.00, "orders": 80 } ], "days": 30}Revenue by platform
Section titled “Revenue by platform”Get revenue breakdown by operating system platform.
GET /v1/api/analytics/ecommerce/revenue-by-platformAuth: Secret key required
Response 200:
{ "platforms": [ { "platform": "ios", "revenue": 6500.00, "orders": 130 }, { "platform": "android", "revenue": 3900.00, "orders": 78 }, { "platform": "web", "revenue": 2050.00, "orders": 37 } ], "days": 30}Revenue by country
Section titled “Revenue by country”Get revenue breakdown by country.
GET /v1/api/analytics/ecommerce/revenue-by-countryAuth: Secret key required
Response 200:
{ "countries": [ { "country": "US", "revenue": 9200.00, "orders": 185 }, { "country": "GB", "revenue": 2100.00, "orders": 42 } ], "days": 30}Cart abandonment
Section titled “Cart abandonment”Get cart abandonment metrics.
GET /v1/api/analytics/ecommerce/cart-abandonmentAuth: Secret key required
Response 200:
{ "abandonment_rate": 68.5, "abandoned_carts": 520, "abandoned_revenue": 32000.00, "completed_carts": 238, "days": 30}Attribution
Section titled “Attribution”Get revenue attribution by campaign with configurable attribution model and window.
GET /v1/api/analytics/ecommerce/attributionAuth: Secret key required
Query parameters:
| Param | Default | Options | Description |
|---|---|---|---|
model | last_click | last_click, linear, time_decay | Attribution model |
window | 30 | 7, 14, 30, 60, 90 | Attribution window in days |
Response 200:
{ "attributed": [ { "campaign": "spring-sale", "source": "email", "medium": "newsletter", "revenue": 4500.00, "orders": 90, "pct_of_total": 36.1 } ], "unattributed": { "revenue": 2100.00, "orders": 45 }, "model": "last_click", "window_days": 30}Attribution models
Section titled “Attribution models”- Last Click: 100% of revenue credit goes to the last campaign the user clicked before purchasing.
- Linear: Revenue is split equally across all campaigns the user clicked within the attribution window.
- Time Decay: More recent clicks receive proportionally more credit, with older clicks decaying exponentially.
Revenue cohorts
Section titled “Revenue cohorts”Get a cohort matrix showing revenue by acquisition month across subsequent months.
GET /v1/api/analytics/ecommerce/cohortsAuth: Secret key required
Query parameters:
| Param | Default | Description |
|---|---|---|
months | 6 | Number of cohort months to include |
Response 200:
{ "cohorts": [ { "month": "2026-01", "users": 120, "revenue_by_month": { "0": 3200.00, "1": 1800.00, "2": 900.00 } }, { "month": "2025-12", "users": 95, "revenue_by_month": { "0": 2800.00, "1": 1500.00, "2": 750.00, "3": 400.00 } } ], "avg_ltv": 82.50, "total_purchasing_users": 580}Each revenue_by_month key is the number of months after the user’s first purchase. Month 0 is the acquisition month.
User journey
Section titled “User journey”Get a single user’s ecommerce event history.
GET /v1/api/analytics/ecommerce/user-journey?user_id=user_123Auth: Secret key required
Query parameters:
| Param | Required | Description |
|---|---|---|
user_id | Yes | The user ID to look up |
Response 200:
{ "events": [ { "event_type": "view_item", "timestamp": "2026-01-15T10:30:00Z", "items": [{ "item_id": "sku_1", "item_name": "T-Shirt" }] }, { "event_type": "add_to_cart", "timestamp": "2026-01-15T10:31:00Z", "items": [{ "item_id": "sku_1" }] }, { "event_type": "purchase", "timestamp": "2026-01-15T10:35:00Z", "transaction_id": "order_456", "revenue": 49.99 } ], "user_id": "user_123"}Delete user data (GDPR)
Section titled “Delete user data (GDPR)”Delete all analytics events for a specific user. This removes the user’s data from all ClickHouse tables (events, event_items, event_properties).
DELETE /v1/api/analytics/user/:userIdAuth: Secret key required
URL parameters: :userId is the user ID to delete.
Response 200:
{ "ok": true, "deleted_user_id": "user_123" }The deletion is asynchronous. Data is typically removed within minutes.
Currency handling
Section titled “Currency handling”All revenue values are automatically converted to your appspace’s base currency using live exchange rates (updated hourly from Open Exchange Rates, 200+ currencies supported).
If a purchase event does not include a currency field, the appspace’s base currency is used as the default. Configure your base currency in Appspace Settings > Ecommerce.
Zero-decimal currencies (JPY, KRW, VND, etc.) are handled automatically. Revenue is stored internally in cents for precision.