Идемпотентные запросы
Запрос может завершиться ошибкой, когда Sursa уже выполнила работу: соединение обрывается или ваш процесс
перезапускается до того, как пришёл ответ. Если отправить тот же POST ещё раз, можно создать вторую карточку или
второй вебхук. Ключ идемпотентности это предотвращает.
Передавайте заголовок Idempotency-Key с каждым POST и PATCH. Если Sursa уже видела запрос с этим ключом, она
не выполняет операцию снова, а возвращает ответ, сохранённый в первый раз.
curl -X POST https://api.sursa.com/v1/cards/text \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Idempotency-Key: 6f1d2c9e-7b0a-4c43-9a51-0d6c1c1f8e21" \
-H "Content-Type: application/json" \
-d '{"title": "Refund policy", "body_markdown": "Refunds are processed within 14 days."}'Повторный запрос получает тот же статус и то же тело, что и первый, плюс дополнительный заголовок:
HTTP/1.1 200 OK
Idempotency-Replayed: true
X-Request-Id: 01JB7R…
У повторного запроса свой X-Request-Id.
Как выбрать ключ
- Используйте новое случайное значение, например UUID v4, для каждой логической операции: «создать эту карточку», «зарегистрировать этот вебхук». Используйте одно и то же значение при каждом повторе этой операции и никогда — для другой операции.
- Хороший ключ выводится из ваших собственных данных, если они есть, например
sync-2026-10-24-record-1042. Тогда даже перезапущенное задание, которое потеряло своё состояние, снова отправит тот же ключ. - Ключ — от 1 до 255 печатных символов ASCII. Всё остальное возвращает
400с кодомapi.idempotency_key_invalid.
Что Sursa делает с ключом
| Ситуация | Ответ |
|---|---|
| Первый запрос с этим ключом | Операция выполняется как обычно. |
Тот же ключ, тот же запрос, первый завершился с 2xx или 4xx | Сохранённый ответ с Idempotency-Replayed: true. Операция не выполняется снова. |
| Тот же ключ, первый запрос ещё выполняется | 409 api.idempotency_in_progress с Retry-After: 1. Подождите и повторите. |
Тот же ключ, но другой метод, путь, Content-Type или тело | 409 api.idempotency_mismatch. Ключ уже занят другим запросом. |
Первый запрос завершился с 5xx или 429 | Ключ освобождается: следующий запрос с ним снова выполнит операцию. |
- Ключ действует 24 часа. После этого тот же ключ запускает новую операцию.
- Ключи разделены по организациям и по вызывающим: два разных ключа API могут использовать одно и то же значение, не влияя друг на друга.
- Ответ с ошибкой
4xxтоже сохраняется. Запрос, не прошедший проверку, при повторе с тем же ключом завершится так же; исправьте его и отправьте с новым ключом.
Каким запросам он нужен
| Метод | Idempotency-Key |
|---|---|
POST, PATCH | Передавайте. У каждой операции, которая сохраняет свой ответ для повтора, этот заголовок указан в справочнике API. |
GET, PUT, DELETE | Не нужен: эти методы по своей сути безопасно повторять. Заголовок принимается и ни на что не влияет. |
POST, который только читает, например поиск, финансовые отчёты и POST /v1/catalog/resolve | Принимается, но ничего не сохраняется: запрос просто выполняется снова. |
Некоторые операции безопасно повторять и без заголовка:
PUT /v1/cards-by-external-id/{external_id}создаёт или заменяет карточку с вашим идентификатором; повтор с тем же содержимым ничего не меняет.- Документы своего источника различаются по вашему
external_id; повторная отправка того же документа возвращаетunchanged. - Потоковый ответ
POST /v1/chatвместо заголовка использует полеrequest_idв теле. См. Бот вопросов и ответов.
Безопасные повторы
Сочетайте ключ с правилами повторов из раздела Ошибки: создайте ключ один раз, до первой попытки, и передавайте его с каждой попыткой той же операции.