Введение
DeckHub — это «GitHub Pages для презентаций, заточенный под агентов». Вы (или ваш кодинг-агент) отдаёте один самодостаточный HTML-файл — получаете шаринговую ссылку и готовый показ. Подходит для трёх сценариев:
Слайдовый дек с навигацией стрелками/свайпом, прогрессом и фуллскрином (режим slides).
Длинный документ, который читают сверху вниз — отчёты, аналитика, дашборды (режим scroll).
Промо-страница с любым CSS/JS, которой можно поделиться одной ссылкой (режим scroll).
Файл нигде не конвертируется в PowerPoint и не редактируется руками: контент — это веб-страница, а DeckHub превращает её в шаринговую публикацию.
Для кого
Показывают и шарят презентации внутри компании. Вход — только через Google SSO с доменом deeplay.io.
Публикуют деки программно, используя персональный API-ключ hv_… — по MCP или по REST.
Ключевые идеи
| Идея | Что это значит |
|---|---|
| Agent-native | Публикация — это один вызов инструмента / HTTP-запрос, а не ручная загрузка и настройка. |
html или slides[] | Либо один самодостаточный дек, либо массив отдельных HTML-документов — каждый становится изолированным слайдом в своём <iframe srcdoc>. |
Режимы slides / scroll | Нарезка на слайды с навигацией — или длинная скролл-страница для лендингов и доков. |
| Два origin'а | Дашборд и сами деки живут на разных доменах — это граница безопасности: чужой JS дека не делит сессию с вашим кабинетом. |
Как это работает
Путь от HTML до показанной презентации:
<section>) либо массив страниц.publish_presentation, POST /api/presentations или загрузка файла в дашборде.<script src="viewer.js"> и отдаёт его на отдельном домене./v/:slug): при открытии проверяется вход и доступ, затем происходит переход на дек-ориджин с короткоживущим токеном. Только public-деки открываются напрямую без входа.viewer.js сам находит слайды, добавляет навигацию, прогресс, фуллскрин (F) и фиксирует просмотр.Быстрый старт
Три шага от нуля до опубликованной презентации.
hv_… показывается полностью один раз — сохраните его. Подробнее — в Аутентификации.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 | Отозвать ключ |
Подключение через Claude-коннектор OAuth
Самый простой путь для пользователей claude.ai (Web и Desktop). Вы добавляете DeckHub как «custom connector», входите своим рабочим Google-аккаунтом — и коннектор готов. Ключи раздавать не нужно: каждый пользователь авторизуется сам, токены выдаются и обновляются автоматически по OAuth 2.1.
DeckHub. Remote MCP server URL: /mcp. Поля OAuth Client ID / Secret в Advanced settings оставьте пустыми — клиент регистрируется автоматически (Dynamic Client Registration).@deeplay.io.Вход ограничен доменом 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 выдаёт админ (секрет показывается один раз):
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 (формат большинства клиентов):
Эндпоинт работает stateless: на каждый POST создаётся свежий сервер и транспорт, сессий не нужно. GET/DELETE на /mcp отвечают 405 — используйте только POST.
Инструменты
Сервер предоставляет четыре инструмента. Все возвращают текстовый контент с JSON-результатом; при ошибке — isError: true с сообщением.
publish_presentationwriteПубликует HTML-презентацию и возвращает рабочую ссылку для показа. Передайте либо html, либо slides. Ответ: { status, slug, url, slides_detected, workspace_id, mode, visibility }.
<section>.<iframe srcdoc>). Берите, когда у слайдов свои стили/шрифты, которые не должны конфликтовать.slides (по умолч.) или scroll. Применяется только к одиночному html-деку.workspace (по умолч.) — участники воркспейса и те, с кем поделились (после входа); internal — любой залогиненный сотрудник (для отчётов, которыми делитесь широко внутри компании); public — любой без входа (редкий случай — только по явной просьбе поделиться наружу).list_workspaces.update_presentationwriteЗаменяет HTML существующей презентации, сохраняя ту же ссылку.
publish_presentation).slides или scroll. Опустите, чтобы сохранить текущий режим.list_presentationsreadВозвращает доступные вам презентации с их ссылками и счётчиками просмотров. Параметров нет.
list_workspacesreadВозвращает воркспейсы, в которых вы состоите. Используйте id как workspace_id при публикации. Параметров нет.
Типичный сценарий
Псевдокод последовательности вызовов для агента:
# 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-ключами (см. Аутентификацию) |
Опубликовать дек
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 | Кто угодно по ссылке, без входа. Редкий случай — только когда явно нужно поделиться наружу. | Прямая, без токена |
# опубликовать сразу «на всю компанию» 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" }
Обновить и получить ссылку
# заменить 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. Персональные воркспейсы приглашать нельзя.
# получить постоянную ссылку-приглашение воркспейса (только модератор) 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 | Дек / воркспейс / пользователь / инвайт-токен не найдены |
405 | GET/DELETE на /mcp — используйте только POST |
410 | Вступление по недействительному инвайт-токену |
413 | HTML больше лимита загрузки |
429 | Слишком много запросов к парольным /api/auth/* (агентов с hv_-ключами не касается) |