Pro API: баланс, лимиты и обученные персонажи

Два маршрута для чтения, доступных при любых правах ключа, плюс журнал активности, который хранится в приложении.

Баланс и лимиты

GET /credits

json
{ "balance": 1830, "licenseId": "lic_...", "key": "k_1a2b3c4d",
  "limits": { "concurrent": 2, "perMinute": 60, "perDay": 0 }, "running": 1,
  "buy_url": "https://tendre.ai/credits?license=lic_..." }
ПолеЗначение
balanceОставшиеся кредиты. null, если баланс неизвестен (тестовая среда).
licenseIdЛицензия, к которой принадлежит этот ключ.
keyПубличный идентификатор ключа, безопасный для логирования. Никогда не секрет.
limits.concurrentКоличество одновременных рендеров, по умолчанию 2.
limits.perMinuteЗапросов в минуту, по умолчанию 60.
limits.perDayДневной лимит кредитов, установленный для ключа. 0 означает отсутствие лимита.
runningРендеры этого ключа, ожидающие получения.
buy_urlСтраница покупки кредитов для твоей лицензии, картой или криптовалютой.

Это самый дешёвый вызов в API и правильный способ проверить работоспособность ключа.

Покупка кредитов с сохранённой карты

POST /credits/purchase

json
{ "pack": "m" }

В pack укажи идентификатор пакета (s, m, l, xl, xxl или xxxl) или "c25000" для произвольного количества сверх самого большого пакета. Оплата идёт с карты, сохранённой в автопополнении на странице твоего аккаунта, только если ты там разрешил агенту покупать, в пределах месячного лимита, который ты там задал (автопополнения учитываются). Каждую покупку подтверждает письмо. Только одна покупка за раз.

Ответ: 200 { credits, eur, balance }. Каждый отказ содержит buy_url, обычную ссылку на покупку, которой можно воспользоваться вместо этого: 402 confirmation_required (банк просит твоего подтверждения) или payment_declined; 409 agent_not_allowed, no_saved_card, monthly_cap_reached, topup_in_progress или purchase_in_progress; 400 unknown_pack. При 503 payment_unavailable мы не знаем, прошло ли списание: не повторяй сразу, прошедшее списание будет зачислено.

Обученные персонажи

Это персонажи, обученные как LoRA, для изображений и обычных видео. Персонажи Multi-Ref Видео, семь ракурсов из одной фотографии, это другое: смотри Characters.

GET /loras

json
{ "image": [ { "name": "megan_krea2", "trigger": "megan", "base": "krea2", "size": 0 } ],
  "video": [ { "name": "megan_ltx", "trigger": "megan", "size": 0 } ] }

Передавай name как lora, беря его из списка image для изображений и из списка video для видео, и вставляй trigger в промпт, иначе персонаж не появится. Персонаж, не принадлежащий аккаунту, возвращает 403 unknown_lora.

Загрузи собственную LoRA

POST /loras/upload

Файл .safetensors, который у тебя уже есть, обученный в другом месте или лежащий на твоём сервере, попадает в пространство аккаунта и становится доступным через lora точно так же, как персонаж, обученный в приложении. Есть два способа загрузки: одним запросом до 90 МБ или по частям при большем размере. LoRA обычно весит от 200 до 500 МБ, так что обычно подходит второй вариант. Максимальный размер в обоих случаях: 800 МБ.

Одним запросом: тело запроса в сыром виде (application/octet-stream, Content-Length обязателен), параметры передаются в URL.

Запросы свыше 100 МБ до API не доходят. Инфраструктура перед ним отклоняет их, поэтому в ответ приходит голый 413 без тела JSON: клиент, который парсит все ошибки как JSON, сломается вместо того, чтобы сообщить об ошибке. Такой размер надо загружать по частям.

ПараметрРоль
nameИмя файла, .safetensors, буквы, цифры, . _ -, не более 80 символов. Имя, которое уже занято, заменяется.
kindimage (по умолчанию) или video. Требует соответственно разрешения images или videos.
triggerТриггерное слово для подстановки в промпт, не более 60 символов.
bash
curl -s -X POST "$B/loras/upload?name=my_character.safetensors&kind=image&trigger=ohwx"   -H "Authorization: Bearer $KEY" -H "Content-Type: application/octet-stream"   --data-binary @my_character.safetensors

Ответ: { "ok": true, "name": "my_character.safetensors", "kind": "image", "size": 314572800, "trigger": "ohwx", "architecture": "krea2", "storage": { ... } }.

Совместимость проверяется при загрузке. Изображения рендерятся через Krea 2, у которого собственная архитектура: подходит только Krea 2 LoRA, обученная в tendre.AI или для Krea 2 в другом месте. Обрати внимание, что LoRA FLUX.1 отклоняется, что не для всех очевидно. Видео рендерятся через LTX 2.5, поэтому нужна LTX 2.5 или 2.3 LoRA.

API читает заголовок файла до его сохранения. LoRA, распознанная как SDXL, SD 1.5, SD3, FLUX.1, Wan или HunyuanVideo, отклоняется с 415 incompatible_lora, в котором указывается найденная architecture, а файл, не являющийся safetensors, получает 415 invalid_safetensors. В обоих случаях ничего не сохраняется и квота не тратится.

Один случай всё же проходит: архитектура, которую заголовок не определяет, принимается с architecture: "inconnue" и оценивается только во время рендера. Это единственная ошибка, которая обойдётся тебе в один рендер.

Отправка большой LoRA по частям

Три вызова плюс один для отмены.

1. Открой сессию. POST /loras/upload/start с { "name", "kind", "size", "trigger" }, где size означает полный размер файла в байтах. Проверяются имя, размер и квота, затем возвращается:

json
{ "uploadId": "...", "part_size": 20971520, "max_part_size": 104857600, "parts_expected": 15 }

2. Отправь каждую часть. POST /loras/upload/part?uploadId=...&part=N, тело в сыром виде, части нумеруются с 1, каждая по part_size байт кроме последней, и не более max_part_size. Каждый ответ содержит etag, и они все нужны тебе для следующего шага, так что сохраняй их по ходу.

Часть 1 особенная: она содержит заголовок файла, поэтому именно здесь проверяется архитектура. Несовместимая LoRA отклоняется с 415, и сессия отменяется. Ты узнаешь об этом после 20 МБ, а не после 400.

3. Закрой сессию. POST /loras/upload/finish с { "uploadId", "parts": [ { "part": 1, "etag": "..." }, ... ] }. Файл собирается и регистрируется, ответ полностью совпадает с ответом одного запроса.

Для отмены: POST /loras/upload/abort с { "uploadId" }. Сессия без finish удаляется через шесть часов. В GET /loras ничего не отображается и в квоту ничего не засчитывается до успешного выполнения finish, так что прерванная загрузка не занимает место.

python
import os, requests
B, H = "https://api.tendre.ai/pro/v1", {"Authorization": "Bearer " + KEY}
path = name = "my_character.safetensors"
s = requests.post(f"{B}/loras/upload/start", headers=H,
                  json={"name": name, "kind": "image", "size": os.path.getsize(path), "trigger": "ohwx"}).json()
parts = []
with open(path, "rb") as f:
    n = 1
    while chunk := f.read(s["part_size"]):
        r = requests.post(f"{B}/loras/upload/part",
                          headers={**H, "Content-Type": "application/octet-stream"},
                          params={"uploadId": s["uploadId"], "part": n}, data=chunk)
        r.raise_for_status()
        parts.append({"part": n, "etag": r.json()["etag"]})
        n += 1
done = requests.post(f"{B}/loras/upload/finish", headers=H,
                     json={"uploadId": s["uploadId"], "parts": parts}).json()
print(done["name"], done["architecture"], done["storage"])

Готовый скрипт PowerShell поставляется с приложением: scripts/api-pro-lora.ps1.

Удаление LoRA

DELETE /loras/{name}?kind=image|video удаляет файл и освобождает квоту. Ответ: { "ok": true, "name": ..., "storage": { ... } }, или 404 unknown_lora, если имя не существует на аккаунте.

Квота хранилища

Каждая лицензия получает максимум 20 файлов и 10 ГБ, изображения и видео вместе, причём персонажи, обученные в приложении, тоже учитываются. GET /loras возвращает состояние в поле storage:

json
{ "count": 3, "max_count": 20, "bytes": 943718400, "max_bytes": 10737418240 }

При превышении любого из лимитов загрузка возвращает 413 lora_quota вместе с остатком. Удали файл, чтобы освободить место.

Обучение персонажей через API пока недоступно. Оно происходит в приложении, а результат появляется в этом списке.

Активность

Приложение хранит журнал всех рендеров, выполненных твоими ключами (дата, ключ, тип, стоимость, статус), а также расход по каждому ключу в разделе Настройки > API > Activity.

Там же ты можешь отозвать скомпрометированный ключ, не затрагивая остальные.

Windows · Mac · облако или локально

Генерируй приватно. Уже сегодня вечером.

Скачай tendre.AI бесплатно и генерируй без ограничений, приватно, на своём собственном GPU.

OS Windows 10/11GPU NVIDIA 8ГБ+VRAM 12ГБ рекомендуетсяДиск 20ГБ

Mac: Apple silicon (M1 или новее), macOS 13 или новее. Intel Mac не поддерживаются.

Для локальной генерации изображений на Mac нужен M4 с 24 ГБ памяти, либо M2 или M3 Pro, Max или Ultra с 24 ГБ. Если у тебя устройство послабее, всё работает онлайн через кредиты. Ретушь и видео на Mac пока тоже работают только онлайн.

Всё о tendre.AI для Mac

Нет видеокарты NVIDIA? Начни на 100% в облаке: 5 бесплатных изображений и 1 бесплатное видео каждый день. Карта NVIDIA (от 8 ГБ) открывает безлимитную локальную генерацию.