Безопасность
Ключи — только на backend
X-API-Key и HMAC-секрет никогда не должны попадать в браузер, мобильное приложение, клиентский JavaScript, публичный HTML, логи или ответы вашего собственного API. Держите их в секретном хранилище backend api.vkusilosos.ru и подписывайте запрос непосредственно перед вызовом AploDelivery — см. Аутентификацию. Сервис проверяет минимальную длину: API-ключ ≥ 8 символов, секрет ≥ 32 символов (internal/auth/hmac.go); коротким значениям сервис откажет при старте.
Секрет вебхука (webhookSecret) — отдельная сущность, не переиспользует API-секрет: сервис отказывает в конфигурации, если оба совпадают (internal/auth/hmac.go, New). Он должен так же храниться только на вашем backend и использоваться исключительно для проверки подписи входящих вебхуков (см. Вебхуки).
Ротация
Ключ и секрет выпускаются и ротируются оператором AploDelivery (администрирование credentials в v1 — конфигурационное, через DELIVERY_CREDENTIALS_JSON; отдельный self-service API для выпуска/ротации ключа из docs/PARTNER_API_V2_SPEC.md §8 планируется). Процедура и SLA ротации: <уточняется>. Скомпрометированный ключ — сообщайте немедленно по каналу из Поддержки; до отзыва старого ключа рекомендуется параллельный выпуск нового и переключение трафика без окна простоя.
IP allowlist (опционально)
<уточняется>: в текущем коде (internal/auth, internal/httpapi) нет отдельного механизма allowlist по IP на уровне приложения — весь контроль доступа идёт через HMAC-подпись и scope credential (tenant/source/точки). Если вашему контуру требуется allowlist по IP как дополнительный рубеж, обсудите его на сетевом уровне (nginx/файрвол перед сервисом) при подключении — отдельного API для управления списком в v1 нет.
PII (персональные данные)
- Канонический заказ содержит PII гостя (имя, телефон, адрес, email) и шифруется AES-256-GCM перед записью в PostgreSQL (
DELIVERY_ENVELOPE_KEY, обязательная переменная окружения сервиса). - Структурные логи содержат только идентификаторы — tenant/source/order/node/state; тело заказа, номер телефона, адрес и содержимое вебхука в логи не пишутся.
- При сбое доставки вебхука в лог пишется причина без тела запроса/ответа (
internal/webhook/worker.go): секрет и URL назначения тоже не логируются. - На вашей стороне: не логируйте API-ключ, HMAC-секрет, тело заказа с PII и заголовок
X-Signatureв открытом виде; если нужен трейс запроса для поддержки — используйтеX-Request-ID.
Модель доверия к гостю (guest trust model)
Это принципиально важное правило для любого эндпоинта, который отдаёт данные или тратит баланс по номеру телефона гостя: партнёрский backend несёт полную ответственность за то, что телефон в запросе действительно принадлежит текущему авторизованному пользователю. AploDelivery доверяет присланному номеру телефона и не проверяет его самостоятельно — партнёр обязан аутентифицировать гостя (SMS-код, логин в своей системе и т. п.) ДО вызова эндпоинта с этим номером. Каждый вызов AploCard (calculate/hold/confirm/cancel) пишется в audit-лог (partner, хэш телефона, route, result — сам телефон в открытом виде не логируется); отдельный rate limit на телефон (DELIVERY_GUEST_LOYALTY_RATE_LIMIT_PER_MINUTE, по умолчанию 30 запросов/мин) снижает скорость перебора чужих номеров, но не заменяет аутентификацию на стороне партнёра.
Это правило применяется к двум группам эндпоинтов с разным статусом:
GET /v1/guests/{phone}/...(профиль, баланс лояльности, история заказов —docs/PARTNER_API_V2_SPEC.md§5) — ещё не задеплоены в v1, раздел зафиксирован заранее, чтобы модель доверия была понятна до интеграции.POST /v1/checkout/calculateиPOST /v1/orders(купон/бонус черезdocs/PARTNER_API_V2_SPEC.md§4, руководство по checkout) — эндпоинты доступны в v1, но купон и бонусы (Вкускоины) начнут применяться только на этапе 3; до этого поля купона и бонусов в запросе игнорируются расчётом (см. статус на странице Checkout).guest.phoneв теле запроса используется напрямую для обращения к AploCard (баланс бонусов, применимость купона, удержание суммы) ДО того, как заказ вообще создан — то же самое доверие к присланному телефону, но на уже живом, а не будущем эндпоинте.
Для остальных живых v1-эндпоинтов (заказы без checkout-полей, точки, адреса) прямого доступа по телефону гостя нет — guest.phone передаётся только внутри уже созданного заказа, привязанного к вашему credential и его scope (tenant + source + externalPoints), поэтому дополнительной проверки владения номером на этом этапе не требуется.
Scope и изоляция между партнёрами
Каждый credential ограничен ровно одним tenantId, одним source (call_center / mobile_app / website) и явным списком externalPoints. Запрос к объекту вне scope credential отвечает 404 not_found (никогда 403 на существующий чужой объект — чтобы не давать «оракул существования» чужих заказов); точка вне списка externalPoints credential отвечает 403 forbidden. Из этого правила есть одно исключение: GET /v1/orders/{id}?source= проверяет только source, но не point-scope (байт-совместимость со старыми интеграциями) — подробности и какие эндпоинты проверяют scope полностью см. в Справочнике ошибок.