Изображения и объектное хранилище
Полная справка по API: https://api.mailoo.app/docs/v1
Mailoo хранит пользовательские изображения в S3-совместимом объектном хранилище (AWS S3, MinIO и др.). Весь доступ проходит через API Mailoo; интеграторы и браузеры никогда не получают учётных данных S3 или внутренних ключей объектов.
Эта страница предназначена для команд, встраивающих интеграции Mailoo (блог, формы, чат и т. д.), которым нужно понять, как хранятся изображения статей и другие пользовательские ресурсы и как безопасно их читать.
- Пространство имён: Каждый пользователь панели управления получает выделенный префикс ключей
users/{userId}/в общем бакете (userId--- внутренний id пользователя Mailoo из базы данных, CUID). - Публичный идентификатор: Клиенты используют id медиа (CUID), возвращаемый API. S3-ключи --- только внутренние.
- Инициализация: API создаёт внутренний маркерный объект под этим префиксом при первой аутентифицированной активности (идемпотентно). Создание логируется на стороне сервера.
- Удаление: При удалении учётной записи пользователя через API объекты в
users/{userId}/удаляются из хранилища в рамках этого процесса. Удаление проекта / интеграции / статьи ставит в очередь фоновую очистку S3 для связанных ключей медиа. - Загрузка / удаление / производные: Потоки панели управления с Bearer-авторизацией (через вашу сессию / BFF). Не передавайте S3-ключи или учётные данные бакета браузерам или сторонним сайтам.
- Оригиналы vs ресурсы статей: Загрузка допускает более крупные оригиналы (до 25 МиБ до обработки);
POST /images/deriveсоздаёт масштабированные / перекодированные копии с той же областью, что и исходный файл. - Валидация: Тип файла проверяется по магическим байтам; EXIF-ориентация применяется и метаданные удаляются на стороне сервера. Анимированные GIF отклоняются.
- Канонические URL встраивания: Сохранённый markdown / HTML использует HTTP-URL Mailoo с ``?id={mediaId}`` на
/api/v1/images/public/content. Браузеры не могут обращаться по этому URL с API-ключом; интеграторы должны проксировать (см. ниже). - Внешнее чтение (API-ключ):
GET /api/v1/images/public/content?id=…с X-API-Key и областьюimage.external-read(или FULL ключом) возвращает байты только для READY медиа, принадлежащих пользователю API-ключа. - ``S3_PUBLIC_BASE_URL``: Опциональная внутренняя деталь только для API; она не раскрывается в JSON-ответах и не должна использоваться как публичный контракт изображений.
Маршруты изображений панели управления используют авторизованную Bearer-сессию. Чтение интеграторами --- X-API-Key с image.external-read (или FULL). Полные схемы: https://api.mailoo.app/docs/v1.
Операция Авторизация
Список изображений (курсор) Bearer; опциональные projectUid / integrationId / articleId для контекста видимости
Загрузка изображения (multipart) Bearer; поля формы file, scope, опциональные id контекста
Создание производного (масштаб / формат / сжатие) Bearer; JSON sourceId и хотя бы одно из maxWidth, maxHeight, format
Получение байтов изображения (владелец) Bearer; GET /images/{id}/content
Обновление / удаление по id Bearer
Получение байтов изображения (интегратор / сервер) X-API-Key с image.external-read (или FULL); id должен ссылаться на READY медиа пользователя ключа
Модель безопасности (нормативная)
- Владелец --- аутентифицированный id пользователя Mailoo из JWT или API-ключа --- никогда не клиентский user id.
- ``projectUid`` / ``integrationId`` / ``articleId`` --- контекст внутри данных этого владельца; API разрешает и проверяет цепочку.
- S3-ключи никогда не возвращаются клиентам.
- Ограниченные API-ключи должны включать
image.external-readдля вызова публичного эндпоинта чтения.
Медиа хранится с одной из областей USER, PROJECT, INTEGRATION или ARTICLE. Запрос списка с контекстом возвращает READY элементы, видимые в этом редакторском контексте.
Каждая интеграция Blog может хранить собственные API-ключи Unsplash и Pexels в разделе Подключение и настройки (зашифрованы в integration.config.stockPhotos; никогда не возвращаются в открытом виде). Платформенных стоковых API-ключей нет.
В панели изображений редактора статей вкладка Stock выполняет поиск с ключами этой интеграции. При выборе фото импортируются байты в UserMedia (те же области и публичные URL встраивания, что и при обычной загрузке). Отслеживание скачиваний Unsplash использует ключ Unsplash интеграции при импорте.
API панели управления (Bearer, редактор проекта):
GET /api/v1/projects/{uid}/integrations/{id}/stock/search?provider=unsplash|pexels&q=…POST /api/v1/projects/{uid}/integrations/{id}/stock/import--- тело включаетprovider,externalId,scopeи опциональные id иерархии
Базовый путь: {apiBase}/api/v1/images.
Список (Bearer, курсор)
GET /api/v1/images --- параметры: limit (1--100, по умолчанию 24), cursor, опциональные фильтры projectUid, integrationId, articleId, scope, includeNonReady=true. Ответ: items, nextCursor, imagePublicEmbedBaseUrl.
Загрузка (Bearer)
POST /api/v1/images --- multipart: file, scope (USER | PROJECT | INTEGRATION | ARTICLE), плюс поля контекста по области (projectUid, integrationId, articleId при необходимости). Ответ содержит id, embedUrl, imagePublicEmbedBaseUrl, метаданные --- без S3-ключа.
Создание производного (Bearer)
POST /api/v1/images/derive --- JSON: sourceId, опциональные maxWidth, maxHeight, format, quality. Хотя бы одно из maxWidth, maxHeight или format обязательно.
Получение контента (Bearer)
GET /api/v1/images/{id}/content --- сырые байты для READY медиа.
Опциональное масштабирование на лету (тот же конвейер sharp, что и derive): параметры запроса ``w``, ``h``, ``fit`` (inside | cover | fill, по умолчанию inside), ``format`` (jpeg | jpg | png | webp), ``q`` (1--100, по умолчанию 85). Хотя бы один из ``w``, ``h`` или ``format`` должен быть указан для включения обработки; иначе объект стримится как есть.
Обновление / удаление (Bearer)
PATCH /api/v1/images/{id}--- JSONname,altText.DELETE /api/v1/images/{id}--- удаление одного медиа с outbox повторов S3 при сбое.
Получение контента (API-ключ)
GET /api/v1/images/public/content?id={mediaId} --- X-API-Key; только для серверных прокси. Те же опциональные параметры трансформации, что и у Bearer-маршрута контента (``w``, ``h``, ``fit``, ``format``, ``q``), применяются при указании хотя бы одного из ``w``, ``h`` или ``format``.
Предварительно сгенерированные варианты через ``POST /api/v1/images/derive`` по-прежнему поддерживаются для стабильных URL (новый id медиа для каждого варианта).
Прокси интегратора и HTML блога
Полезные нагрузки статей Blog API включают ``imagePublicEmbedBaseUrl`` (префикс, заканчивающийся на ?id=). Ответ списка статей также повторяет тот же префикс на верхнем уровне (рядом с data / pagination). Ответы описания категории включают ``imagePublicEmbedBaseUrl`` в data, когда HTML описания может ссылаться на изображения Mailoo. Сохранённый ``htmlContent`` использует абсолютные канонические публичные URL под ``API_PUBLIC_URL``; замените эти URL в HTML на URL прокси вашего сайта с тем же id медиа.
Используйте ``rewriteMailooPublicImageUrls`` из ``@mailoo/images`` (также реэкспортируется для хостов, уже зависящих от этого пакета). См. nextjs-packages{.interpreted-text role="doc"}.
Конфигурация оператора (только API)
Устанавливается на хосте API (не в браузере):
Переменная Назначение
API_PUBLIC_URL Публичный базовый URL API (без завершающего слэша); используется для канонических URL встраивания
S3_BUCKET Имя бакета (обязательно)
S3_REGION Регион (по умолчанию us-east-1 если не задан)
S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY Учётные данные (обязательно)
S3_ENDPOINT Пользовательский эндпоинт для MinIO / S3-совместимых (необязательно)
S3_FORCE_PATH_STYLE true для многих конфигураций MinIO (необязательно; по умолчанию path-style при наличии S3_ENDPOINT)
S3_PUBLIC_BASE_URL Необязательно; внутренняя деталь только для API --- не является частью публичного контракта интеграции
Эти переменные относятся только к развёртыванию API (никогда в браузере).
nextjs-packages{.interpreted-text role="doc"} --- фабрика прокси@mailoo/imagesblog-headless-cms{.interpreted-text role="doc"}website-forms{.interpreted-text role="doc"}- OpenAPI:
https://api.mailoo.app/docs/v1