В API одновременно существуют три разных понятия с похожими названиями. Путать их нельзя: от этого зависит, повторит ли сервер тот же платёж или создаст новый объект.
| Механизм | Где задаётся | Участвует в дедупликации на сервере? |
|---|---|---|
| Бизнес-идемпотентность платежей | Тело POST /api/v1/payments: поле orderId + канал оплаты (method / rubCollect.method) | Да — это основной механизм |
| Идемпотентность депозитов | Тело POST /api/v1/deposits: поле idempotencyKey (UUID) в рамках одной кассы | Да — только для этого метода |
| HTTP-заголовок Idempotency-Key | Заголовок запроса (любой непустой идентификатор по вашему выбору) | Нет — сервер не сопоставляет его с созданием сущностей и не отменяет повторные запросы по этому ключу |
Для POST /api/v1/payments сервер сопоставляет повторные запросы по связке: ваш мерчант + строка orderId (после trim) + канал оплаты. Повтор с тем же orderId и тем же каналом возвращает тот же платёж и согласованные данные, а не вторую оплату.
Заголовок Idempotency-Key на это поведение не влияет — даже если вы каждый раз отправляете новый UUID в заголовке, роль «ключа идемпотентности» для платежа играет только orderId в теле (и канал).
Для POST /api/v1/deposits дедупликация завязана на поле idempotencyKey в JSON-теле и на продуктовой кассе. Это другой объект и другой контракт, не путайте с orderId у платежей и с HTTP-заголовком Idempotency-Key.
Повтор с тем же idempotencyKey и той же кассой возвращает ту же заявку; тот же ключ при другой кассе — ответ с конфликтом (HTTP 409, код idempotency_key_conflict).
Вы можете передавать заголовок Idempotency-Key для собственных логов и корреляции у себя. На стороне API он не используется как ключ идемпотентности: повтор с другим телом или другим orderId не будет «отменён» или слился только из-за заголовка.