Назад к «Рации»

API сообщений: push-уведомления сотрудникам от ваших систем

1С, касса, CRM, мониторинг или любой ваш сервис отправляет короткое сообщение — сотрудник получает push в приложении «Рация», даже если оно закрыто. Один HTTP-запрос, без SDK. База: https://lab.onecdp.ru · JSON, UTF-8.

Быстрый старт

1. Получите ключ отправителя. Ключ (sp_live_…) выдаёт владелец платформы при заведении вашего отправителя — вместе с именем, которое сотрудники увидят как автора сообщений (например «Бухгалтерия 1С»). Ключ показывается один раз — сохраните его в секретах.

2. Отправьте первое сообщение на свой рабочий номер:

curl -X POST https://lab.onecdp.ru/messages \
  -H "Authorization: Bearer sp_live_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"to": "+79991234567", "title": "Тест", "body": "Интеграция работает"}'

3. Проверьте телефон. Push придёт в течение секунд; сообщение появится и во вкладке «Уведомления» приложения. Ответ 202 с messageId — запрос принят.

Модель: отправитель и получатель

Отправитель — ваша система. У неё есть apiKey (аутентификация) и имя (его видит сотрудник как автора). Имя фиксируется при заведении отправителя и в запросах не передаётся.

Получатель — сотрудник, всегда задаётся номером телефона в формате E.164 (+79991234567). Пробелы, скобки и дефисы допустимы — сервер нормализует.

Сообщение уйдёт только сотруднику из корпоративного справочника компании на платформе ClientPulse — тот же контроль доступа, что у звонков. Уволили сотрудника → убрали из справочника → доставка прекращается, интеграцию менять не нужно. Если ни один получатель не прошёл проверку, запрос вернёт 403.

Несколько отправителей — по одному на систему

У организации может быть сколько угодно отправителей, и это рекомендуемый паттерн: одна система — один отправитель. Сотрудник видит, кто именно пишет («Бухгалтерия 1С», «Мониторинг», «Склад WMS»), и уведомления каждой системы живут отдельным тредом — ничего не смешивается.

  • Свой ключ у каждой системы: скомпрометирован один — отзывается один, остальные работают.
  • Свой лимит 60 сообщений/мин на отправителя — «шумная» система не съедает квоту остальных.
  • Идемпотентность считается на отправителя — ключи событий разных систем не конфликтуют.

Транспорт и время доставки

Доставка построена по той же двухканальной схеме, что у крупных мессенджеров: пока приложение открыто, сообщение приходит по постоянному соединению; спящее приложение будит системный push — APNs на iOS, FCM на Android. Серверная часть при этом полностью своя — без сторонних облаков-посредников.

Состояние устройстваКаналТипичная задержка
открытопостоянное соединениедесятки миллисекунд
свёрнуто / закрытоAPNs / FCM push1–5 секунд
вне сетиpush при появлении сети + синхронизация историипри следующем подключении

Порядок жёсткий: сообщение сначала записывается в историю сотрудника и только потом доставляется (history-first). Поэтому «потерянных» сообщений не бывает: даже если телефон был выключен и push не дошёл, сообщение появится при следующем запуске приложения. История хранится 30 дней.

Отправка: POST /messages

Заголовки

Authorization: Bearer sp_live_…
Content-Type: application/json

Тело запроса

ПолеТипОбяз.Описание
tostring | string[] | "all"даНомер, массив номеров (E.164) или «all» — всем сотрудникам справочника.
titlestringнет*Заголовок, до 100 символов. Лишнее обрезается.
bodystringнет*Текст, до 500 символов. Поддерживает кликабельные ссылки и переносы строк \n.
priority"normal" | "high"нетПо умолчанию normal. high — для срочного (инцидент, стоп-лист).
idempotencyKeystringнетЗащита от дублей: повтор с тем же ключом в течение 24 ч → 409.

* хотя бы одно из title/body должно быть непустым.

Ответ 202 Accepted

{
  "status": 202,
  "messageId": "msg_mrn8k2_a41f9c07",
  "recipients": 3,   // валидных получателей принято в обработку
  "delivered": 1,    // доставлено в открытое приложение прямо сейчас
  "pushed": 2        // отправлено push-уведомлением (устройство спало)
}

Гарантия доставки: сообщение сначала записывается в историю сотрудника и только потом доставляется — даже если телефон был выключен, сотрудник увидит сообщение при следующем запуске приложения. delivered/pushed — телеметрия момента отправки; проверять их в интеграции не нужно.

Кликабельные ссылки в тексте

В body работает markdown-формат [подпись](https://…) — в приложении подпись становится кликабельной, а в push-баннере сворачивается до чистого текста. «Голые» https://… распознаются автоматически.

"body": "ООО «М-Лайн», 10 699,50 ₽. В т.ч. НДС 5%.\n[Документ №37574](https://mbill.example/doc/37574)"

Идемпотентность и повторы

Если ваша система ретраит запросы, передавайте idempotencyKey, привязанный к бизнес-событию: invoice-37574, order-9912-created. Повтор с тем же ключом в течение 24 часов вернёт 409 duplicate, и сообщение не задублируется. Рекомендуемые ретраи: сетевые ошибки и 5xx — с экспоненциальной задержкой (1 с → 5 с → 30 с); 409 считать успехом; при 429 подождать минуту.

Ошибки и лимиты

КодТелоЧто значит и что делать
401unauthorizedНет или неверный apiKey. Проверьте заголовок Authorization.
400empty_messageПустые title и body одновременно.
400no_recipientsПоле to пустое или ни один номер не распознан как телефон.
403no_valid_recipientsНи один номер не найден в справочнике. Проверьте, что сотрудник заведён и активен.
409duplicateПовтор idempotencyKey за 24 ч. Для ретраев это успех — сообщение уже отправлено.
429rate_limitedБольше 60 сообщений в минуту от вашего отправителя. Подождите и повторите.
ЛимитЗначение
title100 символов (лишнее обрезается)
body500 символов (лишнее обрезается)
частота60 сообщений/мин на отправителя
история30 дней, последние 200 сообщений на сотрудника
вложениянет — канал текстовый, односторонний

Примеры кода

curl

curl -X POST https://lab.onecdp.ru/messages \
  -H "Authorization: Bearer $RATSIYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": ["+79991234567", "+79997654321"],
    "title": "Оплата по счёту №37574",
    "body": "ООО «М-Лайн», 10 699,50 ₽.\n[Документ №37574](https://mbill.example/doc/37574)",
    "priority": "high",
    "idempotencyKey": "invoice-37574-paid"
  }'

1С:Предприятие 8.3

Функция ОтправитьВРацию(Номер, Заголовок, Текст, КлючСобытия = "")
    Соединение = Новый HTTPСоединение("lab.onecdp.ru", 443, , , ,
        , Новый ЗащищенноеСоединениеOpenSSL);

    Тело = Новый Структура("to, title, body", Номер, Заголовок, Текст);
    Если ЗначениеЗаполнено(КлючСобытия) Тогда
        Тело.Вставить("idempotencyKey", КлючСобытия);
    КонецЕсли;

    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, Тело);

    Запрос = Новый HTTPЗапрос("/messages");
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + КонстантыКлючРации());
    Запрос.Заголовки.Вставить("Content-Type", "application/json");
    Запрос.УстановитьТелоИзСтроки(ЗаписьJSON.Закрыть());

    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    // 202 — принято; 409 — уже отправляли (для ретраев это успех)
    Возврат Ответ.КодСостояния = 202 Или Ответ.КодСостояния = 409;
КонецФункции

PHP

function sendRatsiya(string|array $to, string $title, string $body, ?string $idempotencyKey = null): ?array
{
    $payload = ['to' => $to, 'title' => $title, 'body' => $body];
    if ($idempotencyKey !== null) {
        $payload['idempotencyKey'] = $idempotencyKey;
    }

    $ch = curl_init('https://lab.onecdp.ru/messages');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . getenv('RATSIYA_API_KEY'),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
    ]);
    $response = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($status === 409) return null;                    // дубль — уже отправлено
    if ($status !== 202) throw new RuntimeException("ratsiya: HTTP $status");
    return json_decode($response, true);                 // ['messageId' => …]
}

sendRatsiya('+79991234567', 'Новый заказ №9912',
    "Сборка до 15:00.\n[Открыть заказ](https://wms.example/o/9912)",
    'order-9912-created');

Python

import os, requests

def send_ratsiya(to, title, body, key=None, priority="normal"):
    r = requests.post(
        "https://lab.onecdp.ru/messages",
        headers={"Authorization": f"Bearer {os.environ['RATSIYA_API_KEY']}"},
        json={"to": to, "title": title, "body": body,
              "priority": priority,
              **({"idempotencyKey": key} if key else {})},
        timeout=10,
    )
    if r.status_code in (202, 409):      # 409 = дубль, уже отправлено
        return r.json() if r.status_code == 202 else None
    r.raise_for_status()

send_ratsiya("+79991234567", "Новый заказ №9912",
             "Сборка до 15:00.\n[Открыть заказ](https://wms.example/o/9912)",
             key="order-9912-created")

Node.js

async function sendRatsiya(to, title, body, idempotencyKey) {
  const res = await fetch("https://lab.onecdp.ru/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.RATSIYA_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ to, title, body, idempotencyKey }),
  });
  if (res.status === 409) return null;          // дубль — уже отправлено
  if (res.status !== 202) throw new Error(`ratsiya: HTTP ${res.status}`);
  return res.json();                            // { messageId, recipients, … }
}

Чек-лист интеграции

  • apiKey хранится в секретах/конфигурации сервера, не в коде и не на клиенте.
  • Номера получателей — E.164 из вашей учётной системы; получатели заведены в справочнике компании.
  • Каждое бизнес-событие шлётся с idempotencyKey — ретраи не дублируют уведомления.
  • Обработаны 409 (успех) и 429 (подождать минуту); на 5xx — ретрай с backoff.
  • priority: high используется только для действительно срочного.
  • Тест на своём номере пройден: push пришёл, ссылка в сообщении открывается.

Ключ отправителя выдаёт владелец платформы при подключении услуги — оставьте заявку на странице «Рации». Приложение сотрудникам: скачать для Android и iPhone →