# Условия показа (Display Conditions V2)

Условие показа — это логическое выражение, которое решает, должна ли сущность сработать на конкретном пользователе/странице. Условия — не самостоятельный ресурс: они существуют как поле displayCondition внутри тела сущности (персонализации, A/B-теста, опроса, rule-based действия). Через Public API нет /manage/display-conditions/ — только конструктор-метаданные и встраивание в родителя.

# Структура дерева

Дерево строго бинарное: каждый узел — либо лист (SimpleClauseDto), либо группа (ComplexClauseDto) с двумя детьми и оператором.

# Лист (один предикат)

{
  "fieldCode": "browser_kind",
  "operation": "Equal",
  "value": "Mobile"
}
Поле Описание
fieldCode Код поля из конструктора. См. ниже.
operation Оператор: Equal, NotEqual, Greater, GreaterOrEqual, Less, LessOrEqual, Contains, DoesNotContain, Like, NotLike, NotNullOrEmpty, NullOrEmpty, UrlMatches, UrlDoesNotMatch, Worked, DidNotWork, OptionSelected, OptionDidNotSelected. Для каждого поля допустим свой подсписок — см. allowedOperations в конструкторе.
value Значение, к которому применяется оператор. Строка. Для унарных операторов (NotNullOrEmpty, NullOrEmpty) — null.
parameterKey Опционально: для полей valueType=custom указывает имя custom-параметра.
subEntityCode Опционально: подсказка о суб-сущности (например, id опции персонализации).

# Группа (два потомка)

{
  "operator": "And",
  "left":  { "...": "..." },
  "right": { "...": "..." }
}

Операторы группы: And, Or.

# Три предиката (A AND B AND C)

Нет N-арных групп, есть только бинарные. Группируйте вложением:

{
  "operator": "And",
  "left": {
    "operator": "And",
    "left":  { "fieldCode": "browser_kind", "operation": "Equal",    "value": "Mobile"      },
    "right": { "fieldCode": "page_url",     "operation": "Contains", "value": "/product/"   }
  },
  "right":   { "fieldCode": "session_session_count", "operation": "GreaterOrEqual", "value": "2" }
}

# Конструктор полей

GET https://api.sales-ninja.me/public/api/v1/conditions/constructor?target=<target>
Headers:
  X-SN-TOKEN: <ваш токен>

Возвращает каталог: какие поля доступны, какие операторы допустимы для каждого поля, какие у поля типы значений, какие enum-значения возможны, под какие категории сгруппированы поля.

# Допустимые target

displayCondition.target зависит от того, внутри какой сущности живёт условие:

Слот target
Корень A/B-теста default
Корень персонализации personalizationWeb
Корень опроса default
Корень rule-based действия default

Другие target'ы (modeledConversion, feedItem, feedItemDynamic, yandexDirectCampaign, surveyStepAnswer, personalizationMobile, personalizationBackend) — конструктор тоже умеет, но соответствующих внешних слотов под них на Public API сегодня нет.

# Пример ответа конструктора

{
  "target": "personalizationWeb",
  "connectOperators": ["And", "Or"],
  "clauseOperations": [
    { "code": "Equal", "name": "Equal" },
    { "code": "NotEqual", "name": "Not equal" },
    { "code": "Contains", "name": "Contains" },
    "..."
  ],
  "valueTypes": [
    { "code": "string",   "name": "String" },
    { "code": "number",   "name": "Number" },
    { "code": "datetime", "name": "Date/time" },
    { "code": "enum",     "name": "Enum" },
    "..."
  ],
  "fieldCategories": [
    { "code": "page",    "name": "Page"    },
    { "code": "session", "name": "Session" },
    { "code": "device",  "name": "Device"  },
    "..."
  ],
  "fields": [
    {
      "code": "page_url",
      "name": "Page URL",
      "category": "page",
      "valueType": "string",
      "allowedOperations": ["Contains", "DoesNotContain", "Equal", "NotEqual", "UrlMatches", "UrlDoesNotMatch"],
      "enumValues": null
    },
    {
      "code": "browser_kind",
      "name": "Browser kind",
      "category": "device",
      "valueType": "enum",
      "allowedOperations": ["Equal", "NotEqual"],
      "enumValues": [
        { "code": "Mobile",  "name": "Mobile"  },
        { "code": "Tablet",  "name": "Tablet"  },
        { "code": "Desktop", "name": "Desktop" }
      ]
    }
  ]
}

Имена (name) — English-only. Локализованных подписей в Public API нет; локализация делается на стороне клиента, если нужна.

# Алгоритм для интегратора

  1. Решите, в какой слот вы кладёте условие, и по таблице выше определите target.
  2. Дёрните GET /conditions/constructor?target=<target>, получите список допустимых полей и операторов.
  3. Соберите бинарное дерево из листьев и групп. Каждый лист — fieldCode из fields[] + operation из allowedOperations этого поля + value (строкой).
  4. Поместите дерево в displayCondition тела POST / PUT сущности (персонализации, A/B и т.п.) и сохраните родителя обычным способом.

# cURL

curl "https://api.sales-ninja.me/public/api/v1/conditions/constructor?target=personalizationWeb" \
  -H "X-SN-TOKEN: $SN_TOKEN"

# Совет

Если делаете UI на основе конструктора — кешируйте ответ конструктора per-target на стороне клиента: список полей меняется редко (релизами), а зовётся он часто. Sales Ninja отдаёт его быстро, но лишний раз гонять объёмный JSON смысла нет.

# Аналитический фильтр — другая структура

Фильтр в статистике (filters внутри POST /public/api/v1/analytics/aggregated) — это другая структура: N-арная ({operator, predicates[], nodes[]}), другой набор полей, другой конструктор (GET /public/api/v1/analytics/constructor). Не путать.