Endpoints
GET /api/hub/catalogs/{catalogId}/analytics
DELETE /api/hub/catalogs/{catalogId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
catalogId | string | Yes | The Hub catalog ID |
GET — Analytics
GET /api/hub/catalogs/{catalogId}/analytics
Returns engagement metrics, subscription stats, revenue data (for paid catalogs), and version history.
Response
{
"catalogId": "hub_cat_9x8k2m",
"name": "Spring 2026 Apparel",
"views": 1240,
"clones": 18,
"activeSubscribers": 34,
"cancelledSubscribers": 5,
"versions": [
{
"version": 5,
"publishedAt": "2026-03-10T14:30:00Z",
"publishedBy": "user_abc",
"changeCount": 47,
"changelog": "Added 45 new spring arrivals, removed 2 discontinued SKUs"
},
{
"version": 4,
"publishedAt": "2026-02-20T09:00:00Z",
"publishedBy": "user_abc",
"changeCount": 12,
"changelog": "Price updates for EU market"
}
],
"revenue": {
"total": 1490.00,
"currency": "USD",
"breakdown": {
"oneTime": 540.00,
"recurring": 950.00
}
},
"period": {
"from": "2026-02-01T00:00:00Z",
"to": "2026-03-17T00:00:00Z"
}
}
Analytics fields
| Field | Type | Description |
|---|---|---|
views | number | Total preview opens (all time) |
clones | number | Total one-time clone operations (all time) |
activeSubscribers | number | Workspaces with currently active subscriptions |
cancelledSubscribers | number | Workspaces that unsubscribed |
versions | CatalogVersion[] | Published version history (most recent first) |
revenue.total | number | Total revenue collected (paid catalogs only) |
revenue.currency | string | Currency code (USD) |
revenue.breakdown | object | Split between one-time and recurring revenue |
CatalogVersion fields
| Field | Type | Description |
|---|---|---|
version | number | Version number |
publishedAt | string | ISO 8601 timestamp |
publishedBy | string | User ID who published this version |
changeCount | number | Products added + updated + removed in this version |
changelog | string | Optional publisher note describing changes |
Analytics examples
curl "https://app.alana.shopping/api/hub/catalogs/hub_cat_9x8k2m/analytics" \
-H "Authorization: Bearer sk_live_your_api_key_here"
const catalogId = 'hub_cat_9x8k2m';
const response = await fetch(
`https://app.alana.shopping/api/hub/catalogs/${catalogId}/analytics`,
{
headers: {
'Authorization': `Bearer ${process.env.ALANA_API_KEY}`,
},
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const analytics = await response.json();
console.log(`${analytics.name} — Analytics Summary`);
console.log(`Views: ${analytics.views}`);
console.log(`Clones: ${analytics.clones}`);
console.log(`Active subscribers: ${analytics.activeSubscribers}`);
if (analytics.revenue) {
console.log(`Revenue: $${analytics.revenue.total} ${analytics.revenue.currency}`);
}
console.log('\nVersion history:');
analytics.versions.forEach(v => {
console.log(` v${v.version} (${new Date(v.publishedAt).toLocaleDateString()}): ${v.changeCount} changes`);
if (v.changelog) console.log(` Note: ${v.changelog}`);
});
import requests, os
catalog_id = "hub_cat_9x8k2m"
response = requests.get(
f"https://app.alana.shopping/api/hub/catalogs/{catalog_id}/analytics",
headers={"Authorization": f"Bearer {os.environ['ALANA_API_KEY']}"}
)
response.raise_for_status()
analytics = response.json()
print(f"=== {analytics['name']} ===")
print(f"Views: {analytics['views']}")
print(f"Clones: {analytics['clones']}")
print(f"Active subscribers: {analytics['activeSubscribers']}")
if analytics.get("revenue"):
total = analytics["revenue"]["total"]
currency = analytics["revenue"]["currency"]
print(f"Revenue: {total} {currency}")
print(f"\nVersions published: {len(analytics['versions'])}")
for v in analytics["versions"][:3]:
print(f" v{v['version']}: {v['changeCount']} changes on {v['publishedAt'][:10]}")
DELETE — Unpublish (delist)
DELETE /api/hub/catalogs/{catalogId}
Removes the catalog from the Hub browse feed immediately. Existing subscribers retain their local data but stop receiving new version notifications. Pending syncs are cancelled.
Response
{
"catalogId": "hub_cat_9x8k2m",
"unpublished": true,
"notifiedSubscribers": 34,
"cancelledPendingSyncs": 3
}
Unpublish examples
curl -X DELETE "https://app.alana.shopping/api/hub/catalogs/hub_cat_9x8k2m" \
-H "Authorization: Bearer sk_live_your_api_key_here"
const response = await fetch(
`https://app.alana.shopping/api/hub/catalogs/${catalogId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${process.env.ALANA_API_KEY}`,
},
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const result = await response.json();
console.log(`Unpublished. ${result.notifiedSubscribers} subscribers notified.`);
import requests, os
response = requests.delete(
f"https://app.alana.shopping/api/hub/catalogs/{catalog_id}",
headers={"Authorization": f"Bearer {os.environ['ALANA_API_KEY']}"}
)
response.raise_for_status()
result = response.json()
print(f"Unpublished. Notified {result['notifiedSubscribers']} subscribers.")
print(f"Cancelled {result['cancelledPendingSyncs']} pending syncs.")
What happens when you unpublish
| Audience | Effect |
|---|---|
| Hub browse feed | Catalog removed immediately |
| New visitors | Cannot find, preview, clone, or subscribe |
| Existing cloners | Keep their local copy with no changes |
| Active subscribers | Stop receiving version notifications |
| Paid subscribers | Notified via email; refund policy is your responsibility |
Unpublishing is reversible — you can republish the same catalog. However, all subscriber connections are severed on unpublish and must be re-established.
Error responses
GET analytics
| HTTP status | Code | Description |
|---|---|---|
| 403 | NOT_PUBLISHER | This catalog was not published by your workspace |
| 404 | CATALOG_NOT_FOUND | Hub catalog not found |
DELETE unpublish
| HTTP status | Code | Description |
|---|---|---|
| 403 | NOT_PUBLISHER | Not your catalog to unpublish |
| 403 | INSUFFICIENT_PERMISSIONS | Only workspace owner can unpublish |
| 404 | CATALOG_NOT_FOUND | Hub catalog not found |
| 409 | ALREADY_UNPUBLISHED | Catalog is already in draft/unpublished state |