Контекст запроса: что вы знаете о получателе

Что это?

Когда вы собираете письмо и запрашиваете у нас рекламный блок, вы обычно уже знаете о получателе больше, чем мы: сумму чека, ИНН компании, к какому сегменту он у вас относится. Контекст — это необязательный параметр ctx в том же вызове, которым вы и так забираете блок. Вы кладёте туда то, что знаете; мы сохраняем это рядом с тем, какой баннер показали и был ли по нему клик.

Зачем мне это?

Чтобы ваше место со временем зарабатывало больше при той же цене. Сейчас RMEX выбирает баннер, ничего не зная о получателе: одно и то же предложение уходит и тому, кто купил на 500 рублей, и тому, кто купил на пятьдесят тысяч. Накопив контекст и исходы, платформа научится подбирать баннер под получателя. А чем чаще по вашему месту кликают, тем дороже оно стоит для рекламодателей.

Честно про сроки: сегодня контекст только собирается. На выбор баннера он пока не влияет; когда подбор включится, мы сообщим. Без накопленных данных учиться не на чем: это первый шаг, а не мгновенный эффект.

Кто это увидит?

Контекст — ваше знание о вашей аудитории. Рекламодателю он не показывается никак: ни значением, ни разрезом, ни в виде сводки. Он не увидит ни ИНН, ни сегментов, ни того, что вы вообще что-то присылаете.

А если не слать вовсе?

Ничего не изменится. Параметр необязательный: вызов без него работает ровно как сейчас, ответ прежний. Присылать контекст можно не во всех вызовах, а выборочно, например только там, где чек известен.

Как слать

Куда добавляется параметр?

В тот же запрос за блоком, третьим параметром рядом с u:

GET /v1/ad-slot/{placementId}?u={message_uid}&ctx={JSON, закодированный для URL}

Ключ доступа передаётся как обычно: заголовком Authorization: Bearer <ваш ключ> либо X-API-Key: <ваш ключ>.

Как выглядит сам контекст.
Магазин знает про получателя чека несколько вещей: он в сегменте лояльных, бросил корзину, чек на 5400 рублей, компания с таким-то ИНН. Вот это в нашей форме:

{
  "data": [ {"name": "crm", "segment": [{"id": "loyal"}, {"id": "cart_abandoned"}]} ],
  "ext":  {"amount": 5400, "inn": "0000000000", "city": "msk"}
}

Живой пример вызова.
Здесь --data-urlencode кодирует JSON за вас, руками кодировать не нужно:

CTX='{"ext":{"amount":5400,"inn":"0000000000"}}'

curl -G https://app.rmex.io/v1/ad-slot/{placementId} \
  -H "Authorization: Bearer <ВАШ_КЛЮЧ>" \
  --data-urlencode "u=8f14e45f-ea3f-4b1f-9f1a-2c0d5a7b1e33" \
  --data-urlencode "ctx=$CTX"

Если вы собираете запрос кодом, а не curl, прогоните JSON через обычное URL-кодирование параметра запроса. Кодировать нужно обязательно: в JSON есть знаки, которые в адресе значат другое (кавычки, фигурные скобки, а в значениях может попасться &), и без кодирования запрос либо разберётся неправильно, либо будет отвергнут веб-сервером ещё до RMEX.

Из чего состоит контекст?

Форма взята по образцу OpenRTB — это отраслевой стандарт, чтобы вам не учить наши выдумки. Два верхних ключа, оба необязательные:

  1. data — сегменты и признаки от источника данных. Массив; у каждого источника имя name и список segment. У сегмента обязателен id, можно добавить name.
  2. ext — произвольные пары «ключ — значение» для всего, чего OpenRTB не знает: сумма чека, ИНН, город.

Всё остальное на верхнем уровне мы не сохраняем, просто не берём.

Правила для ключей ext.
Ключ — латиница в нижнем регистре, цифры и подчёркивание, от 1 до 32 знаков. inn, amount, city_code подходят. INN, Сумма, order id не подходят: такая пара отбрасывается, остальные остаются.

Значение — только строка или число, до 256 знаков. Пустое значение, вложенный объект, массив, true/false: пара отбрасывается.

Под ключом inn сохраняется только ИНН организации, ровно десять цифр. ИНН предпринимателя (двенадцать цифр) и любое другое значение под этим ключом отбрасываются: это персональные данные человека, хранить их мы не можем. Остальные пары контекста при этом остаются.

Какие лимиты?

  1. 16 пар в ext. Считаются все присланные, включая те, что мы потом отбросим по правилам ключа.
  2. 32 сегмента суммарно по всем источникам в data. Считаются только сегменты с id.
  3. 256 знаков на одно значение.
  4. 4096 байт на весь контекст. Байт, а не знаков: кириллица весит два байта на букву. На практике раньше срабатывает предел длины адреса у веб-сервера, поэтому держите кириллицу в контексте в пределах примерно тысячи букв.

Что будет, если прислать негодное

Ответ вообще может сломаться?

Нет. Это главное правило: контекст никогда не ломает выдачу. Мы не отвечаем ошибкой 400 и не отдаём пустой блок из-за контекста. Если с ним что-то не так, мы просто ведём себя так, будто его не было, и отдаём тот же блок, что и всегда. Ваше письмо не пострадает ни при каком содержимом ctx, если запрос до нас дошёл. Исключение одно, и оно на стороне веб-сервера: слишком длинный адрес он отвергает сам, до RMEX, с кодом 400 или 414. Отсюда и совет держать кириллицу в пределах тысячи букв.

Когда контекст отбрасывается целиком?

  1. JSON не разобрался.
  2. В корне не объект (например, прислали массив).
  3. Пар в ext больше 16.
  4. Сегментов больше 32.
  5. Весь контекст больше 4096 байт.

Когда режется только одна пара?

  1. Ключ ext не по правилу (заглавные, кириллица, пробел, длиннее 32 знаков).
  2. Значение не строка и не число, либо пустое, либо длиннее 256 знаков.
  3. Незнакомый ключ на верхнем уровне: берём только data и ext.
  4. Сегмент без id: такой сегмент отбрасывается, остальные остаются.

Остальные пары при этом сохраняются. А если после чистки не уцелело ничего, это для нас то же самое, что контекста и не было.

Персональные данные

Что вы делаете с почтой и телефоном?

Храним не само значение, а его хеш SHA-256. Правило работает с двух сторон:

  1. По виду значения. Всё, что выглядит как адрес почты или как телефон, превращается в хеш автоматически, в любом ключе, в том числе внутри сегментов.
  2. По имени ключа. Значение под ключами phone, tel, mobile, msisdn хешируется всегда, какой бы вид оно ни имело. Совпадение точное: telegram_id или mobile_app под это правило не попадают и сохраняются как есть.

Второе правило нужно там, где по виду не разобрать: мобильный без кода страны — это десять цифр, и ИНН юридического лица — тоже десять цифр. Назовите поле phone, и мы не ошибёмся.

Хеш выглядит как sha256: и дальше сама свёртка. Обратно из хеша значение не читается, но телефонов на свете немного, и по хешу телефон можно подобрать перебором. Поэтому почту и телефон лучше не присылать вовсе.

А ИНН и сумма чека?

ИНН организации (10 цифр) и сумма чека сохраняются как есть. Это признак сделки, а не сведения о человеке: по ИНН компании и сумме покупки RMEX и учится подбирать предложение. Если бы мы хешировали и их, собирать контекст было бы незачем. ИНН из 12 цифр принадлежит предпринимателю, то есть человеку: его не присылайте.

Что лучше не присылать?

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

Тонкости

Я кэширую ответ. Контекст сработает?

Если вы забираете блок один раз и подставляете u сами в закэшированный HTML, то один вызов приходится на целую пачку писем. Контекст в этом случае относится ко всей пачке, а не к конкретному получателю, и связать его с кликом по конкретному письму мы не сможем. Контекст имеет смысл там, где вызов идёт на письмо и u передаётся в самом запросе.

Ссылки в блоке изменятся?

Да, но только когда контекст пришёл и уцелел: в ссылке клика и в пикселе открытия появляется ещё один служебный параметр. Вставляйте блок как есть, ничего дописывать или вырезать не нужно. Если контекст не прислан, ссылки в точности прежние.

Сколько это стоит и на скорость влияет?

Нисколько и никак. Разбор контекста происходит внутри того же вызова, отдельных запросов не добавляется, тариф и правила расчётов не меняются.