Сначала проверьте
- Счета создаются прямо сейчас? Не разбирайтесь «на живую» — сначала kill-switch (шаги ниже), разбор потом.
- Передаёте
external_order_id_idempotency? Если нет — каждый POST создаёт новый живой счёт, и любой ретрай = дубль. - Есть ли авторетраи на вашей стороне? Таймаут ≠ неуспех: счёт мог создаться, а ваш код, не дождавшись ответа, послал запрос ещё раз.
Экстренная остановка (kill-switch)
Полный протокол — у этой ситуации нет «мягкого» решения, действуйте по шагам:
- Откройте кабинет apipay.kz → Настройки → «Подключения».
- Удалите API-ключ(и), которыми пользуется сбоящая интеграция. Это мгновенно отключает её: счета перестанут выставляться. Безопасно: созданные счета, оплаты и деньги не затрагиваются.
- Отмените лишние неоплаченные счета — в кабинете (раздел «Счета») или напишите в поддержку: с массовой отменой поможем быстрее.
- Найдите цикл у себя: триггер CRM, срабатывающий по кругу; ретрай без ограничения попыток; вебхук, который сам создаёт новый счёт.
- Внедрите идемпотентность: передавайте
external_order_id_idempotency(уникальный на заказ, ≤191 символ) — повторный запрос получит409 duplicate_idempotency_keyвместо нового счёта. - Выпустите новый ключ, пропишите вебхук и включайте интеграцию обратно.
Ветки диагностики
| Признак | Причина (частота по данным поддержки) | Что сделать | Подробнее |
|---|---|---|---|
| Покупатель получил два пуша и оплатил оба | Два POST без ключа идемпотентности (ретрай кода) — чаще всего | Вернуть лишнюю оплату возвратом; внедрить external_order_id_idempotency |
«Как не выставить два счёта за один заказ?» в «Создании счёта по номеру»; возврат — «Возвраты» |
| Счета льются потоком без вашего участия | Зацикленная CRM/no-code-интеграция — часто в этой группе | Kill-switch выше, затем разбор триггеров | — (протокол в этой статье) |
| Дубль после «зависшего» счёта | Пересоздали счёт в processing — а он не завис, а ждал очереди |
Не пересоздавать processing: система доведёт его сама |
«Какие статусы проходит счёт?» в «Создании счёта» |
Получаете 409 duplicate_idempotency_key |
Это не ошибка, а защита: счёт с этим ключом уже есть | Взять invoice_id и status прежнего счёта из 409-ответа |
Создание счёта по номеру |
Для вашего ИИ-агента
Правила: external_order_id_idempotency уникален в пределах организации, ≤191 символа (длинные order_id хэшируйте, например md5); повтор → 409 duplicate_idempotency_key с invoice_id и status прежнего счёта; для «мёртвых» статусов (expired/cancelled/error) повторный POST с тем же ключом создаёт новый счёт — это штатное перевыставление; счёт в processing не пересоздавать.
Частые вопросы
Удаление API-ключа удалит счета или деньги?
Нет. Удаление ключа лишь отключает интеграцию — созданные счета, оплаты и деньги остаются нетронутыми. Это безопасная экстренная кнопка.
Как остановить лавину счетов прямо сейчас?
Кабинет → Настройки → «Подключения» → удалить API-ключи. Интеграция отключится мгновенно; после разбора выпустите новый ключ.
Покупатель оплатил оба дубля — что делать?
Верните одну из оплат возвратом (кабинет или POST /invoices/{id}/refund), а в интеграцию добавьте идемпотентность, чтобы не повторилось.
Что значит 409 duplicate_idempotency_key?
Защита сработала: счёт с этим external_order_id_idempotency уже существует. В 409-ответе приходят invoice_id и status прежнего счёта — используйте их, не создавайте новый.
Мой order_id длиннее 191 символа — как быть?
Передавайте хэш (например md5) от вашей строки заказа — идемпотентности важна уникальность, а не читаемость.