HiAPI
Blog

Tutoriale

Come usare gpt-image-2/text-to-image tramite l'API hiapi: parametri, codice ed esempi eseguibili

Jun 25, 2026
Come usare gpt-image-2/text-to-image tramite l'API hiapi: parametri, codice ed esempi eseguibili

Questo tutorial mostra il codice minimo necessario per generare un'immagine con gpt-image-2/text-to-image tramite l'API unificata per le attività di hiapi, quindi spiega uno per uno ogni parametro e i modelli di livello produttivo da adottare una volta che il codice funziona (callback, idempotenza, gestione degli errori).

Prerequisiti

Ti serve una chiave API. Creala dalla pagina delle chiavi API della console hiapi — le chiavi iniziano con sk-. La pagina del modello gpt-image-2/text-to-image elenca il prezzo attuale per immagine; il dettaglio completo è nella pagina dei prezzi.

Tutte le chiamate in questa guida vanno all'endpoint unificato per attività asincrone:

  • POST https://api.hiapi.ai/v1/tasks — crea un'attività di generazione
  • GET https://api.hiapi.ai/v1/tasks/{taskId} — esegue il polling dello stato dell'attività

La documentazione di riferimento generale della piattaforma è disponibile in Documentazione dell'API hiapi.

Esempio minimo eseguibile (curl)

Una singola generazione è un'interazione in due passaggi: prima crei l'attività, poi attendi che sia completata.

# 1. Create the task
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/text-to-image",
    "input": {
      "prompt": "a calico cat curled up on a sunlit windowsill, soft focus background",
      "aspect_ratio": "1:1",
      "resolution": "1K"
    }
  }'
# => {"code":200,"data":{"taskId":"tk-hiapi-01KVY...."},"message":"success"}

# 2. Poll until status == "success"
TASK_ID="tk-hiapi-01KVY...."
curl -s "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
  -H "Authorization: Bearer sk-YOUR_KEY"
# => {"code":200,"data":{"status":"success","output":[{"url":"https://..."}], ...}}

L'URL dell'immagine si trova in data.output[0].url. Scaricala subito — output[0].expireAt è molto breve, quindi quell'URL serve solo per il recupero, non per l'incorporamento permanente.

Python: creazione + polling + salvataggio su disco

import os
import time
import urllib.request
import requests  # pip install requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]  # sk-...

def create_task(prompt: str, aspect_ratio: str = "1:1", resolution: str = "1K") -> str:
    payload = {
        "model": "gpt-image-2/text-to-image",
        "input": {
            "prompt": prompt,
            "aspect_ratio": aspect_ratio,
            "resolution": resolution,
        },
    }
    r = requests.post(API_BASE, json=payload,
                      headers={"Authorization": f"Bearer {TOKEN}"},
                      timeout=60)
    r.raise_for_status()
    body = r.json()
    if body.get("error"):
        raise RuntimeError(f"create failed: {body['error']}")
    return body["data"]["taskId"]

def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API_BASE}/{task_id}",
                         headers={"Authorization": f"Bearer {TOKEN}"},
                         timeout=30)
        r.raise_for_status()
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task
        if status == "fail":
            raise RuntimeError(f"task failed: {task.get('error')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")

if __name__ == "__main__":
    task_id = create_task(
        "a calico cat curled up on a sunlit windowsill, soft focus background",
        aspect_ratio="3:2",
        resolution="1K",
    )
    task = wait_task(task_id)
    url = task["output"][0]["url"]
    urllib.request.urlretrieve(url, "cat.png")
    print(f"saved cat.png from task {task_id}")

Node.js: lo stesso flusso con fetch

// Node 18+ has global fetch
const API_BASE = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;

async function createTask(prompt, aspectRatio = "1:1", resolution = "1K") {
  const res = await fetch(API_BASE, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-image-2/text-to-image",
      input: { prompt, aspect_ratio: aspectRatio, resolution },
    }),
  });
  const body = await res.json();
  if (body.error) throw new Error(`create failed: ${body.error.code} ${body.error.message}`);
  return body.data.taskId;
}

async function waitTask(taskId, { timeoutMs = 600_000, pollMs = 5_000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`${API_BASE}/${taskId}`, {
      headers: { "Authorization": `Bearer ${TOKEN}` },
    });
    const task = (await res.json()).data || {};
    if (task.status === "success") return task;
    if (task.status === "fail") throw new Error(`task failed: ${JSON.stringify(task.error)}`);
    await new Promise(r => setTimeout(r, pollMs));
  }
  throw new Error(`task ${taskId} timed out`);
}

(async () => {
  const id = await createTask(
    "a calico cat curled up on a sunlit windowsill, soft focus background",
    "16:9",
    "1K",
  );
  const task = await waitTask(id);
  const url = task.output[0].url;
  const img = await fetch(url).then(r => r.arrayBuffer());
  const { writeFileSync } = await import("node:fs");
  writeFileSync("cat.png", Buffer.from(img));
  console.log(`saved cat.png from task ${id}`);
})();

Riferimento dei parametri

Il corpo della richiesta contiene sempre due campi di primo livello: model (stringa, ID del modello nudo gpt-image-2/text-to-image) e input (oggetto dei parametri specifici del modello).

Campo input Obbligatorio Tipo Descrizione
prompt Sì string Descrizione testuale dell'immagine che desideri.
aspect_ratio Sì string Uno dei seguenti valori: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 o auto.
resolution No string 1K (predefinito), 2K o 4K. Le dimensioni in pixel si adattano in base al rapporto d'aspetto scelto.
callback No object { "url": "https://yours.example/hook", "when": "final" } — vedi la sezione successiva.

La creazione riuscita restituisce {"code":200, "data":{"taskId":"tk-hiapi-..."}, "message":"success"}. Il campo data.status restituito da GET /v1/tasks/{taskId} è uno tra handling, success o fail; in caso di successo, data.output è un array il cui primo elemento contiene url e il timestamp expireAt dell'immagine.

Altri modelli di immagini di hiapi (ad esempio z-image, qwen-image) usano campi input leggermente diversi — aspect_ratio è la convenzione adottata da gpt-image-2/text-to-image. Quando cambi modello, consulta la pagina del modello per confermare la struttura esatta di input.

Modelli di livello produttivo

Usare i callback invece del polling

Eseguire il polling ogni 5 secondi va bene per la prototipazione, ma per il traffico di produzione vuoi che hiapi ti invii le attività completate, liberando così i worker. Aggiungi un blocco callback in input:

{
  "model": "gpt-image-2/text-to-image",
  "input": {
    "prompt": "an astronaut sketching the moon",
    "aspect_ratio": "3:2",
    "resolution": "1K",
    "callback": {
      "url": "https://your-app.example.com/webhooks/hiapi",
      "when": "final"
    }
  }
}

when: "final" viene attivato una volta quando l'attività raggiunge lo stato terminale (success o fail). Il payload ricevuto dal tuo endpoint ha la stessa struttura di GET /v1/tasks/{id}, quindi il gestore può riutilizzare la logica di parsing del polling. Confronta il taskId con quello memorizzato al momento della creazione dell'attività per sapere a quale richiesta appartiene il callback.

Rendere idempotente la creazione

Se un worker si blocca dopo POST /v1/tasks ma prima di memorizzare taskId, potresti generare la stessa immagine due volte. La soluzione a basso costo è: nel momento in cui ricevi la risposta di creazione, memorizza (your_request_id → taskId) nel database nella stessa transazione che invia la richiesta. Se il worker ritenta, troverà il taskId esistente e riprenderà il polling invece di creare una nuova attività.

Gestire correttamente gli errori di autenticazione

I fallimenti di autenticazione di hiapi restituiscono HTTP 200 con un payload di errore incorporato nel corpo della risposta:

{"error":{"code":"permission_denied","message":"This API key cannot use the selected model. ...","type":"hiapi_error"}}

Quindi il solo codice di stato 200 non significa successo. Controlla sempre prima body.error; se presente, esamina error.code (permission_denied, invalid_request, ecc.) e error.message. Il request_id nel messaggio è ciò che incolli nel ticket di supporto quando hai bisogno di aiuto.

Scaricare subito e riospitare autonomamente

data.output[0].url è un URL di breve durata — la risposta include expireAt. Non inserire l'URL di hiapi direttamente in un <img src> del tuo prodotto; non appena l'attività ha successo, scarica immediatamente il flusso di byte, caricalo sul tuo storage (S3, R2, Supabase Storage, ecc.) e servilo da lì.

Impostare timeout ragionevoli

Un valore predefinito ragionevole è: timeout di 60 secondi per la richiesta POST (creare un'attività è veloce — in pratica stai solo aspettando che l'API confermi la ricezione), budget totale di 10 minuti per il ciclo di polling con intervallo di 5 secondi. Un'attività che impiega più di 10 minuti quasi sempre significa che è passata silenziosamente allo stato fail, quindi andare in timeout e registrare nei log l'ultimo corpo di risposta dell'attività è più utile che attendere all'infinito.

Domande frequenti

Qual è la differenza tra gpt-image-2 e gpt-image-2/text-to-image?

gpt-image-2 è la famiglia di modelli; gpt-image-2/text-to-image è l'endpoint specifico che chiami per trasformare un prompt testuale in una nuova immagine. Altre varianti della famiglia espongono strutture input diverse (ad esempio, l'editing di immagini accetta immagini di riferimento). In caso di dubbio, usa l'ID del modello nudo che vedi nella pagina del modello.

Cosa fa aspect_ratio: auto?

auto lascia che il modello decida il rapporto d'aspetto in base al prompt. Usalo quando non hai requisiti di layout stringenti; altrimenti fissa tu il rapporto in modo che il ritaglio a valle sia prevedibile.

Perché la mia richiesta restituisce HTTP 200 con permission_denied?

O la chiave API è errata (errore di battitura, revocata, manca il prefisso sk-), oppure il piano di quella chiave non include gpt-image-2/text-to-image. Apri la console delle chiavi API, verifica la stringa della chiave e controlla il tuo piano nella pagina dei prezzi. Controlla sempre body.error.code — non fidarti mai del solo codice di stato HTTP.

Posso generare più immagini in una singola richiesta?

gpt-image-2/text-to-image genera una sola immagine per attività — data.output è un array, ma per questo modello la sua lunghezza è sempre 1. Per generare N varianti, avvia N attività in parallelo e usa il pattern callback descritto sopra, così non tieni N thread di lavoro in attesa.

Come si annulla un'attività in corso?

L'API unificata per le attività attualmente non fornisce un endpoint di cancellazione. La mitigazione più semplice è far sì che il worker client scarti il risultato quando l'utente non ne ha più bisogno — la generazione già eseguita viene comunque addebitata, quindi il posto giusto per imporre una cancellazione è prima di chiamare POST /v1/tasks.

Come si passa a un altro modello di immagini?

Cambia model con il nuovo ID nudo (ad esempio z-image/text-to-image) e adatta input alla struttura di quel modello. Le strutture dei vari modelli non sono del tutto identiche — alcuni accettano size, altri aspect_ratio, e pochi non accettano resolution. Il catalogo dei modelli elenca tutti i modelli disponibili e ogni pagina di modello documenta i suoi campi input.

Inizia a creare con artefatti IA persistenti

Ottieni la tua chiave API e chiama modelli di immagini, video e audio tramite un'unica API basata sui task.

Leggi la documentazione API