Отправьте первый запрос за 5 минут
Для генерации нужен один POST-запрос на полный адрес https://seomorphy.ru/v1/generate. В нём передаются шаблоны и данные товаров.
https://seomorphy.ru/v1/generateAuthorization: Bearer <API_KEY>Content-Type: application/jsonIdempotency-Key: уникальная строка длиной 8–160 символовНастройка запроса по шагам
Создайте новый HTTP Request и заполните четыре блока.
- 1Метод и адрес
Выберите
POSTи вставьтеhttps://seomorphy.ru/v1/generate. - 2Authorization
Type:
Bearer Token. В поле Token вставьте API-ключ проекта. - 3Headers
Content-Type: application/jsonIdempotency-Key: postman-test-0001 - 4Body
Выберите
raw → JSON, вставьте пример ниже и нажмите Send.
{
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}Тот же запрос через cURL
curl --request POST "https://seomorphy.ru/v1/generate" \
--header "Authorization: Bearer <API_KEY>" \
--header "Idempotency-Key: request-$(date +%s)-$RANDOM" \
--header "Content-Type: application/json" \
--data '{
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}'Что вернёт API
Ответ уже содержит массив items и сформированные outputs.
Сохраните job_id, затем запросите статус и результаты по полным URL ниже.
В ответе 200 ниже показаны главные поля; дополнительные диагностические поля товара опущены.
Основные поля ответа · 200 OK
{
"job_id": "4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"status": "completed",
"items": [{
"external_id": "fashion-2001",
"status": "completed",
"outputs": {
"seo_title": "Купить синюю куртку в Москве и РФ",
"meta_description": "Ищете синюю куртку с доставкой? Закажите синюю куртку бренда Armani онлайн."
},
"warnings": []
}]
}Пример ответа · 202 Accepted
{
"job_id": "4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"status": "queued",
"accepted_items": 1,
"status_url": "/v1/jobs/4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"results_url": "/v1/jobs/4c64b96d-c3eb-4af4-8488-2b7be3a7df41/results",
"replayed": false
}Соберите фразу из данных товара
Обычный текст остаётся без изменений, а значения внутри двойных фигурных скобок берутся из соответствующих полей товара.
Купитьвыводится как написано{{color}}значение из JSON|case:acc|agree:product_nameменяют форму значенияШаблон: Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head}}
Данные: color = "синий", product_name = "женская куртка"
Результат: Купить синюю женскую курткуДвижок умеет автоматически распознавать некоторые конструкции вроде «Купить». Для новых формулировок — например, «Желаете» или «Интересуетесь» — надёжнее явно указать case.
Падежи: фильтр case
Добавьте |case:<падеж> после имени поля. Предлог или управляющее слово пишется обычным текстом перед плейсхолдером.
| Код | Падеж | Вопрос | Шаблон | Результат |
|---|---|---|---|---|
nom | Именительный | кто? что? | {{product_name|case:nom}} | женская куртка |
gen | Родительный | кого? чего? | Для {{product_name|case:gen}} | Для женской куртки |
dat | Дательный | кому? чему? | К {{product_name|case:dat}} | К женской куртке |
acc | Винительный | кого? что? | Купить {{product_name|case:acc}} | Купить женскую куртку |
ins | Творительный | кем? чем? | С {{product_name|case:ins}} | С женской курткой |
prep | Предложный | о ком? о чём? | О {{product_name|case:prep}} | О женской куртке |
Поддерживаются и технические алиасы: nomn, gent, datv, accs, ablt, loct. В новых шаблонах проще читать короткие коды из таблицы.
Главное поле и согласование: head, agree, lock
headВыбирает главное слово{{product_name|case:acc|head}} сообщает движку, что форма остальных характеристик зависит от названия товара. Само слово head в результат не попадёт.
agree:product_nameСогласует характеристику{{color|case:acc|agree:product_name}} превратит «синий» в «синюю» для женской куртки и в «синие» для ботинок.
lockСохраняет написание{{brand|lock}} оставляет Armani, SKU или другое зафиксированное значение без склонения.
Купить {{benefit|case:acc|agree:product_name}}
{{color|case:acc|agree:product_name}}
{{pol|case:acc|agree:product_name}}
{{product_name|case:acc|head|lower}}
бренда {{brand|lock}}Если поле встречается в шаблоне несколько раз, используйте для него одинаковые грамматические фильтры во всех вхождениях.
Необязательные данные: знак ? или блок #if
В примерах ниже brand — настоящее имя поля из JSON. Знак ? пишется сразу после имени поля внутри фигурных скобок: {{brand?}}.
{{brand?}}Скрыть только значениеЕсли brand отсутствует или пуст, его значение исчезнет без warning. Обычный текст рядом — например, слово «бренда» — останется.
{{#if brand}}…{{/if}}Скрыть весь связанный текстЕсли brand отсутствует или пуст, исчезнет всё между открывающим и закрывающим тегами: значение, слова, пробелы и знаки.
Данные: product_name = "сумка", поле brand не передано
Знак ? управляет только значением:
{{product_name|sentence}} бренда {{brand?}} с доставкой
→ Сумка бренда с доставкой
→ warning отсутствует
Условие управляет всем фрагментом:
{{product_name|sentence}}{{#if brand}} бренда {{brand}}{{/if}} с доставкой
→ Сумка с доставкой
Если brand = "Armani":
→ Сумка бренда Armani с доставкойВсе доступные конструкции и фильтры
Поля и условия
{{brand?}}Знак ? — необязательное значениеbrand — имя поля из JSON, а ? — специальный символ. Поставьте ? сразу после имени поля, без пробела. Если brand отсутствует или пуст, исчезнет только его значение и warning не появится.
{{#if brand}}…{{/if}}Необязательный фрагментИспользуйте, когда вместе со значением должны исчезнуть связанные слова или знаки. Весь блок выводится только при непустом brand; вложенные условия не поддерживаются.
Морфология
case:accПадежСклоняет поле. Доступны nom, gen, dat, acc, ins и prep.
headГлавное полеУказывает существительное, от которого зависят согласование и падеж. В шаблоне может быть один head.
agree:product_nameСогласованиеМеняет род, число и падеж зависимого поля по указанному главному полю.
lockЗафиксироватьСохраняет написание бренда, модели, SKU или другого значения без склонения.
Регистр и текст
lowerнижний регистрСумка → сумка
upperВЕРХНИЙ РЕГИСТРArmani → ARMANI
titleНачальные Заглавныеженская куртка → Женская Куртка
sentenceЗаглавная первая букваженская куртка → Женская куртка
translitТранслитерациякуртка → kurtka
Числа
numberНормализация числа12 990,5 → 12990.5
money:₽Цена и валюта12990 → 12 990 ₽
plural:рубль,рубля,рублейФорма словаВыводит только подходящую форму: рубль, рубля или рублей.
amount:рубль,рубля,рублейЧисло и форма22 → 22 рубля
Вариативность
[[Купить|Приобрести]]Варианты текстаРаботает в режиме flexible; выбор стабилен для одного external_id.
Готовые рецепты
Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head}}→ Купить синюю женскую куртку
Для {{color|case:gen|agree:product_name}} {{product_name|case:gen|head}}→ Для синей женской куртки
С {{color|case:ins|agree:product_name}} {{product_name|case:ins|head}}→ С синей женской курткой
{{product_name|sentence}}{{#if price}} — {{price|money:₽}}{{/if}}→ Женская куртка — 12 990 ₽
Какие данные передавать
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
channel | string | Нет · website | Канал результата: website, ozon, wildberries, telegram или собственная метка. |
generation_mode | strict | flexible | Нет · strict | strict — один предсказуемый шаблон. flexible — стабильный выбор вариантов из блоков [[Купить|Приобрести]]. |
templates | object | Да | Один или несколько шаблонов. Ключ становится именем поля в outputs. |
items | array | Да | От 1 до 500 товаров. |
items[].external_id | string | Да | Ваш ID товара, уникальный внутри одного задания. Длина — 1–240 символов. |
items[].<переменная> | string | number | По вашему сценарию | Поля товара из шаблона: product_name, color, brand, price. Имя — 1–128 букв, цифр либо символов _, точки и дефиса. Обычное отсутствующее поле даст warning. В записи {{brand?}} символ ? после имени поля отключает warning. |
Доступные выходные поля templates
Передавайте только те ключи, которые хотите получить. Каждый ключ появится в объекте outputs.
seo_titlemeta_descriptionh1og_titleog_descriptionyandex_market_nameozon_namewildberries_nametelegram_messageЗапуск, статус и готовый результат
После запуска дальнейшие действия зависят от HTTP-статуса ответа.
https://seomorphy.ru/v1/generateЗапустить генерацию
Передайте заголовки Authorization, Idempotency-Key, Content-Type и JSON из быстрого старта.
{
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}Основные поля ответа · 200 OK
{
"job_id": "4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"status": "completed",
"items": [{
"external_id": "fashion-2001",
"status": "completed",
"outputs": {
"seo_title": "Купить синюю куртку в Москве и РФ",
"meta_description": "Ищете синюю куртку с доставкой? Закажите синюю куртку бренда Armani онлайн."
},
"warnings": []
}]
}| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
job_id | UUID | Да | ID созданного задания. |
status | string | Да | Текущий статус: обычно queued, processing или completed. |
accepted_items | integer | Да | Количество принятых товаров. |
status_url | string | Да | Относительный путь для проверки статуса задания. |
results_url | string | Да | Относительный путь для получения готовых результатов. |
replayed | boolean | Да | true, если API вернул ранее созданное задание для того же запроса. |
Пример ответа · 202 Accepted
{
"job_id": "4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"status": "queued",
"accepted_items": 1,
"status_url": "/v1/jobs/4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"results_url": "/v1/jobs/4c64b96d-c3eb-4af4-8488-2b7be3a7df41/results",
"replayed": false
}https://seomorphy.ru/v1/jobs/{job_id}Проверить статус задания
Подставьте job_id из ответа генерации. Проверяйте статус с паузой 1–2 секунды, постепенно увеличивая интервал. При 429 используйте значение заголовка Retry-After.
Остановите проверку при completed, completed_with_warnings, failed или cancelled.
Пример ответа · 200 OK
{
"job_id": "4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"status": "processing",
"generation_mode": "strict",
"processing_stage": "items_processing",
"total": 100,
"completed": 42,
"failed": 0,
"error": null,
"created_at": "2026-08-25T20:15:30Z",
"completed_at": null,
"results_url": "/v1/jobs/4c64b96d-c3eb-4af4-8488-2b7be3a7df41/results"
}https://seomorphy.ru/v1/jobs/{job_id}/results?cursor=0Получить результаты задания
Значения находятся в items[].outputs. Если next_cursor содержит число, запросите следующую страницу с этим курсором. Пустая последняя страница вернёт null.
Основные поля ответа · 200 OK
{
"job_id": "4c64b96d-c3eb-4af4-8488-2b7be3a7df41",
"status": "completed",
"generation_mode": "strict",
"items": [{
"external_id": "fashion-2001",
"version": 1,
"status": "completed",
"outputs": {
"seo_title": "Купить синюю куртку в Москве и РФ",
"meta_description": "Ищете синюю куртку с доставкой? Закажите синюю куртку бренда Armani онлайн."
},
"warnings": []
}],
"next_cursor": 1
}Проверьте результат до массового запуска
Preview показывает реальный текст на одном товаре, а validate быстро проверяет синтаксис без генерации.
https://seomorphy.ru/v1/templates/previewПосмотреть результат на одном товаре
Лучший способ проверить падежи и согласование до отправки всего каталога.
{
"generation_mode": "strict",
"channel": "website",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head}}"
},
"item": {
"external_id": "preview-1",
"product_name": "женская куртка",
"color": "синий"
}
}Основные поля ответа · 200 OK
{
"external_id": "preview-1",
"outputs": {"seo_title": "Купить синюю женскую куртку"},
"warnings": [],
"transform_trace": {"seo_title": [{"stage": "template_graph"}]}
}https://seomorphy.ru/v1/templates/validateПроверить синтаксис шаблона
Проверяет скобки, фильтры, case, agree, head, условные блоки и варианты без генерации товара.
{
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head}}"
}
}Основные поля ответа · 200 OK
{
"valid": true,
"templates": {"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head}}"},
"errors": [],
"rule_version": "asm-grammar-v1"
}Получите сохранённые результаты позже
Эти методы нужны, когда результат уже сформирован и его требуется прочитать повторно.
https://seomorphy.ru/v1/products/{external_id}?channel=websiteПолучить актуальный результат товара
Подставьте свой external_id, чтобы получить последнюю успешную версию товара.
Основные поля ответа · 200 OK
{
"external_id": "fashion-2001",
"status": "completed",
"results": [{
"channel": "website",
"version": 2,
"outputs": {"seo_title": "Купить синюю куртку в Москве и РФ"}
}]
}https://seomorphy.ru/v1/products/lookupПолучить до 500 товаров по external_id
{
"external_ids": ["fashion-2001", "fashion-2002"],
"channel": "website"
}Основные поля ответа · 200 OK
{
"results": {
"fashion-2001": [{"version": 2, "outputs": {"seo_title": "Купить синюю куртку"}}],
"fashion-2002": []
}
}GET https://seomorphy.ru/v1/products/{external_id}/history?limit=100GET https://seomorphy.ru/v1/products/{external_id}/versions/{version}Как быстро найти причину
Ориентируйтесь на HTTP-статус и error.code. Для ошибок шаблона ответ также указывает output-поле и техническую причину.
{
"detail": {
"code": "invalid_templates",
"errors": [{
"output": "meta_description",
"code": "invalid_template_graph",
"message": "unsupported grammatical case: xyz"
}]
},
"error": {
"code": "invalid_templates",
"message": "Invalid templates",
"request_id": "9381dded-ffe0-4a61-9e06-eaaf7ba34a76",
"details": {
"errors": [{
"output": "meta_description",
"code": "invalid_template_graph",
"message": "unsupported grammatical case: xyz"
}]
}
}
}| HTTP | Причина | Что сделать |
|---|---|---|
401 | Ключ не передан или неверен | Проверьте заголовок Authorization: Bearer <API_KEY>. |
404 | Задание или товар не найден | Проверьте job_id, external_id и API-ключ проекта. |
409 | Повтор Idempotency-Key с другим JSON | Создайте новый Idempotency-Key для нового запроса. |
413 | Слишком большой запрос | Разделите каталог на несколько заданий. |
422 | Ошибка JSON или шаблона | Исправьте поле, указанное в error.details или detail. |
429 | Превышен лимит | Повторите запрос после Retry-After или проверьте доступный объём генераций. |
Размер одного запроса
Скопируйте запрос для своего стека
Во всех примерах используется один адрес генерации и одинаковый JSON.
cURLbash
curl --request POST "https://seomorphy.ru/v1/generate" \
--header "Authorization: Bearer <API_KEY>" \
--header "Idempotency-Key: request-$(date +%s)-$RANDOM" \
--header "Content-Type: application/json" \
--data '{
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}'JavaScript / TypeScripttypescript
const response = await fetch("https://seomorphy.ru/v1/generate", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.SEO_MORPHY_API_KEY,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}),
});
const result = await response.json();
console.log(result);Python 3python
import json
import os
import uuid
from urllib.request import Request, urlopen
payload = {
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}
request = Request(
"https://seomorphy.ru/v1/generate",
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
method="POST",
headers={
"Authorization": "Bearer " + os.environ["SEO_MORPHY_API_KEY"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
)
with urlopen(request, timeout=30) as response:
print(json.load(response))PHP 8php
<?php
$payload = <<<'JSON'
{
"channel": "website",
"generation_mode": "strict",
"templates": {
"seo_title": "Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ",
"meta_description": "Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн."
},
"items": [
{
"external_id": "fashion-2001",
"product_name": "куртка",
"brand": "Armani",
"color": "синий"
}
]
}
JSON;
$curl = curl_init('https://seomorphy.ru/v1/generate');
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SEO_MORPHY_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $payload,
]);
echo curl_exec($curl);1С:Предприятие1c
APIКлюч = ПолучитьAPIКлюч();
ТелоJSON = "{""channel"":""website"",""generation_mode"":""strict"",""templates"":{""seo_title"":""Купить {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} в Москве и РФ"",""meta_description"":""Ищете {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} с доставкой? Закажите {{color|case:acc|agree:product_name}} {{product_name|case:acc|head|lower}} бренда {{brand|lock}} онлайн.""},""items"":[{""external_id"":""fashion-2001"",""product_name"":""куртка"",""brand"":""Armani"",""color"":""синий""}]}";
SSL = Новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение("seomorphy.ru", 443,,,, SSL);
Запрос = Новый HTTPЗапрос("/v1/generate");
Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
Запрос.Заголовки.Вставить("Idempotency-Key", Строка(Новый УникальныйИдентификатор));
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(ТелоJSON, КодировкаТекста.UTF8);
Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос);
Сообщить(Ответ.ПолучитьТелоКакСтроку());