Быстрый старт
В веб-панели создайте стороннее приложение для нужной компании. Скопируйте App ID и App Secret, а при необходимости итогового результата укажите необязательный Callback URL.
Engine создаёт записи для пользователей, выбранных необязательным audience (по умолчанию для всей подходящей компании), и пытается отправить системный Push только на подходящие зарегистрированные устройства.
Адрес и аутентификация
Среды API:
- Тестовая: https://aim-api-test.proton-system.com
- Рабочая: https://aim-api.proton-system.com
Каждый межсерверный JSON-запрос должен передавать Authorization: Basic Base64(KEY:SECRET) через HTTP Basic Authentication, где KEY — это App ID, а SECRET — App Secret:
Endpoint: POST /openapi/v1/notifications.
curl --request POST 'https://<your-engine-host>/openapi/v1/notifications' \
--header 'Authorization: Basic <Base64(AppID:AppSecret)>' \
--header 'Content-Type: application/json' \
--data '{"requestId":"order-20260819-001","title":"Заказ выполнен","body":"Ваш заказ выполнен.","imageUrls":["https://cdn.example.com/order/001-1.webp","https://cdn.example.com/order/001-2.webp"],"displayFields":[{"label":"Название магазина","value":"Лапшичная Сяо Хань (Ванцзин)"},{"value":"ORD-10086"}],"tags":["Выполнен","Главный магазин"]}'Контракт запроса
Сводка полей
| Поле | Обязательно | Тип | Значение |
|---|---|---|---|
requestId | Да | string | Уникальный ID запроса от отправителя и ключ идемпотентности. Обрезается и не может быть пустым. |
title | Да | string | Заголовок уведомления. Обрезается и не может быть пустым. |
body | Да | string | Текст уведомления. Обрезается и не может быть пустым. |
imageUrls | Нет | string[] | Изображения в деталях, в порядке показа. |
displayFields | Нет | object[] | Дополнительные текстовые поля в деталях. |
tags | Нет | string[] | Теги plain text только в деталях, в заданном порядке. |
audience | Нет | object | Ограничивает пользователей или роли; без поля получает вся подходящая компания. |
Изображения: imageUrls
- Не передавайте поле, используйте
nullили[], если изображений нет; иначе передайте 1-9 URL по порядку. - URL обрезается, должен быть уникальным и абсолютным
HTTPSURL без имени пользователя и пароля. - Максимум 2048 символов Unicode на URL. Один неверный URL отклоняет весь запрос.
- Engine хранит URL, но не загружает, не проверяет, не проксирует и не кэширует их.
Поля деталей: displayFields
| Подполе | Обязательно | Ограничение | Отображение |
|---|---|---|---|
label | Нет | Обрезается, не пустое, до 32 Unicode символов | Название поля. |
value | Да | Обрезается, не пустое, до 256 Unicode символов | Значение поля. |
{
"displayFields": [
{ "label": "Магазин", "value": "Little Han Noodles (Wangjing)" },
{ "value": "ORD-10086" }
]
}- Отсутствие,
nullили[]означает отсутствие строк; максимум 10 объектов. - Без
labelили приlabel: nullзначениеvalueзанимает всю строку. - Содержимое всегда plain text; HTML, Markdown, ссылки, вложенные данные, типы и стили не поддерживаются.
Теги деталей: tags
- Отсутствие,
nullили[]означает отсутствие тегов. Иначе передайте не более 8 strings в порядке показа. - Каждый тег обрезается и должен содержать 1-20 символов Unicode. Пустое, нестроковое, слишком длинное или повторное после обрезки значение отклоняет весь запрос с
INVALID_REQUEST. - Теги — неинтерактивный plain text только в detail уведомления; порядок сохраняется.
Получатели: audience
type | Селектор | Значение ID |
|---|---|---|
USERS | userIds | ID участника компании |
ROLES | roles | CompanyRole ID; получают допустимые участники любой указанной роли. |
Скопируйте ID участника компании из списка участников компании в Web Admin. Участник должен принадлежать компании, связанной со сторонним приложением.
{
"audience": { "type": "USERS", "userIds": ["companyMemberId"] }
}{
"audience": { "type": "ROLES", "roles": ["roleId"] }
}- Если
audienceнет или переданоnull, получают все подходящие активные пользователи связанной компании. - Список содержит 1-100 исходных строк; ID обрезаются, пустые игнорируются, набор удаляет повторы и сортируется.
- Несуществующие, отключённые, удалённые и чужие для компании ID игнорируются; остальные цели получают уведомление.
- Допустимый селектор без целей принимается и завершается с
recipientCount=0; отправки всей компании не будет. - Другой селектор можно опустить или задать
null. Смешанные не-null поля, неизвестные type или поля, отсутствующие или пустые списки, нестроковые элементы и более 100 записей даютINVALID_REQUEST.
Ограничения и идемпотентность
- Полный body ограничен 256 KiB. Для
requestId,title,bodyмаксимум 128, 100 и 1000 Unicode символов. - Для App ID действует лимит 10 запросов в минуту и 100 в час.
- Повтор
requestIdс эквивалентным нормализованным содержимым возвращает сохранённый результат. Порядок важен для изображений, полей и tags, но не для audience. - Другое содержимое с тем же
requestIdдаётIDEMPOTENCY_CONFLICT. Итоговыйstatus:SUCCESS,PARTIAL_SUCCESSилиFAILED.
Ответ о принятии
Корректный запрос возвращает HTTP 202:
{
"requestId": "order-20260819-001",
"notificationId": "00000000-0000-0000-0000-000000000001",
"status": "ACCEPTED"
}ACCEPTED означает, что Engine сохранил запрос для отправки, но не подтверждает показ уведомления через APNs/FCM на устройстве.
Результат Callback
Если настроен Callback URL, Engine отправляет итоговый результат:
{
"requestId": "order-20260819-001",
"status": "PARTIAL_SUCCESS",
"recipientCount": 8,
"pushAcceptedCount": 1,
"pushFailedCount": 1
}recipientCount — число пользователей-получателей в центре уведомлений. pushAcceptedCount и pushFailedCount — количество пакетов Push Outbox, а не пользователей или устройств и не подтверждение показа системного баннера.
Проверка Callback
Каждая проверка Callback из панели администратора отправляет отдельное тестовое событие:
{
"requestId": "callback-test-<unique-id>",
"status": "SUCCESS",
"recipientCount": 1,
"pushAcceptedCount": 1,
"pushFailedCount": 0,
"test": true
}Если test равно true, проверьте структуру и верните 2xx, но не сопоставляйте тестовое событие с отправленным запросом уведомления и не изменяйте состояние бизнес-доставки. Счётчики содержат фиксированные тестовые значения, а не число реальных получателей или пакетов Push Outbox.
Итоговый status: SUCCESS, PARTIAL_SUCCESS или FAILED. Подтвердите получение любым ответом 2xx.
Иначе повторы выполняются через 1 минуту, 5 минут, 30 минут, 2 часа, 6 часов и 24 часа. Сейчас HMAC-подписи нет: используйте HTTPS, сверяйте requestId для нетестовых результатов, ограничивайте доступ и обрабатывайте Callback идемпотентно.
Ошибки
| HTTP | Code | Значение |
|---|---|---|
| 400 | INVALID_REQUEST | Ошибка Content-Type, JSON, размера или полей. |
| 401 | INVALID_APP_CREDENTIALS | Неверные App ID или App Secret. |
| 403 | APPLICATION_INACTIVE | Приложение или компания неактивны. |
| 409 | IDEMPOTENCY_CONFLICT | requestId повторён с другим содержимым. |
| 429 | RATE_LIMITED | Превышен лимит приложения. |
| 503 | NOTIFICATION_UNAVAILABLE | Сервис временно недоступен. |
Безопасность и область доставки
- App ID и App Secret предназначены только для связи сервер-сервер. Не помещайте их в браузер, мобильное приложение, открытый репозиторий, URL или клиентское хранилище. При утечке сбросьте App Secret.
- Приватные ID целей никогда не записываются в logs приложения. Приватный selector и его ID также не попадают в GraphQL, Push, Callback, realtime или navigation.
- Без
audienceвключаются все подходящие активные пользователи компании; с audience — только допустимые найденные цели. Каждый допустимый получатель получает запись и учитывается вrecipientCount. - Системный Push выполняется только для активного
PushInstallation, разрешающего категориюBUSINESS, и не гарантирует системный баннер на каждом устройстве. - Полный список
imageUrlsдоступен только в авторизованном detail. Engine может отправить первый URL изimageUrlsв APNs/FCM для системного баннера.displayFieldsиtagsне входят в Push или Callback и остаются неинтерактивным plain text; не передавайте секреты, токены доступа, платёжные данные и другие чувствительные значения. titleиbodyдолжны оставаться полными и понятными без изображений. Ошибка загрузки или отображения изображения не изменяет статус accepted, Callback или Push.- Mobile client принимает не более 5 MiB на изображение, а тайм-аут всей операции загрузки составляет 10 секунд. Client не следует редиректам 3xx, поэтому каждый URL должен возвращать изображение напрямую.
- Mobile client загружает изображения напрямую из публичного CDN. Используйте URL без аутентификации и Cookie, сохраняйте их доступными не менее 90 дней и учитывайте, что CDN получает IP пользователя, время запроса и User-Agent.
- Для стабильной истории используйте immutable object URL.