FeedLike API v1
API для серверной части CMS/CSM и других сервисов: один запрос создаёт одно изображение по фото авто, дополнительным логотипам и текстовому заданию. Движок, модель генерации, качество и арт-направление задаёт администратор FeedLike: общие настройки или индивидуальный профиль API-ключа.
Базовый URL: https://feedlike.ru. Публичная документация: /docs.
Аутентификация
Каждый запрос к /api/v1/* отправляйте с заголовком:
Authorization: Bearer flk_<ваш ключ>
Для POST также задайте Content-Type: application/json. Ключ создаётся в Админка → API → Создать ключ и показывается один раз; на сервере хранится его хеш. У активного ключа можно задать собственные системный промт, движок, модель и качество через «Настроить» в админке. По умолчанию ключ наследует общие настройки. Индивидуальный профиль заменяет весь набор общих параметров; пустой системный промт в нём означает отсутствие общих указаний для этого ключа. Возврат к общим настройкам снова включает наследование. Изменения применяются только к новым задачам.
После отзыва ключа новые запросы и опрос его задач возвращают 401. Сам отзыв не отменяет уже поставленные генерации — их можно остановить через очередь в интерфейсе.
Вызывайте API из серверной части вашей CMS/CSM. CORS для запросов с другого сайта не настроен. Пароль входа и cookie админки не заменяют Bearer-ключ внешнего API.
POST/api/v1/generate
Тело — JSON-объект. Запрос ставит одну задачу в общую очередь FeedLike. По умолчанию соединение ожидает завершения до 5 минут, включая ожидание в очереди. Время генерации зависит от модели и загрузки. Для интеграции с CMS/CSM удобно использовать async: true и опрашивать задачу по id.
Поля запроса
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
image | string | нет | Основное фото авто: HTTPS-ссылка или data-URL PNG/JPEG/WebP/SVG, например data:image/png;base64,…. До 12 МБ после скачивания или декодирования base64, для SVG — до 2 МБ. |
additionally | string[] | нет | Дополнительные изображения, в том числе логотипы. Передаются вместе с image: до 15 дополнительных, до 16 изображений всего. Форматы и лимит каждого — как у image. |
prompt | string | условно | Пожелания к сцене и размещению логотипов, до 4000 символов. Без исходников обязателен. С исходниками можно заменить непустым headline, model или cta. |
headline | string | нет | Рекламный заголовок, до 300 символов. Шаблон требует воспроизвести его дословно. |
model | string | нет | Название автомобиля для подписи, до 300 символов. Это текст на макете, а не выбор нейросети. |
cta | string | нет | Надпись на кнопке, до 300 символов. |
async | boolean | нет | true — вернуть id после подготовки исходников и постановки задачи в очередь; false или отсутствие поля — ожидать результат. Используйте JSON boolean, а не строку. |
Пробелы по краям текстовых полей удаляются перед проверкой длины. Пустое или состоящее из пробелов поле считается незаполненным. Хотя сервер преобразует часть значений в строки, в интеграции соблюдайте типы из таблицы; например, строка "false" не выключает async.
Минимальное задание: передайте хотя бы одно непустое поле prompt, headline, model или cta. Одних изображений недостаточно. Без изображений требуется именно prompt; поля headline/model/cta сами по себе не запускают текстовую генерацию.
Изображения и логотипы
image и additionally принимаются вместе. Сначала в модель отправляется image, затем элементы additionally по порядку. В additionally не нужно повторять основное фото. Вместе с image допустим пустой массив []. Если image отсутствует, можно передать непустой additionally: его первый элемент становится основным фото авто. Пустой additionally без image возвращает 400. Для генерации без исходников не передавайте ни одно из этих полей.
Ограничения действуют на весь запрос: до 16 изображений, до 12 МБ каждое и до 48 МБ суммарно после декодирования. В этих лимитах 1 МБ = 1 048 576 байт. JSON-тело вместе с base64 — до 65 МБ; превышение возвращает 413. Используйте корректный base64 без переносов строк. HTTPS-ссылки поддерживаются наравне с data-URL; голый base64 и multipart/form-data не поддерживаются. Для прозрачных логотипов подойдут PNG, WebP и SVG; дополнительные требования к SVG приведены ниже.
Шаблон требует включить приложенные логотипы, сохранить их цвета, форму, пропорции, исходный шрифт, начертание букв, межбуквенные интервалы, прозрачность и надписи на исходном языке. Разрешены только перемещение и равномерное масштабирование без искажений. Место укажите в prompt; по умолчанию используется свободный верхний угол. Надписи внутри приложенных логотипов разрешены и без рекламных текстовых полей. Точность воспроизведения зависит от модели: сервер передаёт логотипы в генерацию, а не накладывает исходные пиксели поверх готового изображения.
Изображения по HTTPS-ссылкам
В image и каждом элементе additionally можно передать прямую HTTPS-ссылку или data-URL с base64. Форматы PNG, JPEG, WebP и SVG можно смешивать в одном запросе. FeedLike скачивает файл самостоятельно; модели передаются скачанные байты, для SVG — результат серверной конвертации в PNG. Порядок изображений сохраняется.
- Нужна прямая ссылка на файл, доступная серверу без cookie и дополнительных заголовков. Подписанные ссылки с параметрами допустимы, пока не истёк срок их действия. Ссылки на страницы просмотра/авторизации не подходят.
- Только
https://, порт 443, до 4096 символов. Логин и пароль внутри URL запрещены. Сертификат HTTPS должен быть действительным. - До 3 перенаправлений; каждый новый адрес проверяется заново. HTTP, локальные, частные и служебные IP-адреса запрещены, в том числе через DNS и редиректы.
- До 20 секунд на скачивание одного файла вместе с DNS и редиректами; до 60 секунд на загрузку всех ссылок запроса. До 4 запросов со скачиванием одновременно.
- До 12 МБ на растровый файл, до 2 МБ на SVG и до 48 МБ на все изображения, включая base64. Лимит применяется и без заголовка Content-Length. Формат определяется по содержимому, а не расширению ссылки.
- Сервер запрашивает файл без HTTP-сжатия (
Accept-Encoding: identity); сжатые gzip/br ответы и SVGZ не поддерживаются. - Ошибка скачивания, формата, размера или таймаут возвращают 400 с именем поля (
imageилиadditionally[0]). При занятом загрузчике возвращается 503 — повторите позже. Задача генерации в обоих случаях не создаётся.
Даже с async: true ответ 202 приходит после скачивания и конвертации исходников. Пятиминутное ожидание синхронной генерации начинается после подготовки изображений. В журнале запросов сохраняются скачанные исходники и PNG-превью SVG; query-параметры ссылок скрываются, чтобы не записывать временные подписи и токены.
{
"image": "https://cdn.example.com/car.jpg",
"additionally": [
"https://cdn.example.com/logo.svg",
"data:image/png;base64,…"
],
"prompt": "Авто у салона, приложенные логотипы в верхних углах",
"async": true
}
Замените адреса примера прямыми ссылками на ваши файлы, а многоточие — base64 PNG. CMS может отправлять исходный SVG по ссылке без предварительного преобразования в PNG.
SVG-логотипы
В image и элементах additionally поддерживается data:image/svg+xml;base64,… или HTTPS-ссылка на SVG. Передавайте ссылку на SVG или кодируйте исходные байты SVG в UTF-8: CMS не должна предварительно преобразовывать их в PNG. FeedLike конвертирует SVG в PNG до постановки генерации в очередь и передаёт модели PNG в той же позиции среди исходников. Пропорции, цвета и прозрачность сохраняются; белая подложка не добавляется, рисунок не обрезается и не перерисовывается нейросетью на этапе конвертации. Это не отменяет ограничений точности последующей генерации самой моделью.
- SVG — до 2 МБ после base64; результирующий PNG — до 12 МБ.
- Размер растра — исходный размер SVG: от 1 до 4096 пикселей по каждой стороне, не более 4 194 304 пикселей суммарно. Задайте
width/heightилиviewBox. - Общий лимит 48 МБ проверяется как для входных файлов, так и после конвертации.
- Поддерживаются статические векторные фигуры, пути, группы, градиенты, маски, обтравка, внутренние ссылки
#id, простые встроенные стили. - Текст логотипа должен быть переведён в кривые (
path). Элементыtext,tspan,textPathотклоняются, чтобы сервер не подменял шрифт и не терял надписи. - Не поддерживаются скрипты, обработчики событий, анимация,
foreignObject, фильтры, вложенные изображения, внешние ссылки/шрифты/CSS, DTD и XML-сущности. CSS-импорты, экранирование и CSS-комментарии также отклоняются. - Требуется XML с корневым
svgиxmlns="http://www.w3.org/2000/svg"; максимум 10 000 элементов и глубина 64. Пустой/полностью прозрачный результат возвращает 400. - Конвертация ограничена 7 секундами на файл и двумя одновременными запросами. При занятости возвращается 503 без создания задачи: повторите запрос позже. Неподдерживаемый SVG возвращает 400 с указанием поля, например
additionally[0]; запрос к модели и списание за генерацию при этом не выполняются.
additionally: [
'data:image/svg+xml;base64,' + fs.readFileSync('logo.svg', 'base64')
]
SVG в логах скачивается как исходный файл; внутри админки показывается безопасное PNG-превью — именно этот PNG передаётся модели. SVG и превью входят в общий лимит хранения журнала. Для отклонённых SVG превью может отсутствовать. Уже повреждённый PNG эти изменения не восстанавливают: отправитель должен передать исходный SVG.
Как собирается промт
При наличии исходников используется шаблон автомобильного креатива: сохранение авто, автосалон как сцена по умолчанию и опциональные текстовые блоки HEADLINE/MODEL/CTA. prompt и арт-направление администратора меняют сцену и расположение элементов. Без исходников отправляется арт-направление администратора, затем prompt клиента.
Рекламные надписи передавайте в headline, model и cta. Фраза «добавить надпись» только в prompt не создаёт текстовый блок: без этих полей шаблон запрещает рекламный текст, сохраняя исключение для надписей в приложенных логотипах.
Отдельных полей price/oldprice и блока цены нет. При этом числа внутри явно переданных текстовых строк или исходных логотипов не удаляются. Неизвестные поля не управляют генерацией и видны в трассе как extra. Параметры клиента engine, quality, size или gen не переопределяют настройки администратора для данного ключа.
Синхронный режим
Успешное завершение — HTTP 200:
{
"ok": true,
"id": 42,
"status": "done",
"file": "img-medium-1789039696836.png",
"model": "x-ai/grok-imagine-image-2.0",
"cost": 0.07,
"image": "data:image/png;base64,…"
}
Значения модели, стоимости, имени файла и id приведены для примера. model в ответе — модель генерации. cost — стоимость успешной генерации в USD, сообщённая OpenRouter; при отсутствии данных, в том числе для OpenAI direct, возвращается null, а не ноль.
Если ожидание превысило 5 минут, сервер возвращает HTTP 504 с id и текущим status. Задача продолжает жить в очереди: забирайте её результат через GET /api/v1/jobs/<id>. Не создавайте повторную генерацию вместо опроса — это новая задача с отдельной стоимостью. Таймаут самой попытки обращения к провайдеру тоже ограничен 5 минутами, но отсчитывается при запуске воркера. Ошибка провайдера возвращается как 502.
Асинхронный режим
При async: true сервер возвращает HTTP 202:
{ "ok": true, "id": 42, "status": "queued" }
Это подтверждение приёма, не готовый результат; воркер уже может начать работу. Сохраните id и опрашивайте GET /api/v1/jobs/42 тем же ключом раз в 3–5 секунд.
Пример: curl без исходника
Ключ возьмите из переменной окружения FEEDLIKE_API_KEY:
curl --max-time 330 -X POST https://feedlike.ru/api/v1/generate \
-H "Authorization: Bearer ${FEEDLIKE_API_KEY}" \
-H "Content-Type: application/json" \
--data '{"prompt":"красный седан на закате, вид сбоку"}'
Пример: фото авто и логотип
Вместо многоточий подставьте base64 соответствующих файлов. Для JPEG используйте data:image/jpeg;base64,, для WebP — data:image/webp;base64,.
{
"image": "data:image/png;base64,…",
"additionally": ["data:image/png;base64,…"],
"prompt": "Авто у салона, приложенный логотип справа сверху",
"headline": "ТОПЛИВНАЯ КАРТА В ПОДАРОК",
"model": "Lada Vesta Cross",
"cta": "БРОНИРУЙ СЕЙЧАС!",
"async": true
}
Пример: Node.js с опросом и сохранением
Сохраните код в .mjs, положите рядом car.png и logo.png, задайте FEEDLIKE_API_KEY и запускайте из этой папки. Пример предназначен для серверной части CMS/CSM. FEEDLIKE_BASE_URL необязателен; по умолчанию используется https://feedlike.ru.
import fs from 'node:fs';
import { setTimeout as delay } from 'node:timers/promises';
const base = process.env.FEEDLIKE_BASE_URL || 'https://feedlike.ru';
const key = process.env.FEEDLIKE_API_KEY;
if (!key) throw new Error('Задайте FEEDLIKE_API_KEY');
const headers = { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' };
async function request(route, body) {
const response = await fetch(base + route, {
method: body === undefined ? 'GET' : 'POST',
headers,
body: body === undefined ? undefined : JSON.stringify(body),
signal: AbortSignal.timeout(60000),
});
const text = await response.text();
let result;
try { result = JSON.parse(text); }
catch { throw new Error(`HTTP ${response.status}: ответ не JSON`); }
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${result.error || 'ошибка'}; id=${result.id ?? 'нет'}`);
}
return result;
}
let job = await request('/api/v1/generate', {
image: 'data:image/png;base64,' + fs.readFileSync('car.png', 'base64'),
additionally: ['data:image/png;base64,' + fs.readFileSync('logo.png', 'base64')],
prompt: 'Авто у салона, приложенный логотип справа сверху',
headline: 'ТОПЛИВНАЯ КАРТА В ПОДАРОК',
model: 'Lada Vesta Cross',
cta: 'БРОНИРУЙ СЕЙЧАС!',
async: true,
});
const id = job.id;
console.log('Задача:', id); // сохраните id в своей CMS/CSM
const deadline = Date.now() + 15 * 60 * 1000; // лимит ожидания этого клиента
while (job.status === 'queued' || job.status === 'running') {
if (Date.now() >= deadline) throw new Error(`Ожидание закончено; продолжите опрос задачи ${id}`);
await delay(4000);
job = await request(`/api/v1/jobs/${id}`);
}
if (!job.ok || job.status !== 'done') {
throw new Error(`Задача ${id}: ${job.error || job.status}`);
}
const bytes = Buffer.from(job.image.slice(job.image.indexOf(',') + 1), 'base64');
const isPng = bytes.subarray(0, 8).equals(Buffer.from('89504e470d0a1a0a', 'hex'));
const isJpeg = bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;
const isWebp = bytes.toString('ascii', 0, 4) === 'RIFF' && bytes.toString('ascii', 8, 12) === 'WEBP';
const ext = isPng ? 'png' : isJpeg ? 'jpg' : isWebp ? 'webp' : 'bin';
fs.writeFileSync(`result.${ext}`, bytes);
console.log(`Сохранено: result.${ext}`);
GET/api/v1/jobs/<id>
Используйте тот же Bearer-ключ, которым создана задача. Другой ключ, даже с таким же именем после перевыпуска, не получает доступ к ней.
| Статус | HTTP | Поля и действие клиента |
|---|---|---|
queued | 200 | ok: true, id, status; продолжайте опрос. |
running | 200 | ok: true, id, status; продолжайте опрос. |
done | 200 | ok: true, id, status, file, model, cost, image; сохраните результат. |
error | 502 | ok: false, id, status, error; задача завершилась ошибкой. |
cancelled | 200 | ok: false, id, status; задача отменена администратором. |
ok: false возможен и при HTTP 200, поэтому проверяйте также статус задачи. Задачи находятся в памяти одного процесса. Завершённые удаляются из очереди при её разрастании примерно до 500 записей; ожидающие и выполняющиеся не удаляются этим лимитом. После рестарта очередь и счётчик id сбрасываются. Старый id может вернуть 404 либо совпасть с id новой задачи этого ключа — не используйте его как постоянный идентификатор. Получайте и сохраняйте результат сразу. Файлы и история на диске переживают рестарт.
Ошибки
Отказ до создания задачи обычно имеет вид {"error":"…"} — без ok, id и status. Ошибка выполнения имеет ok: false, id, статус и текст ошибки. Сервер не возвращает единый набор полей для всех ошибок; сначала проверяйте HTTP-код, затем тело.
| HTTP | Причина |
|---|---|
| 400 | Некорректный JSON или тип тела; отсутствует задание; превышены лимиты 4000/300 символов; некорректные изображения, количество или размер; пустой additionally без image. |
| 401 | Нет Bearer-заголовка, ключ неверный или отозван. |
| 404 | Задача отсутствует или принадлежит другому ключу. |
| 413 | JSON-тело больше 65 МБ. |
| 500 | Непредвиденная внутренняя ошибка, например недоступность файла результата. |
| 502 | Ошибка генерации у провайдера, в том числе его таймаут; подробности в error. |
| 503 | Нет ключа настроенного движка, загрузчик изображений занят либо конвертер SVG занят/недоступен. |
| 504 | Синхронное ожидание истекло; продолжайте опрос по возвращённому id. |
Повторный POST создаёт новую генерацию: ключей идемпотентности и поиска задачи по id клиентского запроса сейчас нет. Если связь оборвалась до получения id, уточните результат по трассе у администратора перед повторной отправкой.
Что важно знать
file— имя файла в истории FeedLike, а не публичная ссылка для Bearer-клиента./output/<file>требует входа в веб-интерфейс; для внешней интеграции используйтеimageв JSON.- Сервис ориентирован на квадратный креатив. OpenAI получает
size: 1024x1024; OpenRouter Images получает размер или соотношение 1:1 согласно каталогу модели. Реальные размеры результата зависят от движка и модели; запросом клиента они не задаются. - Текущий формат выдачи: data-URL всегда объявляет
image/png, аfileимеет расширение.png. Сервер сохраняет байты провайдера без перекодирования, поэтому фактически файл может быть JPEG, как у проверенных результатов Grok. Не считайте MIME-префикс гарантией кодека: определяйте формат по байтам, как в примере, если это важно для вашей CMS/CSM. - Для генерации выбираются индивидуальные настройки ключа, если они заданы, иначе общие. Они фиксируются при постановке задачи. Поддержка нескольких референсов и качества зависит от выбранной модели. Для OpenRouter Chat качество не передаётся отдельным параметром; для Images API учитываются возможности из каталога.
- Расходы записываются для успешных генераций, не для каждого HTTP-вызова; неизвестная стоимость не означает бесплатную генерацию. Внутренний журнал не заменяет биллинг провайдера.
- Раздел API-запросы показывает последние 300 вызовов генерации, включая отказы. Раскройте запрос: входящие файлы из
imageиadditionallyвидны как превью с исходными индексами, форматом и размером. «Открыть оригинал» позволяет рассмотреть файл крупнее. Некорректные элементы отмечаются отдельно. - Исходники новых авторизованных запросов хранятся отдельно от JSON до 7 дней, в пределах последних 300 записей и 256 МБ на весь журнал. При заполнении удаляются самые старые файлы. Сохраняется до 16 исходников и 48 МБ на запрос, включая PNG-превью SVG. Доступ требует входа администратора; Bearer API-ключ не даёт доступа к превью. В старых записях исходников нет.
- Неавторизованные запросы и неразобранный JSON не сохраняют изображения. Ошибка хранения превью не прерывает генерацию. Полный сырой ответ модели не сохраняется, длинные и неизвестные значения могут сокращаться. Опрос задач в трассу не записывается.
- Для проверки логотипа смотрите
request.imageиrequest.additionally.count: фото авто плюс один логотип означают один дополнительный файл.nullозначает, что массив не передан,count: 0— что он пуст. Вextraвидны неизвестные поля запроса.