Ваше приложение взрослых персонажей обещает одну новую картинку. Клиент нажимает Generate, индикатор крутится, затем страница сообщает о тайм-ауте соединения. Он нажимает снова. Через минуту появляются две картинки, а баланс уменьшился дважды.
Вторая картинка может быть прекрасной. Но это дорогой способ узнать, что тайм-аут соединения не означает сбой генерации.
В NSFW API словом «повтор» называют три разных действия: проверку существующей задачи, повтор исходной отправки и оплату новой творческой попытки. Разделяйте их. Если есть ID задачи, проверяйте её. Если ответ создания потерялся, повторите неизменный запрос с исходным ключом идемпотентности. Если задача завершилась, но картинка не подходит брифу, новая генерация — новая покупка.
Последнее различие особенно важно для взрослых персонажей. Модель может успешно завершить работу, смягчив сцену, изменив одежду или создав другое лицо. Успех задачи говорит о доставленном результате, а не обещает, что вы захотите его использовать.
Что произошло и какую кнопку предложить?
| Что видит клиент | Что вы действительно знаете | Следующее действие |
|---|---|---|
| Тайм-аут запроса до получения ID | Принятие неизвестно | Повторить тот же запрос создания с тем же ключом |
Есть ID, задача queued или running | Генерация уже существует | Проверить статус, не создавать новую задачу |
Задача failed или expired | Попытка дошла до конечного исхода | Прочитать причину и итоговый платёж до новой попытки |
| Модель отклонила NSFW-запрос | Отклонён конкретный запрос | Проверить контентное поведение точной модели/задачи и примечание об оплате |
| Картинка пришла, но персонаж или сцена неправильные | Генерация успешна, творческий замысел не выполнен | Решить, стоит ли редактирование или новая вариация ещё одной оплаты |
| Картинка не скачивается | Доставка нарушена или ссылка истекла | Восстановить существующий файл, пока он доступен |

Ожидание, восстановление отправки и новая вариация — разные действия.
Полезный интерфейс автора может назвать их Проверить существующую картинку, Восстановить отправку, Создать другую вариацию и Повторить скачивание. Одна кнопка «Повторить» скрывает разницу между бесплатной проверкой статуса и разрешением новых расходов на генерацию.
Если ID задачи есть, сохраняйте исходную задачу
Асинхронный процесс SpicyAPI принимает запрос, возвращает ID задачи и делает картинку доступной позже. Ответ о принятии создания — не готовая картинка. Задача проходит состояния вроде queued, running и succeeded; failed, canceled и expired тоже являются конечными.
Сохраните ID сразу после получения сервером, до обновления браузера. Если клиент обновляет страницу, входит снова или открывает проект с другого устройства, приложение должно получить сохранённую задачу вместо новой отправки промпта.
Например, автор запрашивает вечерний портрет вымышленного взрослого персонажа. Сервер получает ID, но браузер теряет связь до отображения карточки ожидания. При возвращении карточка должна восстановить связь с этой задачей. Обновлением страницы автор не просил второй портрет.
Используйте GET /api/v1/jobs/recordInfo с ID для восстановления текущего состояния. Документация задач описывает запрос и ответ. Для уведомления о завершении можно использовать webhook, но его задержка не превращает задачу в неудавшуюся. Опрос остаётся способом восстановления.
Не превращайте локальный предел ожидания в решение об оплате. Браузер может прекратить ожидание через 30 секунд, исходящий HTTP-запрос сервера — через 60, а удалённая задача всё ещё работать. В записи задачи есть срок выполнения deadlineAt; он относится к удалённой обработке, а не длительности открытого соединения страницы. Истечение ссылки скачивания — ещё отдельный срок.
На экране ожидания подходит сообщение «Изображение ещё обрабатывается. Можно уйти со страницы и вернуться к той же задаче». Не обещайте точное время без измерений конкретной модели и нагрузки. Измеренная конкурентом задержка обычных товарных картинок не гарантирует срок ваших NSFW-промптов.
Если ответ создания потерялся, повторите ту же отправку
Сложный случай — соединение обрывается после отправки сервером запроса, но до подтверждения. По этой ошибке невозможно понять, приняла ли платформа задачу.
SpicyAPI предоставляет серверную защиту: необязательный заголовок Idempotency-Key. Для одного аккаунта и одного API-ключа повтор ключа с той же нормализованной моделью, вводом и callback URL в течение 24 часов возвращает исходную задачу вместо повторного резервирования денег. Изменённый запрос конфликтует с ключом. Другой API-ключ того же аккаунта также не может повторить его связь: он получает конфликт без раскрытия исходного ID задачи.
Создавайте стабильный ключ для картинки, запрошенной клиентом, а не для каждой HTTP-попытки. Значение приложения вроде project-8-image-12-v1 поясняет идею. Не включайте персональные данные и сырой текст промпта. Создайте и сохраните ключ до первого запроса создания. Новая сетевая попытка использует его; действительно новая картинка получает новую версию или ID операции.
Минимальная последовательность восстановления:
- Сохранить целевую операцию изображения, исходное тело запроса и ключ в приложении.
- Отправить запрос с
Idempotency-Key. - При потере подтверждения отметить локальную операцию как ожидающую подтверждения.
- Повторить неизменное тело с неизменным ключом через те же API-учётные данные.
- Сохранить полученный ID задачи и перейти к проверке статуса.
При восстановлении сохраняйте точный отправленный запрос. Не просите UI собрать его заново из настроек, которые клиент мог изменить. Переход от близкого портрета к широкой композиции, увеличение разрешения, изменение промпта или callback URL уже не являются исходной отправкой.
У защиты есть предел: 24 часа — не бесконечное хранение предотвращения дубликатов приложения. После окна не предполагайте, что старый ключ восстановит старую задачу. Вашей постоянной связи операция→задача нужно обслуживать поздние возвраты. Если принятие остаётся неизвестным и исходная задача не найдена, сверяйте записи задач аккаунта или обращайтесь в поддержку до автоматического создания замены.
Отключённая Generate полезна, но недостаточна
Отключённая при загрузке кнопка предотвращает частый двойной тап. Она не предотвращает отправку из двух вкладок, переподключившегося мобильного клиента, фонового worker или после перезапуска сервера.
Приложение должно связать все эти события с одной логической операцией изображения. Правило уникальности в вашей базе не даст двум worker независимо взять ту же операцию. Затем ключ идемпотентности платформы защищает границу удалённого создания. Это разные меры; обе нужны, если приложение отправляет задачу несколькими путями.
Рассмотрим продукт-компаньон, необязательно создающий новый портрет после разговора. До подтверждения автоматического запроса пользователь нажимает ручную кнопку портрета. Если обе операции выполняют один запрос портрета, свяжите их с одной операцией. Если ручная кнопка явно просит вторую вариацию, покажите новую платную генерацию. Не объединяйте незаметно две осознанные покупки и не списывайте дважды за одно обещание.
Сам ключ не определяет продуктовый смысл. Приложение решает, что считается одним запросом. Локально устранённый дубликат в базе тоже не поможет, если исходящий клиент при каждом восстановлении отправляет свежий удалённый ключ. Значение должно сохраняться по всему пути.
Отказ, технический сбой и нежелательная картинка оплачиваются по-разному
Запрос взрослого контента может закончиться несколькими способами. Избегайте общего обещания, что неудачные NSFW-генерации всегда бесплатны, и обратного утверждения, что оплачивается любая ошибка.

Состояние задачи и творческое удовлетворение различаются. Проверяйте итоговую запись и исключения оплаты конкретной модели.
SpicyAPI резервирует оценённую сумму при принятии задачи. Пока settled false, её cost — резервная оценка. После расчёта это окончательная оплата. Успешная задача оплачивается в пределах резерва; неиспользованные деньги освобождаются.
Неудавшаяся или истёкшая задача обычно освобождает резерв. Политика возвратов описывает исключения: модели, на страницах которых указана оплата отклонённых или неудачных запросов, и уже оказанное использование до прерывания. Для отказа модели в изображении проверьте её примечание об оплате и окончательную запись расчёта. Не объясняйте баланс аккаунта одной HTTP-ошибкой.
Успешная, но смягчённая картинка — другое. Допустим, вы просили уверенного вымышленного взрослого персонажа в конкретной взрослой редакционной сцене, а получили обычный портрет. Если задача успешна и результат доставлен, недовольство сценой не превращает его в возвратный технический сбой. То же касается другой причёски, лишнего аксессуара или не понравившегося выражения.
Поэтому полезным правилам повторов нужен предел творческих расходов, а не только число сетевых повторов. Worker, повторяющий каждую не понравившуюся приложению картинку, может продолжать покупать успешные результаты после устранения технических ошибок.
Читайте точную страницу используемой задачи модели. Свободный text-to-image маршрут не доказывает идентичное поведение редактирования, а названия семейства недостаточно для предсказания любого NSFW-запроса. Используйте только взрослых персонажей и материалы, которые вправе передавать; повторы не делают запрещённые запросы разрешёнными.
Повтор конечного сбоя создаёт новую работу
API также имеет POST /api/v1/jobs/retry, принимающий ID исходной задачи и создающий новую из подходящего конечного сбоя. Он не возвращает старую задачу в работу. Снова оцениваются текущие ввод модели, права, доступность, баланс и цена. Исходнику нужны сохранённый ввод и завершённый расчёт оплаты; активная или успешная задача не подходит этому действию.
Используйте API-ключ, создавший исходную задачу. Если к retry применяется ключ идемпотентности, он защищает конкретную новую попытку и ограничен исходной задачей. Повтор retry может восстановить её новую задачу; это отличается от повторения первого create для восстановления оригинала.
В приложении автора показывайте это новой попыткой генерации с ценой. Если нужно изменить сам промпт, создайте новый запрос с исправленным вводом, а не ожидайте, что retry исходника его отредактирует. Сбой из-за истёкшего референса также требует пригодного референса до новой успешной попытки. Освобождение исходной оплаты и резерв новой попытки — отдельные записи.
Реальная цена повторных попыток
Ниже текущие начальные конфигурации трёх endpoint изображений. Цены описывают генерацию, а не гарантию соответствия каждой картинки NSFW-брифу.

Гипотетический пример планирования: случайные дубликаты добавляют $2.40 к $7.20 осознанных творческих попыток.
| Endpoint и явная конфигурация | Цена изображения | Три оплаченные попытки | Десять оплаченных попыток |
|---|---|---|---|
| Z-Image Turbo text-to-image, расширение промпта выключено | $0.010 | $0.030 | $0.100 |
| Qwen Image 2.1 text-to-image, 1K | $0.024 | $0.072 | $0.240 |
| Seedream 5.0 Pro text-to-image, выбран 1K | $0.036 | $0.108 | $0.360 |
Детали важны. Z-Image Turbo с включённым расширением стоит $0.016, а не $0.010. Seedream 5.0 Pro по умолчанию использует 2K за $0.072 вместо цены 1K $0.036. Явный выбор уровня связывает расчёт с задачей.
Допустим, вы планируете 100 финальных портретов Qwen Image 2.1 при 1K. Если каждой финальной картинке нужно в среднем три оплаченных творческих попытки, расходы генерации $7.20: 100 × 3 × $0.024. Если ошибка подтверждения дублирует ещё одну отправку на каждый финал, добавляется 100 × $0.024 = $2.40, доводя расходы до $9.60. Это примеры планирования, а не измеренная доля успеха.
Нельзя превратить творческий процесс с тремя попытками в одну изменением HTTP-тайм-аута. Можно удалить случайную четвёртую. Учитывайте осознанные вариации отдельно от случайных дубликатов, чтобы видеть, какую проблему оплачиваете.
Для малого процесса автора заранее определите предел: например, один исходный результат и две исправленные попытки для конкретного места. Это совет по бюджету приложения, а не ограничение платформы. Если все три не выполняют одно требование, прекратите покупать почти одинаковые запросы и измените подход.
Завершённая NSFW-картинка не подходит: меняйте одну важную вещь
Если лицо верное, а комната или одежда неправильные, точечное редактирование может быть лучшей покупкой, чем новый text-to-image с нуля. Сохраните полезный результат, опишите изменение и выберите модель с подходящей задачей редактирования. Правка всё равно платная, а не бесплатное исправление исходной генерации.
Если один запрос постоянно даёт смягчённую сцену, сначала выясните, был ли отказ по содержанию, консервативное толкование разрешённого запроса или перегруженный промпт. Повтор неизменного промпта не сообщает причину. Смотрите на полученную картинку и стабильный код ошибки, если он есть, а не считайте слово NSFW универсальным переключателем.
Для неграфического примера планирования портрет может требовать одного вымышленного взрослого персонажа, тёмного атласного пиджака, сидячей позы, тёплого бокового света и незагромождённой комнаты. Если каждый результат даёт насыщенную предметами комнату, уберите второстепенные детали обстановки и оставьте персонажа и свет. Если приходит другое лицо, перейдите к подходящему референсному процессу вместо новых прилагательных в текстовом промпте.
Для настоящей новой вариации используйте новую операцию и ключ. Повтор первого принятого запроса с исходным ключом восстанавливает первую задачу, а не просит модель придумать улучшенную вторую картинку. Если для новой вариации меняете seed, учитывайте это новой творческой попыткой. Seed помогает определить запрос, но не гарантирует того же персонажа между разными моделями.
После первых попыток сравнивайте цену пригодного результата, а не только стартовую рекламную ставку. Четыре генерации по $0.010 стоят $0.040. Одна по $0.024 — $0.024. Арифметика не доказывает большей надёжности второй модели; она показывает, что измерять для собственного брифа персонажа.
Если существующая картинка не скачивается
Не генерируйте заново успешную картинку из-за ошибки скачивания. Файл может ещё существовать при неработающей временной ссылке, либо приложение могло ошибиться при копировании.
Сохраните завершённую задачу и идентификатор файла результата. Восстановите актуальный разрешённый путь скачивания, пока результат хранится, затем повторите передачу этого файла. Не добавляйте API-ключ к отдельному подписанному URL медиа. Подтвердите наличие байтов в целевом хранилище до показа «Сохранено» в библиотеке клиента.
Руководство по доставке медиа объясняет копирование в ваше хранилище. Для взрослого автора это также граница приватности: картинка или референс не становятся материалом публичной галереи лишь из-за успешного копирования. Восстановление должно сохранять задуманный частный доступ.
Если оригинальный результат уже удалён по действующей политике хранения задачи, ID не восстановит отсутствующие байты. Замена будет новой генерацией и может выглядеть иначе. Объясните это клиенту вместо незаметной замены старого портрета новым оплаченным.
Следующее действие клиента должно соответствовать оплате
Показывайте статус существующей задачи вместе с итоговой оплатой. Пока задача не разрешена, сохраняйте её место в проекте, не представляя новую платную попытку единственным продолжением. При сбое покажите причину и факт освобождения резерва. При успехе отделите «Скачать снова» от «Создать другую вариацию».
Для поддержки полезны ID задачи, ID запроса при наличии, время, сумма и короткое описание проблемы. Два разных ID задач — не то же, что двойная оплата одной. Политика возвратов отдельно просит сообщать о двойных списаниях, суммах выше резерва, недоставленных успешных результатах и резервах сбоя, не возвращённых за 24 часа. Не помещайте API-ключи, подписанные медиа-ссылки и чувствительные творческие промпты в обычные логи или снимки поддержки.
Автор должен понимать историю как «один портрет запрошен, одна отправка восстановлена, один результат доставлен», а не список невидимых HTTP-попыток. К этому и нужно стремиться: сетевое восстановление сохраняет исходную покупку, а новая творческая попытка — осознанное решение с видимой ценой.








