Merchant API
Проверка…Песочница
Руководство
Markdown-версия

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

Как безопасно повторять покупку после таймаута или обрыва связи.

Если ответ на POST /purchase не дошёл, вы не знаете, прошла ли покупка. Повтор без защиты — это вторая покупка и второе списание. Поэтому передавайте idempotencyKey — свой уникальный идентификатор покупки, например ID заказа в вашей системе.

  • Первый запрос с ключом создаёт заказ.
  • Повтор с тем же ключом и тем же товаром возвращает исход того же заказа — с тем же кодом ответа и полем "replayed": true. Деньги второй раз не списываются, даже если товар уже закончился.
  • Тот же ключ с другим товаром — 422 idempotency_key_reused.
  • Если заказ не был создан (например, 402 — не хватило денег), ключ не занят: после пополнения можно повторить с ним же.

Формат

1–128 печатных ASCII-символов (!…~), без пробелов и кириллицы. Регистр важен: ABC и abc — разные покупки. Ключ действует в пределах вашего клиента.

Повтор с тем же ключом

JavaScript
async function buy(productId, idempotencyKey) {
  for (let attempt = 1; attempt <= 5; attempt++) {
    try {
      const res = await fetch(`https://merchant.dbdlobby.com/purchase/${productId}`, {
        method: "POST",
        headers: { "X-Entity-Key": KEY, "Content-Type": "application/json" },
        body: JSON.stringify({ idempotencyKey }), // один и тот же ключ во всех попытках
        signal: AbortSignal.timeout(90_000),
      });
      if (res.status >= 500 && res.status !== 502) throw new Error(`HTTP ${res.status}`);
      return { status: res.status, body: await res.json() };
    } catch (e) {
      // Сеть, таймаут или 5xx: исход неизвестен — повторяем С ТЕМ ЖЕ ключом.
      await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
    }
  }
  throw new Error("API недоступен; повторите позже с тем же idempotencyKey");
}

Ключ необязателен, но без него повтор после таймаута создаст вторую покупку. В будущем он может стать обязательным.