Контракт JSON: сначала договор, потом код
На первой встрече команда сайта показала красивый JSON и спросила: «1С сможет это принять?» Неправильный короткий ответ — «да». Правильный начинается с вопросов.
Представим интернет-магазин, который передаёт в 1С оплаченные заказы. В демонстрационном файле есть номер, клиент и две позиции. Но демонстрация ничего не говорит о пустом телефоне, отменённом заказе, количестве 0, повторной отправке или изменении формата через полгода. JSON — лишь синтаксис. Контрактом он становится, когда обе стороны одинаково понимают смысл каждого поля и реакцию на отклонение.
Составляем паспорт сообщения
Для события order.paid зафиксируем пять вещей: идентификатор события, версию схемы, время возникновения, идентификатор заказа и полезную нагрузку. Идентификатор события нужен не для красоты: по нему принимающая сторона отличает повторную доставку от нового платежа. Номер заказа для этого не подходит — один заказ может породить оплату, возврат и повторную оплату.
| Поле | Правило | Зачем оно 1С |
| event_id | UUID, не меняется при повторе | защита от дублей |
| schema_version | целое число | выбор обработчика формата |
| occurred_at | ISO 8601 с часовым поясом | однозначное время события |
| order_id | строка, а не число | сохраняет ведущие нули и составные номера |
| amount | строка с двумя знаками | не зависит от двоичного округления JSON Number |
Денежное значение строкой иногда вызывает спор. Альтернатива — передавать целое число копеек. Оба решения устойчивы, если правило записано. Самый опасный вариант — число без указания масштаба: одна система округляет до двух знаков, другая сохраняет четыре, и сверка начинает «плавать» на копейку.
Пример, который можно валидировать
{
"event_id": "b861b9f0-6d84-4d5f-91cc-3c09863a91c3",
"event": "order.paid",
"schema_version": 1,
"occurred_at": "2026-08-23T09:41:12+03:00",
"order_id": "WEB-001842",
"currency": "RUB",
"amount": "12990.00",
"items": [
{"sku": "KB-104", "quantity": 1, "price": "12990.00"}
]
}
До поиска номенклатуры проверяем оболочку сообщения. Есть ли обязательные поля? Поддерживается ли версия? Совпадает ли сумма заказа с суммой строк? Время удалось прочитать вместе со смещением? Только после этого имеет смысл обращаться к справочникам. Так ошибка формата не маскируется сообщением «номенклатура не найдена».
Функция ПроверитьСообщение(Данные) Экспорт
Обязательные = Новый Массив;
Обязательные.Добавить("event_id");
Обязательные.Добавить("schema_version");
Обязательные.Добавить("order_id");
Обязательные.Добавить("items");
Для Каждого ИмяПоля Из Обязательные Цикл
Если Не Данные.Свойство(ИмяПоля) Тогда
Возврат "Нет обязательного поля: " + ИмяПоля;
КонецЕсли;
КонецЦикла;
Если Данные.schema_version <> 1 Тогда
Возврат "Неподдерживаемая версия схемы";
КонецЕсли;
Возврат "";
КонецФункции
Как менять договор без одновременного релиза
Добавление необязательного поля обычно совместимо назад: старая 1С его проигнорирует. Переименование, смена типа и изменение смысла существующего поля — несовместимы. Для них выпускают новую версию схемы и некоторое время принимают обе. Не стоит определять версию по наличию случайного поля: такая эвристика развалится после следующего изменения.
Неизвестные поля лучше разрешать, а неизвестные значения перечислений — отклонять или складывать в карантин по заранее выбранному правилу. Например, новый статус доставки не должен молча превращаться в «Ожидается». Иначе сообщение технически принято, но бизнес-смысл потерян.
Проверка контракта: возьмите корректное сообщение, удалите
event_id, заменитеamountна число и добавьте неизвестный статус. Для каждого варианта заранее запишите ожидаемый HTTP-ответ и судьбу сообщения.
Готовый контракт — это не один пример в чате. Это таблица полей, несколько положительных и отрицательных примеров, правила совместимости и владелец изменения. После такого документа код на обеих сторонах становится заметно скучнее. Для интеграции это комплимент.