画像生成
テキストプロンプトと参照画像から AI 画像を生成します。同期実行と非同期タスクに対応し、クレジット消費量の事前見積もりもできます。
画像生成 API は、テキストプロンプト(任意で参照画像による誘導つき)を 1 枚以上の画像に変換します。呼び出し方は 3 通りあります。
- 同期 —
POST /v1/images/generationは画像が完成するまでブロックし、モデルの生の出力(base64 画像データ)をレスポンスボディで返します。 - 非同期 —
POST /v1/images/generation/asyncは即座にtaskIdを返します。結果(ホスティングされた画像 URL)はGET /v1/images/generation/tasks/{taskId}をポーリングして取得します。 - 先に見積もり —
POST /v1/images/generation/estimate-creditsは、何も消費せずにクレジットコストとアカウントが生成可能かどうかを返します。
すべてのエンドポイントで API キー(Authorization: Bearer $LISTENHUB_API_KEY)が必要です。キーは listenhub.ai/settings/api-keys で作成できます。
2 つの生成エンドポイントはデータの返し方が異なります。同期エンドポイントはモデルの生の JSON をそのままボディで返します(標準の { code, message, data } エンベロープでラップされません)。非同期と見積もりのエンドポイントは標準のラップ済みエンベロープを使います。レスポンス形式 を参照してください。
画像を生成する(同期)
POST /v1/images/generation
テキストプロンプトから画像を生成し、完成までブロックします。スタイルや内容を誘導するために、任意で参照画像を渡せます。レスポンスボディはモデルの生の出力 — base64 画像データを含む JSON です。
基本的な生成
curl -X POST "https://api.marswave.ai/openapi/v1/images/generation" \
-H "Authorization: Bearer $LISTENHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"model": "gemini-3-pro-image",
"prompt": "A serene mountain landscape at sunset with a reflective lake",
"imageConfig": {
"aspectRatio": "16:9",
"imageSize": "2K"
}
}'const response = await fetch(
'https://api.marswave.ai/openapi/v1/images/generation',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'google',
model: 'gemini-3-pro-image',
prompt: 'A serene mountain landscape at sunset with a reflective lake',
imageConfig: {
aspectRatio: '16:9',
imageSize: '2K',
},
}),
},
)
const data = await response.json()
// data.candidates[0].content.parts[0].inlineData holds the generated imageimport os
import requests
response = requests.post(
'https://api.marswave.ai/openapi/v1/images/generation',
headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
json={
'provider': 'google',
'model': 'gemini-3-pro-image',
'prompt': 'A serene mountain landscape at sunset with a reflective lake',
'imageConfig': {
'aspectRatio': '16:9',
'imageSize': '2K',
},
},
)
data = response.json()
# data['candidates'][0]['content']['parts'][0]['inlineData'] holds the generated imageGPT-Image-2 を使うには、provider を "openai"、model を "gpt-image-2" に設定します。リクエストとレスポンスの形式は同じで、異なるのは provider、model、imageConfig だけです。プロバイダーとモデルのマトリクス を参照してください。
参照画像を使った生成
参照画像を渡して出力を誘導します。各参照画像は URL(fileData)か base64 エンコードされたインラインデータ(inlineData)のいずれかです。1 回のリクエストで両方の形式を混在させられます。
画像 URL を使う
curl -X POST "https://api.marswave.ai/openapi/v1/images/generation" \
-H "Authorization: Bearer $LISTENHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"model": "gemini-3-pro-image",
"prompt": "Transform this scene into a watercolor painting style",
"referenceImages": [
{
"fileData": {
"fileUri": "https://example.com/my-photo.jpg",
"mimeType": "image/jpeg"
}
}
],
"imageConfig": {
"aspectRatio": "1:1",
"imageSize": "2K"
}
}'const response = await fetch(
'https://api.marswave.ai/openapi/v1/images/generation',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'google',
model: 'gemini-3-pro-image',
prompt: 'Transform this scene into a watercolor painting style',
referenceImages: [
{
fileData: {
fileUri: 'https://example.com/my-photo.jpg',
mimeType: 'image/jpeg',
},
},
],
imageConfig: {
aspectRatio: '1:1',
imageSize: '2K',
},
}),
},
)
const data = await response.json()import os
import requests
response = requests.post(
'https://api.marswave.ai/openapi/v1/images/generation',
headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
json={
'provider': 'google',
'model': 'gemini-3-pro-image',
'prompt': 'Transform this scene into a watercolor painting style',
'referenceImages': [
{
'fileData': {
'fileUri': 'https://example.com/my-photo.jpg',
'mimeType': 'image/jpeg',
}
}
],
'imageConfig': {
'aspectRatio': '1:1',
'imageSize': '2K',
},
},
)
data = response.json()base64 インラインデータを使う
curl -X POST "https://api.marswave.ai/openapi/v1/images/generation" \
-H "Authorization: Bearer $LISTENHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"model": "gemini-3-pro-image",
"prompt": "Create a cartoon version of this portrait",
"referenceImages": [
{
"inlineData": {
"data": "<BASE64_ENCODED_IMAGE>",
"mimeType": "image/png"
}
}
]
}'import { readFileSync } from 'fs'
const imageBase64 = readFileSync('reference.png').toString('base64')
const response = await fetch(
'https://api.marswave.ai/openapi/v1/images/generation',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'google',
model: 'gemini-3-pro-image',
prompt: 'Create a cartoon version of this portrait',
referenceImages: [
{
inlineData: {
data: imageBase64,
mimeType: 'image/png',
},
},
],
}),
},
)
const data = await response.json()import os
import base64
import requests
with open('reference.png', 'rb') as f:
image_base64 = base64.b64encode(f.read()).decode('utf-8')
response = requests.post(
'https://api.marswave.ai/openapi/v1/images/generation',
headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
json={
'provider': 'google',
'model': 'gemini-3-pro-image',
'prompt': 'Create a cartoon version of this portrait',
'referenceImages': [
{
'inlineData': {
'data': image_base64,
'mimeType': 'image/png',
}
}
],
},
)
data = response.json()リクエストパラメータ
以下のパラメータは POST /v1/images/generation、POST /v1/images/generation/async、POST /v1/images/generation/estimate-credits に適用されます。この 3 つのエンドポイントは同じリクエストスキーマを共有します。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
provider | string | はい¹ | モデルプロバイダー:google、openai、bytedance |
model | string | いいえ | モデル名。デフォルトは gpt-image-2。プロバイダーとモデルのマトリクス を参照 |
prompt | string | はい² | 生成したい画像のテキスト説明 |
referenceImages | array | いいえ | 生成を誘導する参照画像。参照画像の上限 を参照 |
referenceImages[].fileData | object | いいえ | URL 形式で渡す参照画像 |
referenceImages[].fileData.fileUri | string | はい | 画像 URL — スキームは http、https、gs のいずれか |
referenceImages[].fileData.mimeType | string | はい | MIME タイプ:image/png、image/jpeg、image/webp、image/heic、image/heif |
referenceImages[].inlineData | object | いいえ | base64 エンコードデータ形式で渡す参照画像 |
referenceImages[].inlineData.data | string | はい | base64 エンコードされた画像データ |
referenceImages[].inlineData.mimeType | string | はい | MIME タイプ:image/png、image/jpeg、image/webp、image/heic、image/heif |
imageConfig | object | いいえ | 画像出力の設定。デフォルトは { "imageSize": "2K" } |
imageConfig.imageSize | string | いいえ | 出力解像度:1K、2K(デフォルト)、4K |
imageConfig.aspectRatio | string | いいえ | アスペクト比。デフォルトは 1:1。アスペクト比 を参照 |
imageConfig.quality | string | いいえ | レンダリング品質:low、medium、high。GPT-Image-2 に適用。省略するとモデルが自動で判断 |
¹ provider は 2 つの生成エンドポイントでは必須、estimate-credits では任意です。
² prompt は 2 つの生成エンドポイントでは必須です。estimate-credits では空でも省略でも構いません(入力トークンの見積もりにしか影響しません)。
referenceImages の各要素は、fileData と inlineData のどちらか一方だけを含む必要があります。両方を同時に指定することはできません。
プロバイダーとモデルのマトリクス
provider でベンダーを、model で具体的なモデルを選びます。デフォルトのモデルは gpt-image-2 です。
provider | model | 備考 |
|---|---|---|
google | gemini-3-pro-image | 高品質でディテールの豊かな出力。NanoBanana Pro |
google | gemini-3.1-flash-image | 生成が高速。追加の 1:4 / 4:1 / 1:8 / 8:1 比率に対応 |
openai | gpt-image-2 | プロンプト追従性が高い。参照画像は最大 4 枚。aspectRatio は任意 |
bytedance | seedream-5-0-pro | 精密編集に対応(座標 / カラーコードは prompt に記述)。参照画像は最大 10 枚。1K / 2K のみ |
旧 preview モデル ID の gemini-3-pro-image-preview と gemini-3.1-flash-image-preview は入力として引き続き受け付けられ、上記の GA ID に正規化されます。新規に組み込む場合は GA ID を送信してください。
アスペクト比
imageConfig.aspectRatio のデフォルトは 1:1 です。スキーマが受け付ける比率は次のとおりです。
| 比率 | 説明 |
|---|---|
1:1 | 正方形 |
2:3 | 縦長 |
3:2 | 横長 |
3:4 | 縦長 |
4:3 | 横長 |
9:16 | 縦型 / モバイル |
16:9 | ワイドスクリーン |
21:9 | ウルトラワイド |
1:4 | Flash のみ |
4:1 | Flash のみ |
1:8 | Flash のみ |
8:1 | Flash のみ |
1:4、4:1、1:8、8:1 を受け付けるのは gemini-3.1-flash-image と seedream-5-0-pro だけです。GPT-Image-2 は 8 つの標準比率(1:1、2:3、3:2、3:4、4:3、9:16、16:9、21:9)に対応し、aspectRatio を省略すれば自動で選択させられます。選択したモデルが対応していない比率を指定すると 400 が返ります。
画像サイズ
imageConfig.imageSize は 1K、2K(デフォルト)、4K を受け付けます。サイズが大きいほどクレジット消費は増え、GPT-Image-2 の場合は 4K(および high 品質)に有効な有料サブスクリプションが必要です。Seedream 5.0 Pro は 1K と 2K のみ対応で、4K を指定すると 400 が返ります。 クレジットコストをハードコードせず、正確な数値は クレジットの見積もり を呼び出して取得してください。
参照画像の上限
| モデル | 参照画像の上限 |
|---|---|
gemini-3-pro-image | 14 |
gemini-3.1-flash-image | 14 |
gpt-image-2 | 4 |
seedream-5-0-pro | 10 |
スキーマ全体としては referenceImages を 14 件までに制限しています。GPT-Image-2 はより厳しく 4 枚、Seedream 5.0 Pro は 10 枚を上限として強制し、超えると 400 が返ります。fileData と inlineData のどちらでも受け付ける MIME タイプは image/png、image/jpeg、image/webp、image/heic、image/heif です。
Seedream 5.0 Pro の精密編集
Seedream 5.0 Pro は精密編集に対応しています。画像全体を再生成するのではなく、特定の領域だけを変更できます。
専用の編集エンドポイントはなく、マスクや領域を指定するパラメータもありません。編集は同じ生成エンドポイントで行い、元画像を referenceImages に、「どこを、どう変えるか」を prompt に書きます。モデルは画像の左上を原点とする絶対ピクセル座標と、業界標準のカラーコードをそのまま読み取ります。
{
"provider": "bytedance",
"model": "seedream-5-0-pro",
"prompt": "Treating the top-left corner as the coordinate origin, change the content inside top-left:(376,363) bottom-right:(701,638) to green, and leave everything else unchanged",
"referenceImages": [
{
"fileData": {
"fileUri": "https://assets.listenhub.ai/your-source-image.png",
"mimeType": "image/png"
}
}
],
"imageConfig": { "imageSize": "2K", "aspectRatio": "1:1" }
}自社プロダクトに矩形選択・投げ縄・矢印などの視覚的な編集操作がある場合は、フロントエンド側で座標文字列に変換してから(あるいは注釈を参照画像に焼き込んでから)prompt に書き込んでください。サーバーはプロンプトをそのまま透過的に渡すだけで、座標を解析しません。aspectRatio は元画像の実際の比率に合わせてください。比率が食い違うと、モデルが 1 つの領域を編集せずに画像全体を作り直してしまうことがあります。
クレジットの見積もり
POST /v1/images/generation/estimate-credits
指定した設定のクレジットコストと、アカウントが生成可能かどうかを返します。クレジットは消費せず、モデルも呼び出しません。確定前に価格を表示したり、4K / high のリクエストにサブスクリプションが必要かを確認したりするのに使います。ボディは生成エンドポイントと同じものを受け付け、ここでは provider と prompt が任意です。
curl -X POST "https://api.marswave.ai/openapi/v1/images/generation/estimate-credits" \
-H "Authorization: Bearer $LISTENHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"imageConfig": {
"imageSize": "2K",
"aspectRatio": "1:1",
"quality": "medium"
}
}'const response = await fetch(
'https://api.marswave.ai/openapi/v1/images/generation/estimate-credits',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-image-2',
imageConfig: { imageSize: '2K', aspectRatio: '1:1', quality: 'medium' },
}),
},
)
const { data } = await response.json()
console.log(data.credits, data.canGenerate)import os
import requests
response = requests.post(
'https://api.marswave.ai/openapi/v1/images/generation/estimate-credits',
headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
json={
'model': 'gpt-image-2',
'imageConfig': {'imageSize': '2K', 'aspectRatio': '1:1', 'quality': 'medium'},
},
)
data = response.json()['data']
print(data['credits'], data['canGenerate'])見積もりレスポンス
標準エンベロープでラップされます。data オブジェクトは次のとおりです。
| フィールド | 型 | 説明 |
|---|---|---|
model | string | 見積もりに使われた正規化済みの GA モデル ID |
imageSize | string | 解決された出力サイズ |
aspectRatio | string | 解決されたアスペクト比(モデルが自動選択する場合は返りません) |
quality | string | 解決された品質(該当しない場合は返りません) |
pixels | object | 解決できた場合は { "width": number, "height": number, "size": "WxH" } |
credits | number | この設定で消費されるクレジット |
canGenerate | boolean | アカウントの有効クレジット残高が足りているか |
requiresSubscription | boolean | その設定に有効な有料プランが必要な場合(4K、high など)に true |
pricing | object | 価格メタデータ:pricingVersion、mode(token-estimate/fixed) |
warnings | array | 注意喚起の文字列。例:reference_image_input_tokens_not_included |
{
"code": 0,
"message": "",
"data": {
"model": "gpt-image-2",
"imageSize": "2K",
"aspectRatio": "1:1",
"quality": "medium",
"pixels": { "width": 2048, "height": 2048, "size": "2048x2048" },
"credits": 6,
"canGenerate": true,
"requiresSubscription": false,
"pricing": { "pricingVersion": "...", "mode": "token-estimate" },
"warnings": []
}
}非同期生成
時間のかかるジョブや高解像度のジョブでは、リクエストを開いたままにせず、タスクを送信して結果をポーリングしてください。
非同期タスクを作成する
POST /v1/images/generation/async
リクエストボディは同期エンドポイントと同じです。202 と taskId を即座に返し、生成はバックグラウンドで実行され、生成された画像はホスティングされた URL として永続化されます。
curl -X POST "https://api.marswave.ai/openapi/v1/images/generation/async" \
-H "Authorization: Bearer $LISTENHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"model": "gemini-3-pro-image",
"prompt": "An astronaut riding a horse on Mars, photorealistic",
"imageConfig": { "imageSize": "4K", "aspectRatio": "16:9" }
}'const res = await fetch(
'https://api.marswave.ai/openapi/v1/images/generation/async',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'google',
model: 'gemini-3-pro-image',
prompt: 'An astronaut riding a horse on Mars, photorealistic',
imageConfig: { imageSize: '4K', aspectRatio: '16:9' },
}),
},
)
const { data } = await res.json()
const taskId = data.taskIdimport os
import requests
res = requests.post(
'https://api.marswave.ai/openapi/v1/images/generation/async',
headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
json={
'provider': 'google',
'model': 'gemini-3-pro-image',
'prompt': 'An astronaut riding a horse on Mars, photorealistic',
'imageConfig': {'imageSize': '4K', 'aspectRatio': '16:9'},
},
)
task_id = res.json()['data']['taskId']レスポンス(202):
{
"code": 0,
"message": "",
"data": { "taskId": "65f0...", "status": "pending" }
}単一タスクを取得する
GET /v1/images/generation/tasks/{taskId}
単一タスクのステータスと結果をポーリングします。status は pending、generating、success、fail のいずれかです。成功時は images にホスティングされた結果の URL が入ります。
curl "https://api.marswave.ai/openapi/v1/images/generation/tasks/65f0abc..." \
-H "Authorization: Bearer $LISTENHUB_API_KEY"{
"code": 0,
"message": "",
"data": {
"taskId": "65f0abc...",
"status": "success",
"images": [
{ "url": "https://.../0.png", "mimeType": "image/png" }
],
"createdAt": 1750000000000,
"completedAt": 1750000020000
}
}| フィールド | 型 | 説明 |
|---|---|---|
taskId | string | タスク識別子 |
status | string | pending、generating、success、fail |
images | array | 成功時に返ります。各要素は { url, mimeType } |
failMsg | string | status が fail のときの失敗メッセージ |
createdAt | number | 作成時刻(epoch ミリ秒) |
completedAt | number | 完了時刻(epoch ミリ秒)。完了後に返ります |
タスク一覧を取得する
GET /v1/images/generation/tasks
自分の画像タスクを新しい順に一覧します。
| クエリパラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
page | number | 1 | ページ番号、最小値は 1 |
pageSize | number | 20 | 1 ページあたりの件数、1–100 |
status | string | — | pending、generating、success、fail で絞り込み |
curl "https://api.marswave.ai/openapi/v1/images/generation/tasks?page=1&pageSize=20&status=success" \
-H "Authorization: Bearer $LISTENHUB_API_KEY"{
"code": 0,
"message": "",
"data": {
"items": [
{ "taskId": "65f0...", "status": "success", "images": [/* ... */], "createdAt": 1750000000000, "completedAt": 1750000020000 }
],
"page": 1,
"pageSize": 20,
"total": 1
}
}バックグラウンドタスクが pending または generating のまま 30 分を超えると、まとめて fail に更新され、タイムアウトを示す failMsg が付きます。それより古い非終端ステータスは失敗とみなして再試行してください。
レスポンス形式
| エンドポイント | エンベロープでラップ? | ボディ |
|---|---|---|
POST /v1/images/generation | いいえ — モデルの生 JSON | base64 画像データ(下記参照) |
POST /v1/images/generation/async | はい | { taskId, status } |
POST /v1/images/generation/estimate-credits | はい | 見積もりオブジェクト |
GET /v1/images/generation/tasks | はい | ページング形式の { items, page, pageSize, total } |
GET /v1/images/generation/tasks/{taskId} | はい | タスクオブジェクト |
同期エンドポイントはモデルの生の出力をそのまま返します(ラップされません)。成功時のボディには、生成された画像が base64 データとして含まれます。
{
"candidates": [
{
"content": {
"parts": [
{
"inlineData": {
"mimeType": "image/png",
"data": "<BASE64_ENCODED_IMAGE>"
}
}
]
}
}
]
}data フィールドを base64 からデコードすると画像ファイルが得られます。非同期の経路では画像がこちらで永続化され、タスクオブジェクトにホスティングされた url が返るため、base64 のデコードは不要です。
NanoBanana Pro 無料枠
API キーからの呼び出しは、Web アプリや Labnana アプリと同じアカウント単位の無料枠(freeUsages)残高を使います。新規登録、招待、チェックインで枠を獲得し続け、それを API 経由で消費できます。現在の残高は GET /v1/user/subscription で取得し、その freeUsages マップを読んでください。
対応する残高が 0 より大きい場合、1K / 2K のリクエストはクレジットではなく無料生成を 1 回消費します。残高が 0 になると、同じリクエストは通常のクレジット課金にフォールバックします。
無料枠が適用されるのは 1K と 2K のサイズだけです。4K のリクエストが freeUsages を使うことはなく、常にクレジットで課金されます。
NanoBanana Pro の relax 呼び出しの挙動は、アカウント種別によって変わります。
- 有料または課金実績のあるアカウント(有効なサブスクリプション、チャージ、クレジットパック購入)は、無料枠を消費している間も通常の有料生成と同じ体験になります。優先度は完全、キャパシティも通常、フォールバックも通常どおりです。無料枠は課金だけを変えるもので、制限付きレーンに回されるわけではありません。
- 完全無料アカウント(一度も支払っていないアカウント)は、最低優先度の無料レーンで NanoBanana Pro relax を実行し、スループットに固定の上限があります。ピーク時にはリクエストがキューに入るか、再試行可能な busy / timeout レスポンスで拒否されることがあります。その場合はクレジットも無料枠も消費されません。時間をおいて再試行してください(深夜のほうが速くなります)。
完全無料の relax が失敗した場合は、ローカライズされたテキストを解析しなくても検知できるよう、機械可読なメタデータが返ります。
failReasonはfree_relax_busyまたはfree_relax_timeoutです。retryableはtrueです。- 無料枠が払い戻されると
freeUsageRolledBackがtrueになります。 userMessageにはユーザー向けでローカライズ可能な文言が入ります。
同期リクエストではエラーボディに、非同期リクエストでは失敗したタスクの詳細(およびタスク一覧)に現れます。どちらの理由も「後で再試行、課金は発生していない」として扱ってください。
レート制限と参照画像モード
標準的なテキストから画像へのリクエストには、ユーザー単位およびグローバルのレート制限がかかります。
参照画像モード(inlineData を伴う referenceImages)には、サーバー側の追加のリソース制約がかかります。ピーク時には base64 リクエストがより強く制限されることがあります。429 を受け取ったら Retry-After ヘッダーを読み、バックオフしてから再試行してください。クライアント側で指数バックオフを実装してください。
エラーコード
エラーは標準エンベロープ(code が非ゼロ)で返ります。同期エンドポイントの場合は、NanoBanana Pro 無料枠 に記載した生のエラーボディで返ります。
| HTTP ステータス | 意味 |
|---|---|
400 | リクエストパラメータが不正(選択したモデルが対応しないアスペクト比など) |
402 | クレジット不足 |
429 | レート制限、またはサービス混雑 — Retry-After を読んで再試行 |
500 | 画像生成に失敗 — リクエストを再試行 |