Documentação

Documentação

Geração de imagens

Dois endpoints: texto para imagem e edição/conversão de imagem em imagem. Ambos retornam URLs de resultado permanentes: a Kunavo arquiva todas as imagens na própria CDN.

A Kunavo disponibiliza /v1/images/generations (texto para imagem) e /v1/images/edits (imagem para imagem/edição). Ambos são síncronos por padrão — a chamada fica bloqueada até a conclusão do processamento upstream e, em seguida, retorna as URLs dos resultados — ou use o modo assíncrono com "async": true ou um webhook_url.

Texto para imagem

Endpoint: POST /v1/images/generations. Use o método images.generate do SDK da OpenAI ou faça a chamada diretamente com curl.

img = client.images.generate(
    model="nano-banana-pro",
    prompt="a red origami crane on a white desk, soft window light",
    size="1024x1024",
)
print(img.data[0].url)

Parâmetros comuns

ParâmetroTipoObservações
modelstringQualquer slug de modelo de imagem de /v1/models.
promptstringPrompt de texto. Sempre obrigatório.
sizestringFormato no estilo OpenAI, como "1024x1024". Mapeado para a proporção do provedor upstream.
qualitystandard|hdQuando compatível (gpt-image).
resolution1K|2K|4KNível de resolução para modelos com níveis — veja abaixo Resolution tiers. A cobrança é feita por nível.
nintNúmero de imagens. A maioria dos modelos retorna 1, independentemente do valor.
inputobjectOpção de escape — veja abaixo Raw input.
As URLs de resultado são links permanentes de files.kunavo.com: a Kunavo arquiva todas as imagens na própria CDN, então, ao contrário das URLs upstream diretas, elas nunca expiram. Se uma imagem não puder ser arquivada, a URL dela será a URL temporária do upstream, em outro host: baixe essa imagem e hospede-a novamente.

Faixas de resolução

Vários modelos de imagem cobram preços escalonados de acordo com a resolução de saída. Informe resolution para escolher um nível; se omitir, será usado o nível padrão. A cobrança corresponde ao nível efetivamente produzido.

Modelo (e sua variante -edit)Níveis — preço de cada umPadrão
nano-banana-21K $0.0469 · 2K $0.0707 · 4K $0.10571K
nano-banana-pro1K / 2K $0.067 · 4K $0.122K
gpt-image-21K / 2K / 4K — $0.0633 (valor fixo)1K

A família veo-3 também tem níveis de resolução — os preços por nível estão na página de cada modelo em /models.

O GPT-Image-2 não consegue renderizar em 4K com proporção 1:1 (quadrada). Se você solicitar resolution = 4K com tamanho quadrado, a chamada será automaticamente reduzida para 2K, e a cobrança será feita nessa resolução.

Edição de imagem/conversão de imagem em imagem

Endpoint: POST /v1/images/edits. Envie a imagem de origem como URL (HTTPS ou dados base64 em data:) por meio de image para edições de imagem única ou de image_urls para referências de várias imagens.

# Image edit / image-to-image: pass the source image URL
import requests

resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue, keep composition",
        "image": "https://your-cdn.com/source.png",
    },
)
print(resp.json()["data"][0]["url"])

Referências de várias imagens

Alguns modelos (Nano Banana Edit, GPT-Image-2 Edit) aceitam várias imagens de referência.

# nano-banana-edit accepts multiple reference images
resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "nano-banana-edit",
        "prompt": "merge subject from img1 with background from img2",
        "image_urls": [
            "https://your-cdn.com/subject.png",
            "https://your-cdn.com/background.png",
        ],
    },
)

Modelos de edição compatíveis

  • nano-banana-edit — edição do Google Nano Banana
  • gpt-image-2-edit — conversão de imagem em imagem da OpenAI

Como fornecer uma imagem de origem

A edição de imagens e a conversão de imagem em vídeo precisam de uma imagem de origem que o modelo consiga acessar. Você tem três opções — escolha a que melhor se adapta ao seu aplicativo:

  • Você já tem uma URL pública — informe-a diretamente em image (ou em image_url para vídeo). Pronto.
  • Você tem um arquivo local — envie-o uma vez por POST /v1/files e reutilize a URL permanente retornada.
  • Você tem bytes brutos no código — inclua-os em uma URI base64 data:; a Kunavo os hospeda de forma transparente.

Opção A — enviar por POST /v1/files

Envie multipart/form-data com um campo file (ou um { "file": "data:..." } JSON). Você receberá uma URL files.kunavo.com permanente — arquivos de até 25 MB.

# Upload a local file → get a permanent Kunavo URL
import requests

with open("source.png", "rb") as f:
    up = requests.post(
        "https://api.kunavo.com/v1/files",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"file": f},
    ).json()

# up["url"] is now a permanent https://files.kunavo.com/... URL
edit = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue",
        "image": up["url"],
    },
).json()
print(edit["data"][0]["url"])

Opção B — incluir em base64

Ignore totalmente o envio separado: inclua uma URI data: no campo image / image_url. A Kunavo a decodifica, hospeda na CDN e fornece ao modelo a URL hospedada.

# Or skip the upload step — pass base64 inline, we host it for you.
import base64, requests

with open("source.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue",
        "image": f"data:image/png;base64,{b64}",
    },
)
O mesmo se aplica a POST /v1/video/generations — image_url aceita uma URL HTTPS ou uma URI base64 data: para modelos de imagem para vídeo, como Veo.

Formato da resposta

Ambos os endpoints retornam a resposta padrão de imagens da OpenAI:

{
  "created": 1779360636,
  "data": [
    { "url": "https://files.kunavo.com/image/.../result.png" }
  ]
}

Latência e tempos limite

A geração de imagens costuma levar de 5 a 60 segundos, dependendo do modelo. No modo síncrono padrão, a Kunavo mantém a conexão aberta e consulta o provedor upstream por até 540 segundos antes de retornar um erro 504. Ajuste o tempo limite do cliente conforme necessário — ou use a API assíncrona para enviar a solicitação em segundos e consultar o status no seu próprio ritmo:

  • Nano Banana/Nano Banana 2: geralmente menos de 10 s.
  • Nano Banana Pro/GPT-Image-2: de 15 a 60 s.
  • Referências múltiplas + nível premium: até cerca de 2 minutos.

API assíncrona (envio + consulta de status/webhook)

Por padrão, ambos os endpoints de imagem são síncronos — a chamada mantém a conexão aberta até o provedor upstream renderizar a imagem e, em seguida, retorna a resposta padrão de imagens da OpenAI. Para tarefas em lote, níveis premium lentos ou chamadas de ambientes serverless que não podem manter uma solicitação aberta por muito tempo, adicione "async": true (ou um webhook_url) a /v1/images/generations ou /v1/images/edits.

O envio retorna imediatamente um ID img_*; consulte GET /v1/images/{id} até que status seja completed ou failed — ou registre um webhook e dispense totalmente as consultas de status.

# Async: add "async": true (or a webhook_url) to either image endpoint.
# The call returns instantly with an img_ id instead of holding the connection.
import requests, time

API = "https://api.kunavo.com/v1"
H = {"Authorization": f"Bearer {API_KEY}"}

submit = requests.post(
    f"{API}/images/generations",
    headers=H,
    json={"model": "gpt-image-2", "prompt": "a red panda", "async": True},
).json()

task_id = submit["id"]        # "img_abc..."
status  = submit["status"]    # "queued"

# Poll GET /v1/images/{id} until terminal — or skip polling and use a webhook.
while status not in ("completed", "failed"):
    time.sleep(3)
    r = requests.get(f"{API}/images/{task_id}", headers=H).json()
    status = r["status"]

if status == "completed":
    print(r["output"]["url"])
else:
    print("failed:", r["error"])

Objeto da tarefa

CampoTipoObservações
idstringID de tarefa img_* — passe-o para GET /v1/images/{id}.
statusstringqueued | in_progress | completed | failed.
outputobject|nullQuando concluído: { url, urls, archived }. archived é false quando uma imagem não pôde ser arquivada e a URL dela é a URL temporária do upstream.
errorobject|nullQuando falha: { code, message }.
expires_atint|nullSegundos Unix, 30 dias após o envio: a tarefa pode ser consultada pelo menos até lá. As URLs dos resultados não expiram.
GET /v1/images/{id} é restrito ao proprietário: consultar um ID que não é seu retorna 404, indistinguível de um ID que nunca foi emitido. Cadência recomendada para consultar o status: 3 s, com recuo exponencial até cerca de 30 s.

Webhooks

Informe webhook_url (https) no envio, e a Kunavo enviará por POST um evento assinado image.completed / image.failed quando a tarefa terminar — com o mesmo envelope e assinatura dos webhooks de vídeo e música:

  • X-Kunavo-Webhook-Id — ID de evento estável, idêntico em todas as tentativas de entrega (use-o para eliminar duplicatas).
  • X-Kunavo-Webhook-Timestamp — segundos Unix em que a assinatura foi calculada.
  • X-Kunavo-Webhook-Signature — HMAC-SHA256 de {timestamp}.{rawBody}, assinado com sha256= usando seu segredo de webhook.
As tentativas de entrega são repetidas com recuo por cerca de 9 h. A linha assíncrona continua disponível para consulta durante todo esse período; portanto, sempre é possível recuperar um webhook perdido usando GET.

Opção de escape para entrada bruta

Para parâmetros específicos de cada modelo que a Kunavo não mapeia (seed, prompt negativo, formato de saída), informe input. Ele é enviado ao provedor upstream exatamente como foi escrito, no lugar da entrada que nosso adaptador criaria.

O campo que seleciona o nível de preço de um modelo é a exceção: resolution, ou rendering_speed no Ideogram. Em modelos com níveis, ele é sempre enviado como um dos níveis do modelo, e a cobrança corresponde a esse nível. Quando input o omite ou fornece um valor que não corresponde a nenhum dos níveis do modelo, o nível padrão é enviado e cobrado. O mesmo campo na raiz da solicitação não é lido quando input está definido.

# Raw upstream 'input': sent as written, in place of what our adapter builds.
# "resolution" sets the billed tier: 2K here, the default tier when left out.
resp = client.images.generate(
    model="nano-banana-2",
    prompt="",  # ignored when input is set
    extra_body={"input": {
        "prompt": "a futuristic cyberpunk skyline at dusk",
        "aspect_ratio": "16:9",
        "resolution": "2K",
        "output_format": "png",
    }},
)
Ao informar input, você ignora a validação da Kunavo. Se o provedor upstream rejeitar seus campos, você receberá um erro 422 nosso — consulte a documentação de erros e a documentação upstream do modelo.

Próximos passos