Контракт JSON: сначала договор, потом код

На первой встрече команда сайта показала красивый JSON и спросила: «1С сможет это принять?» Неправильный короткий ответ — «да». Правильный начинается с вопросов.

Представим интернет-магазин, который передаёт в 1С оплаченные заказы. В демонстрационном файле есть номер, клиент и две позиции. Но демонстрация ничего не говорит о пустом телефоне, отменённом заказе, количестве 0, повторной отправке или изменении формата через полгода. JSON — лишь синтаксис. Контрактом он становится, когда обе стороны одинаково понимают смысл каждого поля и реакцию на отклонение.

Составляем паспорт сообщения

Для события order.paid зафиксируем пять вещей: идентификатор события, версию схемы, время возникновения, идентификатор заказа и полезную нагрузку. Идентификатор события нужен не для красоты: по нему принимающая сторона отличает повторную доставку от нового платежа. Номер заказа для этого не подходит — один заказ может породить оплату, возврат и повторную оплату.

ПолеПравилоЗачем оно 1С
event_idUUID, не меняется при повторезащита от дублей
schema_versionцелое числовыбор обработчика формата
occurred_atISO 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-ответ и судьбу сообщения.

Готовый контракт — это не один пример в чате. Это таблица полей, несколько положительных и отрицательных примеров, правила совместимости и владелец изменения. После такого документа код на обеих сторонах становится заметно скучнее. Для интеграции это комплимент.

Проверьте себя
1. Какое поле надёжнее всего использовать для защиты от повторной доставки события?
AНомер заказа
Bevent_id, неизменный при повторах
CВремя получения в 1С
DСумму документа
2. Какое изменение JSON-контракта обычно совместимо со старым получателем?
AПереименование обязательного поля
BЗамена строки на объект
CДобавление необязательного поля
DИзменение смысла существующего статуса
3. Почему денежную сумму опасно передавать без явно заданного правила масштаба?
AJSON запрещает числа
BСистемы могут по-разному округлить значение
C1С читает только целые числа
DHTTP удаляет десятичную часть