Нотили

Документация

HTTP API

Один эндпоинт для отправки события с сервера и один — для браузера. Всё остальное — необязательные поля.

Ключи доступа

Ключи создаются в кабинете на вкладке «Подключение». Их два типа, и они не взаимозаменяемы.

sk_live_…
Секретный. Только для кода на вашем сервере. Показывается один раз при создании.
pk_live_…
Публичный. Вставляется в HTML, виден посетителям. Умеет только создавать события и только с разрешённых доменов.
Секретный ключ не должен попадать в код страницы, в репозиторий и в мобильное приложение. Если он утёк — отзовите его в кабинете и создайте новый, старый перестанет работать сразу.

Отправка с сервера

POST/api/v1/notify

Заголовок Authorization: Bearer sk_live_…. Тело — JSON.

curl -X POST https://notily.ru/api/v1/notify \
  -H "Authorization: Bearer sk_live_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Новая заявка",
    "body":  "Иван, +7 900 000-00-00",
    "level": "info",
    "source": "Форма на главной",
    "url":   "https://mysite.ru/zayavka",
    "fields": {
      "Имя":     "Иван",
      "Телефон": "+7 900 000-00-00"
    }
  }'

Отправка из браузера

POST/api/v1/collect

Используется сниппетом. Ключ передаётся в поле key внутри тела, а не в заголовке: этого требует navigator.sendBeacon, который единственный не теряет запрос при уходе со страницы.

notily.notify({
  title: 'Оплата прошла',
  body:  'Заказ №4812 · 34 900 ₽',
  level: 'success',
  fields: { 'Заказ': '4812', 'Сумма': '34 900 ₽' }
})

Функция notily.notify появляется после подключения сниппета. Автоматический перехват форм при этом продолжает работать.

Поля запроса

title
Обязательное. Заголовок, до 200 символов. Принимается также как message или text.
body
Текст под заголовком, до 4000 символов.
level
info · success · warning · error. По умолчанию info. Влияет на цвет и на фильтр по важности.
source
Откуда пришло: «Форма на главной», «Онлайн-касса».
url
Ссылка кнопки «Открыть». Только http и https.
fields
Поля формы. Объект или массив пар. До 50 штук. Вложенные объекты и массивы разворачиваются сами.
items
Состав заказа. Массив позиций. Принимается также как cart или products.
amount
Сумма заказа. Число в рублях либо строка вида «4 900,50 ₽». Если не передать — сложим позиции.
orderId
Номер заказа в вашей системе. Принимается также как order_id или orderNumber.
dedupKey
Схлопывание дублей в пределах окна, заданного в настройках проекта.
idempotencyKey
Защита от повторной отправки при ретрае. Повтор вернёт тот же id события.

Состав заказа

Имя и телефон отвечают на вопрос «кто написал». Состав заказа — на вопрос «что именно заказали», и без него заявку из магазина приходится уточнять звонком.

{
  "title": "Заказ звёздного неба",
  "orderId": "1043",
  "amount": 4900,
  "fields": { "Имя": "Иван", "Телефон": "+7 900 000-00-00" },
  "items": [
    {
      "name": "Постер «Звёздное небо»",
      "quantity": 1,
      "price": 3900,
      "options": {
        "Дата":    "12 мая 1990, 03:40",
        "Место":   "Липецк",
        "Размер":  "60 × 90",
        "Надпись": "Тот самый вечер"
      }
    },
    { "name": "Рама, чёрный дуб", "quantity": 1, "price": 1000 }
  ]
}

Ключи позиции распознаются под привычными именами: name или title, quantity или qty, price, sum, sku, url. Всё остальное, что вы положите в позицию, попадёт в её характеристики — объявлять их заранее не нужно.

Числа в price и amount — это рубли. Если вы считаете в копейках, используйте priceKopecks и sumKopecks.

Корзина из браузера

Сниппет собирает состав заказа сам, если на странице есть что собирать. Четыре способа, от простого к подробному.

// 1. Корзина из кода сайта — уедет с ближайшей отправкой формы
notily.cart(
  [{ name: 'Постер 60×90', quantity: 1, price: 3900,
     options: { 'Дата': '12.05.1990', 'Место': 'Липецк' } }],
  { amount: 4900, order: '1043' }
)

// 2. Готовый JSON на форме
<form data-notily-items='[{"name":"Постер","price":3900}]'>

// 3. JSON в скрытом поле — так отдают корзину конструкторы
<input type="hidden" data-notily-items value="[...]">

// 4. Разметка корзины прямо на странице
<div data-notily-item data-notily-name="Постер" data-notily-price="3900">
  <span data-notily-option="Дата">12.05.1990</span>
  <span data-notily-option="Место">Липецк</span>
</div>

Сумму и номер заказа можно указать атрибутами data-notily-amount и data-notily-order на форме или на любом элементе внутри неё.

Ответы

{ "ok": true, "id": "evt_...", "status": "created" }

status равен duplicate, если событие схлопнулось с предыдущим или пришло с уже использованным idempotencyKey. Это не ошибка — повторять запрос не нужно.

400
Тело не JSON или превышает 64 КБ.
401
Ключ не найден или отозван.
403
Не тот тип ключа либо домен не в списке разрешённых.
422
Не хватает обязательного поля или значение не проходит проверку.
429
Превышен лимит. В заголовке Retry-After — через сколько секунд повторить.
402
Исчерпан месячный лимит тарифа.

Лимиты

По ключу
120 запросов в минуту
По IP на публичном эндпоинте
20 запросов в минуту
Размер тела
64 КБ
Хранение событий
зависит от тарифа: от 10 до 60 дней, дольше не хранятся

При штатной работе лимиты незаметны. Они существуют, чтобы ошибка в цикле на одном сайте не мешала остальным.

Проверка ключа

GET/api/v1/ping
curl https://notily.ru/api/v1/ping \
  -H "Authorization: Bearer sk_live_ВАШ_КЛЮЧ"

{ "ok": true, "keyType": "secret" }

Отвечает, жив ли ключ, не создавая события в ленте. Удобно для проверки после настройки.