# Управление персонализациями

Программный CRUD над персонализациями. См. сначала общие правила.

База: https://api.sales-ninja.me/public/api/v1/manage/personalizations

HTTP Что делает
GET / Список персонализаций (search, state, page, pageSize).
POST /list Список со сложным фильтром (по ids, диапазонам дат и т.п.).
GET /{id} Полная сущность с вариантами, модификациями и условием показа.
POST / Создать персонализацию (полное дерево в теле).
PUT /{id} Обновить персонализацию целиком (полное дерево).
DELETE /{id} Удалить.

# Тело запроса

{
  "title": "Размер шрифтов на каталоге",
  "state": "Working",
  "scope": "Web",
  "optimizationMetric": "ConversionCount",
  "mlModelConversionSource": "Goals",
  "sourceType": "Manual",
  "slotFrom": 0,
  "slotTo": 100,
  "goals": [
    { "goalId": "299837db-9b51-45a4-996b-844d3fd05bbd" }
  ],
  "modeledConversionId": null,
  "customProvedModelMlGroupRatio": null,
  "isSmart": false,
  "pessimizeControlGroup": false,
  "pessimizeControlGroup_TurnOffIfReallyBad": false,
  "protectAgainstChanges": false,
  "onlyForManualCalling": false,
  "reapplying": false,
  "startTrainAfterEdition": false,
  "mlModelAtributionType": "FirstSession",
  "variants": [
    {
      "title": "Контроль",
      "isWorking": true,
      "isOriginal": true,
      "isDefaultOption": false,
      "modifications": []
    },
    {
      "title": "Крупный шрифт",
      "isWorking": true,
      "isOriginal": false,
      "isDefaultOption": false,
      "customScript": null,
      "modifications": [
        {
          "type": "ChangeStyle",
          "actionJson": {
            "selector": ".catalog-item__title",
            "property": "font-size",
            "value": "20px"
          }
        }
      ]
    }
  ],
  "displayCondition": {
    "fieldCode": "page_url",
    "operation": "Contains",
    "value": "/catalog/"
  }
}

# Поля

Поле Тип Описание
title string Название (видно в админке).
state enum EBaseRootEntityState: Working | Active | Stopped | Paused | Archived Состояние.
scope enum EPersonalizationScope: Web | Mobile | Backend Где применяется. Web — через бандл; Mobile/Backend — через runtime API.
optimizationMetric enum EMlModelOptimizationMetric: ConversionCount | Revenue | NetProfit | LtvRevenue | LtvNetProfit По какой метрике система выбирает победителя.
goals[*].goalId UUID Цели, на которые опирается модель. Минимум одна (для модельных персонализаций).
modeledConversionId UUID | null Если оптимизируем по моделируемой конверсии — её id.
isSmart bool Включить умный режим (см. админку).
protectAgainstChanges bool Зафиксировать решение после первого применения и не перетыкать.
onlyForManualCalling bool Не применять автоматически, только через явный applied в runtime.
displayCondition clause-tree Условие показа V2. Target: personalizationWeb. См. Условия показа.

# variants[]

Варианты персонализации. Один из них обычно отмечен isOriginal: true (контрольный, изменений нет), остальные — конкретные изменения.

Поле Описание
id UUID для существующего варианта; null или отсутствует — будет создан.
title Название варианта.
isWorking Активен ли вариант.
isOriginal Контрольный вариант (без изменений на сайте).
isDefaultOption Дефолт, применяется когда модель не определилась.
customScript Произвольный JS, выполняется на странице (только для scope: "Web").
redirectTo Куда редиректить (только для scope: "Web").
modifications Список модификаций DOM (см. ниже).

# variants[].modifications[]

Каждая модификация — это одно изменение DOM/контента, которое применит бандл (или ваша интеграция, если вы сами интерпретируете ответ runtime API).

Поле Описание
type Тип модификации (ChangeText, ChangeStyle, ChangeHtml, AddClass, RemoveClass, …). Конкретный список — см. админку.
actionJson JSON-объект с параметрами модификации. Структура зависит от type.

Для веб-сценария проще создавать варианты через визуальный редактор в админке Sales Ninja и далее синхронизировать через API только то, что нужно автоматизировать.

# Ответ при сохранении

{
  "personalizationId": "8f3a1e4b-7c4d-4d5e-9aaf-2c1b6d3e5f01",
  "variantIds": [
    "a1b2c3d4-e5f6-7890-abcd-ef0123456789",
    "11112222-3333-4444-5555-666677778888"
  ],
  "displayConditionId": "ccddeeff-0011-2233-4455-66778899aabb",
  "createdPersonalization": true,
  "createdVariantIds": [
    "11112222-3333-4444-5555-666677778888"
  ]
}

# Примеры

# Создать минимальную персонализацию

curl -X POST "https://api.sales-ninja.me/public/api/v1/manage/personalizations" \
  -H "X-SN-TOKEN: $SN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Тест размера шрифта",
    "state": "Working",
    "scope": "Web",
    "optimizationMetric": "ConversionCount",
    "goals": [{"goalId":"299837db-9b51-45a4-996b-844d3fd05bbd"}],
    "variants": [
      {"title":"Контроль","isOriginal":true,"isWorking":true,"modifications":[]},
      {"title":"Крупный","isOriginal":false,"isWorking":true,"modifications":[
        {"type":"ChangeStyle","actionJson":{"selector":".title","property":"font-size","value":"20px"}}
      ]}
    ]
  }'

# Обновить (полная замена)

curl -X PUT "https://api.sales-ninja.me/public/api/v1/manage/personalizations/8f3a1e4b-7c4d-4d5e-9aaf-2c1b6d3e5f01" \
  -H "X-SN-TOKEN: $SN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @personalization.json

Помните: PUT — это полная замена. Если вы хотите изменить только название — сначала GET, поменяйте поле в полученном JSON и пошлите его обратно PUT. Иначе можно случайно стереть варианты, не передав их в теле.

# Список

curl "https://api.sales-ninja.me/public/api/v1/manage/personalizations?state=Working&pageSize=20" \
  -H "X-SN-TOKEN: $SN_TOKEN"

# Удалить

curl -X DELETE "https://api.sales-ninja.me/public/api/v1/manage/personalizations/8f3a1e4b-7c4d-4d5e-9aaf-2c1b6d3e5f01" \
  -H "X-SN-TOKEN: $SN_TOKEN"

# Интеграционные модификации

Внутри variants[].modifications[] можно вызывать API внешних систем (Mindbox, Carrot Quest, Jivo, RoiStat, CallTouch, Яндекс.Метрика) — это JS-действия, срабатывающие в момент показа варианта. Полный список и формат actionJson для каждого — на странице JS-действия в персонализациях.