Полная справка по API: https://api.mailoo.app/docs/v1
Используйте Mailoo как централизованную headless-CMS для блога: создавайте и управляйте статьями в панели управления, а доставляйте их через внешний API по проекту. Внешние сайты (или ваш собственный) могут потреблять тот же API.
Обзор
Интеграция блога работает как другие интеграции Mailoo (например, Form): вы добавляете интеграцию Blog к проекту. Все статьи этого блога принадлежат этой интеграции. API не предоставляет доступ к статьям блога без авторизации. API чтения: список статей и получение одной по slug; требует X-API-Key с областью blog.external-read; доступ по UID проекта и ID интеграции. API управления: создание, обновление и удаление статей с X-API-Key и областью blog.manage (тот же путь /api/v1/blog/.../articles). Агенты могут использовать MCP-сервер Mailoo с персональным токеном MCP, созданным в Профиль → Безопасность; см. mailoo-mcp{.interpreted-text role="doc"}.
Возможности:
- Создание, редактирование и удаление статей в панели управления Mailoo (для каждой интеграции) или через API управления / MCP с
blog.manage - Публикация как черновик или опубликованная; опциональные отрывок, SEO-метаданные (
metaTitle,metaDescription,ogImageMediaId→ публичныйogImageUrl), классификаторы (темы, интенты, аудитории, SEO-кластеры), теги - API чтения (требуется X-API-Key): список опубликованных статей и получение одной по slug, по UID проекта и ID интеграции
- API управления (X-API-Key +
blog.manage):POST/GET/PUT/DELETE …/blog/{projectUid}/integrations/{integrationId}/articles; список значений классификаторов сblog.external-readилиblog.manage - Ответ по статье (список): id, title, slug, excerpt, content (Markdown, основной источник), htmlContent (HTML, сгенерированный из content API; используйте для отображения), status, publishedAt, createdAt, updatedAt, author (id, name, email?, avatar, bio --- локализованные при указании
locale), category (основная тема для обратной совместимости: первая тема по slug или null), themes, intents, audiences, seoClusters (каждый --- массив{ id, slug, name }), metaTitle, metaDescription (null если не задано --- потребители могут использоватьtitle/excerpt), ogImageUrl (null если не задано), canonicalUrl (абсолютный URL при настроенном каноническом шаблоне интеграции; иначе null), seoWords ([{ slug, word }]--- объединение записей каталога SEO-слов интеграции, привязанных к SEO-кластерам статьи; локализованные при указанииlocale; пустой массив если отсутствуют), featured, readTimeMinutes, tags (массив, по умолчанию []). Пагинация включаетpage,limit,total,totalPages,hasNextPage,hasPrevPage. Встроенные изображения используют URL API изображений Mailoo (см.images{.interpreted-text role="doc"}); отдельного поляimageверхнего уровня у статьи нет. - Ответ по статье (одна по slug): те же поля, что и в элементе списка, плюс опциональные linkedLinks --- упорядоченный массив (макс. 10 на статью) курированных ссылок:
id,type(internal_article|update_announcement|external_resource),label,url,intro(может быть null),date(может быть null, ISO datetime),sortOrder. Внутренние ссылки используют путь того же сайта/blog/{targetSlug}вurl; при построении публичного href добавьте сегмент локали (например,/{locale}/blog/...). Редакторы управляют ссылками в панели управления; строкиinternal_articleмогут автоматически заполнять label/date/intro из целевой статьи с опциональными переопределениями. - JSON-LD (опционально):
GET …/slug/{slug}/json-ld?locale=возвращает Schema.orgBlogPosting. Если канонический шаблон интеграции настроен,url/mainEntityOfPage/inLanguage/ имя издателя --- абсолютные (или с подставленной локалью). Если нет --- остаются плейсхолдеры{{canonicalUrl}},{{origin}},{{locale}}для замены интегратором. Не включён в стандартный ответ списка/slug. BFF того же домена:GET /api/v1/blog/slug/{slug}/json-ld.
SEO страниц для потребителей: Соотнесите metaTitle ?? title → title документа / OG title, metaDescription ?? excerpt → description, ogImageUrl (или первое изображение из тела) → OG/Twitter image, canonicalUrl (или slug + префикс локали и origin сайта при null) → canonical / rel=canonical. Опционально seoWords / tags могут заполнять <meta name="keywords"> или внутреннюю перелинковку. Абсолютные каноники не хранятся для каждой статьи; настройте канонический шаблон для всей интеграции в разделе Подключение и настройки (publicBaseUrl + паттерн пути с {locale} / {slug}).
Профили авторов (панель управления)
Каждая учётная запись может поддерживать принадлежащие пользователю профили авторов (отображаемое имя, slug, опциональный публичный e-mail, URL аватара, биография, опциональные переопределения по локалям). Статьи хранят живую ссылку на выбранный профиль, поэтому обновления распространяются. Поддерживаются псевдонимы (isAlias). Один профиль можно отметить как глобальный по умолчанию; можно также задать значение по умолчанию для конкретной интеграции блога (только ваше предпочтение --- не хранится в общей конфигурации интеграции).
- Вкладка Авторы в интеграции Blog: список и создание/редактирование профилей.
- Вкладка Подключение и настройки: Автор по умолчанию сохраняет переопределение для конкретной интеграции (при отсутствии используется глобальное значение по умолчанию). Канонический шаблон URL сохраняет
config.canonicalTemplate(publicBaseUrl,pathPattern), чтобы внешние запросы могли возвращатьcanonicalUrl. IndexNOW уведомление (опциональноеconfig.indexNow) отправляет POST с идентификаторами статей на ваш сайт при публикации/изменении --- вы вызываете IndexNOW (см.indexnow-notify{.interpreted-text role="doc"}). Стоковые фото хранят API-ключи Unsplash / Pexels для каждой интеграции (зашифрованные), чтобы редакторы могли искать и импортировать стоковые изображения в статьи; импортированные фото становятся обычными встраиваемыми UserMedia Mailoo (см.images{.interpreted-text role="doc"}). Агенты могут читать/обновлять те же санитизированные настройки черезGET/PATCH /api/v1/blog/.../settingsили MCP-инструментmanage_blog_integration_settings(см.mailoo-mcp{.interpreted-text role="doc"}). - Новая/Редактирование статьи: выберите профиль автора или оставьте значение по умолчанию интеграции / глобальное, чтобы API автоматически определил автора.
Создание интеграции Blog
- Перейдите в Панель управления → Проекты → [Ваш проект]
- Нажмите Создать интеграцию
- Выберите Blog (Headless CMS)
- Задайте имя и статус (например, Active)
- После создания откройте интеграцию, чтобы увидеть список Статей и блок Подключение
Управление статьями
На странице интеграции доступны:
- Таблица статей: заголовок, slug, сводка классификаторов, статус, дата и Редактировать для каждой статьи; быстрые фильтры по теме, интенту, аудитории и SEO-кластеру; Экспорт Markdown-отчёта (с полным текстом или без) для планирования контента с помощью ИИ
- Создание статьи: открывает форму новой статьи (заголовок, отрывок, SEO-метаданные, контент, статус). Контент вводится в Markdown (заголовки, списки, жирный, ссылки, изображения через панель изображений в панели управления --- включая вкладку Stock для Unsplash/Pexels при настроенных ключах --- или публичные URL встраивания); API преобразует его в HTML при сохранении.
- Редактирование: открывает форму редактирования статьи (сохранение как черновик, публикация или архивирование). Тот же Markdown-редактор для локали по умолчанию и для каждого перевода (локали).
- Связанные ссылки: при создании/редактировании можно прикрепить до 10 курированных связанных ссылок (тип, URL или внутренняя целевая статья, опциональные label/intro/date). Внешний API получения по slug предоставляет их как linkedLinks для headless-фронтендов (например, примечания к релизу на странице портфолио).
Формат контента: Тело статьи хранится как content в Markdown. API генерирует htmlContent из него. Потребители должны использовать htmlContent для отображения, чтобы получить корректную структуру и типографику.
Ссылки в htmlContent: Абсолютные URL http:// / https:// и протоколо-относительные //… ссылки содержат target="_blank" и rel="noopener noreferrer". Поведение в той же вкладке применяется к путям от корня сайта (/path), явным относительным ссылкам (./…, ../…), якорям на странице (#section) и URL только с параметрами (?q=1).
Ссылки внутри сайта --- используйте начальный слэш. В Markdown [label](support/docs) превращается в HTML href="support/docs". Это относительный путь: браузеры разрешают его согласно RFC 3986 относительно каталога страницы, отображающей статью, а не корня сайта. Например, на странице https://example.com/en/blog/my-post support/docs разрешится в /en/blog/support/docs. Чтобы сослаться на раздел сайта от корня, пишите [label](/support/docs) (или полный https://… URL). Односегментные ссылки без слэша (например, [other](other-slug)) также являются относительными, поэтому они остаются в том же каталоге, что и URL записи --- удобно для соседних записей только если ваши публичные URL записей имеют общий префикс пути.
Mermaid в htmlContent: Ограждённые блоки кода с меткой mermaid преобразуются в статический встроенный SVG (внутри <figure class="mailoo-mermaid">). Клиентская среда выполнения Mermaid в браузере не требуется; тот же HTML подходит для рендеринга в стиле электронной почты. Невалидный синтаксис Mermaid приводит к отклонению сохранения API (статьи, локализованный контент, кампании и т. д.).
Блоки печатного резюме в htmlContent: Ограждённые блоки кода с меткой mailoo-print становятся самоописывающимся разделом для печати. Авторы пишут:
```mailoo-print Short summary title
## Key points
- First **takeaway**
- Second [link](/docs)
```
API преобразует это в HTML примерно такого вида:
<section class="mailoo-printable" data-mailoo-print="true" data-print-title="Short summary title">
<div class="mailoo-printable-body">…разобранный Markdown как HTML…</div>
</section>
Опциональный заголовок после mailoo-print в информационной строке блока становится data-print-title. Внутренний контент поддерживает полный Markdown (заголовки, списки, ссылки, изображения, вложенные блоки mermaid). Потребители (ваш сайт или блог этого репозитория) должны обнаружить [data-mailoo-print], внедрить кнопку печати в браузере и печатать только .mailoo-printable-body --- API не встраивает обработчики onclick (совместимо с CSP). Пример паттерна клиентского улучшения в blog-nextjs-example{.interpreted-text role="doc"}.
Управление темами (категориями) и классификаторами
Контент блога организован по четырём осям классификаторов, каждая со связями «многие ко многим» к статьям:
- THEME (заменяет прежнюю модель «категорий»): опорные темы; блок Категории в панели управления по-прежнему управляет значениями theme для этой интеграции (те же CRUD-пути:
…/categories). - INTENT, AUDIENCE, SEO_CLUSTER: опциональные оси для редакционного и SEO-согласования (например, информационный vs транзакционный интент, ICP, кластеры запросов). Управление значениями через
GET/POST …/blog-classifier-values?type=…(панель управления / Bearer API).
SEO-слова (локализованные фразы) --- опционально для каждой интеграции: короткие фразы для SEO-планирования, не хранятся на статьях. Каждое SEO-слово имеет URL-стиль slug, каноническое английское word, опциональные переопределения locales (та же идея формата JSON, что и переводы статей) и связь «многие ко многим» только с значениями классификатора SEO_CLUSTER. Вкладка Товары панели управления: GET/POST /api/v1/projects/{projectUid}/integrations/{integrationId}/blog-seo-words и PUT/DELETE …/blog-seo-words/{wordId} (Bearer). Список поддерживает опциональный ?clusterId= (CUID значения SEO-кластера). При создании или редактировании статьи форма показывает в режиме чтения объединение SEO-слов, привязанных к SEO-кластерам, выбранным для этой статьи.
При создании или редактировании статьи выберите любое количество значений по каждой оси. Фильтры внешнего списка поддерживают category / categoryId для тем плюс intentId, audienceId, seoClusterId (CUID значения классификатора).
Описание темы (опционально): Для значения темы выберите статью как descriptionPostId (аналог прежнего описания категории). Внешний GET …/categories/slug/{slug}/description по-прежнему разрешает slug тем.
Системные темы (about / portfolio)
Mailoo резервирует два slug темы для каждой интеграции Blog: about и portfolio. Используйте их для отдельных страниц, которые не должны появляться в списке публичных статей по умолчанию.
- Создание: Создание интеграции Blog автоматически создаёт значения тем About (slug
about) и Portfolio (slugportfolio). - Список по умолчанию:
GET …/blog/{projectUid}/integrations/{integrationId}безcategoryи безcategoryIdисключает опубликованные статьи, привязанные к теме со slugaboutилиportfolio. Статьи без классификаторов тем, но с унаследованной строкойcategory, совпадающей с этими slug (без учёта регистра), также исключаются. - Явный фильтр: Передайте
category(slug темы или унаследованную строку) илиcategoryId(id значения темы) для включения этих статей. - Панель управления показывает все статьи, если не применены фильтры.
Параметр category в запросе фильтрует по slug BlogClassifierValue (тип THEME) или унаследованной строке category записи. Если указаны оба category и categoryId, применяются оба условия (логическое И).
Markdown-отчёт (панель управления)
Авторизованные редакторы проекта могут скачать структурированный Markdown-отчёт по интеграции Blog:
GET /api/v1/projects/{projectUid}/integrations/{integrationId}/blog/report?includeFullText=true|false&format=md&publishedFrom=YYYY-MM-DD&publishedTo=YYYY-MM-DD
Параметры запроса:
includeFullText--- приtrueкаждый раздел статьи включает полное тело Markdown.format--- поддерживается толькоmd.publishedFrom/publishedTo(необязательно, включительно, UTC календарные датыYYYY-MM-DD) --- фильтр поpublishedAt. Если указан хотя бы один, включаются только записи с ненулевымpublishedAt(черновики без даты публикации исключаются). Если указаны оба,publishedFromдолжен быть не позднееpublishedTo.
В панели управления поток Экспорт отчёта открывает отдельную страницу (навигация по хлебным крошкам) для выбора месяца, квартала или произвольного диапазона, предварительного просмотра Markdown и сохранения в файл.
Файл содержит метаданные, агрегаты по каждой оси классификатора, матрицу тема × интент и раздел по каждой статье (опционально с полными телами Markdown). Предназначен для передачи внешним LLM для планирования контента.
Подключение (внешний API)
Блок Подключение на странице интеграции показывает значения переменных окружения для копирования (базовый URL API, UID проекта, ID интеграции) и готовый фрагмент .env. Для веб-приложений единственный рекомендуемый подход --- BFF (API-ключ на сервере); прямые вызовы API с X-API-Key --- для межсерверного использования. Полные пути эндпоинтов документированы ниже; в панели управления они не дублируются. Для Next.js см. blog-nextjs-example{.interpreted-text role="doc"}.
BFF-маршруты (Next.js, тот же домен) --- используйте переменные окружения MAILOO_BLOG_PROJECT_UID, MAILOO_BLOG_INTEGRATION_ID, MAILOO_BLOG_API, MAILOO_BLOG_API_KEY:
-
Список опубликованных статей:
GET /api/v1/blogПараметры:page,limit,category,categoryId,intentId,audienceId,seoClusterId,search,locale,featured,tag(необязательные); фильтры комбинируются логическим И. БезcategoryиcategoryIdстатьи с зарезервированными slug темaboutиportfolioисключаются (см. Системные темы выше).tag--- точное совпадение одного значения в массивеtagsстатьи (регистрозависимо). Возвращает{ success, data: [...], pagination }сhasNextPage,hasPrevPage. SDK Next.jscreateMailooBlogClient().listPostsсохраняетdata,paginationиimagePublicEmbedBaseUrl(см.nextjs-packages{.interpreted-text role="doc"}). -
Одна статья по slug:
GET /api/v1/blog/slug/{slug}Параметр:locale(необязательный). Возвращает{ success, data: article }. Возвращаются только опубликованные статьи. -
JSON-LD по slug:
GET /api/v1/blog/slug/{slug}/json-ldПараметр:locale(необязательный). Возвращает{ success, data: { jsonLd } }(BlogPosting с плейсхолдерами). Next.js: подключитеcreateBlogJsonLdHandler(); RSC/карта сайта должны вызыватьcreateMailooBlogClient(config).getPostJsonLd(прямой API, без обратного вызова BFF). См.nextjs-packages{.interpreted-text role="doc"}. -
Список категорий (тем):
GET /api/v1/blog/categoriesВозвращает{ success, data: Category[] }(id, slug, name) --- только значения классификатора theme (обратно совместимое имя пути). -
Описание категории по slug:
GET /api/v1/blog/categories/slug/{slug}/descriptionПараметр:locale(необязательный). Возвращает{ success, data: { description, descriptionHtml } }. Если у категории нет статьи-описания, оба поля --- пустые строки. Если slug категории не существует ---404. -
Публичный профиль автора (по id или slug): BFF того же домена не обязателен; вызывайте API напрямую с
X-API-Key:GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/authors/{authorSlugOrId}Параметр:
locale(необязательный). Возвращает локализованные name, bio, avatar и email только если профиль публикует e-mail (псевдонимы не раскрывают e-mail учётной записи).
Прямые вызовы API --- требуют заголовок X-API-Key и область blog.external-read:
- Список:
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}Необязательные параметры:page,limit,category,categoryId,intentId,audienceId,seoClusterId,search,locale,featured,tag(та же семантика, что и у BFF-маршрута списка выше). - Одна статья:
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/slug/{slug}Параметр:locale(необязательный). - JSON-LD:
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/slug/{slug}/json-ldПараметр:locale(необязательный). - Категории:
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/categories - Описание категории:
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/categories/slug/{slug}/descriptionПараметр:locale(необязательный). Поведение аналогично BFF-эндпоинту выше. - Профиль автора:
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/authors/{authorSlugOrId}Параметр:locale(необязательный). Публичное чтение профиля автора владельца проекта для подписей и страниц авторов.
API управления --- требует X-API-Key и область blog.manage (ключи FULL тоже подходят):
- Список (все статусы):
GET {baseUrl}/api/v1/blog/{projectUid}/integrations/{integrationId}/articles - Создание:
POST …/articles--- тело аналогично созданию в панели управления (title, Markdowncontent, необязательныеlocalesвключаяmetaTitle/metaDescriptionпо локалям,themeValueIds/intentValueIds/audienceValueIds/seoClusterValueIds,tags,metaTitle,metaDescription,ogImageMediaId,status,slug,authorProfileId, ...). Автор по умолчанию --- профиль по умолчанию владельца ключа, если не указан; 400 если профиля нет. - Получение / обновление / удаление:
GET|PUT|DELETE …/articles/{articleId} - Значения классификаторов (чтение или управление):
GET …/classifier-values?type=THEME|INTENT|AUDIENCE|SEO_CLUSTER--- требуетblog.external-readилиblog.manage
Обнаружение для агентов (любой валидный API-ключ; только проекты, принадлежащие пользователю ключа):
GET {baseUrl}/api/v1/agent/projectsGET {baseUrl}/api/v1/agent/projects/{uid}/integrations?type=BLOG
Настройка MCP описана в mailoo-mcp{.interpreted-text role="doc"}.
Базовый URL --- ваш API Mailoo (например, https://api.mailoo.app). projectUid и integrationId указаны в блоке Подключение. Изображения в телах статей используют API загрузки изображений Mailoo и публичные URL встраивания внутри content / htmlContent (см. images{.interpreted-text role="doc"} для хранения, областей действия и чтения байтов через Bearer или X-API-Key). Теги возвращаются как массив; пустой массив если отсутствуют. Статьи, используемые как описания категорий, исключаются из внешнего списка статей, чтобы не дублировались в обычной ленте. Список по умолчанию также исключает статьи категорий about и portfolio, если не передан явный фильтр категории. Полные поля ответа и коды ошибок см. в документации API выше.
Полный пример для Next.js в blog-nextjs-example{.interpreted-text role="doc"}.