API g.pis для учётных систем

Версия 1. Адрес — https://g-pis.ru/api/v1.

Доступ — ключ кабинета в заголовке X-Api-Key. Ключ выдаёт администратор кабинета: «Интеграция» → «Приёмное API» → «Выдать ключ». Ключ показывается один раз, в g.pis хранится только его отпечаток. Права ключа: write — приём товаров и чтение каталога; read — только чтение; feed — только фид витрины.

Ключ определяет кабинет: чужой каталог им не виден и не изменяем.

Приём товаров: POST /api/v1/products

Пакет до 500 товаров в поле items. Ключ товара — артикул sku: повторная присылка того же товара обновляет его, второй карточки не заводит. Товары разбираются по одному: ошибка в одном не отменяет остальные.

curl -X POST "https://g-pis.ru/api/v1/products" \
  -H "X-Api-Key: pim_…" -H "Content-Type: application/json" \
  -d '{"items":[{
        "sku": "A-1001",
        "title": "Сковорода 24 см",
        "brand": "Tefal",
        "barcode": "3168430384934",
        "category": "Посуда / Сковороды",
        "description": "Антипригарное покрытие, подходит для индукции.",
        "country": "Франция",
        "weightGross": 1.2, "length": 45, "width": 26, "height": 8,
        "attributes": {"Материал": "алюминий", "Диаметр (см)": 24},
        "images": ["https://shop.example.ru/img/a-1001-1.jpg"],
        "erpId": "0000-0012345"
      }]}'

Поля товара

ПолеЧто это
skuартикул, обязателен; ключ товара
titleнаименование, до 500 символов
brandбренд
barcodeосновной штрихкод; проверяется контрольная сумма EAN
barcodesвсе штрихкоды товара, массив до 100; первый годный станет основным, если barcode не передан
categoryраздел источника: путь «Раздел / Подраздел» или имя раздела; найденный в каталоге ставится товару без раздела
descriptionописание, до 20 000 символов
modelмодель
manufacturerпроизводитель
countryстрана производства
vendorCodeартикул производителя
tnvedкод ТН ВЭД, 4–10 цифр
colorцвет
weightGrossвес с упаковкой, кг
weightNetвес без упаковки, кг
length, width, heightгабариты упаковки, см
attributesлюбые другие характеристики: {"название": значение}; единицу можно писать в значении («23 см»)
imagesфото ссылками, до 30; первая — главная
imageFilesфото файлами: [{"name": "фото.jpg", "data": "<base64>"}], до 10 файлов по 10 МБ
erpIdваш внутренний код, например GUID 1С
archivedtrue — снят с продажи, false — вернуть в работу

Единицы не угадываются: вес — в килограммах, размеры — в сантиметрах.

Фото ссылками. g.pis сам скачивает файл и кладёт в своё хранилище. Узлы, откуда можно брать фото, задаёт администратор кабинета: «Интеграция» → «Приёмное API» → «Откуда брать фото по ссылкам» (склады картинок площадок разрешены всегда). Ссылка, уже забранная к товару, повторно не скачивается. Адреса внутренних сетей не принимаются.

Фото файлами — для систем, где у картинки нет адреса (1С): содержимое в base64.

Что учёт может перезаписать: штрихкод, бренд, вес, габариты (паспортные поля). Наименование и характеристики учёт только заполняет, если они пусты. Правку, сделанную человеком в g.pis, не перетирает никто.

Ответ

По каждому товару отдельно:

{"dryRun": false, "accepted": 1, "rejected": 1,
 "results": [{"sku": "A-1001", "status": "created", "productId": "cmt…",
              "category": {"найден": "Посуда / Сковороды"},
              "images": {"принято": 1, "отказано": 0, "причины": []},
              "unknownAttributes": ["Тип аптечки"]}],
 "errors": [{"index": 1, "sku": "A-1002", "errors": ["barcode: контрольная сумма штрихкода не сходится"]}]}
  • status: created | updated | unchanged | rejected.
  • errors — товары, отклонённые при разборе: номер в пакете, артикул и причины словами.
  • unknownAttributes — характеристики, которых нет в справочнике каталога: они сохранены в данных источника, но полем каталога не стали.
  • category.неНайден — раздел не найден, товар принят без раздела.
  • conflicts — паспортное значение учёта разошлось со значением площадки.
  • rejectedBarcode — штрихкод не принят (товар принят без него).

Проверка без записи: POST /api/v1/products?dryRun=1

Тот же пакет, но ничего не записывается: ответ показывает, что будет с каждым товаром (created — заведётся, updated — обновится), какие характеристики и разделы не найдутся, какие поля с ошибкой. Работает и с ключом read. Тот же разбор — на экране «Интеграция» → «Проверить пакет без записи».

Отдача каталога: GET /api/v1/products

curl "https://g-pis.ru/api/v1/products?limit=200&updatedSince=2026-10-01" -H "X-Api-Key: pim_…"
ПараметрСмысл
limit1…200, по умолчанию 50
afterкурсор: артикул последнего товара предыдущей страницы
skuодин товар по артикулу
brandбренд или несколько через запятую; регистр не важен
updatedSinceтолько изменённые с этого момента (2026-10-01 или 2026-10-01T10:00:00Z)
images=0без адресов фото (быстрее)
{"items": [{"sku": "A-1001", "title": "…", "brand": "Tefal", "barcode": "…", "origin": "erp",
            "category": "Сковороды", "lifecycle": "draft", "updatedAt": "2026-10-19T10:00:00.000Z",
            "attributes": {"Материал": {"value": "алюминий", "values": ["алюминий"], "source": "учётная система"}},
            "images": ["https://g-pis.ru/media/…jpg"],
            "listings": [{"marketplace": "wildberries", "status": "published", "externalId": "12345"}]}],
 "nextAfter": "A-1001"}

Страницы идут курсором по артикулу: идите, пока nextAfter не станет null. Номер страницы не используется — каталог меняется под чтением, и товар, изменившийся между запросами, потерялся бы.

Коды ответов

КодКогда
200принято или отдано; отказы отдельных товаров — в results и errors
400пакет не разобран или параметр неверен; текст называет поле и причину
401ключ неизвестен, отозван или истёк
403у ключа нет нужного права (например, read для записи)

Пример на 1С

Готовое решение для 1С:Управление торговлей 11 — расширение «Выгрузка в PIM» (страница «Интеграция» → «1С»). Для своей конфигурации — тот же запрос:

Соединение = Новый HTTPСоединение("pim.example.ru", 443, , , , 300, Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос("/api/v1/products");
Запрос.Заголовки.Вставить("X-Api-Key", Ключg.pis);
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Товар = Новый Структура("sku, title, brand", Артикул, Наименование, Марка);
Запись = Новый ЗаписьJSON; Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Новый Структура("items", ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Товар)));
Запрос.УстановитьТелоИзСтроки(Запись.Закрыть(), КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
// Ответ.КодСостояния = 200 → разберите results и errors по каждому товару

Пример на Python

import requests
r = requests.post("https://g-pis.ru/api/v1/products", headers={"X-Api-Key": KEY},
                  json={"items": [{"sku": "A-1001", "title": "Сковорода 24 см", "brand": "Tefal"}]}, timeout=300)
r.raise_for_status()
for x in r.json()["results"]:
    print(x["sku"], x["status"])
for e in r.json()["errors"]:
    print("отклонён:", e.get("sku"), "; ".join(e["errors"]))

Без программиста: g.pis забирает данные сам

«Интеграция» → «Источники данных»: файл выгрузки по ссылке (CSV, XLSX, JSON, YML), база данных (PostgreSQL, MySQL, MS SQL — один запрос SELECT) или 1С по OData — по расписанию, с журналом каждого прогона. Каждый прогон проходит тот же разбор, что и этот API.

События (вебхуки)

Каталог сам сообщает об изменениях, чтобы вам не приходилось опрашивать его по расписанию. Подписка заводится администратором на странице «Пользователи»; секрет подписи показывается один раз.

POST <ваш адрес>
X-Pim-Event: product.updated
X-Pim-Signature: sha256=<HMAC-SHA256 от тела запроса вашим секретом>
Content-Type: application/json

{"event":"product.updated","at":"2026-08-26T18:20:00.000Z","productId":"...","field":"Мощность","value":"1450","percent":57}

События: product.updated (правка характеристики), product.published (площадка подтвердила карточку), listing.status (карточка сменила состояние: принята, отклонена, на проверке).

Проверка подписи (Node.js):

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, rawBody, signature) {
  const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`;
  const a = Buffer.from(expected);
  const b = Buffer.from(signature ?? "");
  return a.length === b.length && timingSafeEqual(a, b);
}

Ответ 2xx считается доставкой. Любой другой — поводом повторить: 1, 5, 25 минут, дальше час, всего пять попыток. После пятой событие помечается недоставленным и видно на экране подписок.