API de edición de imágenes de GPT Image
Edita referencias GPT Image con la API compatible con OpenAI de BetterToken. Configura multipart y máscaras; guarda resultados y revisa costes y errores.
POST /v1/images/edits
El endpoint de imagen a imagen usa un cuerpo de solicitud multipart/form-data. Sube una o varias imágenes de referencia y envía el prompt y los parámetros como campos de formulario.
Valores recomendados
Son valores iniciales recomendados, no requisitos fijos. Empieza con n=1; el endpoint acepta de 1 a 10, pero puede devolver menos imágenes.
model=gpt-image-2n=1response_format=b64_jsonoutput_format=pngUsa image para una sola imagen de referencia. Para varias imágenes, repite image[]. La edición normal con referencias no requiere mask. quality es opcional: gpt-image-2 acepta auto, low, medium, high; los dos modelos 2.5 también aceptan xhigh y max. En multipart debe ser una cadena no vacía. Que se acepte no garantiza disponibilidad para la combinación de modelo, tamaño y edición ni que un nivel superior mejore la calidad. Omítela si no necesitas fijar una preferencia. size también es opcional, pero no puede ser una cadena vacía.
Una imagen de referencia
Prepara reference.png y sustituye YOUR_API_KEY por tu BetterToken API Key. Una clave funciona con todos los modelos disponibles. Deja que curl -F o Python files genere el boundary de Content-Type.
| Campo del formulario | Ejemplo |
|---|---|
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 | Selecciona el archivo 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'Varias imágenes de referencia
Envía estos campos:
| Campo del formulario | Ejemplo |
|---|---|
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[] | Selecciona reference-1.png |
image[] | Selecciona reference-2.jpg |
image[] | Selecciona 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'Edita una zona seleccionada con una máscara
Añade el campo de archivo opcional mask cuando quieras orientar la edición a una zona seleccionada. El endpoint actual de BetterToken admite un solo archivo en mask. No envíes campos mask[] repetidos.
- La imagen original y la máscara deben tener el mismo formato y las mismas dimensiones en píxeles. Cada archivo debe pesar menos de 50 MB. Para obtener la máxima compatibilidad, usa PNG con canal Alpha en ambos archivos.
- La máscara debe incluir un canal Alpha. Los píxeles totalmente transparentes (
Alpha 0) marcan la zona que el modelo puede volver a dibujar. Los píxeles totalmente opacos (Alpha 255) indican al modelo que conserve esa zona. - Una imagen RGB normal en blanco y negro no es una máscara válida si no contiene realmente un canal Alpha.
- Si envías varios campos
image[], la máscara se aplica a la primera imagen de entrada. - La máscara orienta al modelo. No garantiza que los píxeles fuera de la zona transparente permanezcan exactamente iguales.
- La disponibilidad de la máscara depende de la combinación de modelo y tamaño. En pruebas con GPT Image 2 y Flare se observaron cambios visibles fuera de la zona objetivo; el control local de Sunburst no se ha verificado. Revisa el resultado antes de usarlo en productos, logotipos o retoques precisos.
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'Edición con máscara en Python
Abre ambos archivos en una sola sentencia with para que Python los cierre después de la solicitud:
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()Comprueba los archivos antes de subirlos
Esta comprobación mínima con Pillow verifica los requisitos de formato, dimensiones y canal Alpha. Para una máscara local típica, también muestra una advertencia si el canal Alpha no incluye zonas totalmente transparentes y opacas:
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")Ejemplo con 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)Tamaños recomendados
size | Proporción | Uso |
|---|---|---|
auto | Automática | Selección automática del tamaño |
1024x1024 | 1:1 | Imágenes cuadradas, avatares, portadas y recursos |
1536x1024 | 3:2 | Pósteres horizontales, banners y escenas |
1024x1536 | 2:3 | Portadas móviles y pósteres verticales |
1536x1152 | 4:3 | Imágenes horizontales estándar, productos y gráficos de contenido |
1152x1536 | 3:4 | Imágenes verticales estándar, portadas móviles y pósteres verticales |
2048x2048 | 1:1 | Imágenes cuadradas de alta resolución |
2048x1152 | 16:9 | Imágenes horizontales de alta resolución |
3840x2160 | 16:9 | Imágenes horizontales 4K |
2160x3840 | 9:16 | Imágenes verticales 4K |
Los valores de la tabla son ejemplos, no una lista cerrada. Puedes omitir size o usar auto; null en JSON también activa la selección automática. Las dimensiones explícitas deben ser positivas y múltiplos de 16, cada una de hasta 3840; la proporción no puede superar 3:1 y el total debe estar entre 655360 y 8294400 píxeles. 2080x2080 también es válido. Las dimensiones entregadas pueden variar; comprueba la imagen y no la recortes a la fuerza.
Guarda la imagen
Una respuesta correcta sigue la estructura de imagen compatible con OpenAI. Los importes siguientes ilustran el formato del recibo y no son precios fijos:
{ "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" } ] }}Lee cada data[].b64_json y permite campos adicionales como revised_prompt. output_format solicita un formato, pero no garantiza la codificación ni la conversión. Inspecciona los bytes y usa la extensión correspondiente. La página De texto a imagen incluye ejemplos que detectan la firma PNG, JPEG o WebP de cada resultado.
Consulta el coste real
bettertoken_image_billing se devuelve con el resultado; no necesitas una consulta aparte.
| Campo | Significado |
|---|---|
currency | Moneda liquidada; no siempre es USD o CNY. |
settled_amount | Importe total de la solicitud como cadena decimal. |
requested_resolution | Nivel de resolución deducido de la solicitud. |
outputs[].index | Índice desde cero correspondiente a data[]. |
outputs[].width, height | Ancho y alto reales en píxeles. |
outputs[].billing_resolution | Nivel final de facturación de la imagen. |
outputs[].currency, amount | Moneda e importe liquidados por imagen. |
El tamaño solicitado y el nivel facturado pueden diferir: una solicitud 1024x1024 ha devuelto 1254x1254 con facturación 2K. Usa el importe del recibo y consulta los precios actuales en el model plaza. Conserva los importes como cadenas para mostrarlos y usa aritmética decimal al calcular. Un recibo ausente no equivale a coste cero.
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']}" )Flujo de respuesta
Este endpoint es síncrono. Después de enviar POST /images/edits, mantén abierta la solicitud HTTP hasta que responda el servidor. Si se completa, todas las imágenes aparecen en data[].b64_json.
El endpoint no devuelve un task_id, y no existe un endpoint separado para consultar el estado o descargar el resultado.
Tiempos de espera, reintentos y facturación
Configura el timeout del cliente HTTP en varios minutos. Un timeout, una desconexión o un 5xx ambiguo no indica si la edición se ejecutó o se cobró; la conexión puede fallar al escribir el resultado después del cobro. No repitas automáticamente el POST. Revisa primero el consumo o los registros de solicitudes y conserva el request ID recibido y, si existen, las cabeceras X-BetterToken-Image-Receipt y X-BetterToken-Billing-State. Un request ID generado por el cliente no aporta idempotencia y no hay un endpoint de consulta de estado.
Corrige los datos, la autenticación o la cuota rechazados antes de volver a enviar. Reintenta 429 con backoff solo tras confirmar el rechazo. BetterToken puede preautorizar el mayor precio unitario aplicable multiplicado por n; el saldo puede cubrir la imagen 1K entregada y no la retención, que produce 403 con error.code=insufficient_user_quota. El importe final depende de las imágenes entregadas.
Lista de comprobación de integración
- La Base URL es
https://bettertoken.ai/v1. - La cabecera incluye
Authorization: Bearer sk-.... - La solicitud usa
multipart/form-data. - Elige un Model ID disponible para esta solicitud:
gpt-image-2,gpt-image-2.5-flareogpt-image-2.5-sunburst. - Usa
imagepara una referencia y camposimage[]repetidos para varias. - Para editar con máscara, envía una sola
maskcon el mismo formato y dimensiones que la imagen y con canal Alpha. - Usa
response_format=b64_json.output_formates un valor solicitado; identifica el formato real por los bytes antes de guardar. nacepta enteros de1a10. Empieza con1; pueden devolverse menos imágenes.- Omite
size, usaautoo indica dimensiones que cumplan las restricciones. - El cliente HTTP permite esperar varios minutos a que termine la generación.
- Los registros y las capturas de errores no revelan la API Key ni el contenido base64 completo.
Documentación relacionada
/v1/images/editsAutorizaciones
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Cuerpo 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"Respuesta
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"
}
