В дашборд
Документация

DeckHub

Сервис для публикации самодостаточного HTML — презентаций, репортов и лендингов. Отдаёте один HTML-файл — получаете шаринговую ссылку и показ: слайдами (с полноэкранной навигацией) или длинной скролл-страницей. Публиковать можно двумя способами: по MCP (для AI-агентов) или по REST API (для любого HTTP-клиента).

Введение

DeckHub — это «GitHub Pages для презентаций, заточенный под агентов». Вы (или ваш кодинг-агент) отдаёте один самодостаточный HTML-файл — получаете шаринговую ссылку и готовый показ. Подходит для трёх сценариев:

Презентации

Слайдовый дек с навигацией стрелками/свайпом, прогрессом и фуллскрином (режим slides).

Репорты

Длинный документ, который читают сверху вниз — отчёты, аналитика, дашборды (режим scroll).

Лендинги

Промо-страница с любым CSS/JS, которой можно поделиться одной ссылкой (режим scroll).

Файл нигде не конвертируется в PowerPoint и не редактируется руками: контент — это веб-страница, а DeckHub превращает её в шаринговую публикацию.

Для кого

Сотрудники Deeplay

Показывают и шарят презентации внутри компании. Вход — только через Google SSO с доменом deeplay.io.

AI-агенты

Публикуют деки программно, используя персональный API-ключ hv_… — по MCP или по REST.

Ключевые идеи

ИдеяЧто это значит
Agent-nativeПубликация — это один вызов инструмента / HTTP-запрос, а не ручная загрузка и настройка.
html или slides[]Либо один самодостаточный дек, либо массив отдельных HTML-документов — каждый становится изолированным слайдом в своём <iframe srcdoc>.
Режимы slides / scrollНарезка на слайды с навигацией — или длинная скролл-страница для лендингов и доков.
Два origin'аДашборд и сами деки живут на разных доменах — это граница безопасности: чужой JS дека не делит сессию с вашим кабинетом.

Как это работает

Путь от HTML до показанной презентации:

Генерация. Агент или человек создаёт один HTML-файл (каждый слайд — <section>) либо массив страниц.
Публикация. Вызов MCP publish_presentation, POST /api/presentations или загрузка файла в дашборде.
Хостинг. DeckHub сохраняет дек, вставляет ровно один <script src="viewer.js"> и отдаёт его на отдельном домене.
Ссылка. Ссылка для шаринга — постоянная, на app-ориджине (/v/:slug): при открытии проверяется вход и доступ, затем происходит переход на дек-ориджин с короткоживущим токеном. Только public-деки открываются напрямую без входа.
Показ. Зритель открывает ссылку → viewer.js сам находит слайды, добавляет навигацию, прогресс, фуллскрин (F) и фиксирует просмотр.

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

Три шага от нуля до опубликованной презентации.

Получите API-ключ. В дашборде откройте «Подключить агента» → «Сгенерировать». Ключ вида hv_… показывается полностью один раз — сохраните его. Подробнее — в Аутентификации.
Выберите канал. MCP — если публикует AI-агент через MCP-клиент. REST — для любого HTTP-клиента (curl, скрипт, бэкенд).
Опубликуйте дек. Передайте HTML — в ответ придёт slug и готовая ссылка для показа.

Выберите канал подключения:

Аутентификация

Эндпоинт /mcp и REST принимают один механизм: заголовок Authorization: Bearer <токен>. Принимаются три вида токенов:

ТипПрефиксДля когоСрок
API-ключhv_…Агенты / автоматизация (MCP-конфиг, REST)Не истекает (отзывается вручную)
OAuth access-token (JWT)Claude-коннектор — выдаётся автоматически после входа1 час, обновляется по refresh-токену
Сессионный JWTЧеловек после входа в дашбордИстекает (по умолчанию 7 дней)

Подключаете claude.ai? Ничего раздавать не нужно — используйте Claude-коннектор: вход через Google, токены выдаются и обновляются автоматически. hv_-ключ нужен только для агентов и других MCP-клиентов (ручной конфиг) или REST — он не истекает и привязан к пользователю.

Управление ключами

Ключи можно создавать в дашборде или через REST. POST /api/keys возвращает плейнтекст ключа единственный раз — сразу сохраните его. Дальше ключ доступен только по префиксу.

МетодПутьДействие
POST/api/keysСоздать ключ (опц. name) → { id, key, key_prefix, name }
GET/api/keysПеречислить ключи (без плейнтекста — только key_prefix)
DELETE/api/keys/:idОтозвать ключ

Формат дека

Раздел общий для обоих каналов — и MCP, и REST принимают один и тот же контент. DeckHub не трогает ваш HTML: он лишь инжектит один <script> (viewer.js), который на стороне клиента находит слайды и добавляет навигацию, прогресс, полноэкранный режим и beacon просмотра. Плюс два мобильных удобства: если в деке нет своего <meta name="viewport">, он добавляется автоматически, а слайды, свёрстанные под фиксированную десктопную ширину, ужимаются по ширине экрана телефона (адаптивные деки не трогаются).

Вариант A — один самодостаточный HTML (html)

Один документ, где каждый слайд обёрнут в <section>. Viewer определяет слайды по соглашению: <section>, reveal.js, [data-slide] или .slide.

deck.htmlhtml
<!doctype html>
<html><body>
  <section><h1>Заголовок</h1></section>
  <section><h2>Слайд 2</h2></section>
  <section><p>Спасибо</p></section>
</body></html>

Вариант B — массив страниц (slides)

Массив отдельных HTML-документов. Сервер собирает их в один дек, где каждый документ живёт в своём <iframe srcdoc> — полная изоляция стилей, слайды с разными :root/шрифтами/дизайном не конфликтуют.

Режим показа — slides или scroll

Параметр mode управляет тем, как дек отображается. Применяется к одиночному html-деку; массив slides всегда показывается как слайды.

РежимПоведениеКогда брать
slides (по умолч.)Страница нарезается на слайды, навигация стрелками/свайпом.Обычные презентации.
scrollДокумент рендерится как есть — одна длинная скролл-страница.Лендинги, доки, всё, что читают сверху вниз.

Для телефона — резиновая вёрстка: задавайте размеры относительно экрана (min-height:100vh, отступы и шрифты через clamp()), а не фиксированной шириной. Тогда дек тянется под телефон сам. Ужимание слайдов фиксированной десктопной ширины по ширине экрана — это фоллбэк на крайний случай, он слегка мылит текст.

MVP-компромисс: ассеты не вендорятся — внешние CDN-ресурсы грузятся как есть. Дек открывается на отдельном origin (:3001 в dev) — это граница безопасности: недоверенный JS дека не выполняется на origin дашборда.

Подключение через Claude-коннектор OAuth

Самый простой путь для пользователей claude.ai (Web и Desktop). Вы добавляете DeckHub как «custom connector», входите своим рабочим Google-аккаунтом — и коннектор готов. Ключи раздавать не нужно: каждый пользователь авторизуется сам, токены выдаются и обновляются автоматически по OAuth 2.1.

Откройте добавление коннектора. В Claude → Settings → Connectors → Add custom connector.
Заполните два поля. Name: DeckHub. Remote MCP server URL: /mcp. Поля OAuth Client ID / Secret в Advanced settings оставьте пустыми — клиент регистрируется автоматически (Dynamic Client Registration).
Нажмите Connect и войдите. Откроется вход через Google — авторизуйтесь рабочим аккаунтом @deeplay.io.
Подтвердите доступ. На экране согласия нажмите «Разрешить» — коннектор подключён, инструменты DeckHub доступны в чате.

Вход ограничен доменом deeplay.io — авторизоваться через коннектор могут только сотрудники. Защита кода — PKCE (S256); access-токен живёт 1 час и прозрачно обновляется по refresh-токену. Публикации создаются от имени вошедшего пользователя и попадают в его воркспейсы.

Эндпоинты OAuth

Claude находит их сам через discovery — таблица для справки и для других OAuth-совместимых MCP-клиентов.

НазначениеПуть
Метаданные защищённого ресурса (RFC 9728)/.well-known/oauth-protected-resource/mcp
Метаданные сервера авторизации (RFC 8414)/.well-known/oauth-authorization-server
Динамическая регистрация клиента (RFC 7591)POST /register
Авторизация (PKCE S256)GET /authorize
Выдача / обновление токенаPOST /token
Отзыв токенаPOST /revoke

Для агентов и MCP-клиентов без OAuth используйте подключение по MCP с hv_-ключом — оно проще, когда OAuth-логина в браузере нет.

Платформы-коннекторы: сервисная авторизация

Некоторые платформы (например Sigma → Manage Workspace → Connectors) читают список инструментов до того, как хоть один пользователь авторизовался, — под сервисной учёткой. Для этого поддерживается грант client_credentials. Сервисный токен умеет ровно одно: initialize, ping и tools/list. Вызвать инструмент им нельзя — вызовы идут по пользовательским токенам, поэтому каждая публикация остаётся привязанной к реальному аккаунту.

Пару client_id/client_secret выдаёт админ (секрет показывается один раз):

service clientbash
curl -s -X POST http://localhost:3000/api/oauth/service-clients \
  -H "Authorization: Bearer hv_…" -H "Content-Type: application/json" \
  --data-binary '{"name":"Sigma"}'

# -> { "client_id":"svc_…", "client_secret":"svs_…", "issuer":"https://…",
#      "token_endpoint":"https://…/token", "scope":"mcp", "resource":"https://…/mcp" }

В ответе — всё, что просит форма коннектора: issuer, token_endpoint, scope (mcp), resource (/mcp) и метод аутентификации client_secret_post. Список всех клиентов — GET /api/oauth/clients, удаление — DELETE /api/oauth/clients/<client_id>; для сервисного клиента удаление отзывает его токены сразу же. Пользовательский OAuth настраивается отдельно и независимо — именно он даёт вызовы от имени каждого сотрудника.

Подключение по MCP

Канал для AI-агентов. MCP-сервер deckhub доступен как Streamable-HTTP эндпоинт /mcp и публикует дек одним вызовом инструмента.

Конфигурация клиента

Пропишите эндпоинт в конфиге вашего MCP-клиента с ключом в заголовке Authorization (формат большинства клиентов):

mcp-config.jsonjson

        

Эндпоинт работает stateless: на каждый POST создаётся свежий сервер и транспорт, сессий не нужно. GET/DELETE на /mcp отвечают 405 — используйте только POST.

Инструменты

Сервер предоставляет четыре инструмента. Все возвращают текстовый контент с JSON-результатом; при ошибке — isError: true с сообщением.

publish_presentationwrite

Публикует HTML-презентацию и возвращает рабочую ссылку для показа. Передайте либо html, либо slides. Ответ: { status, slug, url, slides_detected, workspace_id, mode, visibility }.

htmlstring · опц.
Полный HTML одного самодостаточного дека. Каждый слайд — в своём <section>.
slidesstring[] · опц.
Массив самостоятельных HTML-документов; каждый становится одним изолированным слайдом (через <iframe srcdoc>). Берите, когда у слайдов свои стили/шрифты, которые не должны конфликтовать.
titlestring · опц.
Заголовок презентации.
modeenum · опц.
slides (по умолч.) или scroll. Применяется только к одиночному html-деку.
visibilityenum · опц.
workspace (по умолч.) — участники воркспейса и те, с кем поделились (после входа); internal — любой залогиненный сотрудник (для отчётов, которыми делитесь широко внутри компании); public — любой без входа (редкий случай — только по явной просьбе поделиться наружу).
workspace_idnumber · опц.
ID воркспейса для публикации (по умолчанию — ваш первый). Список — через list_workspaces.
update_presentationwrite

Заменяет HTML существующей презентации, сохраняя ту же ссылку.

slugstring · обяз.
Идентификатор презентации (из ответа publish_presentation).
htmlstring · обяз.
Новый полный HTML дека.
titlestring · опц.
Новый заголовок.
modeenum · опц.
slides или scroll. Опустите, чтобы сохранить текущий режим.
list_presentationsread

Возвращает доступные вам презентации с их ссылками и счётчиками просмотров. Параметров нет.

list_workspacesread

Возвращает воркспейсы, в которых вы состоите. Используйте id как workspace_id при публикации. Параметров нет.

Типичный сценарий

Псевдокод последовательности вызовов для агента:

agent-flowpseudo
# 1. (опц.) узнать, в какой воркспейс публиковать
ws = list_workspaces()

# 2. опубликовать дек
res = publish_presentation(
  html = "<!doctype html>…<section>…</section>…",
  title = "Q3 review",
  workspace_id = ws[0].id,
)
# -> { status:"published", slug:"…", url:"https://…/v/…", mode:"slides", visibility:"workspace" }

# 3. позже — обновить тот же дек (ссылка не меняется)
update_presentation(slug = res.slug, html = "…новый HTML…")

# 4. проверить просмотры
list_presentations()

Поле url в ответе — это постоянная ссылка для шаринга. Для workspace и internal деков она ведёт на app-ориджин (/v/:slug): открывающему нужен вход в DeckHub, доступ проверяется на месте. Для public-деков ссылка прямая и открывается без входа. GET /api/presentations/:slug/link дополнительно возвращает direct — подписанную прямую ссылку (?t=…) для немедленного открытия без сессии.

Подключение по REST API

Те же действия доступны по обычному HTTP — для любого клиента без MCP (curl, скрипт, бэкенд). Тот же заголовок Authorization: Bearer hv_… и тот же контент (формат дека).

Эндпоинты

Презентации

МетодПутьДействие
POST/api/presentationsОпубликовать (html | slides, title, mode, visibility, workspace_id)
PUT/api/presentations/:slugОбновить HTML (html, title, mode) — ссылка не меняется
GET/api/presentationsСписок доступных деков со ссылками, видимостью и просмотрами
DELETE/api/presentations/:slugУдалить дек (автор или модератор воркспейса)
GET/api/presentations/:slug/linkСсылки для показа: url (постоянная, через вход) + direct (подписанная ?t=)
PATCH/api/presentations/:slug/visibilityСменить видимость (workspace | internal | publicсм. ниже)
PATCH/api/presentations/:slug/modeСменить режим показа (slides | scroll)

Доступ к деку — персональный шеринг (дополняет visibility: даёт конкретному человеку доступ к workspace-деку, не открывая его всем)

МетодПутьДействие
GET/api/presentations/:slug/sharesС кем поделились → [{ id, email }]
POST/api/presentations/:slug/sharesПоделиться с пользователем по email (он должен быть зарегистрирован)
DELETE/api/presentations/:slug/shares/:userIdОтозвать персональный доступ

Воркспейсы, участники и заявки

МетодПутьДействие
GET/api/workspacesСписок своих воркспейсов (с member_count)
GET/api/workspaces/:idДетали: участники; модератору — ещё pending (заявки) и invite (ссылка)
POST/api/workspacesСоздать воркспейс (name) — только админ платформы; создатель становится модератором
DELETE/api/workspaces/:idУдалить воркспейс со всеми его деками — только админ (личный удалить нельзя)
POST/api/workspaces/:id/membersДобавить участника по email (+ role: member | moderator) — доступ сразу
PATCH/api/workspaces/:id/members/:userIdСменить роль участника
DELETE/api/workspaces/:id/members/:userIdУбрать участника
GET/api/workspaces/:id/inviteПостоянная ссылка-приглашение → { token, url } (только модератор)
POST/api/workspaces/:id/requests/:userId/approveОдобрить заявку на вступление
DELETE/api/workspaces/:id/requests/:userIdОтклонить заявку
GET/api/invites/:tokenИмя воркспейса по инвайт-токену (без авторизации)
POST/api/invites/:token/joinПодать заявку на вступление (от имени вошедшего)
GET/api/decks/:slug/requestИмя воркспейса за деком + joinable (без авторизации)
POST/api/decks/:slug/requestЗапросить доступ к воркспейсу дека → та же заявка на вступление

Служебные

МетодПутьДействие
GET/api/meКто я: { id, email, is_admin, workspaces } — удобно проверить ключ
GET / POST / DELETE/api/keysУправление API-ключами (см. Аутентификацию)

Опубликовать дек

publishbash
curl -s -X POST http://localhost:3000/api/presentations \
  -H "Authorization: Bearer hv_…" \
  -H "Content-Type: application/json" \
  --data-binary '{"title":"demo","html":"<section>hi</section>"}'

# -> { "slug":"…", "url":"https://…/v/…",
#      "slides_detected":1, "workspace_id":1, "mode":"slides", "visibility":"workspace" }

Видимость — visibility

Передаётся при публикации (POST /api/presentations) или меняется потом (PATCH /api/presentations/:slug/visibility). Определяет, кто откроет ссылку дека.

ЗначениеКто видитСсылка
workspace (по умолч.)Автор, участники воркспейса и те, с кем явно поделились — после входа.Постоянная, /v/:slug
internalЛюбой залогиненный сотрудник — для отчётов «на всю компанию».Постоянная, /v/:slug
publicКто угодно по ссылке, без входа. Редкий случай — только когда явно нужно поделиться наружу.Прямая, без токена
visibilitybash
# опубликовать сразу «на всю компанию»
curl -s -X POST http://localhost:3000/api/presentations \
  -H "Authorization: Bearer hv_…" -H "Content-Type: application/json" \
  --data-binary '{"title":"quarterly","html":"…","visibility":"internal"}'

# сменить видимость существующего дека
curl -s -X PATCH http://localhost:3000/api/presentations/SLUG/visibility \
  -H "Authorization: Bearer hv_…" -H "Content-Type: application/json" \
  --data-binary '{"visibility":"internal"}'
# -> { "slug":"…", "visibility":"internal" }

Обновить и получить ссылку

update + linkbash
# заменить HTML, ссылка не меняется
curl -s -X PUT http://localhost:3000/api/presentations/SLUG \
  -H "Authorization: Bearer hv_…" -H "Content-Type: application/json" \
  --data-binary '{"html":"<section>v2</section>"}'

# ссылки для показа: url — постоянная (вход через DeckHub),
# direct — подписанная, открывается сразу и без сессии
curl -s http://localhost:3000/api/presentations/SLUG/link \
  -H "Authorization: Bearer hv_…"
# -> { "slug":"…", "url":"https://…/v/…", "direct":"https://…/p/…?t=…" }

Пригласить в воркспейс

У каждого воркспейса есть одна постоянная ссылка-приглашение. Любой, кто перейдёт по ней и войдёт в DeckHub, может нажать «Вступить» — создаётся заявка, которую одобряет модератор воркспейса — в дашборде или по REST (approve / reject в таблице выше). До одобрения человек не получает доступа к декам воркспейса. Ссылку выдаёт модератор — из дашборда (модалка «Участники») или по REST. Персональные воркспейсы приглашать нельзя.

invite linkbash
# получить постоянную ссылку-приглашение воркспейса (только модератор)
curl -s http://localhost:3000/api/workspaces/1/invite \
  -H "Authorization: Bearer hv_…"
# -> { "id":7, "token":"inv_…", "url":"https://…/join/inv_…" }

# ссылкой делятся с людьми; они переходят, входят и жмут «Вступить»,
# затем модератор одобряет заявку в дашборде → доступ выдан

Лимиты и ошибки

ЧтоЗначение
Макс. размер загрузки10 MB (настраивается через MAX_UPLOAD_BYTES); превышение → 413
Срок ссылки на декurl — постоянная (доступ проверяется при открытии); direct с ?t=12 ч (настраивается)
Ошибка инструментаMCP-ответ с isError: true и текстом Error: …

Коды ошибок REST

Тело ошибки всегда одно: { "error": "человекочитаемое сообщение" }.

КодКогда
400Невалидные параметры: пустой html/slides, неизвестные mode/visibility/role
401Нет токена, неверный или отозванный (invalid or missing credentials)
403Нет прав: не участник воркспейса, не модератор, персональный воркспейс для инвайта
404Дек / воркспейс / пользователь / инвайт-токен не найдены
405GET/DELETE на /mcp — используйте только POST
410Вступление по недействительному инвайт-токену
413HTML больше лимита загрузки
429Слишком много запросов к парольным /api/auth/* (агентов с hv_-ключами не касается)
DeckHub · agent-native presentation hosting Дашборд Статус