> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alana.shopping/llms.txt
> Use this file to discover all available pages before exploring further.

# Publisher Analytics

> GET analytics for your published Hub catalog — views, clones, active subscribers, revenue, and version history. DELETE to unpublish.

## Endpoints

```
GET    /api/hub/catalogs/{catalogId}/analytics
DELETE /api/hub/catalogs/{catalogId}
```

View performance data for a catalog you've published to the Hub, and unpublish (delist) it when needed. Both endpoints require authentication and are restricted to the catalog's publisher workspace.

***

## 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

```json theme={null}
{
  "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

<CodeGroup>
  ```bash curl theme={null}
  curl "https://app.alana.shopping/api/hub/catalogs/hub_cat_9x8k2m/analytics" \
    -H "Authorization: Bearer sk_live_your_api_key_here"
  ```

  ```javascript JavaScript theme={null}
  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}`);
  });
  ```

  ```python Python theme={null}
  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]}")
  ```
</CodeGroup>

***

## 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

```json theme={null}
{
  "catalogId": "hub_cat_9x8k2m",
  "unpublished": true,
  "notifiedSubscribers": 34,
  "cancelledPendingSyncs": 3
}
```

### Unpublish examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X DELETE "https://app.alana.shopping/api/hub/catalogs/hub_cat_9x8k2m" \
    -H "Authorization: Bearer sk_live_your_api_key_here"
  ```

  ```javascript JavaScript theme={null}
  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.`);
  ```

  ```python Python theme={null}
  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.")
  ```
</CodeGroup>

***

## 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 |

<Warning>
  Unpublishing is reversible — you can republish the same catalog. However, all subscriber connections are severed on unpublish and must be re-established.
</Warning>

***

## 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 |
