> ## Documentation Index
> Fetch the complete documentation index at: https://wallet-docs.iexexchanger.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Идемпотентность

> Безопасные повторы запросов без дубликатов: order_id и X-Idempotency-Key

Сетевые сбои неизбежны: вы отправили `POST`, не получили ответа и не знаете, дошёл ли он.
Идемпотентность гарантирует, что безопасный повтор **не создаст вторую заявку**. На платформе для
этого есть два независимых механизма — их можно использовать вместе.

<Info>
  Примеры используют единый стиль: базовый URL `https://wallet.your-exchange.com`,
  `order_id` вида `INV-2026-000042`. Подпись запросов — на странице [Аутентификация](/authentication).
</Info>

## Два механизма

<AccordionGroup>
  <Accordion title="order_id — связь с вашей заявкой и защита от дублей" icon="fingerprint">
    `order_id` — это ваш собственный идентификатор заявки. Вы передаёте его при создании депозита
    или выплаты, а затем по нему находите ресурс через `GET .../by-order-id/{order_id}`.

    **По умолчанию действует строгий режим.** `order_id` должен быть уникальным **в рамках всего
    сайта** — это общий номер на все валюты, а не отдельный счётчик на каждый актив. Повторный
    `POST` с уже использованным `order_id` вернёт `409 DUPLICATE_ORDER_ID`. В том числе если вы
    попробуете тот же `order_id` с **другим** активом (`assetCode`) — переиспользовать номер на
    другой валюте нельзя, это всегда `409`.

    Строгий режим — это защита от случайной двойной заявки. Для безопасных повторов он не
    предназначен: используйте `X-Idempotency-Key` (ниже).

    Оператор может включить для вашего сайта **мягкий режим** (`allowDuplicateOrderId`). В нём
    повтор с тем же `order_id` и тем же активом идемпотентно вернёт **существующую** заявку вместо
    `409`. Если вы полагаетесь на это поведение — уточните режим у оператора.

    Если `order_id` не передан, платформа сгенерирует уникальный код автоматически (формат
    `NNNN-NNNN-NNNN`). Авто-сгенерированные коды всегда уникальны, поэтому каждый такой вызов
    создаёт новую заявку.
  </Accordion>

  <Accordion title="X-Idempotency-Key — безопасный повтор одного запроса" icon="key">
    Заголовок `X-Idempotency-Key: <uuid>` на write-операциях. Первый запрос с этим ключом
    выполняется и его результат сохраняется. Любой **повтор с тем же ключом** возвращает тот же
    сохранённый результат — без выполнения операции, без дубликата и **без** `409`, независимо от
    режима `order_id`.

    Ключ изолирован в пределах вашего сайта (другие сайты не видят и не пересекаются с вашими
    ключами) и хранится **24 часа**. После истечения срока тот же ключ будет обработан как новый.
  </Accordion>
</AccordionGroup>

## Когда что использовать

| Сценарий                                                 | Механизм                         |
| -------------------------------------------------------- | -------------------------------- |
| Привязать заявку платформы к заявке в вашей CMS          | `order_id`                       |
| Найти ранее созданный депозит/выплату                    | `GET .../by-order-id/{order_id}` |
| Не допустить случайной второй заявки на один заказ       | `order_id` (строгий режим)       |
| Безопасно повторить запрос после таймаута/сетевой ошибки | `X-Idempotency-Key`              |

<Tip>
  Рекомендуемый паттерн: на каждое создание передавайте **и** `order_id` (как бизнес-ключ заявки),
  **и** `X-Idempotency-Key` (как технический ключ повтора). Тогда повтор после сбоя вернёт исходный
  результат, а не упрётся в `409 DUPLICATE_ORDER_ID`.
</Tip>

## Что считается «повтором»

`X-Idempotency-Key` сопоставляет запросы **по самому ключу**. Первый запрос с данным ключом
фиксирует результат на 24 часа; все последующие запросы с этим же ключом получают тот же
сохранённый ответ — содержимое их тела при этом повторно не исполняется.

<Warning>
  Один `X-Idempotency-Key` — для одного и того же запроса. Если переслать тот же ключ с **другим**
  телом, операция не выполнится: вы получите назад **результат первого** запроса. Для нового,
  по-настоящему другого запроса всегда генерируйте **новый** UUID.
</Warning>

`order_id` сопоставляется иначе — по бизнес-правилу уникальности в рамках сайта:

* тот же `order_id` на **другой** валюте — всегда `409 DUPLICATE_ORDER_ID`;
* та же валюта, строгий режим (по умолчанию), явно переданный `order_id` — `409 DUPLICATE_ORDER_ID`;
* та же валюта, мягкий режим (`allowDuplicateOrderId`) — идемпотентно возвращается существующая заявка.

## Пример: безопасный повтор

Сгенерируйте `X-Idempotency-Key` один раз на бизнес-операцию и переиспользуйте его при ретраях.

<CodeGroup>
  ```javascript Node.js theme={null}
  import crypto from 'node:crypto';

  // Один UUID на одну бизнес-операцию. При ретраях НЕ меняем его.
  const idempotencyKey = crypto.randomUUID();

  const rawBody = JSON.stringify({
    assetCode: 'USDT_TRC20',
    orderId: 'INV-2026-000042',
    expectedAmount: '100.50',
  });

  async function createDeposit() {
    const ts = Math.floor(Date.now() / 1000).toString();
    const signature = crypto
      .createHmac('sha256', process.env.WALLET_API_SECRET)
      .update(`${ts}.${rawBody}`)
      .digest('hex');

    return fetch('https://wallet.your-exchange.com/v1/public/deposits', {
      method: 'POST',
      headers: {
        'X-Api-Id': 'pk_live_a1b2c3d4',
        'X-Timestamp': ts,
        'X-Signature': signature,
        'X-Idempotency-Key': idempotencyKey, // одинаковый на всех попытках
        'Content-Type': 'application/json',
      },
      body: rawBody,
    });
  }

  // Повтор после сетевой ошибки вернёт ИСХОДНУЮ заявку, а не создаст новую.
  let res = await createDeposit().catch(() => null);
  if (!res || !res.ok) res = await createDeposit();
  ```

  ```bash cURL theme={null}
  # Сгенерируйте UUID один раз и используйте его на всех попытках.
  IDEMP=$(uuidgen)
  TS=1735680000
  BODY='{"assetCode":"USDT_TRC20","orderId":"INV-2026-000042","expectedAmount":"100.50"}'
  SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$API_SECRET" -hex | sed 's/^.* //')

  curl -X POST https://wallet.your-exchange.com/v1/public/deposits \
    -H "X-Api-Id: pk_live_a1b2c3d4" \
    -H "X-Timestamp: $TS" \
    -H "X-Signature: $SIG" \
    -H "X-Idempotency-Key: $IDEMP" \
    -H "Content-Type: application/json" \
    -d "$BODY"
  ```
</CodeGroup>

## Рекомендации по ретраям

<Steps>
  <Step title="Фиксируйте X-Idempotency-Key до первой отправки">
    Сгенерируйте UUID, сохраните его рядом с заявкой и используйте на всех попытках одного и того
    же запроса. Не генерируйте новый ключ на каждый ретрай.
  </Step>

  <Step title="Повторяйте с задержкой">
    При таймаутах и ошибках `5xx` используйте экспоненциальную задержку. На каждой попытке шлите
    тот же `X-Idempotency-Key` и то же тело.
  </Step>

  <Step title="Свежий X-Timestamp на каждой попытке">
    Подпись зависит от времени, а окно — ±300 секунд. Для каждой попытки берите **актуальный**
    `X-Timestamp` и заново вычисляйте `X-Signature`. Ключ идемпотентности при этом не меняется.
  </Step>

  <Step title="Сомневаетесь, прошёл ли запрос — проверьте по order_id">
    Если ретраи исчерпаны, выполните `GET .../by-order-id/{order_id}` — так вы узнаете, была ли
    заявка создана, не рискуя дублем.
  </Step>
</Steps>

<Note>
  `X-Idempotency-Key` хранится 24 часа. Для повторов после длительного простоя полагайтесь на
  `order_id`: в строгом режиме он по-прежнему не даст создать вторую заявку (вернёт
  `409 DUPLICATE_ORDER_ID`), а вы сможете найти существующую через `by-order-id`.
</Note>

## Частые вопросы

<AccordionGroup>
  <Accordion title="Получаю 409 DUPLICATE_ORDER_ID на повторе" icon="triangle-exclamation">
    В строгом режиме (по умолчанию) повтор с уже использованным `order_id` намеренно отклоняется —
    это защита от двойной заявки. Для безопасных ретраев добавьте `X-Idempotency-Key`: тогда повтор
    вернёт исходную заявку без `409`.
  </Accordion>

  <Accordion title="Можно ли использовать один order_id для разных валют?" icon="coins">
    Нет. `order_id` уникален в рамках всего сайта, общий на все активы. Тот же номер с другим
    `assetCode` всегда даёт `409 DUPLICATE_ORDER_ID`.
  </Accordion>

  <Accordion title="Что вернётся, если послать тот же ключ с другим телом?" icon="rotate">
    Вернётся результат **первого** запроса с этим ключом. Операция с новым телом не выполнится.
    Для другого запроса всегда генерируйте новый UUID.
  </Accordion>

  <Accordion title="Действует ли мой ключ на других сайтах?" icon="shield">
    Нет. `X-Idempotency-Key` изолирован в пределах вашего сайта. Ключи разных сайтов не
    пересекаются.
  </Accordion>
</AccordionGroup>

Коды ошибок целиком — на странице [Ошибки](/errors). Подпись запросов — [Аутентификация](/authentication).
