Публичный API

HTTP-интерфейс к своим лентам: читать посты, добавлять отзывы и объявления, модерировать. Нужен, если Feedwall встраивается в вашу админку или мобильное приложение.

Ключ доступа

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

Ключ — это доступ ко всем вашим лентам. Он для запросов с вашего сервера. Не вставляйте его в код страницы и в мобильное приложение: оттуда его достанет любой, кто откроет исходники. Для показа ленты на сайте ключ не нужен — там работает widget.js с публичным ключом ленты.

Передавайте его любым из двух способов:

curl https://ВАШ_ДОМЕН/api/v1/feeds \
  -H "X-Api-Key: fw_ВАШ_КЛЮЧ"

curl https://ВАШ_ДОМЕН/api/v1/feeds \
  -H "Authorization: Bearer fw_ВАШ_КЛЮЧ"

Без ключа или с отозванным — 401. Сессия кабинета для API не подходит: это разные способы доступа.

Ключ всегда состоит из латиницы, цифр и -_. Если подставить в заголовок строку с другими символами, ответ будет 400, а не 401: такой заголовок отбивает веб-сервер ещё до приложения.

Ограничения

Считаются по аккаунту, а не по ключу: второй ключ квоту не удваивает. При превышении — 429 с указанием, сколько ждать.

ТарифЗапросов в минуту
Старт30
Про120
Бизнес300
Агентство900

Права

Ключ открывает ровно то, что видит его владелец в кабинете, — не больше. Если вас пригласили в чужую ленту модератором, через API вы так же сможете модерировать и не сможете менять настройки. Обращение к чужой ленте возвращает 404, а не 403: иначе по коду ответа можно было бы перебором узнать, какие ленты существуют.

Методы

GET/api/v1/feeds

Ленты, доступные ключу: свои и те, куда пригласили.

[
  {
    "id": 1,
    "name": "Новости кофейни",
    "publicKey": "e70548a83fedc7c6aae94866",
    "role": "OWNER",
    "moderationMode": "MANUAL",
    "views": 1248,
    "clicks": 97
  }
]

role — OWNER, ADMIN или MODERATOR. publicKey — тот ключ, что подставляется в widget.js.

GET/api/v1/feeds/{id}/sources

Источники ленты с состоянием последнего обновления и фильтром по хештегам.

[
  {
    "id": 6,
    "type": "TELEGRAM",
    "value": "telegram",
    "title": "Telegram News",
    "lastFetchAt": "2026-10-03T01:12:04Z",
    "lastError": null,
    "includeTags": "анонс",
    "excludeTags": "репост"
  }
]

lastError непустой — источник сломался: сменился адрес, закрыли доступ, кончился токен. Это то, на что стоит навесить оповещение у себя.

GET/api/v1/feeds/{id}/posts

Посты ленты, свежие сверху.

ПараметрЗначение
statusPENDING, APPROVED, REJECTED. Пусто — все
limitсколько вернуть, по умолчанию 50, максимум 100
curl "https://ВАШ_ДОМЕН/api/v1/feeds/1/posts?status=PENDING&limit=20" \
  -H "X-Api-Key: fw_ВАШ_КЛЮЧ"
[
  {
    "id": 412,
    "source": "TELEGRAM",
    "author": "Кофейня «Зерно»",
    "text": "Новый сезонный латте уже в меню",
    "media": "/media/d7/d7731693d8b41960af5d3687.jpg",
    "link": "https://t.me/zerno/118",
    "publishedAt": "2026-10-02T09:30:00Z",
    "status": "PENDING",
    "rating": null,
    "clicks": 0,
    "manual": false,
    "expiresAt": null
  }
]

text — уже с учётом вашей правки подписи. media — наша копия картинки, если она есть, иначе исходный адрес в соцсети; относительный путь берётся от домена сервиса. rating заполнен только у отзывов. manual: true — запись внесена руками, её можно удалить. expiresAt — когда своя запись снимается с показа, null — без срока.

Это список для кабинета, а не то, что видит посетитель: здесь есть и запись, запланированная на будущее, и та, у которой срок показа уже прошёл. Ленту для сайта отдаёт /api/public/feeds/{publicKey} — там ни той, ни другой нет.

POST/api/v1/sources/{id}/posts

Добавляет запись в ручной источник: отзыв с карт или своё объявление. У обычных источников посты приходят сами, поэтому для них метод отвечает 400.

curl -X POST https://ВАШ_ДОМЕН/api/v1/sources/6/posts \
  -H "X-Api-Key: fw_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Лучший капучино в районе",
    "author": "Мария К.",
    "rating": 5,
    "publishedAt": "2026-09-28T12:00:00Z"
  }'
ПолеОписание
textобязательно, до 8000 символов
authorбез него у отзыва будет «Гость», у объявления — название ленты
rating1–5, только для источников отзывов; в объявлении игнорируется
mediaUrlкартинка объявления; мы скопируем её себе
linkкуда вести по нажатию
publishedAtдата в ленте; по умолчанию сейчас, не раньше 2005 года. У своей записи это ещё и планирование: дату можно поставить вперёд не дальше чем на год, и до неё запись на сайте не появится. У отзыва дата в будущем — опечатка, а не план, и поэтому отбивается
expiresAtкогда снять запись с показа; только для своих записей, позже publishedAt
publishedAt решает место записи в ленте, а виджет показывает лишь несколько десятков свежих. Опечатка в годе уносит запись в конец, и на сайте её не видно. Если даты нет — не присылайте поле вовсе.

Созданная запись сразу APPROVED: её внёс человек, который и есть модератор.

PATCH/api/v1/posts/{id}

Модерация и правка подписи. Поля необязательны — можно поменять только текст.

curl -X PATCH https://ВАШ_ДОМЕН/api/v1/posts/412 \
  -H "X-Api-Key: fw_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"status": "APPROVED", "text": "Текст для сайта"}'

Исходный текст источника не затирается: при обновлении источника правка сохранится. Пустая строка в text возвращает исходный текст.

DELETE/api/v1/posts/{id}

Удаляет запись, внесённую руками. Пост из источника удалить нельзя — он вернётся при следующем обновлении; такой пост скрывают через status: REJECTED.

Ошибки

Ошибка — это код состояния и тело {"error": "текст на русском"}. Текст написан для человека, разбирать его программой не стоит: ориентируйтесь на код.

КодКогда
400неверное поле: пустой текст, статус с опечаткой, дата отзыва в будущем, срок показа не позже даты публикации, ручная запись в обычный источник
401ключа нет, он выдуман или отозван
403роли не хватает: модератор пытается править настройки
404объекта нет — или он чужой
429превышен лимит запросов в минуту

Совместимость

/v1 в адресе — не украшение. Этот контракт мы обязуемся не ломать: поля могут добавляться, но существующие не будут переименованы или удалены. Если формат придётся менять по-настоящему, появится /v2, а /v1 продолжит работать.

Чего в API пока нет: создания лент и источников, настроек оформления, статистики по дням. Если вам нужно что-то из этого — напишите, добавим по реальному запросу, а не на всякий случай.