К содержанию

Все статьи

Provider API v1

Emperor забирает зарегистрированных пользователей и дневную активность из приложений по общему контракту. Его реализует любое приложение, не только собственные. Источник (приложение) сохраняется, повторная синхронизация обновляет данные. Один человек из нескольких приложений не создаёт дубль Person.

Страница для команд, которые реализуют контракт. Машиночитаемая спецификация OpenAPI 3.1: спецификация Provider API. Клиентские типы генерируют из этого пути на том же origin, что и сайт.

v1 — черновик, может меняться до финализации. После финализации несовместимые изменения выходят как /v2.

Ресурсы

Приложение отдаёт три GET-ресурса под /v1 относительно baseUrl соединения Facility:

  • /v1/manifest — версия контракта (1), название приложения, IANA часовой пояс агрегации дней и каталог ключей активности с подписями.
  • /v1/users — пользователи. Запрос: updatedSince, cursor, limit.
  • /v1/activity — дневные агрегаты: одна строка на пользователя, день и ключ из каталога. Те же параметры запроса, что у users.

Если contractVersion не 1, Emperor отклоняет подключение с явной ошибкой.

Курсоры и перезапись активности

updatedSince — datetime ISO-8601 со смещением или Z. Нужно отдать записи с updatedAt больше или равным этому значению. Без параметра — полная выгрузка. cursor — непрозрачная строка из nextCursor предыдущей страницы. limit по умолчанию 100, максимум 100.

Ответ списка: { "data": [...], "nextCursor": null | string }. nextCursor равен null на последней странице.

Поздняя строка активности для той же корзины (externalUserId, day, metricKey) перезаписывает сохранённый счётчик. Приложение отдаёт дневные итоги, а не сырые события.

Email или телефон

У каждой записи должен быть email, phone (E.164, например +79991234567) или оба. Запись без того и другого контракт отклоняет. В статистике синхронизации она учитывается как отклонённая, Person не создаётся.

Как Emperor склеивает контакты

Человек в CRM — Person. Email и телефон — строки Contact (типы EMAIL и TELEPHONE). Идентичность в приложении живёт на отдельной связке: один человек — несколько приложений.

  • Email нормализуется. Телефон хранится в E.164.
  • Уже связанная идентичность обновляется.
  • Новая идентичность без совпадений создаёт Person.
  • Любое совпадение с существующим Person, включая конфликт email/телефона, попадает в очередь ручной проверки. Автослияния нет.

Чек-лист подключения

  1. В production публиковать /v1/manifest, /v1/users и /v1/activity только по HTTPS.
  2. Выдать Bearer-токен с высокой энтропией на связку проект–приложение, только чтение Provider API. Не использовать общий ключ сервиса.
  3. Сравнивать токен за постоянное время. Запрос без валидного Bearer — 401 в RFC 7807 application/problem+json. Не различать «токена нет» и «токен неверен».
  4. Принимать User-Agent: Emperor-AppProvider/1.0 и X-Request-Id (UUID). Тот же id возвращать в problem-документе при ошибке.
  5. При 429 отдавать Retry-After.
  6. Ротация: в окне ротации принимать текущий и предыдущий токен, затем отозвать старый.
  7. В локальной разработке plain HTTP для baseUrl разрешён только при APP_PROVIDER_ALLOW_PLAIN_HTTP=true (выставляет dev-скрипт frontend). В production принимается только HTTPS.

Безопасность и аудит-лог приложения

v1 — HTTPS и Bearer-токен на связку проект–приложение. HMAC, mTLS и OAuth2 в эту версию не входят.

Рекомендуется (не требование схемы): на каждый запрос Provider API писать время, исходящий IP, X-Request-Id, User-Agent, ресурс (manifest / users / activity), updatedSince, HTTP-статус и число отданных записей. Не писать токен, заголовок Authorization, email, телефон и тела ответов.

Также: отдельный токен только для этого API; rate limit; алерты на пачку 401, чужой User-Agent, неожиданный IP, резкий рост объёма. IP allowlist не требовать: egress Emperor в Kubernetes не фиксирован.

Статьи