Розділи документації API
Документація API/Запити/Idempotency-Key

Idempotency-Key

Мережа обірвалась, а замовлення, можливо, вже створено. Якщо повторити, можна отримати дубль, а якщо ні, можна втратити замовлення. Заголовок Idempotency-Key розв’язує цю проблему.

POST і PATCHВідповідь зберігається 24 години

Як працює

Згенеруйте унікальний ключ на кожну операцію (не на кожну спробу) і передавайте його в усіх повторах:

POST /api/v1/order
Idempotency-Key: 7b0c1f1e-3a52-4c9e-9d2a-5f3e6c1b8a10
Content-Type: application/json

{ "name": "Замовлення з сайту №1001", ... }
СитуаціяВідповідь
Перший запит із ключемВиконується як звичайно, відповідь запам’ятовується на 24 години.
Повтор із тим самим ключем і тим самим тіломТа сама відповідь (код і тіло) без повторного виконання + заголовок Idempotent-Replayed: true.
Повтор, поки перший ще виконується409 idempotency_in_progress, повторіть за секунду.
Той самий ключ, але інший шлях чи тіло422 idempotency_key_reused, це помилка клієнта.
Перша спроба завершилась 5xxНе запам’ятовується, тож при повторі запит виконається знову.
Перша спроба завершилась 4xxЗапам’ятовується: повтор отримає ту саму помилку. Для виправлених даних потрібен новий ключ.

Правила

  • ●Ключ складається з 1–255 друкованих ASCII-символів без пробілів. Зручно: UUID v4 або order-site-1001.
  • ●Ключі розділені між токенами: однаковий ключ у двох інтеграцій не конфліктує.
  • ●На GET, PUT, DELETE заголовок не діє, ці методи й так можна повторювати.
  • ●Відповіді більше 1 МБ не зберігаються (на практиці таких POST немає).
Разом із external_idIdempotency-Key захищає від повтору протягом доби, а external_id назавжди. Для замовлень із сайту використовуйте обидва.

Приклад

JavaScript

import { randomUUID } from 'node:crypto'

async function createOrder(order) {
  const key = randomUUID()                  // один ключ на всі спроби
  for (let attempt = 0; attempt < 5; attempt++) {
    try {
      const res = await fetch(`${API}/order`, {
        method: 'POST',
        headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json', 'Idempotency-Key': key },
        body: JSON.stringify(order),
      })
      if (res.status === 409 || res.status === 429 || res.status >= 500) {
        await new Promise(r => setTimeout(r, 1000 * (attempt + 1)))
        continue
      }
      return res.json()
    } catch (networkError) {
      await new Promise(r => setTimeout(r, 1000 * (attempt + 1)))
    }
  }
  throw new Error('Не вдалося створити замовлення')
}