Система уведомлений о событиях (Webhooks)

Webhook — механизм оповещения пользователей системы о событиях. События, о которых может уведомлять Webhook:

  • изменение статуса письма (отправлено, доставлено, отклонено, прочитано, получатель перешел по ссылке);
  • подписчик отписался от списка/подписался на другой список;
  • изменение статуса рассылки;
  • изменение данных пользователя;
  • добавление подтвержденного обратного адреса
  • изменение состояния счета
  • добавление нового пользователя (для реселлеров)

Webhook используют для отслеживания изменения статусов писем в реальном времени. В данном случае вызывать метод, возвращающий статистику доставки (например, метод UniSender getCampaignDeliveryStats) неэффективно, потому что это pull, а не push модель. Pull модель добавляет проблем как клиентской стороне (необходимость вызывать метод X раз в Y часов/минут/секунд), так и серверной (система перегружена избыточным и неконтролируемым потоком клиентских запросов о статусах писем).

Push модель, используемая в Webhook, работает следующим образом:при возникновении события установленный ранее обработчик отправляет HTTP-запрос на URL, который был указан для этого Webhook. Используются стандартные порты: 80 порт для HTTP и 443 порт для HTTPS. Для установки Webhook на URL с указанным портом можно передавать URL в виде: http://11.111.111.11:80

Если URL, на который отправляется Webhook, недоступен (отвечает не HTTP 200 OK, таймаут - 3 секунды), попытки отправки Webhook на этот URL до получения ожидаемого 200 ОК будут продолжаться в течение 24 часов с интервалом в 10 минут с дополнительным параметром retry_count, значение которого будет увеличиваться на 1 с каждой повторной отправкой Webhook.

Это позволяет настраивать триггеры, которые зависят от конкретных событий, например:

  1. подписчик получает письмо с предложением участвовать в программе лояльности;
  2. если он переходит по ссылке в письме, то система должна сразу же отправить ему письмо с промо-кодом.

В примере выше показан кейс настройки обработчика изменения статуса письма на “перешел по ссылке”.

Далее следует документация о том, как установить, настроить, удалить обработчики.

Установить обработчик

установить/заменить обработчик оповещений о событиях определенного типа.

Синтаксис и URL для вызова метода
setHook (hook_url, events, [event_format, max_parallel])
https://api.unisender.com/ru/api/setHook?api_key=KEY&hook_url=URL&event_format=FORMAT&events[]=EVENT&max_parallel=NUM
Аргументы
api_key* ключ доступа к API
hook_url * на какой URL отправлять запрос при возникновении события. Фактически является идентификатором обработчика. При повторном вызове setHook с таким же hook_url данные обработчика будет заменены
event_format

формат, в котором передаются данные о событии, обязательный параметр с тремя вариантами значений:

  • json_post — параметры оповещения будут переданы в теле POST-запроса в JSON-формате, возможна группировка сразу нескольких событий разных типов в одном запросе;
  • json_post_gzip— рекомендованный способ. Совпадает с json_post, только тело POST-запроса сжато с помощью gzip;
  • http_get— устаревший вариант, параметры оповещения передаются как GET-параметры HTTP-запроса, не поддерживается событие email_status
events*

ассоциативный массив, перечисляющий оповещения, которые получает обработчик. Ключами массива могут быть строки:

email_status

Изменение статуса отправленного email.

Допустимые значения:

ok_sent — письмо отправлено;

ok_delivered — письмо доставлено;

ok_read— письмо прочитано;

ok_link_visited — зафиксирован переход по ссылке

err_will_retry— письмо не доставлено, но будут попытки отправить его повторно.

Другие допустимые значения можно посмотреть здесь.

Разрешается использовать только с форматами json_post_gzip и json_post, и запрещается с форматом http_get.

unsubscribe

Изменение статуса подписки получателя (отписался от списка, подписался на список).

Допустимое значение:*
subscribe

Изменение статуса подписки получателя (подписался на список)

Допустимые значения:

* - отправлять при подписке на любой список

id списка - отправлять при подписке на список с заданным id

subscribe_primary

Изменение статуса подписки получателя (подписался на список впервые)

Допустимые значения:

* - отправлять при подписке на любой список

id списка - отправлять при подписке на список с заданным id

campaign_status

Изменение статуса массовой рассылки.

Допустимое значение: *

email_check

Добавление подтвержденного обратного адреса.

Допустимое значение: *

user_payment

Доступен только для реселлеров. Изменение состояния счета. Учитываются движения,связанные с основным и бонусным счетом.

Допустимое значение: *
user_info

Изменение полей информации о пользователе.

Допустимое значение: *

max_parallel

необязательное указание максимального количество параллельных вызовов к этому обработчику. По умолчанию равно 10.

single_event

Принимает значения 1 и 0. По умолчанию: 0

1 - оповещение Webhook не содержит массивов, за одно оповещение информация будет возвращаться только по одному событию;

0 - оповещение Webhook возвращает информацию в виде массивов (см. пример ниже).

Пример вызова

https://api.unisender.com/ru/api/setHook?api_key=XXX&hook_url=https%3A
%2F%2Fmycompany.com%2Funisender-hook&event_format=json_post_gzip
&events[unsubscribe]=*&events[email_status]=ok_read,ok_link_visited

Список обработчиков

listHooks - получить список всех обработчиков.

Синтаксис и URL для вызова метода
listHooks ()
https://api.unisender.com/ru/api/listHooks?api_key=KEY
Аргументы
api_key * ключ доступа к API
Возвращаемое значение
{
"result":
[
{
"id":3,
"url":"https:\/\/site.com\/unisender-hook",
"event_format":"json_post_gzip",
"max_parallel":1,
"single_event":0,
"events":
{
"subscribe": ["1","2","3"]
}
}
]
}

Удалить обработчик

removeHook - удалить обработчик оповещений.

Синтаксис и URL для вызова метода
removeHook (hook_url)
https://api.unisender.com/ru/api/removeHook?api_key=KEY&hook_url=URL
Аргументы
api_key * ключ доступа к API
hook_url* URL-идентификатор удаляемого обработчика

Оповещение JSON-формата

Пример возвращаемого оповещения

{ 
  "auth":"6931402abc4b2a76b9719d911017c592",
  "num":"12",
  "events_by_user":
  [
    {
      "login":"user_zz",
      "Events":
      [
        {
          "event_name":"email_status",
          "event_time":"2015-04-24 15:18:34",
          "event_data":
          {
            "email":"user@example.com",
            "campaign_id":"124345",
            "user_campaign_id":"346134",
            "status":"ok_read",
            "status_group":"success_group",
            "delivery_info":
            {
              "user_agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
              "ip":"111.111.111"
            }
          }
        },
        {
          "event_name":"email_status",
          "event_time":"2015-04-24 15:18:36",
          "event_data":
          {
            "email":"user2@example.com",
            "email_id":"346134",
            "status":"ok_link_visited",
            "status_group":"success_group",
            "delivery_info":
            {
              "user_agent":"Mozilla/5.0 (X11; Linux x86_64)",
              "ip":"111.111.111"
            }
          }
        },
        {
          "event_name":"unsubscribe",
          "event_time":"2015-04-24 15:18:58",
          "event_data":
          {
            "email":"user2@example.com",
            "campaign_id":"87434",
            "user_campaign_id":"camp-5464",
            "list_id":"3346",
            "Just_unsubscribed_list_ids":
            [
              "3346", "7473"
            ],
            "Just_subscribed_list_ids":
            [
              "9745"
            ]
          }
        }
      ]
    }
  ]

Описание параметров оповещения (для single_event = 0)

Оповещения форматов json_post и json_post_gzip отправляются в виде POST-запроса на URL оповещения без дополнительных аргументов с Content-Type=application/json (и для json_post_gzip с Content-Encoding: gzip). В случае выбора формата json_post_gzip , необходимо проводить декомпрессию GZIP объекта, перед чтением JSON. JSON-объект передается в теле запроса без задания каких-либо переменных, для чтения данных. К примеру на PHP, можно использовать команды:- gzdecode($postData); - для декомпрессии GZIP - file_get_contents('php://input'); - для чтения JSON

Данные оповещения — JSON-объект со следующими полями:

массив из JSON-объектов, каждый элемент которого соответствует одному пользователю. Более одного элемента в этом массиве может быть только для реселлеров - реселлеры могут получить уведомление о событиях сразу нескольких своих пользователей в одном вызове, в остальных случаях этот массив состоит из одного элемента.

auth

MD5-хэш строкового тела сообщения, в котором значение auth заменено на api_key пользователя, чей обработчик вызывается. С помощью этого получатель оповещения может как провести аутентификацию, так и проверить целостность оповещения.

Для генерации auth сформировать полностью тело оповещения в JSON, вместо значения auth подставить значение api_key пользователя и вычислить md5 от тела. Затем заменить в сообщении api_key на получившийся md5, записанный в шестнадцатеричном виде в lowercase.

Для проверки auth надо заменить его значение на api_key, также вычислить md5 от тела оповещения и сверить его со значением auth, полученном в изначальном теле оповещения.

num

на какой URL отправлять запрос при возникновении события. Фактически является идентификатором обработчика. При повторном вызове setHook с таким же hook_url данные обработчика будет заменены

events_by_user

массив из JSON-объектов, каждый элемент которого соответствует одному пользователю. Более одного элемента в этом массиве может быть только для реселлеров - реселлеры могут получить уведомление о событиях сразу нескольких своих пользователей в одном вызове, в остальных случаях этот массив состоит из одного элемента.

login

логин пользователя, оповещение о событиях которого мы передаём в рассматриваемом элементе массива events_by_user.

events

массив событий пользователя с вышеуказанным логином, каждый элемент массива имеет следующие поля:

event_name

имя события, одно из: email_check, unsubscribe, activate, reject, campaign_status, user_payment, user_info, email_status

event_time

время возникновения события в формате "YYYY-MM-DD hh:mm:ss" в часовом поясе UTC

event_data

объект с данными события, формат которых зависит от имени события. Форматы описаны ниже:

email_status
  • email - email подписчика, статус доставки сообщения по которому изменён
  • email_id - идентификатор сообщения, полученный через sendEmail. Только для сообщений, отправленных через sendEmail
  • campaign_id - только для отправленных через createCampaign
  • user_campaign_id - только если был указан пользователем при отправке
  • status - статус доставки сообщения.
  • status_group - группа статуса в соответствии с названиями из результатов отправки email : "not_sent_group", "not_allowed_group" и т.п.
unsubscribe
  • email - email отписавшегося
  • campaign_id - идентификатор рассылки, по письму из которой произошла отписка
  • user_campaign_id - необязательный пользовательский идентификатор рассылки, по письму из которой произошла отписка. Отсутствует, если пользователь не передавал свой идентификатор рассылки в sendEmail/createCampaign.
  • list_id - либо "0", либо код списка, по которому было отправлено письмо, после которого произошла отписка. "0" означает, что выполнена отписка от всех списков.
  • just_unsubscribed_list_ids - необязательный массив кодов списков, от которых только что произошла отписка. Отсутствует в случае, если была глобальная отписка была от всех списков (включая будущие).
  • just_subscribed_list_ids - необязательный массив кодов списков, на которые только что подписались (на странице отписки можно и вернуть подписку). Отсутствует в случае, если отписка была от всех списков или ни на что не подписались.
campaign_status
  • campaign_id - идентификатор рассылки, который был возвращён вызовом метода createCampaign.
  • status - статус рассылки
  • contact_count - количество контактов в рассылке
  • period_messages - количество сообщений, отправленных за счёт включённых в период. Для SMS-сообщений всегда равно 0.
  • prepaid_messages - Количество сообщений, отправленных за счёт ранее купленных.
  • pay_sum - сумма за отправку писем.
  • currency - трёхбуквенный международный код валюты, в которой посчитана сумма за отправку писем (RUB, USD, EUR, UAH)

email_check

email - Email, право использования которого в качестве обратного адреса подтверждено пользователем.

user_payment
  • sum
  • sum_bonus
  • currency
  • description
  • new_balance
  • new_balance_bonus
user_info
  • email
  • firstname
  • middlename
  • firstname
  • phone
  • company
  • timezone
  • master
  • country
  • language
  • rights

Пример на PHP

?php
class hook {
public function handle($receiver_path)
{
$filename = basename($receiver_path, '.php');
$api_key = '';
$postData = file_get_contents('php://input');
if (strlen($postData) > 0) {
$decodedData = json_decode($postData, true);
if ($decodedData == '') {
$decodedData = json_decode(gzdecode($postData), true);
}
$hash = $decodedData['auth'];
$decodedData['auth'] = $api_key;
file_put_contents('/tmp/__' . $filename . '__'
. time() . md5(rand(0, 100000000)) . '.log', "
---------------Received message: ------------------\n" . var_export
($decodedData, true) . "\n\n Hash received: {$hash}\n Hash verifying: " . md5(json_encode($decodedData)), FILE_APPEND); } else { $actual_link = "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URL]"; file_put_contents('/tmp/GET__' . $filename . '__' . time() . md5(rand(0, 100000000)) . '.log', $actual_link, FILE_APPEND); echo 'Yep! It works! Filename: ' . $filename; } } }  <?php require 'hook.php'; $h = new hook; $h->handle(__FILE__);