Pro API: 残高、上限、トレーニング済みキャラクター
キーの権限に関わらず常に許可される2つの読み取りルートと、アプリ内に保存されるアクティビティログについて説明します。
残高と上限
GET /credits
{ "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 | 1分あたりのリクエスト送信数。デフォルトは60。 |
limits.perDay | キーに設定した1日あたりのクレジット上限。0 は上限なしを意味します。 |
running | このキーからのレンダリングのうち、まだ収集待ちのもの。 |
buy_url | ライセンスのクレジット購入ページ(カードまたは暗号資産)。 |
これはAPI内で最も軽量な呼び出しであり、キーが正常に機能しているか確認するのに適しています。
登録済みのカードでクレジットを購入する
POST /credits/purchase
{ "pack": "m" }pack にはパックのID(s、m、l、xl、xxl、xxxl)、または最大のパックを超える任意の数として "c25000" を指定します。支払いは、アカウントページの自動チャージに登録したカードで行われます。そこでエージェントによる購入を許可している場合に限り、設定した月間上限の範囲内で行われます(自動チャージも含みます)。購入のたびに確認メールが届きます。購入は一度に1件のみです。
レスポンスは 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としてトレーニングされたキャラクターです。1枚の写真から7つのビューを作成するMulti-Ref Videoのキャラクターは別の仕組みです。Charactersをご覧ください。
GET /loras
{ "image": [ { "name": "megan_krea2", "trigger": "megan", "base": "krea2", "size": 0 } ],
"video": [ { "name": "megan_ltx", "trigger": "megan", "size": 0 } ] }画像の場合は image リスト、動画の場合は video リストから name を取得し、lora として渡してください。また、プロンプトに trigger を必ず含めてください。含めない場合、キャラクターが表示されません。アカウントに属していないキャラクターを指定すると 403 unknown_lora が返されます。
独自のLoRAをアップロードする
POST /loras/upload
他の場所でトレーニングしたか、自分のサーバーに保存している .safetensors ファイルをアカウントのスペースに追加し、アプリ内でトレーニングしたキャラクターと同様に lora 経由で使用できるようになります。アップロード方法は2種類あります。90 MB以下の一括アップロードと、それを超える場合の分割アップロードです。LoRAは通常200〜500 MBであるため、分割アップロードが一般的なケースです。上限はどちらも800 MBです。
一括アップロード: rawボディ(application/octet-stream、Content-Length 必須)で、パラメーターはURLに含めます。
100 MBを超えるリクエストはAPIに到達しません。 前段のインフラがリクエストを拒否するため、返ってくるのはJSONボディのない素の 413 です。すべてのエラーをJSONとしてパースするクライアントは、エラーを報告する代わりにクラッシュします。このサイズは分割アップロードを使用してください。
| パラメーター | 役割 |
|---|---|
name | ファイル名。.safetensors形式で、英数字、. _ - を使用可能、最大80文字。既存の名前と同じ場合は上書きされます。 |
kind | image(デフォルト)または video。それぞれ images または videos 権限が必要です。 |
trigger | プロンプトに含めるトリガーワード。最大60文字。 |
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でレンダリングされ、独自のアーキテクチャを持っています。tendre.AIでトレーニングしたものか、他の場所でKrea 2向けにトレーニングしたものかに関わらず、Krea 2のLoRAのみが適用されます。FLUX.1のLoRAは拒否される点に注意してください(多くの方が最初に驚かれます)。動画はLTX 2.5でレンダリングされるため、LTX 2.5または2.3のLoRAが必要です。
APIはファイルを保存する前にヘッダーを読み取ります。SDXL、SD 1.5、SD3、FLUX.1、Wan、HunyuanVideoと認識されたLoRAは 415 incompatible_lora で拒否され、検出された architecture が返されます。safetensors形式でないファイルは 415 invalid_safetensors で拒否されます。どちらの場合も保存は行われず、クォータも消費されません。
ただし1つのケースは通過します。ヘッダーでアーキテクチャが特定できない場合、architecture: "inconnue" として受け入れられ、レンダリング時にのみ判断されます。この場合、問題を発見するためにレンダリングを1回消費することになります。
大きなLoRAを分割して送信する
3つの呼び出しに加え、中断用の呼び出しが1つあります。
1. セッションを開始する。 POST /loras/upload/start に { "name", "kind", "size", "trigger" } を送信します。size はファイル全体のバイト数です。名前、サイズ、クォータを確認した後、以下が返されます。
{ "uploadId": "...", "part_size": 20971520, "max_part_size": 104857600, "parts_expected": 15 }2. 各パートを送信する。 POST /loras/upload/part?uploadId=...&part=N、rawボディ、パートは1から番号が付き、最後のパートを除いて part_size バイトずつ、max_part_size を超えてはいけません。各レスポンスに etag が含まれており、次のステップで全て必要になるため、順番に保存してください。
パート1は特別です。ファイルヘッダーを含むため、アーキテクチャの判定はここで行われます。互換性のないLoRAは 415 で検出され、セッションはキャンセルされます。400 MBではなく20 MB時点で問題がわかります。
3. セッションを閉じる。 POST /loras/upload/finish に { "uploadId", "parts": [ { "part": 1, "etag": "..." }, ... ] } を送信します。ファイルを組み立てて登録し、一括アップロードと同じ形式のレスポンスを返します。
中断する場合は、POST /loras/upload/abort に { "uploadId" } を送信します。finish されないまま放置されたセッションは6時間後に削除されます。finish が成功するまでは GET /loras には表示されず、クォータにもカウントされないため、中断したアップロードはストレージを消費しません。
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"])アプリには scripts/api-pro-lora.ps1 にPowerShellスクリプトが同梱されています。
LoRAを削除する
DELETE /loras/{name}?kind=image|video はファイルを削除してクォータを解放します。レスポンスは { "ok": true, "name": ..., "storage": { ... } } です。アカウントに存在しない名前の場合は 404 unknown_lora が返されます。
ストレージクォータ
各ライセンスには最大20ファイル、10 GBが割り当てられており、画像と動画を合わせてカウントされます。アプリ内でトレーニングしたキャラクターもこの上限に含まれます。GET /loras はその状態を storage フィールドで返します。
{ "count": 3, "max_count": 20, "bytes": 943718400, "max_bytes": 10737418240 }いずれかの上限を超えると、アップロードは 413 lora_quota と残り容量を返します。ファイルを削除してスペースを確保してください。
キャラクターのトレーニングはAPIではまだ公開されていません。アプリ内で行われ、結果はこのリストに表示されます。
アクティビティ
アプリには、キーで行ったすべてのレンダリングのログ(日付、キー、タイプ、コスト、ステータス)とキーごとの消費量が Settings > API > Activity に保存されます。
また、漏洩したキーを他のキーに影響を与えずに無効化する場合もここで行います。