API de edição de imagens do GPT Image
Edite referências GPT Image pela API compatível com OpenAI da BetterToken. Configure multipart e máscaras, salve resultados e consulte cobrança e erros.
POST /v1/images/edits
O endpoint de imagem para imagem usa um corpo de solicitação multipart/form-data. Envie uma ou mais imagens de referência e informe prompt e parâmetros como campos de formulário.
Valores recomendados
Estes são valores iniciais recomendados, não requisitos fixos. Comece com n=1; o endpoint aceita de 1 a 10, mas pode retornar menos imagens.
model=gpt-image-2n=1response_format=b64_jsonoutput_format=pngUse image para uma referência ou repita image[] para várias. A edição comum com referências não exige mask. quality é opcional: gpt-image-2 aceita auto, low, medium, high; os dois modelos 2.5 também aceitam xhigh e max. Em multipart, o valor precisa ser uma string não vazia. A aceitação não garante disponibilidade para a combinação de modelo, tamanho e edição nem melhora da qualidade com níveis maiores. Omita o campo se não quiser definir uma preferência. size também é opcional, mas não pode ser uma string vazia.
Uma imagem de referência
Prepare reference.png e substitua YOUR_API_KEY pela sua BetterToken API Key. Uma chave funciona com todos os modelos disponíveis. Deixe curl -F ou Python files gerar o boundary de Content-Type.
| Campo do formulário | Exemplo |
|---|---|
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 | Selecione 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'Várias imagens de referência
Envie estes campos:
| Campo do formulário | Exemplo |
|---|---|
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[] | Selecione reference-1.png |
image[] | Selecione reference-2.jpg |
image[] | Selecione 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'Edite uma área selecionada com máscara
Adicione o campo de arquivo opcional mask quando quiser direcionar a edição para uma área selecionada. O endpoint atual da BetterToken lê um único arquivo em mask. Não envie campos mask[] repetidos.
- A imagem original e a máscara devem ter o mesmo formato e as mesmas dimensões em pixels. Cada arquivo deve ter menos de 50 MB. Para máxima compatibilidade, use PNG com canal Alpha nos dois arquivos.
- A máscara deve conter um canal Alpha. Pixels totalmente transparentes (
Alpha 0) marcam a área que o modelo pode redesenhar. Pixels totalmente opacos (Alpha 255) orientam o modelo a preservar essa área. - Uma imagem RGB comum em preto e branco não é uma máscara válida se não tiver de fato um canal Alpha.
- Se você enviar vários campos
image[], a máscara será aplicada à primeira imagem de entrada. - A máscara orienta o modelo. Ela não garante que os pixels fora da área transparente permaneçam absolutamente idênticos.
- A disponibilidade da máscara depende da combinação de modelo e tamanho. Testes com GPT Image 2 e Flare mostraram mudanças perceptíveis fora da área-alvo; o controle local do Sunburst ainda não foi verificado. Confira o resultado antes de usá-lo em produtos, logotipos ou 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'Edição com máscara em Python
Abra os dois arquivos em uma única instrução with para que o Python os feche após a solicitação:
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()Verifique os arquivos antes do upload
Esta verificação mínima com Pillow valida os requisitos de formato, dimensões e canal Alpha. Para uma máscara local típica, ela também exibe um aviso se o canal Alpha não incluir áreas totalmente transparentes e 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")Exemplo em 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)Tamanhos recomendados
size | Proporção | Caso de uso |
|---|---|---|
auto | Automática | Seleção automática de tamanho |
1024x1024 | 1:1 | Imagens quadradas, avatares, capas e materiais |
1536x1024 | 3:2 | Pôsteres, banners e cenas horizontais |
1024x1536 | 2:3 | Capas e pôsteres verticais para celular |
1536x1152 | 4:3 | Imagens horizontais padrão, imagens de produto e gráficos de conteúdo |
1152x1536 | 3:4 | Imagens verticais padrão, capas de celular e pôsteres verticais |
2048x2048 | 1:1 | Imagens quadradas de alta resolução |
2048x1152 | 16:9 | Imagens horizontais de alta resolução |
3840x2160 | 16:9 | Imagens horizontais em 4K |
2160x3840 | 9:16 | Imagens verticais em 4K |
Os valores da tabela são exemplos, não uma lista fechada. Você pode omitir size ou usar auto; null em JSON também ativa a seleção automática. As dimensões explícitas devem ser positivas e múltiplas de 16, cada uma com no máximo 3840; a proporção não pode exceder 3:1 e o total deve ficar entre 655360 e 8294400 pixels. 2080x2080 também é válido. As dimensões entregues podem variar; confira a imagem e não a corte à força.
Salve a imagem
Uma resposta bem-sucedida segue o formato de resposta de imagem compatível com OpenAI. Os valores abaixo ilustram o formato do recibo e não são preços fixos:
{ "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" } ] }}Leia cada data[].b64_json e permita campos adicionais como revised_prompt. output_format solicita um formato, mas não garante codificação nem conversão. Inspecione os bytes e use a extensão correspondente. A página Texto para imagem inclui exemplos que detectam a assinatura PNG, JPEG ou WebP de cada resultado.
Consulte o custo real
bettertoken_image_billing é retornado com o resultado; não é necessária outra consulta.
| Campo | Significado |
|---|---|
currency | Moeda liquidada; não presuma que seja sempre USD ou CNY. |
settled_amount | Total da solicitação como string decimal. |
requested_resolution | Nível de resolução identificado na solicitação. |
outputs[].index | Índice iniciado em zero, correspondente a data[]. |
outputs[].width, height | Largura e altura reais em pixels. |
outputs[].billing_resolution | Nível final de cobrança da imagem. |
outputs[].currency, amount | Moeda e valor liquidados por imagem. |
O tamanho solicitado pode diferir do nível cobrado: uma solicitação 1024x1024 já retornou 1254x1254 com cobrança 2K. Use o valor do recibo e consulte os preços atuais no model plaza. Mantenha valores como strings na exibição e use aritmética decimal nos cálculos. Recibo ausente não significa custo zero.
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']}" )Fluxo de resposta
Este endpoint é síncrono. Depois de enviar POST /images/edits, mantenha a solicitação HTTP aberta até o servidor responder. Em caso de sucesso, todas as imagens são retornadas em data[].b64_json.
O endpoint não retorna task_id, nem há endpoint separado para consultar status ou baixar o resultado.
Timeouts, novas tentativas e cobrança
Defina o timeout do cliente HTTP para vários minutos. Um timeout, desconexão ou 5xx ambíguo não confirma se a edição foi executada ou cobrada; a conexão pode falhar enquanto o resultado é gravado após a cobrança. Não reenvie o POST automaticamente. Primeiro confira o consumo ou os logs da solicitação e guarde o request ID recebido e, quando disponíveis, os headers X-BetterToken-Image-Receipt e X-BetterToken-Billing-State. Um request ID gerado pelo cliente não garante idempotência e não há endpoint de consulta de status.
Corrija dados, autenticação ou cota rejeitados antes de reenviar. Só tente novamente um 429 com backoff depois de confirmar a rejeição. A BetterToken pode pré-autorizar o maior preço unitário aplicável multiplicado por n; o saldo pode cobrir a imagem 1K entregue, mas não a retenção, gerando 403 com error.code=insufficient_user_quota. O valor final depende das imagens entregues.
Checklist de integração
- A Base URL é
https://bettertoken.ai/v1. - O cabeçalho inclui
Authorization: Bearer sk-.... - A solicitação usa
multipart/form-data. - Escolha um Model ID disponível para esta solicitação:
gpt-image-2,gpt-image-2.5-flareougpt-image-2.5-sunburst. - Use
imagepara uma referência ou camposimage[]repetidos para várias. - Na edição com máscara, envie uma única
maskcom o mesmo formato e dimensões da imagem e com canal Alpha. - Use
response_format=b64_json.output_formaté um valor solicitado; identifique o formato real pelos bytes antes de salvar. naceita inteiros de1a10. Comece com1; menos imagens podem ser retornadas.- Omita
size, useautoou informe dimensões que atendam às restrições. - O cliente HTTP permite aguardar vários minutos pela geração.
- Os logs e as capturas de erros não revelam a API Key nem todo o conteúdo base64 da imagem.
Documentos relacionados
/v1/images/editsAutorizações
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Corpo 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"Resposta
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"
}
