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

# Clone & Subscribe

> POST endpoints to clone a one-time copy or subscribe to live updates from a Hub catalog.

## Endpoints

```
POST /api/hub/catalogs/{catalogId}/clone
POST /api/hub/catalogs/{catalogId}/subscribe
```

Two ways to acquire a Hub catalog:

* **Clone** — creates a local copy in your workspace with no ongoing connection
* **Subscribe** — creates a live link that receives publisher version updates

Both require authentication. Paid catalogs require a completed Stripe Checkout before these endpoints succeed.

***

## Path parameters

| Parameter   | Type   | Required | Description        |
| ----------- | ------ | :------: | ------------------ |
| `catalogId` | string |    Yes   | The Hub catalog ID |

***

## Clone

`POST /api/hub/catalogs/{catalogId}/clone`

Creates a complete copy of the catalog in your workspace as a new, standalone catalog. No ongoing connection to the publisher — you own the copy entirely.

### Request body

```json theme={null}
{
  "targetWorkspaceId": "ws_your_workspace",
  "catalogName": "Spring 2026 Apparel (Cloned)"
}
```

| Field               | Type   | Required | Description                                                       |
| ------------------- | ------ | :------: | ----------------------------------------------------------------- |
| `targetWorkspaceId` | string |    No    | Workspace to clone into (defaults to the key's workspace)         |
| `catalogName`       | string |    No    | Name for the new catalog (defaults to original name + " (Clone)") |

### Response

```json theme={null}
{
  "cloneId": "clone_7x3p9q",
  "catalogId": "cat_new_local_123",
  "status": "processing",
  "productCount": 512,
  "estimatedSeconds": 30
}
```

### Clone examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://app.alana.shopping/api/hub/catalogs/hub_cat_9x8k2m/clone" \
    -H "Authorization: Bearer sk_live_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "catalogName": "Spring 2026 Apparel (My Copy)"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://app.alana.shopping/api/hub/catalogs/${hubCatalogId}/clone`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.ALANA_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        catalogName: 'Spring 2026 Apparel (My Copy)',
      }),
    }
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error.message);
  }

  const { catalogId, status } = await response.json();
  console.log(`Clone created: ${catalogId}, status: ${status}`);
  ```

  ```python Python theme={null}
  import requests, os

  response = requests.post(
      f"https://app.alana.shopping/api/hub/catalogs/{hub_catalog_id}/clone",
      headers={
          "Authorization": f"Bearer {os.environ['ALANA_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={"catalogName": "Spring 2026 Apparel (My Copy)"}
  )

  response.raise_for_status()
  clone = response.json()
  print(f"New catalog ID: {clone['catalogId']}, status: {clone['status']}")
  ```
</CodeGroup>

***

## Subscribe

`POST /api/hub/catalogs/{catalogId}/subscribe`

Creates a live subscription to the Hub catalog. When the publisher releases a new version, your workspace receives a notification and can sync.

### Request body

```json theme={null}
{
  "syncStrategy": "manual",
  "conflictResolution": "keep_local"
}
```

| Field                | Type   | Required | Description                                             |
| -------------------- | ------ | :------: | ------------------------------------------------------- |
| `syncStrategy`       | string |    Yes   | `"auto"` or `"manual"`                                  |
| `conflictResolution` | string |    Yes   | `"keep_local"`, `"accept_remote"`, or `"manual_review"` |

### Sync strategies

| Strategy | Behavior                                                               |
| -------- | ---------------------------------------------------------------------- |
| `auto`   | New publisher versions are automatically applied to your local catalog |
| `manual` | New versions are queued — you must explicitly trigger sync             |

### Conflict resolution strategies

| Strategy        | Behavior                                                              |
| --------------- | --------------------------------------------------------------------- |
| `keep_local`    | Your local edits always win when they conflict with publisher changes |
| `accept_remote` | Publisher changes always win — your local edits are overwritten       |
| `manual_review` | Conflicts are queued for manual resolution via the UI or API          |

### Response

```json theme={null}
{
  "subscriptionId": "sub_4k2n8x",
  "catalogId": "cat_local_456",
  "hubCatalogId": "hub_cat_9x8k2m",
  "status": "active",
  "syncStrategy": "manual",
  "conflictResolution": "keep_local",
  "currentVersion": 5,
  "createdAt": "2026-03-17T10:00:00Z"
}
```

### Subscribe examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://app.alana.shopping/api/hub/catalogs/hub_cat_9x8k2m/subscribe" \
    -H "Authorization: Bearer sk_live_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "syncStrategy": "manual",
      "conflictResolution": "keep_local"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://app.alana.shopping/api/hub/catalogs/${hubCatalogId}/subscribe`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.ALANA_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        syncStrategy: 'manual',
        conflictResolution: 'keep_local',
      }),
    }
  );

  if (!response.ok) {
    const error = await response.json();
    if (error.error.code === 'ALREADY_SUBSCRIBED') {
      console.log('Already subscribed to this catalog');
      return;
    }
    throw new Error(error.error.message);
  }

  const subscription = await response.json();
  console.log(`Subscription ID: ${subscription.subscriptionId}`);
  console.log(`Local catalog: ${subscription.catalogId}`);
  ```

  ```python Python theme={null}
  import requests, os

  response = requests.post(
      f"https://app.alana.shopping/api/hub/catalogs/{hub_catalog_id}/subscribe",
      headers={
          "Authorization": f"Bearer {os.environ['ALANA_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "syncStrategy": "manual",
          "conflictResolution": "keep_local",
      }
  )

  if response.status_code == 409:
      print("Already subscribed to this catalog")
  else:
      response.raise_for_status()
      sub = response.json()
      print(f"Subscription ID: {sub['subscriptionId']}")
      print(f"Local catalog: {sub['catalogId']}")
      print(f"Current version: {sub['currentVersion']}")
  ```
</CodeGroup>

***

## Clone vs Subscribe comparison

| Feature                   | Clone       | Subscribe                           |
| ------------------------- | ----------- | ----------------------------------- |
| Creates local catalog     | Yes         | Yes                                 |
| Ongoing publisher updates | No          | Yes                                 |
| Sync on new versions      | No          | Yes (auto or manual)                |
| Conflict resolution       | N/A         | Configurable                        |
| Can edit local copy       | Yes (fully) | Yes (with conflict resolution)      |
| Cost (paid catalogs)      | One-time    | Recurring (if subscription pricing) |

***

## Error responses

| HTTP status | Code                       | Description                                                   |
| ----------- | -------------------------- | ------------------------------------------------------------- |
| 402         | `PAYMENT_REQUIRED`         | Paid catalog — complete Stripe Checkout first                 |
| 403         | `INSUFFICIENT_PERMISSIONS` | API key lacks required permission                             |
| 404         | `CATALOG_NOT_FOUND`        | Hub catalog not found or unpublished                          |
| 409         | `ALREADY_SUBSCRIBED`       | Workspace already has an active subscription (subscribe only) |
| 429         | `RATE_LIMIT_EXCEEDED`      | Too many requests                                             |
