# Миграция с API V1 на API V2

API V2 можно внедрять постепенно. V1-документация и существующие `/ssapi/*` интеграции остаются доступными, поэтому миграцию лучше начинать с нового selector, рекламного placement, нового канала или ограниченного набора кампаний.

При миграции ориентируйтесь не только на замену URL, но и на новую форму payload: `ctx`, `user.uid`, `user.ses`, `data[]`, `customProps` и tracking URL из ответа `/choose`.

## Краткая схема замены

| V1 | V2 | Что меняется |
| :--- | :--- | :--- |
| `POST /ssapi/page` | [`POST /visit`](./personalization/visit.md) | Pageview или screenview передаётся отдельным visit-событием. |
| `POST /ssapi/event` | [`POST /event`](./personalization/events.md) | События передаются в `data[]`; кастомные свойства - в `customProps`. |
| `POST /ssapi/choose` | [`POST /choose` для персонализации](./personalization/choose.md) или [`POST /choose` для рекламы](./retail_media/choose.md) | Кампанию можно запросить по `selector`, `group`, `campaignId` или `placementId`. |
| `POST /ssapi/engagement` | [`GET /engagement` для персонализации](./personalization/engagement.md) или [`GET /engagement` для рекламы](./retail_media/engagement.md) по tracking URL | Tracking URL лучше брать из `content.events[].urls[]` и `products.slots[].events[].urls[]` в ответе `/choose`. |

## Основные изменения payload

### Контекст

В V1 контекст страницы передавался в `context.page`:

```json
{
  "context": {
    "page": {
      "type": "PRODUCT",
      "data": ["sku-123"],
      "location": "https://example.com/product/sku-123"
    }
  }
}
```

В V2 тот же смысл передаётся в `ctx`:

```json
{
  "ctx": {
    "type": "PRODUCT",
    "data": ["sku-123"],
    "location": "https://example.com/product/sku-123"
  }
}
```

Подробно о типах контекста и формате `ctx.data`: [Контекст](./context.md).

### Пользователь и сессия

В V1 часто использовались `user.slid` и `session.sl`. В V2 используйте `user.uid` и `user.ses`:

```json
{
  "user": {
    "uid": "USER_UID",
    "ses": "SESSION_ID"
  }
}
```

После ответов API сохраняйте новые значения `uid` и `ses`, если Gateway вернул их в `user`.

### События

В V1 custom event properties обычно передавались в `events[].properties`. В V2 события передаются в `data[]`, а дополнительные свойства - в `customProps`:

```json
{
  "data": [
    {
      "type": "purchase-v1",
      "name": "Purchase",
      "productId": "sku-123",
      "quantity": 1,
      "value": 1990,
      "currency": "RUB",
      "uniqueTransactionId": "order-100500",
      "customProps": {
        "paymentMethod": "card"
      }
    }
  ]
}
```

## Миграция `/choose`

### Персонализация

V1 selector request:

```json
{
  "selector": {
    "names": ["homepage-recommendations"]
  }
}
```

V2 selector request:

```json
{
  "data": [
    {
      "selector": "homepage-recommendations"
    }
  ]
}
```

Для in-app или trigger-based сценариев используйте activation flow:

1. Отправьте `/visit` или `/event`.
2. Получите `campaigns[].campaignId`.
3. Вызовите `/choose` с `data[].campaignId`.
4. Отрендерите контент и отправьте engagement по URL из ответа.

### Рекламная платформа

В V1 retail media API рекламный плейсмент запрашивался через `/choose` с `placementId` и отдельным объектом `session`:

```json
{
  "user": {
    "uid": "USER_UID"
  },
  "session": {
    "ses": "SESSION_ID"
  },
  "ctx": {
    "type": "CATEGORY",
    "data": ["Parent category", "Sub category"],
    "url": "https://shop.ru/cat/1"
  },
  "data": [
    {
      "placementId": "PLACEMENT_ID",
      "options": {
        "isImplicitImpression": true,
        "rtRule": []
      }
    }
  ]
}
```

В V2 используйте общий объект `user`, поле `ctx.location` и Gateway options:

```json
{
  "user": {
    "uid": "USER_UID",
    "ses": "SESSION_ID"
  },
  "ctx": {
    "type": "CATEGORY",
    "data": ["Parent category", "Sub category"],
    "location": "https://shop.ru/cat/1"
  },
  "options": {
    "isBuildEngagementUrl": true,
    "isImplicitPageview": true,
    "isImplicitImpression": false
  },
  "data": [
    {
      "placementId": "PLACEMENT_ID"
    }
  ]
}
```

Если в V1 вы учитывали потенциальный показ через `data.options.isImplicitImpression`, для V2 согласуйте режим с настройками плейсмента. Для manual rendering включите `isBuildEngagementUrl`, обрабатывайте content-level handler-ы из `variables.on*` и product-level события из `products.slots[].events[]`.

## Миграция engagement

В V2 для ручного рендеринга включите:

```json
{
  "options": {
    "isBuildEngagementUrl": true
  }
}
```

После этого Gateway добавит готовые tracking URL в ответ `/choose`. Используйте:

- `content.events[].urls[]` для content-level tracking;
- `products.slots[].events[].urls[]` для product-level tracking.

Не заменяйте product-level tracking content-level tracking-ом: для рекомендаций и товарной рекламы важно отправлять события конкретных слотов.

## Рекомендуемый порядок перехода

1. Выберите один selector или placement, который можно безопасно перевести на V2.
2. Реализуйте хранение `uid` и `ses`.
3. Замените `context.page` на `ctx`, `selector.names` на `data[].selector`.
4. Включите `isBuildEngagementUrl` и подключите вызов URL из `content.events[]` и `products.slots[].events[]`.
5. Сравните показы, клики и бизнес-события в отчётах.
6. После проверки переносите следующие placements.

## Что проверить после миграции

- `ctx.type`, `ctx.data` и `ctx.location` совпадают с настройками кампаний и фидом. Подробнее: [Контекст](./context.md).
- `uid` сохраняется между сессиями, `ses` обновляется после ответов API.
- Для `/choose` с pageview используется `isImplicitPageview` только один раз на страницу.
- Для товаров отправляются `products.slots[].events[]`, а не только content-level events.
- Для рекламных плейсментов `placementId`, tracking URL, товарные `slotId` и рекламные метаданные, если они вернулись в response, не теряются при передаче ответа в UI-слой.
- Для login/signup передаются одинаковые `cuid` и `cuidType` во всех каналах интеграции.
