Интеграция GoDeli с 1С
Версия контракта: v1
Формат: HTTPS + JSON (UTF-8)
Префикс API GoDeli: /api/v1
Документ предназначен для разработчиков 1С и описывает первичную загрузку каталога, изменение цен и остатков, контроль обработки и передачу заказов.
1. Схема и направления обмена
входящие события
1С ── каталог/цены/остатки ─────────────► GoDeli API ─► inbox ─► каталог GoDeli
│ │
│ └─ 202 после сохранения
│
◄──────────────── заказы ────────────── GoDeli order outbox
исходящий API 1С
- 1С сама отправляет полный каталог и оперативные изменения. GoDeli её не опрашивает.
- GoDeli отправляет подтверждённые заказы в HTTP API на стороне 1С.
- Временная недоступность одной стороны не должна приводить к потере данных: обе стороны используют устойчивые очереди и идемпотентные идентификаторы.
- При первом подключении и раз в ночь отправляется полный снимок; днём — только изменившиеся цены и остатки.
Одна интеграция v1 соответствует одной торговой точке GoDeli и одному складу 1С.
2. Реквизиты подключения
GoDeli передаёт команде 1С:
| Параметр | Назначение |
|---|---|
base_url | адрес API GoDeli нужного окружения |
integration_id | UUID интеграции торговой точки |
client_id | идентификатор workload-клиента этой интеграции |
client_secret | секрет workload-клиента; показывается один раз |
token_url | endpoint получения короткоживущего JWT |
Команда 1С передаёт GoDeli:
| Параметр | Назначение |
|---|---|
base_url | адрес HTTP-сервиса 1С |
token | секрет запросов GoDeli → 1С |
order_path | приём заказов, по умолчанию /godeli/v1/orders |
timeout_seconds | таймаут, по умолчанию 10 секунд |
3. Общие правила запросов 1С → GoDeli
Авторизация
Authorization: Bearer <access_token>
Content-Type: application/json
Idempotency-Key: <event_id>
Перед запросом 1С получает JWT по client_credentials, как описано в разделе
Workload Identity. Постоянные
exchange_token не поддерживаются. JWT относится только к указанным tenant,
точке и integration_id; его нельзя передавать в URL или писать в логи.
Форматы
- Дата и время — ISO 8601 с часовым поясом, предпочтительно UTC:
2026-08-21T11:30:00Z. - Деньги и количества — JSON number; GoDeli хранит их как decimal.
- ID из 1С — непрозрачные строки до 128 символов. Рекомендуются стабильные GUID.
- Отображаемое имя не является идентификатором и может меняться.
Идемпотентность
Каждый пакет получает уникальный event_id. Заголовок Idempotency-Key обязан
совпадать с ним. При сетевой ошибке 1С повторяет то же тело с тем же event_id.
GoDeli сохранит событие один раз и вернёт duplicate на повторы.
Запрещено использовать один event_id для разных тел: v1 считает это повтором и
не сравнивает содержимое.
catalog:6f9619ff-8b86-d011-b42d-00cf4fc964ff
changes:1c-node:000000018452
Асинхронный приём
Новый пакет:
{"event_id":"changes:000000018452","status":"accepted"}
Повтор:
{"event_id":"changes:000000018452","status":"duplicate"}
Оба ответа имеют HTTP 202. Это означает, что пакет надёжно сохранён, но ещё не
обязательно применён. После 202 его можно убрать из транспортной очереди 1С, а
результат проверить endpoint статуса.
4. Полный снимок каталога
POST /api/v1/integrations/1c/{integration_id}/catalog-snapshot
Снимок — полное состояние каталога точки, не порция. Категории и товары с внешними ID, отсутствующие в новом снимке, архивируются. Части одного снимка нельзя отправлять отдельными запросами.
Верхний уровень
| Поле | Тип | Обязательно | Ограничение |
|---|---|---|---|
event_id | string | да | 1–128, уникален |
generated_at | datetime | да | время формирования в 1С |
attribute_definitions | array | нет | до 5000 |
categories | array | да | полный список |
products | array | да | полный список |
Категория
{"id":"category-guid","name":"Напитки"}
id: 1–128 символов; name: 1–255. product.category_id должен ссылаться на
категорию этого же снимка.
Дополнительные реквизиты
Названия свойств в магазинах могут отличаться. GoDeli связывает их не по имени, а
по стабильному attribute_definitions[].id внутри интеграции.
{
"id":"property-brand-guid",
"code":"BRAND",
"name":"Торговая марка",
"type":"enum",
"canonical_code":"brand",
"unit":null,
"values":[{"id":"brand-acme-guid","code":"ACME","name":"ACME"}]
}
| Поле | Обязательно | Описание |
|---|---|---|
id | да | GUID определения, до 128 |
code | нет | внутренний код 1С, до 128 |
name | да | отображаемое имя, до 255 |
type | да | string, decimal, integer, boolean, date, enum |
unit | нет | единица, до 32 |
canonical_code | нет | согласованное системное назначение, до 64 |
values | для enum | допустимые значения |
canonical_code не выводится из русского названия. Коды вроде brand, color,
size задаются только после согласования. Enum-значение имеет собственный ID.
Скалярное значение товара:
{"attribute_id":"property-fat-guid","value":3.2,"unit":"%"}
Enum-значение:
{"attribute_id":"property-brand-guid","value_id":"brand-acme-guid"}
Каждый attribute_id должен находиться в определениях этого снимка. У записи
должно быть value или value_id.
Товар
| Поле | Обязательно | Описание |
|---|---|---|
id | да | GUID номенклатуры, до 128 |
name | да | наименование, до 255 |
description | нет | описание |
composition | нет | состав |
category_id | нет | ID категории |
available | нет | доступность, default true |
tax | нет | НДС и предмет расчёта |
marking | нет | маркировка |
attributes | нет | значения реквизитов, до 500 |
option_axes | нет | оси характеристик, до 20 |
variants | да | минимум один вариант |
allergens | нет | массив строк |
tags | нет | массив строк |
Для полного снимка явно передавайте все поддерживаемые поля, включая пустые. Это исключает неоднозначность между удалённым значением и временно не выгруженным.
НДС и маркировка
"tax":{"vat_rate":"20","vat_included":true,"tax_category":"goods"},
"marking":{"required":true,"group":"dairy","traceable":true}
vat_rate: none, 0, 5, 7, 10, 20, 105/5, 107/7, 110/10,
120/20. tax_category: goods, service, excise, marked_goods,
agent_goods. vat_included=true означает, что цена включает НДС.
marking.group — согласованный код группы до 64 символов.
Характеристики и варианты
option_axes задаёт ось и допустимые значения, а вариант выбирает ровно одно
значение каждой оси.
"option_axes":[{
"id":"property-size-guid",
"code":"SIZE",
"name":"Размер",
"values":[
{"id":"size-m-guid","code":"M","name":"M"},
{"id":"size-l-guid","code":"L","name":"L"}
]
}],
"variants":[{
"id":"characteristic-m-guid",
"name":"M",
"price":1990.00,
"sku":"00001234-M",
"barcodes":["4601234567890"],
"default":true,
"measure_unit":"piece",
"measure_value":1,
"option_values":[
{"axis_id":"property-size-guid","value_id":"size-m-guid"}
],
"option_groups":[]
}]
Правила:
- минимум один вариант; для товара без характеристик используется стабильный искусственный ID;
- если осей нет,
option_valuesпуст; price >= 0,measure_value > 0, до 100 штрихкодов;measure_unit:piece,gram,kilogram,milliliter,liter;- рекомендуется ровно один
default=true.
option_groups описывает модификаторы: группа содержит id, name, required,
min_select, max_select, options; опция — id, name, price_delta,
необязательный sku, available.
Полный пример
{
"event_id":"catalog:2026-08-21T00:00:00Z",
"generated_at":"2026-08-21T00:00:00Z",
"attribute_definitions":[{
"id":"property-fat-guid","code":"FAT_PERCENTAGE","name":"Жирность",
"type":"decimal","unit":"%","canonical_code":"fat_percentage","values":[]
}],
"categories":[{"id":"category-milk-guid","name":"Молочные продукты"}],
"products":[{
"id":"product-milk-guid",
"name":"Молоко 3,2%",
"description":"Пастеризованное молоко",
"composition":"Молоко цельное",
"category_id":"category-milk-guid",
"available":true,
"tax":{"vat_rate":"10","vat_included":true,"tax_category":"marked_goods"},
"marking":{"required":true,"group":"dairy","traceable":true},
"attributes":[{"attribute_id":"property-fat-guid","value":3.2,"unit":"%"}],
"option_axes":[],
"variants":[{
"id":"product-milk-guid:default","name":"1 л","price":119.90,
"sku":"00001234","barcodes":["4601234567890"],"default":true,
"measure_unit":"liter","measure_value":1,
"option_values":[],"option_groups":[]
}],
"allergens":["milk"],
"tags":["refrigerated"]
}]
}
5. Изменения цен и остатков
POST /api/v1/integrations/1c/{integration_id}/changes
Передаётся итоговое состояние, а не движение регистра. В пакете допускается до 5000 остатков и до 5000 цен.
{
"event_id":"changes:000000018452",
"generated_at":"2026-08-21T14:31:00+03:00",
"stocks":[{
"product_id":"product-milk-guid",
"variant_id":"product-milk-guid:default",
"warehouse_id":"warehouse-guid",
"available_quantity":21
}],
"prices":[{
"product_id":"product-milk-guid",
"variant_id":"product-milk-guid:default",
"price":129.90
}]
}
- Пара product/variant должна существовать после снимка.
- Цена неотрицательна.
- Остаток уже учитывает резерв по согласованному правилу 1С; отрицательное значение GoDeli приводит к нулевой доступности.
- v1 хранит остаток в целых единицах. Дробный складской учёт требует расширения.
warehouse_idзарезервирован: v1 использует один склад на интеграцию.- Пакет применяется транзакционно: все строки или ни одна.
- Первый
changesотправляется только после успешного полного снимка.
Быстрые повторные изменения одного SKU рекомендуется объединять и отправлять последнее состояние.
6. Статус события
GET /api/v1/integrations/1c/{integration_id}/events/{event_id}
Authorization: Bearer <access_token>
{
"event_id":"changes:000000018452",
"event_type":"delta",
"status":"applied",
"attempts":1,
"received_at":"2026-08-21T11:31:01Z",
"processed_at":"2026-08-21T11:31:03Z",
"last_error":null
}
| Статус | Значение | Действие 1С |
|---|---|---|
accepted | ждёт обработки | проверить позже |
processing | обрабатывается | проверить позже |
applied | полностью применён | завершить контроль |
retry | GoDeli повторит обработку | разобрать ошибку, если постоянная |
failed | окончательная ошибка | вмешательство оператора |
При retry повторно отправлять пакет не нужно: он уже сохранён в GoDeli.
7. Ошибки и очередь 1С
| HTTP | Значение | Действие |
|---|---|---|
202 | сохранено/дубликат | контролировать статус |
401 | неверные реквизиты | остановить очередь, обновить токен |
404 | событие не найдено | проверить окружение и ID |
422 | неверный контракт | исправить данные до повтора |
429 | ограничение частоты | повторить с задержкой, учесть Retry-After |
5xx | временная ошибка | повторить то же событие |
Доменная ошибка:
{"error":{"code":"validation_error","message":"Idempotency-Key must equal event_id"}}
Ошибка структуры JSON возвращает стандартный FastAPI 422 с массивом detail.
Алгоритм очереди 1С:
- Сформировать неизменяемое тело и новый event ID.
- Сохранить его в регистре/очереди до HTTP-вызова.
- При
202завершить транспортную доставку. - При сети,
429,5xxповторять то же тело через 5, 15, 30, 60, 120 секунд, затем раз в 5 минут. - При
401/422прекратить автоматические повторы и создать диагностику. - Проверять статус до
applied.
8. Ночная сверка
1С формирует консистентный полный срез, отправляет один snapshot и ждёт applied.
Изменения, возникшие во время формирования, сохраняются и отправляются после
снимка. Иначе старый снимок может временно перезаписать новую цену.
9. Нагрузка: 15 000 SKU
15 000 SKU подходят для событийной схемы: полная нагрузка возникает ночью, днём передаются только изменения.
Ограничения v1:
- HTTP body на текущем ingress — не более 25 МБ;
- snapshot нельзя разбивать на независимые запросы;
- gzip нельзя считать поддержанным без проверки окружения;
- delta: максимум 5000 остатков + 5000 цен.
До запуска нужно сформировать реальный UTF-8 JSON на 15 000 SKU и измерить его.
Если размер приближается к 25 МБ, сначала реализуется составной снимок с
snapshot_id, номерами частей и финализацией.
Для delta рекомендуется debounce 1–5 секунд, объединение по product/variant и пакеты по 500–2000 реально изменившихся строк.
10. Заказы GoDeli → 1С
Health check
GET /godeli/v1/health
Authorization: Bearer <1c_api_token>
Любой 2xx означает доступность. Рекомендуемый ответ: {"status":"ok"}.
Приём заказа
POST /godeli/v1/orders
Authorization: Bearer <1c_api_token>
Content-Type: application/json
Idempotency-Key: <godeli_order_uuid>
{
"id":"0191f66e-8525-7e06-9354-0b46311e85c7",
"number":"DL-10482",
"created_at":"2026-08-21T14:42:10+03:00",
"point_id":"0191f61f-b386-79e2-a6aa-80fa80cf01cb",
"type":"delivery",
"status":"confirmed",
"payment_method":"card_online",
"payment_status":"paid",
"currency":"RUB",
"subtotal":"389.70",
"delivery_fee":"99.00",
"total":"488.70",
"customer":{"name":"Иван","phone":"+79990000000"},
"delivery":{"address":"Москва, ул. Примерная, 1","scheduled_for":null},
"comment":"Позвонить за 5 минут",
"items":[{
"product_id":"product-milk-guid",
"variant_id":"product-milk-guid:default",
"name":"Молоко 3,2%",
"quantity":"3",
"unit_price":"129.90",
"line_total":"389.70",
"modifiers":[]
}]
}
Перечисления:
type:delivery,pickup;- штатный
status:confirmed; payment_method:cash,card_offline,card_online,sbp,null;payment_status:pending,paid,refunded,failed.
Деньги и количества — decimal-строки. ID товара, варианта и модификатора — ID 1С из снимка.
Успешный ответ:
{"accepted":true,"order_id":"1c-order-document-guid","number":"ЗК-00001234"}
При accepted=true обязателен order_id. Повтор с тем же Idempotency-Key
возвращает ранее созданный документ, не создавая новый. UUID GoDeli рекомендуется
сделать уникальным в базе 1С в рамках интеграции.
| Ответ 1С | Поведение GoDeli |
|---|---|
2xx, принят и есть order_id | заказ принят |
2xx, accepted=false | отклонён |
принят без order_id | ошибка контракта, повтор |
4xx, 5xx, таймаут | повтор через outbox с тем же UUID |
В v1 бандлы в заказе не поддерживаются; обычные позиции и модификаторы поддерживаются.
11. Безопасность
- Только HTTPS; разные токены для test/prod и для двух направлений.
- Секреты хранятся защищённо и маскируются в логах.
- После согласованной ротации старый токен недействителен.
- Персональные данные заказа не логируются целиком.
- IP-фильтр допустим как дополнительная мера, но не заменяет Bearer-токен.
12. Приёмка
- Snapshot создаёт категории, товары, свойства и варианты.
- Повтор с тем же event ID возвращает
duplicateбез дублей. - Новый snapshot обновляет товар и архивирует отсутствующий.
- Одинаковые имена с разными GUID не склеиваются.
- Delta меняет цену и остаток нужного варианта.
- Delta с неизвестным вариантом не применяется частично и получает
retry. - После
5xx1С повторяет тот же event ID. - Неверный токен даёт
401, неверный JSON —422. - Реальный snapshot 15 000 SKU укладывается в 25 МБ.
- Несколько HTTP-попыток заказа создают один документ 1С.
- Недоступность 1С не мешает входящему каталогу и не теряет заказ.
13. Ограничения v1
- один склад на интеграцию;
- нет multipart snapshot и дробного остатка;
- удаление товара выполняется полным snapshot, не delta;
- нет входящих статусов заказа из 1С;
- нет заказов с бандлами;
- устаревшие delta по
generated_atавтоматически не отбрасываются: очередь 1С должна сохранять причинный порядок.
14. Что согласовать до разработки
- тестовые URL, integration ID и токены;
- GUID склада, организации и типа цен;
- правило расчёта доступного остатка и резерва;
- НДС, предмет расчёта и группы маркировки;
canonical_codeважных реквизитов;- ID варианта для товара без характеристик;
- расписание snapshot и допустимую задержку delta;
- контакты дежурных и передачу диагностического event ID.