---
title: Идемпотентность
description: Заголовок Idempotency-Key делает повтор отправки генерации безопасным — тот же запрос вернёт тот же request_id без второй задачи и второго списания.
icon: Repeat
---

Передавайте заголовок `Idempotency-Key` при отправке генерации. Если соединение оборвалось и вы повторили запрос с тем же ключом и тем же телом, Clipia вернёт **тот же ответ** с тем же `request_id`: вторая задача не создастся, кредиты второй раз не спишутся. Запись хранится 24 часа.

## Заголовок

<TypeTable
  type={{
    'Idempotency-Key': {
      type: 'string',
      description: 'Ключ логического запроса, до 255 символов. Рекомендуется UUID v4. Действует 24 часа в пределах одного API-ключа.',
    },
  }}
/>

## Как использовать

<Tabs items={['cURL', 'TypeScript', 'Python']}>
<Tab value="cURL">

```bash
curl -X POST https://api.clipia.ai/v1/models/nano-banana-2 \
  -H "Authorization: Bearer $CLIPIA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f3a1c7e-2b41-4d2a-9c0e-1200304cf45b" \
  -d '{ "input": { "prompt": "a sunset over mountains, cinematic" } }'
```

</Tab>
<Tab value="TypeScript">

```ts
import { createClient } from 'clipia-ai';

const clipia = createClient({ apiKey: process.env.CLIPIA_KEY! });

// SDK ставит Idempotency-Key на каждую отправку сам.
// Чтобы повторы вашего кода попадали в ту же задачу, передайте свой ключ:
await clipia.queue.submit('nano-banana-2', {
  input: { prompt: 'a sunset over mountains, cinematic' },
  idempotencyKey: '8f3a1c7e-2b41-4d2a-9c0e-1200304cf45b',
});
```

</Tab>
<Tab value="Python">

```python
import os
from clipia import Clipia

client = Clipia(api_key=os.environ["CLIPIA_KEY"])

# SDK ставит Idempotency-Key на каждую отправку сам; при необходимости передайте свой.
client.submit(
    "nano-banana-2",
    {"prompt": "a sunset over mountains, cinematic"},
    idempotency_key="8f3a1c7e-2b41-4d2a-9c0e-1200304cf45b",
)
```

</Tab>
</Tabs>

Создавайте новый ключ на каждый **логический** запрос, а не на каждую сетевую попытку. Если ключ генерирует SDK, он свой у каждого вызова `submit`; повторы внутри вашего кода с новым вызовом получат новый ключ.

## Поведение при повторе

| Ситуация | Результат |
|----------|-----------|
| Тот же ключ, та же модель и то же тело | Тот же ответ целиком (включая `warnings`, если они были) и тот же `request_id`. Новой задачи и списания нет |
| Тот же ключ, другая модель или другое тело | `409 idempotency_key_reuse` |
| Повтор, пока первый запрос ещё обрабатывается | `409 request_in_progress` — повторите через несколько секунд |
| Первый запрос завершился ошибкой | Ключ освобождается, повтор обрабатывается заново |
| Прошло больше 24 часов | Ключ считается новым и создаёт новую задачу |

Ключи разных API-ключей не пересекаются: одинаковый `Idempotency-Key` на двух API-ключах — это два разных запроса.

Любой повторный ответ — с явным ключом или по склейке без заголовка — приходит с заголовком `Idempotent-Replayed: true`; у ответа на новую задачу его нет.

## Без заголовка

Если заголовка нет, одинаковые запросы с одного API-ключа, пришедшие в течение 20 секунд, тоже склеиваются в одну задачу. Это страховка от случайного двойного клика или быстрого сетевого повтора. Если вы намеренно хотите две одинаковые генерации подряд, передайте разные `Idempotency-Key`.

<Callout type="warn" title="Где это работает">
Заголовок действует для `POST /v1/models/{model}` и для обычных ответов `POST /v1/chat/completions` и `POST /v1/completions`; со `stream: true` он игнорируется. Склейка без заголовка — только у отправки генерации. Запросы `GET` повторять безопасно и без неё. Не кладите в ключ email или другие личные данные — используйте случайный UUID v4.
</Callout>
