---
title: "Погасить одноразовый токен запуска слота интерфейса"
method: POST
path: "/api/v1/app/slot-launch"
tags: ["App runtime"]
---

# Погасить одноразовый токен запуска слота интерфейса

`POST /api/v1/app/slot-launch`

## Request

- Base URL: `https://erp.akeda.ru`
- URL: `https://erp.akeda.ru/api/v1/app/slot-launch`
- Auth: HTTP bearer

Единственная дверь, за которой приложение узнаёт, кто из людей кабинета открыл его панель. Зовёт её сервер приложения своим токеном установки, предъявляя одноразовый токен запуска, который оболочка Akeda передала странице сообщением моста.

ЧТО ПРИЛОЖЕНИЕ УЗНАЁТ О ЧЕЛОВЕКЕ: псевдоним, язык и тему. Ни имени, ни почты, ни числового идентификатора, ни ролей. Псевдоним (actor.subject) свой у каждой пары «установка + человек»: он устойчив, поэтому панель помнит выбор конкретного сотрудника, и бесполезен за пределами установки. Числовой идентификатор не отдаётся потому, что реестр людей в Akeda общий на всю платформу — по нему приложение, стоящее в двух кабинетах, связало бы двух разных клиентов между собой. Псевдоним умирает вместе с установкой: после переустановки это для приложения новые люди.

ТОКЕН ОДНОРАЗОВЫЙ и живёт минуту. Он проходит через браузер человека, то есть попадает в код чужой страницы, её консоль и журналы её собственного сервера; многоразовый превратил бы каждый такой след в возможность назваться тем человеком. Второе предъявление отвечает 410 и остаётся в журнале установки отдельной записью — повтор означает либо утечку токена, либо переигрывание запросов приёмником, и разбирают это люди. Не дошедший запуск не чинится повтором: человек открывает панель заново, это одно нажатие.

NONCE придумывает САМА страница расширения и присылает его оболочке сообщением akeda.slot.ready; оболочка запрашивает запуск под этим значением и возвращает его тем же сообщением. Благодаря этому страница отличает ответ на свой запрос от чужого сообщения, посланного ей извне: проверки источника для этого мало — она доказывает, КТО прислал, но не то, что прислано в ответ. Неверный nonce отвечает 400 и живой запуск НЕ сжигает.

Кабинета в адресе нет: он берётся из токена установки. Чужой запуск отвечает 404 — тем же, чем отвечает несуществующий, потому что «есть, но не ваш» рассказало бы о запуске в соседнем кабинете.

КАКИМ ТОКЕНОМ ГАСИТЬ. Сообщение akeda.slot.launch несёт поле tenant — slug кабинета, в котором выдан запуск; тот же slug сервер приложения называет при самовыдаче токена установки (POST /api/v1/app/token). Сервер, обслуживающий много кабинетов, берёт токен установки этого кабинета и не перебирает остальные. Поле — открытая метка, а не доверие: страница могла назвать любой кабинет, и гашение его не читает. Запуск, предъявленный токеном установки другого кабинета, отвечает 404 и живым для своей установки остаётся. Поле может отсутствовать (оболочка прежней версии) — тогда приложение выбирает установку так же, как до его появления.

## Headers

- `X-Tenant` string, required

## Request body

- AppRuntimeSlotLaunchInput
  - `token` string, required: Одноразовый токен запуска (`al_…`), который оболочка передала странице сообщением akeda.slot.launch. Учётными данными не является: без токена установки он не открывает ничего
  - `nonce` string, required: Значение, которое страница расширения придумала сама и прислала оболочке сообщением akeda.slot.ready. Секретом не является — оно доказывает, что запуск отвечает именно на этот запрос страницы

## Response `200`

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

- AppRuntimeSlotLaunch
  - `tenant` AppRuntimeTenant, required
    - `id` string, uuid, required
    - `slug` string, required: Канонический slug кабинета из справочника, а не строка заголовка; его же ставят в X-Tenant следующего запроса
  - `installation_id` string, uuid, required
  - `slot` string, required: Ключ слота с версией: место на экране, откуда открыли панель
  - `nonce` string, required: Тот же nonce, что прислала страница: по нему сервер расширения связывает погашенный запуск с конкретной рамкой, не веря на слово ей самой
  - `actor` AppRuntimeSlotActor, required: Человек, открывший панель, в том объёме, в каком приложению позволено его знать. Имени, почты, ролей и числового идентификатора здесь нет и не появится: имя и почта — это штат клиента, роли — его оргструктура, а числовой идентификатор общий на всю платформу и связал бы два кабинета между собой. Карточка сотрудника (employee_id) — единственное поле, называющее человека настоящей записью кабинета, и приезжает она не всем: только слоту, который назвал actor_employee_id объявлением, и только в той версии, чей лист согласия кабинет читал. Общего на всю платформу в ней ничего нет — она живёт в базе кабинета, и тот же человек у двух клиентов это две разные строки, поэтому довод про связывание кабинетов к ней не относится.
    - `subject` string, uuid, required
    - `employee_id` string, uuid
    - `locale` 'ru' | 'en', required: Язык интерфейса человека: слот обязан показывать текст на русском и английском, и без языка он показал бы не тот
    - `theme` 'light' | 'dark', required: Тема кабинета. Слот, объявивший themeAware, без неё исполнить объявленное не может
  - `anchor` AppRuntimeSlotAnchor, required: Экран и запись, рядом с которыми стоит слот. Модуль назван всегда — по нему считается право ЧЕЛОВЕКА на запуск; вид и запись есть только у слота, стоящего на карточке. Само содержимое записи здесь не приезжает: читать её приложение идёт в public API своими одобренными scopes.
    - `module` string, required: Модуль экрана, с которого открыли панель
    - `entity` string: Вид записи. Отсутствует у слота без карточки
    - `entity_id` string: Идентификатор записи: uuid, код или номер документа
  - `origin` string, required: Источник, из которого оболочка загрузила рамку. Пусто, если кабинет успел обновить приложение на версию без этого слота: запуск был разрешён по прежнему объявлению и обрывать его незачем
  - `issued_at` string, date-time, required
  - `redeemed_at` string, date-time, required
  - `audit_id` string, uuid, required

## Other responses

- `400`: Некорректный запрос или нарушение бизнес-правила
- `401`: Сессия, ключ или кабинет не подтверждены
- `403`: Текущая роль не имеет требуемого права
- `404`: Такого запуска нет — в том числе если он принадлежит другой установке
- `410`: Запуск истёк или уже погашен: токен одноразовый, панель открывают заново

---

[API](https://skmtc.dev/akeda/apis/akeda-erp-client-api.md) · [All operations](https://skmtc.dev/akeda/apis/akeda-erp-client-api/llms.txt) · [OpenAPI document](https://skmtc.dev/akeda/apis/akeda-erp-client-api/revisions/3c60ded179f2?raw)
