Витрина
Через API бэк-офиса приложение может управлять содержимым витрины: блогами, статьями, страницами, меню, JS-тегами и редиректами.
Если объекта с указанным идентификатором нет, API возвращает 404 с HTML-страницей, даже при запросе JSON. Это относится к блогам, статьям, страницам, меню, пунктам меню, JS-тегам и редиректам.
Для изменения записи используйте PUT. У блогов и страниц также поддерживается PATCH: он выполняет то же изменение и возвращает тот же статус. Редиректы нельзя изменить: для них PUT и PATCH возвращают 404.
Если page меньше 1 или больше либо равен 1000000, API возвращает 422:
{"message": "page должен иметь значение, большее 0"}
Если метод ожидает корневой объект, а тело пустое, API возвращает 422 с сообщением param is missing or the value is empty or invalid. В сообщении указывается нужный ключ: blog, menu, js_tag или redirect.
Для создания записи используйте POST к соответствующему ресурсу, для удаления — DELETE.
Язык
Параметр lang выбирает язык для чтения и записи текстовых полей блога и статьи. Язык должен быть включён в магазине. При чтении без lang возвращается текст на языке магазина по умолчанию.
Чтобы добавить перевод существующей записи, отправьте PUT на её идентификатор с нужным lang. Поля title, content и author сохранятся на указанном языке, а permalink останется прежним. Для чтения перевода передайте тот же lang в GET-запросе.
Каждый POST создаёт отдельную запись. Если повторить его с другим lang, появится вторая запись, а не перевод первой.
Если язык из lang не включён в магазине, текст сохраняется на языке по умолчанию, заменяя его текущее значение.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
id обязательныйчисло |
id статьи в пути. |
lang обязательныйстрока |
Код языка, включённого в магазине. |
article[title] необязательныйстрока |
Название на этом языке. |
article[content] необязательныйстрока |
Текст на этом языке. |
article[author] необязательныйстрока |
Автор на этом языке. |
PUT /admin/blogs/9/articles/121.json?lang=en
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "docs-api english",
"content": "<p>english</p>",
"author": "Author"
}
}
Ответ · 200
{
"id": 121,
"title": "docs-api english",
"content": "<p>english</p>",
"author": "Author",
"permalink": "docs-api-russkaya"
}
В примере изменяются только переводимые поля. Остальные поля статьи описаны в разделе «Создание статьи».
Блоги
GET /admin/blogs.json возвращает все блоги одним массивом, без постраничного деления. Адрес блога, который не является главным, имеет вид /blogs/{handle}. В JSON используется поле handle; отдельного поля permalink у блога нет.
commentable на витрине использует no, yes и moderable. Другое значение тоже сохраняется и возвращается.
Поле category принимает одно из значений: Авто, Военторг, Дизайн, Дом, Еда, Здоровье, Знаменитости, Игры, Кино, Культура, Литература, Мода, Музыка, Наука, Общество, Политика, Природа, Происшествия, Психология, Путешествия, Спорт, Технологии, Фотографии, Хобби, Экономика, Юмор. Другие значения отклоняются со статусом 422.
Поля category, check_spam_enabled и custom_layout принимаются в запросе, но не возвращаются в JSON блога, в том числе при повторном чтении. Поле custom_template возвращается. О назначении файла шаблона читайте в разделе «Темы, ассеты и файлы».
Список блогов
GET /admin/blogs.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
[
{
"id": 9,
"commentable": "no",
"notify_about_comment": true,
"captcha_enabled": false,
"disallow_links_in_comments": false,
"custom_template": null,
"handle": "docs-api-blog",
"title": "docs-api блог",
"html_title": null,
"meta_keywords": null,
"meta_description": null,
"tags": []
}
]
tags — массив объектов с title.
Создание блога
Для создания блога обязателен title. Значение handle формируется из названия транслитерацией. Если оно уже занято, InSales добавляет суффикс -2 и создаёт блог со статусом 201. Значение длиной больше 16 символов также сохраняется.
| Параметр | Описание |
|---|---|
blog[title] обязательныйстрока |
Название. Из него строится handle, если handle не передан. |
blog[handle] необязательныйстрока |
Сегмент адреса `/blogs/{handle}`. |
POST /admin/blogs.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"blog": {
"title": "docs-api блог"
}
}
Ответ · 201
{
"id": 9,
"commentable": "no",
"notify_about_comment": true,
"captcha_enabled": false,
"disallow_links_in_comments": false,
"custom_template": null,
"handle": "docs-api-blog",
"title": "docs-api блог",
"html_title": null,
"meta_keywords": null,
"meta_description": null,
"tags": []
}
Повтор с тем же handle создаёт второй блог.
| Параметр | Описание |
|---|---|
blog[title] обязательныйстрока |
Название второго блога. |
blog[handle] необязательныйстрока |
Занятое значение. В ответе к нему добавлен суффикс. |
POST /admin/blogs.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"blog": {
"title": "docs-api другой",
"handle": "docs-api-blog"
}
}
Ответ · 201
{
"id": 17,
"commentable": "no",
"notify_about_comment": true,
"captcha_enabled": false,
"disallow_links_in_comments": false,
"custom_template": null,
"handle": "docs-api-blog-2",
"title": "docs-api другой",
"html_title": null,
"meta_keywords": null,
"meta_description": null,
"tags": []
}
Изменение блога
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id блога в пути. |
blog[title] необязательныйстрока |
Название. |
blog[handle] необязательныйстрока |
Сегмент адреса. |
blog[html_title] необязательныйстрока |
Заголовок окна. |
blog[meta_keywords] необязательныйстрока |
Ключевые слова. |
blog[meta_description] необязательныйстрока |
Описание. |
blog[commentable] необязательныйстрока |
`no`, `yes` или `moderable`. |
blog[notify_about_comment] необязательныйлогический |
Письмо о комментарии. |
blog[captcha_enabled] необязательныйлогический |
Капча в комментариях. |
blog[disallow_links_in_comments] необязательныйлогический |
Запрет ссылок в комментариях. |
blog[custom_template] необязательныйстрока |
Имя шаблона. Возвращается в JSON. |
blog[category] необязательныйстрока |
Категория из списка выше. В JSON блога поля нет. |
PUT /admin/blogs/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"blog": {
"title": "docs-api блог полный",
"handle": "docs-api-blog",
"html_title": "HTML блога",
"meta_keywords": "ключи",
"meta_description": "описание",
"commentable": "yes",
"notify_about_comment": false,
"captcha_enabled": true,
"disallow_links_in_comments": true,
"category": "Технологии",
"custom_template": "blog.custom"
}
}
Ответ · 200
{
"id": 9,
"commentable": "yes",
"notify_about_comment": false,
"captcha_enabled": true,
"disallow_links_in_comments": true,
"custom_template": "blog.custom",
"handle": "docs-api-blog",
"title": "docs-api блог полный",
"html_title": "HTML блога",
"meta_keywords": "ключи",
"meta_description": "описание",
"tags": []
}
Чужая категория отклоняется. Ключ ошибки — category.
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id блога в пути. |
blog[category] обязательныйстрока |
Значение вне списка категорий. |
PUT /admin/blogs/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"blog": {
"category": "Несуществующая"
}
}
Ответ · 422
{"category": ["имеет непредусмотренное значение"]}
Удаление блога
При удалении блога его статьи переносятся в архив. После этого чтение блога и его статей возвращает 404.
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id блога в пути. |
DELETE /admin/blogs/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
{"status": "ok"}
Статьи
Чтобы создать статью, отправьте POST /admin/blogs/:blog_id/articles.json в нужный блог.
GET /admin/blogs/:blog_id/articles.json возвращает статьи одного блога. Сначала идёт закреплённая статья, затем остальные по убыванию published_at и id.
По умолчанию на странице 10 статей. Параметры per_page и limit ограничены диапазоном от 10 до 250: значения за его пределами заменяются ближайшей границей. Параметр updated_since не фильтрует список статей.
Для создания статьи обязательны title, content, author и published_at. Пустые значения отклоняются со статусом 422. Ошибка текста возвращается под ключом content_with_urls, а не content.
Если дата публикации передана без времени, InSales использует полночь в часовом поясе магазина. Например, 2024-05-02 в магазине с поясом +03:00 сохраняется как 2024-05-02T00:00:00.000+03:00.
permalink можно задать. Если его нет, он строится из названия транслитом.
Опубликованная статья доступна на витрине по адресу /blogs/{handle}/{permalink} со статусом 200. Если published_at находится в будущем, статья уже доступна в API, но её обычный адрес возвращает 404. Предпросмотр /blogs/{handle}/{permalink}/preview возвращает 200. Адрес /blog/{permalink} для статьи неглавного блога возвращает 404.
Комментариев статьи в этом API нет. GET /admin/comments.json и GET /admin/blogs/:blog_id/articles/:id/comments.json отвечают 404.
Создание статьи
Поле all_tags заменяет список тегов целиком. Можно назначить не более 30 тегов. При передаче 31 тега API возвращает 422: «Невозможно задать больше 30 тегов к статье.»
Чтобы привязать товары к статье, передайте related_products_attributes с product_id. Массив идентификаторов в related_products не привязывает товары: статья создаётся с пустым списком. Несуществующий идентификатор отклоняется со статусом 422: «Товары 999999999 не найдены». Для удаления привязки передайте элемент того же массива с _destroy: true.
related_products — товары статьи.
Одновременно может быть закреплена одна статья. Если сохранить другую статью с pinned: true, у ранее закреплённой статьи pinned станет false.
HTML в content сохраняется как передан, включая meta и script.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
article[title] обязательныйстрока |
Название. |
article[content] обязательныйстрока |
Текст. В ошибке ключ называется `content_with_urls`. |
article[author] обязательныйстрока |
Автор. |
article[published_at] обязательныйстрока |
Дата публикации. |
article[notice] необязательныйстрока |
Анонс. |
article[permalink] необязательныйстрока |
Сегмент адреса статьи. |
article[html_title] необязательныйстрока |
Заголовок окна. |
article[meta_keywords] необязательныйстрока |
Ключевые слова. |
article[meta_description] необязательныйстрока |
Описание. |
article[all_tags] необязательныймассив |
Теги. Новый список заменяет прежний. Максимум 30. |
article[pinned] необязательныйлогический |
Закрепить. Предыдущая закреплённая снимается. |
article[custom_template] необязательныйстрока |
Имя шаблона. |
article[related_products_attributes] необязательныймассив |
Товары статьи. Элемент содержит `product_id`. |
POST /admin/blogs/9/articles.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "docs-api статья",
"content": "<p>Текст статьи</p>",
"notice": "<p>Анонс</p>",
"author": "Документация",
"permalink": "docs-api-article",
"html_title": "HTML статьи",
"meta_keywords": "статья",
"meta_description": "описание статьи",
"published_at": "2024-05-01T10:00:00+03:00",
"all_tags": ["docs-api", "витрина"],
"pinned": true,
"custom_template": "article.custom",
"related_products_attributes": [
{"product_id": 601}
]
}
}
Ответ · 201
{
"id": 9,
"created_at": "2026-10-21T22:15:45.000+03:00",
"updated_at": "2026-10-21T22:15:45.000+03:00",
"published_at": "2024-05-01T10:00:00.000+03:00",
"pinned": true,
"custom_template": "article.custom",
"title": "docs-api статья",
"author": "Документация",
"permalink": "docs-api-article",
"html_title": "HTML статьи",
"meta_keywords": "статья",
"meta_description": "описание статьи",
"tags": [
{"title": "docs-api"},
{"title": "витрина"}
],
"related_products": [
{
"id": 601,
"title": "Футболка с принтом"
}
],
"notice": "<p>Анонс</p>",
"content": "<p>Текст статьи</p>"
}
Массив id в related_products статью создаёт, товары не привязывает.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
article[title] обязательныйстрока |
Название. |
article[content] обязательныйстрока |
Текст. |
article[author] обязательныйстрока |
Автор. |
article[published_at] обязательныйстрока |
Дата публикации. |
article[related_products] необязательныймассив |
Список id. Привязки товаров не создаёт. |
POST /admin/blogs/9/articles.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "docs-api товары массивом",
"content": "<p>x</p>",
"author": "Документация",
"published_at": "2024-05-02",
"related_products": [601]
}
}
Ответ · 201
{
"id": 17,
"published_at": "2024-05-02T00:00:00.000+03:00",
"pinned": false,
"title": "docs-api товары массивом",
"author": "Документация",
"permalink": "docs-api-tovary-massivom",
"tags": [],
"related_products": [],
"notice": null,
"content": "<p>x</p>"
}
Неизвестный товар отклоняет всю статью.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
article[related_products_attributes] обязательныймассив |
Элемент с id, которого нет в магазине. |
POST /admin/blogs/9/articles.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "docs-api чужой товар",
"content": "<p>x</p>",
"author": "Документация",
"published_at": "2024-05-03",
"related_products_attributes": [
{"product_id": 999999999}
]
}
}
Ответ · 422
{"related_products_attributes": ["Товары 999999999 не найдены"]}
Без текста, автора и даты статья не создаётся. Если название передано, ключа title в ошибке нет.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
article[title] обязательныйстрока |
Название. Остальные обязательные поля в запросе пустые. |
POST /admin/blogs/9/articles.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "только название"
}
}
Ответ · 422
{
"published_at": ["Не заполнены обязательные поля"],
"author": ["Не заполнены обязательные поля"],
"content_with_urls": ["Не заполнены обязательные поля"]
}
Картинка статьи
Изображение статьи передаётся при создании или изменении статьи, в том же POST или PUT. Отдельного метода загрузки нет. Используйте один из способов: содержимое файла в Base64 в attachment вместе с filename или публичный адрес в src. Пока InSales обрабатывает файл, original_url может указывать на /images/loading.gif.
Внутренний адрес в src отвечает 422, ключ ошибки — image.src, текст «Недопустимый URL».
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
article[image_attributes][filename] обязательныйстрока |
Имя файла. |
article[image_attributes][attachment] обязательныйстрока |
Содержимое файла, base64. |
POST /admin/blogs/9/articles.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "docs-api с картинкой",
"content": "<p>картинка</p>",
"author": "Документация",
"published_at": "2024-06-01",
"image_attributes": {
"filename": "dot.png",
"attachment": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
}
}
}
Ответ · 201
{
"id": 41,
"published_at": "2024-06-01T00:00:00.000+03:00",
"pinned": false,
"title": "docs-api с картинкой",
"author": "Документация",
"permalink": "docs-api-s-kartinkoy",
"image": {
"id": 1,
"created_at": "2026-10-21T22:15:46.000+03:00",
"original_url": "/images/loading.gif"
},
"tags": [],
"notice": null,
"content": "<p>картинка</p>"
}
Публичный адрес тоже создаёт картинку. В ответе снова временный original_url.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
article[image_attributes][src] обязательныйстрока |
Публичный URL файла. |
POST /admin/blogs/33/articles.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"title": "docs-api картинка по ссылке",
"content": "<p>картинка</p>",
"author": "Документация",
"published_at": "2024-07-02",
"image_attributes": {
"src": "https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png"
}
}
}
Ответ · 201
{
"title": "docs-api картинка по ссылке",
"image": {
"id": 9,
"created_at": "2026-10-21T22:27:13.000+03:00",
"original_url": "/images/loading.gif"
}
}
Список статей блога
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
per_page необязательныйчисло |
Размер страницы. Меньше 10 становится 10, больше 250 становится 250. |
limit необязательныйчисло |
То же, что `per_page`. |
page необязательныйчисло |
Номер страницы. `0` отвечает 422. |
GET /admin/blogs/9/articles.json?per_page=10&page=2
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
[
{
"id": 81,
"created_at": "2026-10-21T22:15:48.000+03:00",
"updated_at": "2026-10-21T22:15:48.000+03:00",
"published_at": "2020-01-04T00:00:00.000+03:00",
"pinned": false,
"custom_template": null,
"title": "docs-api пачка 3",
"author": "Документация",
"permalink": "docs-api-pachka-3",
"html_title": null,
"meta_keywords": null,
"meta_description": null,
"tags": [],
"related_products": [],
"notice": null,
"content": "<p>пачка</p>"
}
]
Если per_page меньше 10, API использует размер страницы 10.
page=0 отклоняется.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
page обязательныйчисло |
Номер страницы меньше 1. |
GET /admin/blogs/9/articles.json?page=0
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 422
{"message": "page должен иметь значение, большее 0"}
Замена тегов и товаров
Чтобы заменить все теги статьи, передайте полный список в all_tags запросом PUT. Для удаления привязки товара передайте _destroy в related_products_attributes.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
id обязательныйчисло |
id статьи в пути. |
article[all_tags] обязательныймассив |
Новый полный список тегов. |
PUT /admin/blogs/9/articles/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"all_tags": ["только-этот"]
}
}
Ответ · 200
{
"id": 9,
"title": "docs-api статья",
"permalink": "docs-api-article",
"tags": [
{"title": "только-этот"}
]
}
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
id обязательныйчисло |
id статьи в пути. |
article[related_products_attributes] обязательныймассив |
Элемент с `product_id` и `_destroy: true` снимает товар. |
PUT /admin/blogs/9/articles/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"article": {
"related_products_attributes": [
{"product_id": 601, "_destroy": true}
]
}
}
Ответ · 200
{
"id": 9,
"title": "docs-api статья",
"related_products": []
}
Удаление статьи
Удаление архивирует статью. Следующий GET отвечает 404, в списке её нет.
| Параметр | Описание |
|---|---|
blog_id обязательныйчисло |
id блога в пути. |
id обязательныйчисло |
id статьи в пути. |
DELETE /admin/blogs/9/articles/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
{"status": "ok"}
Страницы
Адрес страницы — /page/{permalink}. GET /admin/pages.json возвращает страницы без фиксированного порядка.
По умолчанию на странице до 25 записей. Если per_page меньше 25, API использует 25; если больше 1000 — 1000.
content обязателен. permalink можно задать. Занятый permalink сохраняется с суффиксом -2. Занятое название отвечает 422: «уже существует». created_at можно передать, значение сохраняется. custom_template сохраняется и возвращается. Файл шаблона — в темах.
is_hidden и kind из запроса не применяются. В ответе is_hidden равен false, kind — only_page.
Если в магазине уже есть меню, новая страница автоматически добавляется в первое из них. Параметр menu_id не позволяет выбрать другое меню. Пункт получает название страницы и адрес /page/{permalink}.
Создание страницы
| Параметр | Описание |
|---|---|
page[title] обязательныйстрока |
Название. Повтор того же названия отвечает 422. |
page[content] обязательныйстрока |
Текст. Пустой текст отвечает 422. |
page[permalink] необязательныйстрока |
Сегмент адреса `/page/{permalink}`. Занятый получает суффикс. |
page[html_title] необязательныйстрока |
Заголовок окна. |
page[meta_keywords] необязательныйстрока |
Ключевые слова. |
page[meta_description] необязательныйстрока |
Описание. |
page[custom_template] необязательныйстрока |
Имя шаблона. Сохраняется как передано. |
page[created_at] необязательныйстрока |
Дата создания. Сохраняется из запроса. |
page[is_hidden] необязательныйлогический |
В объект не записывается. |
page[kind] необязательныйстрока |
В объект не записывается. В ответе остаётся `only_page`. |
page[menu_id] необязательныйчисло |
Меню не выбирает. Пункт создаётся в первом меню. |
POST /admin/pages.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"page": {
"title": "docs-api страница",
"content": "<p>Текст страницы</p>",
"permalink": "docs-api-page",
"html_title": "HTML страницы",
"meta_keywords": "страница",
"meta_description": "описание страницы",
"custom_template": "page.custom",
"created_at": "2014-09-09T00:00:00+04:00",
"is_hidden": true,
"kind": "privacy_policy"
}
}
Ответ · 201
{
"id": 31,
"meta_keywords": "страница",
"meta_description": "описание страницы",
"is_hidden": false,
"kind": "only_page",
"permalink": "docs-api-page",
"custom_template": "page.custom",
"created_at": "2014-09-09T00:00:00.000+04:00",
"updated_at": "2026-10-21T22:15:51.000+03:00",
"is_main": false,
"title": "docs-api страница",
"html_title": "HTML страницы",
"content": "<p>Текст страницы</p>"
}
Пустой текст отклоняется. В ключе ошибки — content_with_urls.
| Параметр | Описание |
|---|---|
page[title] обязательныйстрока |
Название. Текст в запросе пустой. |
POST /admin/pages.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"page": {
"title": "docs-api без текста"
}
}
Ответ · 422
{"content_with_urls": ["Добавьте какой-нибудь текст на страницу, даже если она будет скрыта."]}
Занятый permalink создаёт страницу с суффиксом.
| Параметр | Описание |
|---|---|
page[title] обязательныйстрока |
Другое название. |
page[content] обязательныйстрока |
Текст. |
page[permalink] обязательныйстрока |
Permalink, который уже есть у другой страницы. |
POST /admin/pages.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"page": {
"title": "docs-api другая страница",
"content": "<p>ещё</p>",
"permalink": "docs-api-page"
}
}
Ответ · 201
{
"id": 32,
"is_hidden": false,
"kind": "only_page",
"permalink": "docs-api-page-2",
"is_main": false,
"title": "docs-api другая страница",
"content": "<p>ещё</p>"
}
Изменение страницы
При изменении страницы PUT и PATCH возвращают {"status":"ok"}. Чтобы получить обновлённый объект страницы, выполните отдельный GET-запрос.
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id страницы в пути. |
page[title] необязательныйстрока |
Название. |
page[content] необязательныйстрока |
Текст. |
PUT /admin/pages/31.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"page": {
"title": "docs-api страница обновлена",
"content": "<p>Новый текст</p>"
}
}
Ответ · 200
{"status": "ok"}
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id страницы в пути. |
GET /admin/pages/31.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
{
"id": 31,
"meta_keywords": "страница",
"meta_description": "описание страницы",
"is_hidden": false,
"kind": "only_page",
"permalink": "docs-api-page",
"custom_template": "page.custom",
"created_at": "2014-09-09T00:00:00.000+04:00",
"updated_at": "2026-10-21T22:15:51.000+03:00",
"is_main": false,
"title": "docs-api страница обновлена",
"html_title": "HTML страницы",
"content": "<p>Новый текст</p>"
}
Удаление страницы
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id страницы в пути. |
DELETE /admin/pages/31.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
{"status": "ok"}
Меню
GET /admin/menus.json возвращает все меню без постраничного деления. Пункты не включаются в объект меню; запрашивайте их отдельно.
Поле handle задаёт имя меню латиницей. Допустимы строчные буквы, цифры, дефис и точка. Ошибки этого поля возвращаются под ключом liquid_name.
POST /admin/menus/order.json отвечает 404. Порядок пунктов задаётся полем position.
Создание меню
| Параметр | Описание |
|---|---|
menu[name] обязательныйстрока |
Название. |
menu[handle] необязательныйстрока |
Латинское имя. В ошибке ключ называется `liquid_name`. |
menu[used_in_theme] необязательныйлогический |
Меню используется в теме. По умолчанию `false`. |
POST /admin/menus.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"menu": {
"name": "docs-api меню",
"handle": "docs-api-menu"
}
}
Ответ · 201
{
"id": 1,
"name": "docs-api меню",
"handle": "docs-api-menu",
"used_in_theme": false
}
Кириллица и пробел в handle отклоняются.
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id меню в пути. |
menu[handle] обязательныйстрока |
Имя с символами вне латиницы, цифр, дефиса и точки. |
PUT /admin/menus/1.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"menu": {
"handle": "Плохой Хэндл"
}
}
Ответ · 422
{"liquid_name": ["имеет неверное значение"]}
Занятый handle тоже отвечает 422, ключ тот же: «уже существует».
Удаление меню
Тело ответа пустое.
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id меню в пути. |
DELETE /admin/menus/1.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
Пункты меню
GET /admin/menus/:menu_id/items.json возвращает плоский список пунктов меню. Поля родителя нет, поэтому задать вложенность через этот ресурс нельзя. При создании пункты получают последовательные позиции, начиная с 1.
Поле related_object_id связывает пункт меню с объектом магазина. Для страницы, коллекции и блога InSales формирует url автоматически:
related_object_id |
url в ответе |
|---|---|
Page_31 |
/page/docs-api-page |
Collection_53486010 |
/collection/all |
Blog_9 |
/blogs/docs-api-blog |
Page_0 |
адрес из url |
Page_-2 |
/cart_items |
Page_-3 |
/client_account/login |
Page_-5 |
/compares |
Page_-6 |
/favorites |
Page_-7 |
якорь из url, сохраняется #delivery |
Внешняя ссылка без related_object_id сохраняется как Page_0. Произвольный путь тоже: Page_0 и url /page/docs-api-page.
Название уникально внутри меню. Пустое название и неверный адрес отвечают 422, ошибки возвращаются в объекте errors. У блога и страницы объект errors в таком ответе не используется.
Свободное значение position, например 50, сохраняется. Если позиция занята, PUT возвращает 200 и переданное число в теле ответа, но фактическая позиция остаётся прежней. Проверяйте её отдельным GET-запросом.
Удаление пункта отвечает 200 с пустым телом.
Пункт на страницу
| Параметр | Описание |
|---|---|
menu_id обязательныйчисло |
id меню в пути. |
menu_item[title] обязательныйстрока |
Название пункта. |
menu_item[related_object_id] обязательныйстрока |
`Page_` и id страницы. Адрес собирается из permalink. |
POST /admin/menus/1/items.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"menu_item": {
"title": "docs-api пункт страница",
"related_object_id": "Page_31"
}
}
Ответ · 201
{
"id": 1,
"position": 1,
"title": "docs-api пункт страница",
"url": "/page/docs-api-page",
"related_object_id": "Page_31"
}
Внешняя ссылка и корзина
| Параметр | Описание |
|---|---|
menu_id обязательныйчисло |
id меню в пути. |
menu_item[title] обязательныйстрока |
Название пункта. |
menu_item[url] обязательныйстрока |
Абсолютный адрес. Пункт сохраняется как `Page_0`. |
POST /admin/menus/1/items.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"menu_item": {
"title": "docs-api внешняя",
"url": "https://example.com/docs"
}
}
Ответ · 201
{
"id": 25,
"position": 4,
"title": "docs-api внешняя",
"url": "https://example.com/docs",
"related_object_id": "Page_0"
}
| Параметр | Описание |
|---|---|
menu_id обязательныйчисло |
id меню в пути. |
menu_item[title] обязательныйстрока |
Название пункта. |
menu_item[related_object_id] обязательныйстрока |
`Page_-2` — корзина. Адрес в ответе `/cart_items`. |
POST /admin/menus/1/items.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"menu_item": {
"title": "docs-api корзина",
"related_object_id": "Page_-2"
}
}
Ответ · 201
{
"id": 33,
"position": 5,
"title": "docs-api корзина",
"url": "/cart_items",
"related_object_id": "Page_-2"
}
Адрес not a url отвечает 422.
| Параметр | Описание |
|---|---|
menu_id обязательныйчисло |
id меню в пути. |
menu_item[title] обязательныйстрока |
Название пункта. |
menu_item[url] обязательныйстрока |
Строка, которая не является адресом. |
POST /admin/menus/1/items.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"menu_item": {
"title": "docs-api плохой url",
"url": "not a url"
}
}
Ответ · 422
{"errors": {"url": ["имеет неверное значение"]}}
JS-теги
JS-тег позволяет добавить код на витрину. GET /admin/js_tags.json возвращает только теги приложения, указанного в авторизации HTTP Basic. Другой ключ получает пустой массив. Попытка прочитать или удалить чужой тег возвращает 404.
В текст JS-тега передавайте JavaScript. Конструкции Liquid остаются текстом и не выполняются. Код подключается на витрине, если у тега enabled: true. Поле enabled принимается и сохраняется, но в JSON-ответ не включается.
Для скрипта в карточке заказа или товара бэк-офиса есть виджеты приложения.
JS-тег может иметь тип JsTag::TextTag или JsTag::FileTag. Тип можно изменить через PUT.
Для TextTag передавайте сам JavaScript без тега script. Если добавить тег, API вернёт 422: «В теле не должно быть тега <script>». Для FileTag передавайте URL файла в content. Если значение не является адресом, ошибка 422 возвращается под ключом url, а не content. Неизвестный тип отклоняется со статусом 422 с ошибками по content, account_id и type; поля не сохраняются.
Текст и файл
| Параметр | Описание |
|---|---|
js_tag[type] обязательныйстрока |
`JsTag::TextTag` или `JsTag::FileTag`. |
js_tag[content] обязательныйстрока |
Код без тега `script` либо URL файла. |
js_tag[name] необязательныйстрока |
Название тега. |
js_tag[enabled] необязательныйлогический |
Вывод на витрину. В ответе поля нет. |
POST /admin/js_tags.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"js_tag": {
"type": "JsTag::TextTag",
"content": "console.log('docs-api')",
"name": "docs-api text",
"enabled": false
}
}
Ответ · 201
{
"content": "console.log('docs-api')",
"id": 1,
"name": "docs-api text",
"created_at": "2026-10-21T22:15:58.000+03:00",
"updated_at": "2026-10-21T22:15:58.000+03:00",
"type": "JsTag::TextTag"
}
| Параметр | Описание |
|---|---|
js_tag[type] обязательныйстрока |
`JsTag::FileTag`. |
js_tag[content] обязательныйстрока |
URL скрипта. |
js_tag[name] необязательныйстрока |
Название тега. |
POST /admin/js_tags.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"js_tag": {
"type": "JsTag::FileTag",
"content": "https://example.com/docs-api.js",
"name": "docs-api file"
}
}
Ответ · 201
{
"content": "https://example.com/docs-api.js",
"id": 9,
"name": "docs-api file",
"created_at": "2026-10-21T22:15:58.000+03:00",
"updated_at": "2026-10-21T22:15:58.000+03:00",
"type": "JsTag::FileTag"
}
Тег script в тексте отклоняется. Если для файла передать некорректный URL, ошибка возвращается под ключом url.
| Параметр | Описание |
|---|---|
js_tag[type] обязательныйстрока |
`JsTag::TextTag`. |
js_tag[content] обязательныйстрока |
Текст, внутри которого есть тег `script`. |
POST /admin/js_tags.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"js_tag": {
"type": "JsTag::TextTag",
"content": "<script>alert(1)</script>",
"name": "docs-api script"
}
}
Ответ · 422
{"content": ["В теле не должно быть тега <script>"]}
Строка, которая не является адресом, у JsTag::FileTag отвечает 422. Ключ ошибки — url.
| Параметр | Описание |
|---|---|
js_tag[type] обязательныйстрока |
`JsTag::FileTag`. |
js_tag[content] обязательныйстрока |
Текст, который не разбирается как URL. |
js_tag[name] необязательныйстрока |
Название тега. |
POST /admin/js_tags.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"js_tag": {
"type": "JsTag::FileTag",
"content": "не адрес",
"name": "docs-api bad"
}
}
Ответ · 422
{"url": ["Невалидный URL-адрес."]}
Неизвестный тип отвечает так, как будто поля не заданы.
| Параметр | Описание |
|---|---|
js_tag[type] обязательныйстрока |
Тип вне `JsTag::TextTag` и `JsTag::FileTag`. |
js_tag[content] необязательныйстрока |
Код. При неизвестном типе до проверки содержания не доходит. |
POST /admin/js_tags.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"js_tag": {
"type": "JsTag::Other",
"content": "alert(1)",
"name": "x"
}
}
Ответ · 422
{
"content": ["Не заполнены обязательные поля"],
"account_id": ["Не заполнены обязательные поля"],
"type": ["Unknown type"]
}
Удаление JS-тега
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id тега этого приложения. |
DELETE /admin/js_tags/9.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
{"status": "ok"}
Редиректы
Для создания редиректа используйте POST /admin/redirects.json. Изменение не поддерживается: PUT и PATCH возвращают 404. Удаляйте редиректы по одному через DELETE; успешный ответ содержит {"status":"ok"}. Метода массового удаления нет.
Витрина отвечает 301 на адрес, который находится по правилам ниже. Редирект действует на запрос страницы. Адрес с суффиксом .json витрина по этим правилам не перенаправляет.
По умолчанию список содержит до 100 записей. У per_page нет нижней границы. Порядок записей не задан, поэтому одна запись может попасть на несколько страниц. При сборе списка увеличьте per_page или исключайте повторы по id.
q[q] ищет подстроку в старом и новом адресе. q[c_from] и q[c_to] ограничивают created_at по часовому поясу магазина.
Создание
При сохранении старого адреса InSales удаляет схему и хост, оставляя путь. Например, https://example.com/from-outside сохраняется как /from-outside. Завершающий / также удаляется. При этом запрос витрины с завершающим / не совпадёт с сохранённым правилом.
Новый адрес на домене магазина также сохраняется как путь без завершающего /: https://abc.myinsales.ru/catalog/ станет /catalog. Адрес другого сайта сохраняется целиком: https://example.com/catalog.
Одинаковые старый и новый адреса отвечают 422, ключ new_url: «имеет неверное значение».
Нельзя создать редирект с корня / или с адреса, первый сегмент которого входит в список ниже. Для /delivery возвращается ошибка «Недопустимый URL. Путь '/delivery/' не может быть использован в качестве первой составной части старого URL.». Для корня в таком же сообщении указан путь ///.
Запрещённый первый сегмент: orders, cart_items, payments, auth, address, delivery, payment, fast_checkout, new_order, compares, cities, bank_receipts, yandex_market, yandex_snippets, torg_mail, sitemap, robots, juridical_person_receipts, yandex_market_fast_checkout, counter_settings, codes_settings.
| Параметр | Описание |
|---|---|
redirect[old_url] обязательныйстрока |
Старый адрес. Абсолютный сохраняется путём. |
redirect[new_url] обязательныйстрока |
Новый адрес. |
POST /admin/redirects.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"redirect": {
"old_url": "/docs-api-old",
"new_url": "/page/docs-api-page"
}
}
Ответ · 201
{
"id": 1,
"old_url": "/docs-api-old",
"new_url": "/page/docs-api-page",
"created_at": "2026-10-21T22:16:05.251+03:00"
}
Абсолютные адреса своего домена myinsales становятся путями.
| Параметр | Описание |
|---|---|
redirect[old_url] обязательныйстрока |
Абсолютный адрес. В ответе остаётся путь. |
redirect[new_url] обязательныйстрока |
Адрес на поддомен.myinsales. В ответе возвращается путь без завершающего /. |
POST /admin/redirects.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"redirect": {
"old_url": "https://example.com/from-outside",
"new_url": "https://abc.myinsales.ru/catalog/"
}
}
Ответ · 201
{
"id": 11,
"old_url": "/from-outside",
"new_url": "/catalog",
"created_at": "2026-10-21T22:26:54.750+03:00"
}
Чужой новый адрес остаётся абсолютным.
| Параметр | Описание |
|---|---|
redirect[old_url] обязательныйстрока |
Старый путь. |
redirect[new_url] обязательныйстрока |
Адрес другого сайта. |
POST /admin/redirects.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"redirect": {
"old_url": "/docs-api-out",
"new_url": "https://example.com/catalog"
}
}
Ответ · 201
{
"id": 3,
"old_url": "/docs-api-out",
"new_url": "https://example.com/catalog",
"created_at": "2026-10-21T22:16:05.613+03:00"
}
/delivery отклоняется.
| Параметр | Описание |
|---|---|
redirect[old_url] обязательныйстрока |
Путь с запрещённым первым сегментом. |
redirect[new_url] обязательныйстрока |
Новый адрес. |
POST /admin/redirects.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"redirect": {
"old_url": "/delivery",
"new_url": "/page/docs-api-page"
}
}
Ответ · 422
{"old_url": ["Недопустимый URL. Путь '/delivery/' не может быть использован в качестве первой составной части старого URL."]}
Цепочки
При создании редиректа InSales проверяет, не образуется ли цепочка. Старый адрес новой записи не должен совпадать с новым адресом существующей, а новый адрес — со старым адресом другой записи. При совпадении API возвращает 422.
«Уже существует редирект на адрес ...» — ключ old_url. «Уже существует редирект с адреса ...» — ключ new_url.
Чтобы объединить цепочку, передайте remove_redirect_chains: 1. InSales создаст новую запись и изменит конечный адрес существующих редиректов, которые вели на её старый адрес. Идентификаторы существующих записей сохранятся.
| Параметр | Описание |
|---|---|
redirect[old_url] обязательныйстрока |
Адрес, который уже стоит новым у другого редиректа. |
redirect[new_url] обязательныйстрока |
Новый адрес. |
POST /admin/redirects.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"redirect": {
"old_url": "/page/docs-api-page",
"new_url": "/docs-api-next"
}
}
Ответ · 422
{"old_url": ["Нельзя создавать цепочки редиректов. Уже существует редирект на адрес /page/docs-api-page"]}
| Параметр | Описание |
|---|---|
redirect[old_url] обязательныйстрока |
Старый адрес новой записи. |
redirect[new_url] обязательныйстрока |
Адрес, на который перепишутся прежние редиректы. |
redirect[remove_redirect_chains] обязательныйчисло |
`1` разрешает цепочку и переписывает прежние новые адреса. |
POST /admin/redirects.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"redirect": {
"old_url": "/page/docs-api-page",
"new_url": "/docs-api-final",
"remove_redirect_chains": 1
}
}
Ответ · 201
{
"id": 7,
"old_url": "/page/docs-api-page",
"new_url": "/docs-api-final",
"created_at": "2026-10-21T22:16:06.001+03:00"
}
Повтор того же старого адреса отвечает 422: «Для указанного URL редирект уже настроен». Регистр различается: /Docs-Api-Case не совпадает с правилом /docs-api-case.
Список и фильтр
| Параметр | Описание |
|---|---|
per_page необязательныйчисло |
Размер страницы. По умолчанию 100. Нижней границы нет. |
page необязательныйчисло |
Номер страницы. Порядок записей не фиксирован. |
q[q] необязательныйстрока |
Подстрока старого или нового адреса. |
q[c_from] необязательныйстрока |
Начало интервала `created_at`. |
q[c_to] необязательныйстрока |
Конец интервала `created_at`. |
GET /admin/redirects.json?q[q]=docs-api-old
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
[
{
"id": 1,
"old_url": "/docs-api-old",
"new_url": "/docs-api-final",
"created_at": "2026-10-21T22:16:05.251+03:00"
}
]
Новый адрес в ответе уже переписан правилом remove_redirect_chains.
Как витрина выбирает адрес
Пока среди редиректов нет старых адресов с ?, InSales сравнивает только путь запроса и переносит параметры URL на новый адрес. Правило со знаком ? в старом адресе в этом режиме не применяется.
При добавлении первого правила с ? запрос POST может вернуть 500 без сохранения записи. При этом магазин переключается на точное сравнение адресов. Повторный такой же POST возвращает 201.
В режиме точного сравнения должны совпасть и путь, и параметры URL. Параметры domain и locale отбрасываются. Параметры _ga, tagtag_uid, erid, gsaid, advcake_params, utm_source, utm_medium, utm_campaign, yclid, ysclid, utm_referrer, utm_content и utm_term не влияют на совпадение и переносятся на новый адрес.
Параметр page влияет на сравнение: адрес с page не совпадёт с правилом без параметров URL.
Знак * в конце старого адреса позволяет сопоставить этот путь как с параметрами URL, так и без них. Более длинные пути с правилом не совпадают. Регулярные выражения не поддерживаются.
Повторяющиеся слэши в пути заменяются одним, даже если для адреса нет отдельного редиректа. Например, /foo//bar перенаправляется на /foo/bar.
В таблице цель цепочки — /docs-api-final. В колонке «точный режим» среди редиректов есть старый адрес с ?. В колонке «только путь» таких редиректов нет.
| Запрос | Точный режим | Только путь |
|---|---|---|
/docs-api-old |
/docs-api-final |
/docs-api-final |
/docs-api-old?utm_source=ads |
/docs-api-final?utm_source=ads |
/docs-api-final?utm_source=ads |
/docs-api-old?page=2 |
совпадения нет | /docs-api-final?page=2 |
/docs-api-q?color=red |
/docs-api-final |
правило с ? не используется |
/docs-api-q?color=blue |
совпадения нет | правило с ? не используется |
/docs-api-q?utm_source=ads |
совпадения нет | правило с ? не используется |
/docs-api-wild и /docs-api-wild?x=1 |
/docs-api-final |
/docs-api-final, query дописывается |
/docs-api-wild/extra |
совпадения нет | совпадения нет |
/page/docs-api-page?utm_source=ads&page=2 |
совпадения нет | /docs-api-final?utm_source=ads&page=2 |
Удаление редиректа
| Параметр | Описание |
|---|---|
id обязательныйчисло |
id редиректа в пути. |
DELETE /admin/redirects/1.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Ответ · 200
{"status": "ok"}