콘텐츠로 이동
무료 가입
GPT Image

GPT Image 이미지 편집 API

BetterToken의 OpenAI-compatible API를 통해 GPT Image로 reference images에서 이미지를 생성하거나 편집하세요.

POST /v1/images/edits

image-to-image endpoint는 multipart/form-data request body를 사용합니다. 하나 이상의 reference images를 업로드하고 prompt 및 parameter fields를 form fields로 제출하세요.

권장 값

다음은 권장 시작값이며 필수 조건은 아닙니다. n=1부터 시작하세요. endpoint는 1~10을 허용하지만 더 적은 이미지를 반환할 수 있습니다.

model=gpt-image-2
n=1
response_format=b64_json
output_format=png

reference image 하나에는 image, 여러 개에는 반복된 image[]를 사용하세요. 일반 reference edit에는 mask가 필요하지 않습니다. quality는 선택 사항입니다. gpt-image-2는 auto, low, medium, high를, 두 2.5 모델은 xhigh, max도 허용합니다. multipart에서 지정할 때는 비어 있지 않은 문자열이어야 합니다. 값이 허용되어도 model-size-edit 조합의 사용 가능성이나 더 높은 설정의 화질 개선을 보장하지 않습니다. 선호값을 정하지 않으려면 생략하세요. size도 선택 사항이지만 빈 문자열은 허용되지 않습니다.

단일 참조 이미지

reference.png를 준비하고 YOUR_API_KEY를 BetterToken API Key로 바꾸세요. 하나의 Key로 사용 가능한 모든 모델을 호출할 수 있습니다. curl -F 또는 Python files가 boundary가 포함된 Content-Type을 생성하게 하세요.

Form field예시 값
modelgpt-image-2
promptUsing this reference image, create a more polished square product key visual while preserving the subject style.
n1
size1024x1024
response_formatb64_json
output_formatpng
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'

여러 참조 이미지

다음 form fields를 제출하세요.

Form field예시 값
modelgpt-image-2
promptCombine these reference images into a promotional poster with a consistent style.
n1
size1024x1024
response_formatb64_json
output_formatpng
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 endpoint는 하나의 mask 파일만 읽습니다. mask[] 필드를 여러 번 보내지 마세요.

  • 원본 이미지와 mask는 파일 형식과 픽셀 크기가 같아야 합니다. 각 파일은 50 MB보다 작아야 합니다. 최대 호환성을 위해 두 파일 모두 Alpha channel이 있는 PNG를 사용하세요.
  • Mask에는 Alpha channel이 있어야 합니다. 완전히 투명한 픽셀(Alpha 0)은 모델이 다시 그릴 수 있는 영역을 표시합니다. 완전히 불투명한 픽셀(Alpha 255)은 해당 영역을 유지하도록 모델을 유도합니다.
  • 일반 RGB 흑백 이미지는 실제 Alpha channel을 포함하지 않으면 유효한 mask가 아닙니다.
  • 여러 image[] 필드를 보내면 mask는 첫 번째 입력 이미지에 적용됩니다.
  • Mask는 모델을 안내하지만, 투명 영역 밖의 픽셀이 완전히 동일하게 유지된다고 보장하지는 않습니다.
  • Mask 지원 여부는 model과 size 조합에 따라 달라집니다. GPT Image 2와 Flare 테스트에서는 target 영역 밖에도 눈에 띄는 변화가 있었고, Sunburst의 local-region control은 검증되지 않았습니다. 제품 이미지, 로고 또는 정밀 보정에 사용하기 전에 결과를 확인하세요.
터미널 창
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이 두 파일을 닫도록 하나의 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 channel을 확인합니다. 일반적인 local mask의 경우 Alpha channel에 완전히 투명한 영역과 완전히 불투명한 영역이 모두 없으면 경고도 표시합니다.

from pathlib import Path
from 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 base64
from 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자동자동 size 선택
1024x10241:1정사각형 images, avatars, covers, assets
1536x10243:2가로 posters, banners, scenes
1024x15362:3세로 mobile covers 및 posters
1536x11524:3표준 가로 images, product images, content graphics
1152x15363:4표준 세로 images, mobile covers, vertical posters
2048x20481:1고해상도 정사각형 images
2048x115216:9고해상도 가로 images
3840x216016:94K 가로 images
2160x38409:164K 세로 images

표의 값은 예시이며 전체 목록이 아닙니다. size를 생략하거나 auto를 지정할 수 있고, JSON null도 자동 선택을 사용합니다. 명시적 width와 height는 양수인 16의 배수이며 각각 최대 3840, aspect ratio는 3:1 이하, 총 pixels는 655360~8294400이어야 합니다. 2080x2080도 유효합니다. 실제 반환 dimensions는 다를 수 있으므로 이미지를 확인하고 강제로 crop하지 마세요.

이미지 저장

성공한 response는 다음 OpenAI-compatible image response shape를 따릅니다. 아래 금액은 receipt 형식의 예시이며 고정 가격이 아닙니다.

{
"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 등의 추가 fields를 허용하세요. output_format은 형식 요청일 뿐 실제 encoding이나 변환을 보장하지 않습니다. image bytes를 확인하고 일치하는 확장자로 저장하세요. 텍스트를 이미지로 변환에 각 결과의 PNG, JPEG, WebP signature를 감지하는 예제가 있습니다.

실제 비용 확인

bettertoken_image_billing은 결과와 함께 반환되므로 별도 비용 조회 요청이 필요하지 않습니다.

필드의미
currency정산 통화이며 항상 USD 또는 CNY인 것은 아닙니다.
settled_amount요청의 총 정산 금액이며 decimal string입니다.
requested_resolution요청에서 식별한 해상도 등급입니다.
outputs[].indexdata[]와 대응하는 0부터 시작하는 이미지 인덱스입니다.
outputs[].width, height이미지의 실제 너비와 높이이며 단위는 픽셀입니다.
outputs[].billing_resolution이미지에 최종 적용된 과금 등급입니다.
outputs[].currency, amount이미지별 정산 통화와 금액입니다.

요청 크기와 과금 등급은 다를 수 있습니다. 1024x1024 요청에서 1254x1254가 반환되어 2K로 과금된 사례가 있습니다. 영수증의 실제 금액을 사용하고 현재 가격은 모델 광장에서 확인하세요. 표시에는 문자열을 유지하고 계산에는 decimal 연산을 사용하세요. 영수증이 없다고 비용을 0으로 기록하지 마세요.

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는 synchronous입니다. POST /images/edits를 보낸 후 server가 response할 때까지 현재 HTTP request를 열어 두세요. 성공하면 모든 이미지가 data[].b64_json으로 반환됩니다.

endpoint는 task_id를 반환하지 않으며 별도의 status query 또는 result download endpoint가 없습니다.

시간 초과, 재시도 및 과금

HTTP client timeout을 몇 분으로 설정하세요. Timeout, disconnect 또는 의미가 불분명한 5xx만으로 edit 실행이나 과금 여부를 알 수 없습니다. 정산 후 결과를 기록하는 중 connection이 끊길 수도 있습니다. POST를 자동으로 다시 보내지 마세요. 먼저 usage records나 request logs를 확인하고 반환된 request ID와 수신한 경우 X-BetterToken-Image-Receipt, X-BetterToken-Billing-State headers를 보관하세요. client-generated request ID는 idempotency를 보장하지 않으며 status query endpoint도 없습니다.

거부된 입력, 인증 또는 quota 문제를 먼저 수정하세요. 429는 request가 거부되었음을 확인한 경우에만 backoff로 retry하세요. BetterToken은 적용 가능한 최고 unit price에 n을 곱한 금액을 사전 승인할 수 있습니다. 제공된 1K 이미지 비용을 감당할 balance가 있어도 hold가 부족할 수 있으며, 이때 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.
  • 참조 이미지가 하나면 image, 여러 개면 반복된 image[] 필드를 사용합니다.
  • 마스크 편집에서는 원본과 같은 형식과 크기이며 Alpha 채널이 있는 mask 하나만 전송합니다.
  • response_format=b64_json을 사용합니다. output_format은 요청값이므로 저장 전에 바이트로 실제 형식을 확인합니다.
  • n은 1부터 10까지 정수를 허용합니다. 1부터 시작하고 반환 이미지가 적은 경우도 처리합니다.
  • size를 생략하거나 auto 또는 제약을 충족하는 크기를 지정합니다.
  • HTTP 클라이언트는 생성 완료까지 수 분 동안 기다릴 수 있어야 합니다.
  • 로그와 오류 스크린샷에 API Key나 전체 base64 이미지가 노출되지 않도록 합니다.

관련 문서

POST/v1/images/edits

인증

Authorizationstringheader필수

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

본문 multipart/form-data

modelenum<string>기본값: gpt-image-2필수

GPT Image Model ID. One BetterToken API Key works with all available models.

사용 가능한 옵션: gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst

예제:"gpt-image-2"
promptstring필수

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."
imagestring<binary>

The reference image field for a single input image.

image[]string[]

Repeat this field for each input when sending multiple reference images.

maskstring<binary>

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.

ninteger | string기본값: 1

Allowed range: 1–10; start with 1. Fewer images may be delivered than requested. Iterate data[] and use actual-delivery billing.

예제:"1"
sizestring기본값: 1024x1024

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"]
response_formatenum<string>기본값: b64_json

Use b64_json.

사용 가능한 옵션: b64_json

예제:"b64_json"
output_formatstring기본값: png

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"
qualityenum<string>기본값: auto

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, low, medium, high, xhigh, max

예제:"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.

createdinteger
예제:1710000000
dataobject[]
Show child attributes

Base64-encoded image content.

예제:"iVBORw0KGgoAAAANSUhEUgAA...(truncated)"

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[].

필수 범위: x >= 0

필수 범위: x >= 1

필수 범위: x >= 1

사용 가능한 옵션: 1K, 2K, 4K

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.
errorobject
Show child attributes
예제:"invalid request"
예제:"invalid_request_error"
예제:"invalid_request"
messagestring
예제:"insufficient quota"
예제
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
401The BetterToken API Key is missing or invalid.
errorobject
Show child attributes
예제:"invalid request"
예제:"invalid_request_error"
예제:"invalid_request"
messagestring
예제:"insufficient quota"
예제
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
402The account has insufficient credit or balance.
errorobject
Show child attributes
예제:"invalid request"
예제:"invalid_request_error"
예제:"invalid_request"
messagestring
예제:"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.
errorobject
Show child attributes
예제
{
  "error": {
    "code": "insufficient_user_quota",
    "message": "Insufficient balance or token quota."
  }
}
429A rate or concurrency limit was reached, or the upstream service is busy.
errorobject
Show child attributes
예제:"invalid request"
예제:"invalid_request_error"
예제:"invalid_request"
messagestring
예제:"insufficient quota"
예제
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
500The gateway or upstream service returned an error.
errorobject
Show child attributes
예제:"invalid request"
예제:"invalid_request_error"
예제:"invalid_request"
messagestring
예제:"insufficient quota"
예제
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}