Документація 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_id
Idempotency-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('Не вдалося створити замовлення')
}