GPT Image 画像編集 API
BetterToken の OpenAI 互換 API を通じて、GPT Image で参照画像から画像を生成または編集します。
POST /v1/images/edits
画像から画像への変換 Endpoint では multipart/form-data のリクエスト本文を使用します。1 枚以上の参照画像をアップロードし、プロンプトとパラメーターフィールドをフォームフィールドとして送信します。
推奨値
以下は推奨する開始値であり、固定要件ではありません。まず n=1 を使用してください。endpoint は 1~10 を受け付けますが、返却数は少ない場合があります。
model=gpt-image-2n=1response_format=b64_jsonoutput_format=png参照画像 1 枚には image、複数には image[] を繰り返し使用します。通常の参照画像編集に mask は不要です。quality は任意です。gpt-image-2 は auto、low、medium、high、2.5 の 2 モデルは xhigh と max も受け付けます。multipart で指定する場合は空でない文字列が必要です。受け付けられてもモデル・サイズ・編集の組み合わせの利用可能性や、高い設定による画質向上は保証されません。指定しない場合は省略してください。size も任意ですが、空文字列は無効です。
1 枚の参照画像
reference.png を用意し、YOUR_API_KEY を BetterToken API Key に置き換えてください。1 つの Key ですべての利用可能なモデルを呼び出せます。curl -F または Python の files に Content-Type の boundary を生成させてください。
| フォームフィールド | 例 |
|---|---|
model | gpt-image-2 |
prompt | Using this reference image, create a more polished square product key visual while preserving the subject style. |
n | 1 |
size | 1024x1024 |
response_format | b64_json |
output_format | png |
image | ローカルファイル reference.png を選択 |
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -F 'model=gpt-image-2' \ -F 'prompt=Using this reference image, create a more polished square product key visual while preserving the subject style.' \ -F 'n=1' \ -F 'size=1024x1024' \ -F 'response_format=b64_json' \ -F 'output_format=png' \ -F 'image=@reference.png'複数の参照画像
次のフォームフィールドを送信してください。
| フォームフィールド | 例 |
|---|---|
model | gpt-image-2 |
prompt | Combine these reference images into a promotional poster with a consistent style. |
n | 1 |
size | 1024x1024 |
response_format | b64_json |
output_format | png |
image[] | reference-1.png を選択 |
image[] | reference-2.jpg を選択 |
image[] | reference-3.png を選択 |
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -F 'model=gpt-image-2' \ -F 'prompt=Combine these reference images into a promotional poster with a consistent style.' \ -F 'n=1' \ -F 'size=1024x1024' \ -F 'response_format=b64_json' \ -F 'output_format=png' \ -F 'image[]=@reference-1.png' \ -F 'image[]=@reference-2.jpg' \ -F 'image[]=@reference-3.png'マスクで選択範囲を編集する
選択した範囲の編集を指示するには、任意の mask ファイルフィールドを追加します。現在の BetterToken エンドポイントが読み込む mask ファイルは 1 つです。mask[] フィールドを複数送信しないでください。
- 元画像とマスクは、ファイル形式とピクセル寸法を同じにする必要があります。各ファイルは 50 MB 未満にしてください。最大限の互換性を得るには、両方のファイルに Alpha チャンネル付き PNG を使用することを推奨します。
- マスクには Alpha チャンネルが必要です。完全に透明なピクセル(
Alpha 0)は、モデルが再描画できる範囲を示します。完全に不透明なピクセル(Alpha 255)は、その範囲を保持するようモデルを誘導します。 - 通常の RGB 白黒画像は、実際に Alpha チャンネルを含んでいない限り、有効なマスクではありません。
- 複数の
image[]フィールドを送信した場合、マスクは最初の入力画像に適用されます。 - マスクはモデルへの指示です。透明な範囲の外側にあるピクセルが完全に同一のままになることを保証するものではありません。
- マスクを利用できるかはモデルとサイズの組み合わせによります。GPT Image 2 と Flare のテストでは対象範囲外にも目立つ変化が見られました。Sunburst の局所制御は未検証です。商品画像、ロゴ、精密なレタッチに使う前に結果を確認してください。
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -F 'model=gpt-image-2' \ -F 'prompt=Replace only the masked area with a blue circle. Preserve everything else.' \ -F 'n=1' \ -F 'size=1024x1024' \ -F 'response_format=b64_json' \ -F 'output_format=png' \ -F 'image=@original.png' \ -F 'mask=@mask.png'Python でマスク編集する
リクエスト後に Python が両方のファイルを閉じるよう、1 つの with 文で開きます。
import requests
url = "https://bettertoken.ai/v1/images/edits"headers = {"Authorization": "Bearer YOUR_API_KEY"}data = { "model": "gpt-image-2", "prompt": "Replace only the masked area with a blue circle. Preserve everything else.", "n": "1", "size": "1024x1024", "response_format": "b64_json", "output_format": "png",}
with open("original.png", "rb") as image_file, open("mask.png", "rb") as mask_file: files = { "image": ("original.png", image_file, "image/png"), "mask": ("mask.png", mask_file, "image/png"), } response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
response.raise_for_status()result = response.json()アップロード前にファイルを確認する
この最小限の Pillow チェックで、必須の形式、寸法、Alpha チャンネルを確認できます。一般的な局所マスクについては、Alpha チャンネルに完全に透明な領域と完全に不透明な領域の両方がない場合に警告も表示します。
from pathlib import Pathfrom PIL import Image
image_path = Path("original.png")mask_path = Path("mask.png")
if image_path.stat().st_size >= 50 * 1024 * 1024 or mask_path.stat().st_size >= 50 * 1024 * 1024: raise ValueError("Each file must be smaller than 50 MB")
with Image.open(image_path) as image, Image.open(mask_path) as mask: if image.format != mask.format: raise ValueError("The image and mask formats must match") if image.size != mask.size: raise ValueError("The image and mask dimensions must match") if "A" not in mask.getbands(): raise ValueError("The mask must contain an Alpha channel") alpha_min, alpha_max = mask.getchannel("A").getextrema() if alpha_min > 0 or alpha_max < 255: print("Warning: for a typical local mask, include fully transparent and fully opaque areas")Python の例
import base64from pathlib import Path
import requests
url = "https://bettertoken.ai/v1/images/edits"headers = { "Authorization": "Bearer YOUR_API_KEY",}
data = { "model": "gpt-image-2", "prompt": "Using this reference image, create a more polished square product key visual while preserving the subject style.", "n": "1", "size": "1024x1024", "response_format": "b64_json", "output_format": "png",}
with open("reference.png", "rb") as image_file: files = { "image": ("reference.png", image_file, "image/png"), } response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
response.raise_for_status()result = response.json()for index, item in enumerate(result["data"], start=1): encoded = item["b64_json"] if "," in encoded and "base64" in encoded.split(",", 1)[0]: encoded = encoded.split(",", 1)[1] image_bytes = base64.b64decode(encoded) if image_bytes.startswith(b"\x89PNG\r\n\x1a\n"): extension = "png" elif image_bytes.startswith(b"\xff\xd8\xff"): extension = "jpg" elif image_bytes.startswith(b"RIFF") and image_bytes[8:12] == b"WEBP": extension = "webp" else: raise ValueError("Unsupported image signature") Path(f"output-{index}.{extension}").write_bytes(image_bytes)推奨サイズ
size | 比率 | 用途 |
|---|---|---|
auto | 自動 | サイズを自動選択 |
1024x1024 | 1:1 | 正方形の画像、アバター、カバー、アセット |
1536x1024 | 3:2 | 横長のポスター、バナー、シーン |
1024x1536 | 2:3 | 縦長のモバイルカバーとポスター |
1536x1152 | 4:3 | 標準的な横長画像、商品画像、コンテンツグラフィック |
1152x1536 | 3:4 | 標準的な縦長画像、モバイルカバー、縦長ポスター |
2048x2048 | 1:1 | 高解像度の正方形画像 |
2048x1152 | 16:9 | 高解像度の横長画像 |
3840x2160 | 16:9 | 4K 横長画像 |
2160x3840 | 9:16 | 4K 縦長画像 |
表の値は例であり、指定可能な値の一覧ではありません。size を省略するか auto を指定でき、JSON の null も自動選択になります。明示する幅と高さは正の 16 の倍数で、それぞれ 3840 以下、縦横比は 3:1 以下、総画素数は 655360~8294400 です。2080x2080 も有効です。実際の寸法は異なる場合があるため、画像を確認し、無理に切り抜かないでください。
画像を保存する
成功時のレスポンスは、次の OpenAI 互換画像レスポンス形式に従います。以下の金額はレシート形式の例であり、固定価格ではありません。
{ "created": 1710000000, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)", "revised_prompt": "Optional revised prompt" } ], "bettertoken_image_billing": { "currency": "CNY", "settled_amount": "0.15", "outputs": [ { "index": 0, "width": 1254, "height": 1254, "billing_resolution": "2K", "currency": "CNY", "amount": "0.15" } ] }}data[].b64_json の各画像を読み取り、revised_prompt などの追加フィールドも許可してください。output_format は形式の指定であり、実際のエンコードや変換を保証しません。バイト列を確認し、対応する拡張子で保存してください。テキストから画像への生成には、各結果の PNG、JPEG、WebP シグネチャを判定する例があります。
実際の料金を確認する
bettertoken_image_billing は結果とともに返されるため、別の料金確認リクエストは不要です。
| フィールド | 意味 |
|---|---|
currency | 決済通貨。USD または CNY とは限りません。 |
settled_amount | リクエストの決済合計額。小数文字列です。 |
requested_resolution | リクエストから判定された解像度レベル。 |
outputs[].index | data[] に対応する 0 始まりの画像番号。 |
outputs[].width、height | 実際の幅と高さ(ピクセル)。 |
outputs[].billing_resolution | 画像に適用された最終料金レベル。 |
outputs[].currency、amount | 画像ごとの決済通貨と金額。 |
要求サイズと料金レベルは異なる場合があります。1024x1024 の要求から 1254x1254 が返り、2K で課金された例があります。領収情報の金額を使用し、現在の単価は モデル広場で確認してください。表示では文字列を保ち、計算では Decimal を使います。領収情報がない場合に費用をゼロとして扱わないでください。
from decimal import Decimal
billing = result.get("bettertoken_image_billing")if billing is None: print("Billing receipt unavailable; check your usage records.")else: total = Decimal(billing["settled_amount"]) print(f"Total: {billing['currency']} {total}") for output in billing.get("outputs", []): print( f"Image {output['index'] + 1}: " f"{output['width']}x{output['height']}, " f"{output['billing_resolution']}, " f"{output['currency']} {output['amount']}" )レスポンスの流れ
この Endpoint は同期式です。POST /images/edits を送信した後、サーバーが応答するまで現在の HTTP リクエストを開いたままにしてください。成功すると、すべての画像が data[].b64_json に返されます。
この Endpoint は task_id を返さず、個別のステータス照会や結果ダウンロード用の Endpoint もありません。
タイムアウト、再試行、課金
HTTP クライアントのタイムアウトは数分に設定してください。タイムアウト、切断、または意味が不明な 5xx では、編集が実行・課金されたか判断できません。課金後に結果を書き込む際に接続が切れる場合もあります。POST を自動で再送しないでください。先に利用記録またはリクエストログを確認し、返された request ID と、受信できた場合は X-BetterToken-Image-Receipt および X-BetterToken-Billing-State ヘッダーを保存してください。クライアント側の request ID は冪等性を保証せず、状態確認用 endpoint もありません。
拒否された入力、認証、またはクォータの問題を修正してから再送してください。429 は拒否されたことを確認できた場合に限り、backoff を使って再試行します。BetterToken は適用可能な最高単価に n を掛けた額を事前承認する場合があります。納品された 1K 画像分の残高があっても保留額に足りず、403 と error.code=insufficient_user_quota が返ることがあります。最終額は納品画像に基づきます。
接続チェックリスト
- Base URL は
https://bettertoken.ai/v1です。 - ヘッダーに
Authorization: Bearer sk-...を含めます。 - リクエストには
multipart/form-dataを使用します。 - このリクエストで利用可能な Model ID を選びます:
gpt-image-2、gpt-image-2.5-flare、gpt-image-2.5-sunburst。 - 参照画像が 1 枚なら
image、複数ならimage[]を繰り返し指定します。 - マスク編集では、原画像と同じ形式・寸法で Alpha チャンネルを持つ
maskを 1 つ送信します。 response_format=b64_jsonを使用します。output_formatは要求値なので、保存前にバイト列から実際の形式を識別します。nは1から10の整数です。まず1を使い、返却枚数が少ない場合も処理します。sizeは省略、auto、または制約を満たす寸法を指定します。- HTTP クライアントは生成完了まで数分待機できるようにします。
- ログやエラーのスクリーンショットで API Key や画像の完全な base64 を公開しません。
関連ドキュメント
/v1/images/edits承認
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
ボディ multipart/form-data
GPT Image Model ID. One BetterToken API Key works with all available models.
"gpt-image-2"Instructions for editing the image or generating from reference images.
"Use this reference image to create a more polished square product hero image while preserving the main style."The reference image field for a single input image.
Repeat this field for each input when sending multiple reference images.
An optional single mask file. The mask and original image must have the same format and dimensions, each file must be smaller than 50 MB, and the mask must contain an Alpha channel. For maximum compatibility, use PNG with an Alpha channel for both files. With multiple image[] inputs, the mask applies to the first image. Availability depends on the model and size combination. Ordinary reference-image edits do not require a mask. A mask guides generation but does not guarantee that pixels outside the target area remain unchanged; review the result.
Allowed range: 1–10; start with 1. Fewer images may be delivered than requested. Iterate data[] and use actual-delivery billing.
"1"Omit or use auto for automatic sizing. For WxH, both dimensions must be positive multiples of 16, each at most 3840, aspect ratio at most 3:1, total pixels 655360–8294400. Examples are not an exhaustive enum; 2080x2080 also meets the geometry rules. Inspect actual decoded dimensions. Valid parameters do not guarantee an available service.
"1024x1024"["auto","1024x1024","2048x2048","2080x2080","3840x2160"]Requested output format; png is recommended, but the response is not guaranteed to have been transcoded to PNG. Detect PNG, JPEG, or WebP from actual bytes before choosing an extension. Convert locally if a specific format is required.
"png"gpt-image-2 accepts auto, low, medium, high. The two 2.5 models also accept xhigh and max. Omit for the model default; JSON null is treated as omitted, while multipart requires a nonempty string. Valid values do not guarantee an available service for every model, size, and editing combination. Acceptance does not guarantee that a higher setting improves image quality.
"auto"レスポンス
200BetterToken billing extension. Settlement follows the actual delivered pixels and billing tier, which can differ from the requested tier. Amounts are decimal strings; use the returned values.
OpenAI-compatible image response. Iterate data[] and read each image from b64_json. Fewer images may be delivered than requested.
1710000000Show child attributes
An optional revised prompt.
BetterToken billing extension. Settlement follows the actual delivered pixels and billing tier, which can differ from the requested tier. Amounts are decimal strings; use the returned values.
Show child attributes
Settlement currency; do not assume a fixed currency.
Final request amount as a decimal string; use decimal arithmetic for calculations.
Delivered image indices, actual dimensions, billing tiers, and per-image amounts. index is zero-based and corresponds to data[].
Settled amount for this image as a decimal string.
Resolution tier inferred from the request; it may differ from the actual billing tier.
{
"created": 1710000000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
"revised_prompt": "<string>"
}
],
"bettertoken_image_billing": {
"currency": "<string>",
"settled_amount": "<string>",
"outputs": [
{
"index": 0,
"width": 1,
"height": 1,
"billing_resolution": "1K",
"currency": "<string>",
"amount": "<string>"
}
],
"partial": false,
"requested_resolution": "<string>"
}
}400Invalid request format, missing parameters, malformed JSON or multipart data, or invalid dimensions.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}401The BetterToken API Key is missing or invalid.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}402The account has insufficient credit or balance.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}403Insufficient balance or token quota: error.code is insufficient_user_quota. Funds must also cover the reservation of the highest-tier unit price times the image-count upper bound, before actual-delivery settlement. Inspect error.code rather than treating every 403 as an authorization error.
{
"error": {
"code": "insufficient_user_quota",
"message": "Insufficient balance or token quota."
}
}429A rate or concurrency limit was reached, or the upstream service is busy.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}500The gateway or upstream service returned an error.
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}
