охват
RUEN

Публичный API

REST API Охвата для своих интеграций — бренды, каналы, генерация постов, свои файлы, публикации и календарь. Ключ, лимиты, коды ошибок и три примера curl.

Зачем

Публичный API — для тех, кому нужно завести генерацию и публикацию из своей системы: CRM, скрипт по расписанию, внутренний дашборд агентства. Он даёт то же самое, что кабинет: создание креатива по теме или по чужому посту, свои файлы, постановку публикации и календарь — но без браузера и без сессии.

Открытая спецификация лежит по адресу /api/v1/openapi.json в формате OpenAPI 3.1 — из неё клиенты и SDK генерируются любым генератором OpenAPI (openapi-generator, Postman, Kiota и так далее), без ручного описания эндпоинтов.

Ключ

Ключ выпускается в кабинете, в разделе «API и интеграции» (пункт меню в нижней части сайдбара, страница /app/api-keys).

При выпуске указываешь:

  • Областьread (только чтение: бренды, каналы, статус креативов и публикаций) или write (то же плюс создание креативов, загрузка файлов, постановка и отмена публикаций).
  • Бренды — список брендов, которые ключ открывает. Бренд не из списка закрыт даже тому, кто им владеет: у ключа нет доступа «по умолчанию ко всему».

Секрет ключа (ohv_…) показывается один раз, в момент выпуска — сохрани его сразу, второй раз кабинет его не покажет. Забыл сохранить — выпускай новый и отзывай старый. Отзыв ключа в кабинете необратим: все интеграции, которые его использовали, начинают получать invalid_key.

Заголовок

Ключ передаётся заголовком Authorization, схема Bearer:

curl https://ohvat.top/api/v1/me \
  -H "Authorization: Bearer ohv_5f2b9c1a7e4d3f80b6c2a91d5e7f3c40"

Cookie-сессия кабинета здесь не принимается — только этот заголовок.

Лимиты

ЧтоПотолок
Чтение (GET)300 запросов в минуту на ключ
Изменения (POST/DELETE)по тарифу владельца бренда, в сутки

Суточный потолок изменений:

ТарифИзменений в сутки
Бесплатный30
Старт300
Рост1 000
Бизнес5 000

Ответ, упёршийся в лимит, — 429 rate_limited с заголовками Retry-After, X-RateLimit-Limit и X-RateLimit-Remaining: по ним понятно, сколько осталось и когда пробовать снова, без угадывания.

Ошибки

Любой отказ — одна форма:

{ "error": { "code": "not_found", "message": "Креатив не найден" } }

message — по-русски, для человека, который смотрит логи интеграции. Разбирать код — только по error.code: набор кодов закрыт, внутренние коды модулей наружу не просачиваются.

КодСтатусКогда
invalid_key401заголовка нет, ключ не найден или отозван
read_only_key403ключ только для чтения, а вызов меняет данные
forbidden_brand403бренд не в списке ключа или недоступен владельцу
demo_mode403ключ выпущен в демо-кабинете — он ничего не меняет
no_brands400у ключа нет ни одного доступного бренда
not_found404сущности не существует или она закрыта ключом (чужая — тот же ответ, что несуществующая)
rate_limited429исчерпан бакет чтения или суточный потолок изменений
bad_url400адрес картинки не http/https, приватный или локальный адрес, битая ссылка или редирект в приватную сеть
bad_request400тело не прошло разбор — конкретное поле в message
insufficient_credits402не хватает кредитов на генерацию или публикацию
plan_locked402формат или функция закрыты тарифом владельца бренда
language_locked403формат не поддерживает язык контента бренда — код появится после волны «Язык контента»
creative_not_ready409публикуем креатив, который ещё не ready
publication_not_cancelable409публикация уже вышла или публикуется — отменить нельзя
busy409креатив занят другой операцией
internal500внутренняя ошибка

Долгие операции (генерация, скачивание картинки по адресу, публикация) отвечают 202 с идентификатором — результат спрашивают опросом GET-роута. Вебхуков в v1 нет.

Пример 1: пост по теме → публикация

Тема поста → ждём готовности креатива → ставим публикацию в канал.

KEY="Authorization: Bearer ohv_5f2b9c1a7e4d3f80b6c2a91d5e7f3c40"
BRAND="cljk3x9p10000qzrmn8g4d2yx"

# 1. Создать креатив и запустить генерацию
curl -s -X POST "https://ohvat.top/api/v1/brands/$BRAND/creatives" \
  -H "$KEY" -H "Content-Type: application/json" \
  -d '{
    "type": "imagePost",
    "source": { "kind": "idea", "text": "Открытие нового зала для йоги на Ленина, 12 — расписание и первое бесплатное занятие" }
  }'
# → 202 { "creativeId": "clm...", "versionId": "clm..." }

# 2. Опрашивать статус, пока не ready или failed
curl -s "https://ohvat.top/api/v1/creatives/clm..." -H "$KEY"
# → 200 { "status": "generating", ... } — повторить через пару секунд
# → 200 { "status": "ready", "media": [{ "assetId": "...", "kind": "image", "url": "https://..." }], ... }

# 2a. Скачать картинку, если она нужна у себя. Ссылка НЕ публичная — тот же заголовок ключа.
curl -s -H "$KEY" "https://ohvat.top/api/generation/media/..." -o post.jpg

# 3. Поставить публикацию готовым креативом
curl -s -X POST "https://ohvat.top/api/v1/publications" \
  -H "$KEY" -H "Content-Type: application/json" \
  -d '{
    "brandId": "'"$BRAND"'",
    "channelIds": ["chn_telegram_1", "chn_vk_1"],
    "creativeId": "clm...",
    "scheduledAt": "2026-09-10T09:00:00+03:00"
  }'
# → 202 { "publications": [{ "id": "pub...", "channelId": "chn_telegram_1" }, { "id": "pub...", "channelId": "chn_vk_1" }] }

Канал вне списка ключа или несуществующий бренд ответят 403/404; попытка опубликовать креатив раньше готовности — 409 creative_not_ready.

Пример 2: свой файл → публикация «Своим контентом»

Загружаем готовую фотографию, пишем свой текст, публикуем без генерации.

KEY="Authorization: Bearer ohv_5f2b9c1a7e4d3f80b6c2a91d5e7f3c40"
BRAND="cljk3x9p10000qzrmn8g4d2yx"

# 1. Загрузить файл (jpeg/png/webp/heic/heif/avif до 20 МБ)
curl -s -X POST "https://ohvat.top/api/v1/brands/$BRAND/media" \
  -H "$KEY" \
  -F "file=@photo.jpg"
# → 201 { "assetId": "ast..." }

# 2. Поставить публикацию своим текстом и своим файлом
curl -s -X POST "https://ohvat.top/api/v1/publications" \
  -H "$KEY" -H "Content-Type: application/json" \
  -d '{
    "brandId": "'"$BRAND"'",
    "channelIds": ["chn_vk_1"],
    "text": "Сегодня привезли свежую партию — заходи посмотреть на месте",
    "mediaAssetIds": ["ast..."],
    "scheduledAt": "2026-09-09T18:00:00+03:00"
  }'
# → 202 { "publications": [{ "id": "pub...", "channelId": "chn_vk_1" }] }

Файла нет под рукой, а есть только ссылка на фото (частый случай для CRM) — вместо multipart/form-data шлём JSON с адресом, и файл качает воркер:

curl -s -X POST "https://ohvat.top/api/v1/brands/$BRAND/media" \
  -H "$KEY" -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/photo.jpg" }'
# → 202 { "fetchId": "fch..." }

curl -s "https://ohvat.top/api/v1/media/fetch/fch..." -H "$KEY"
# → 200 { "state": "pending", "assetId": null, "error": null } — опрос
# → 200 { "state": "ready", "assetId": "ast...", "error": null }

Загрузка своих файлов — платная функция: тариф берётся у владельца бренда, бесплатному она закрыта (402 plan_locked).

Пример 3: календарь публикаций за месяц

Окно fromto не шире 62 дней; отменённые публикации в выборку не попадают.

curl -s "https://ohvat.top/api/v1/publications?brandId=$BRAND&from=2026-09-01T00:00:00Z&to=2026-09-30T23:59:59Z" \
  -H "$KEY"
# → 200 { "publications": [
#     { "id": "pub...", "status": "published", "scheduledAt": "2026-09-03T09:00:00Z", "platform": "telegram", "channelTitle": "Йога на Ленина", "text": "...", "externalUrl": "https://t.me/..." },
#     { "id": "pub...", "status": "scheduled", "scheduledAt": "2026-09-10T09:00:00Z", "platform": "vk", "channelTitle": "Йога на Ленина | ВКонтакте", "text": "..." }
#   ] }

Одну публикацию с полным текстом, причиной отказа и ссылкой на пост площадки — отдельным запросом:

curl -s "https://ohvat.top/api/v1/publications/pub..." -H "$KEY"

Отменить можно только то, что ещё не ушло — DELETE на тот же адрес; публикация уже публикуется или вышла отвечает 409 publication_not_cancelable.

Чего нет в v1

  • Один тип креатива — imagePost (пост-картинка). Каруселей, видео и других форматов генерации в API пока нет.
  • Источник поста — только текст: тема своими словами (kind: "idea") или текст чужого поста для рерайта (kind: "donor"). Разбора сайта или ссылки на чужой пост в API нет.
  • Свои файлы — только картинки, до 20 МБ. Видео через POST /brands/{id}/media не принимается.
  • Вебхуков нет: результат долгой операции (генерация, скачивание по адресу, публикация) узнают опросом GET-роута, а не пуш-уведомлением.

В v1 поля в схемах только добавляются — переименование и удаление возможны только в v2, с отдельным анонсом.

Помогла страница?Обновлено 9 сентября 2026