Felo API PlatformFelo API Platform

Guide

Generazione di immagini

Genera e modifica immagini in modo asincrono: invia un'attività, monitora il completamento e scarica gli URL di output firmati.

L'API per le immagini di Felo genera e modifica immagini con i modelli del catalogo Felo. È asincrona: la richiesta di invio restituisce subito un ID attività e interroghi l'attività finché non raggiunge uno stato terminale.

Questa pagina descrive il contratto specifico delle immagini. Per il ciclo di vita condiviso delle attività, vedi Attività asincrone.

Prima di iniziare

Come si differenzia dalla OpenAI Images API

Il percorso è simile a quello della Images API di OpenAI. La risposta no:

OpenAI Images APIFelo Image API
Risposta di invio200 con i dati dell'immagine202 con task_id, status: "queued"
Quando l'immagine esisteNella risposta di invioDopo che il polling raggiunge succeeded
Payload dell'immagineb64_json o urlUn url firmato con scadenza
Errori della richiestaErrore HTTP all'invioDi solito status: "failed" sull'attività

Non inviare openai.images.generate() a questo endpoint. L'SDK si aspetta un array data sincrono e non può interrogare un'attività. Chiama l'endpoint via HTTP e interroga l'attività, oppure scrivi un piccolo wrapper per entrambi i passaggi.

Inviare un'attività

curl -X POST "https://openapi.felo.ai/api/v1/images/generations" \
  -H "Authorization: Bearer ${FELO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3-pro-image",
    "prompt": "A studio product photo of a ceramic coffee cup on warm linen, soft morning light",
    "resolution": "2K",
    "aspect_ratio": "4:3"
  }'

Un invio riuscito restituisce HTTP 202:

{
  "task_id": "6d1f0c9a-...",
  "status": "queued",
  "kind": "image",
  "outputs": []
}

202 significa che la piattaforma ha accettato l'attività. Non significa che il prompt, i parametri o le immagini di riferimento siano validi. La chiamata upstream avviene dopo la risposta, quindi la maggior parte dei problemi della richiesta compare più tardi come attività non riuscita. L'eccezione è il routing dei modelli: un modello di chat o video viene rifiutato all'invio.

Interrogare finché l'attività è terminale

curl "https://openapi.felo.ai/api/v1/images/generations/${TASK_ID}" \
  -H "Authorization: Bearer ${FELO_API_KEY}"
StatoSignificatoCosa fare
queuedAccettata; in attesa di avvioContinua a interrogare
runningIl modello sta generandoContinua a interrogare
succeededTerminale; outputs è popolatoScarica gli output
failedTerminale; leggi error.messageCorreggi la richiesta; non riprovare senza modifiche
interruptedTerminale; il risultato non è stato recuperabileInvia di nuovo l'attività

Gli errori delle attività mantengono lo stato HTTP a 200. Controlla status nel corpo, non solo lo stato HTTP.

Parti da un intervallo di 2–5 secondi e aumentalo. La maggior parte delle immagini termina entro un minuto; l'output 4K e le modifiche con molte immagini di riferimento richiedono più tempo. Imposta sempre una scadenza tua.

import os
import time

import requests

BASE = "https://openapi.felo.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['FELO_API_KEY']}"}


def generate_image(prompt: str, **params) -> list[dict]:
    response = requests.post(
        f"{BASE}/api/v1/images/generations",
        headers=HEADERS,
        json={"model": "gemini-3-pro-image", "prompt": prompt, **params},
        timeout=30,
    )
    response.raise_for_status()
    task = response.json()

    deadline = time.monotonic() + 300
    delay = 2.0
    while time.monotonic() < deadline:
        time.sleep(delay)
        delay = min(delay * 1.5, 10.0)

        poll = requests.get(
            f"{BASE}/api/v1/images/generations/{task['task_id']}",
            headers=HEADERS,
            timeout=30,
        )
        poll.raise_for_status()
        task = poll.json()

        if task["status"] == "succeeded":
            return task["outputs"]
        if task["status"] in {"failed", "interrupted"}:
            message = task.get("error", {}).get("message", task["status"])
            raise RuntimeError(message)

    raise TimeoutError(f"image task {task['task_id']} did not finish")

Leggere e conservare gli output

Quando l'attività riesce, outputs contiene una voce per ogni immagine generata:

{
  "task_id": "6d1f0c9a-...",
  "status": "succeeded",
  "kind": "image",
  "outputs": [
    {
      "media_type": "image/png",
      "url": "https://openapi.felo.ai/api/v1/media/...?exp=...&sig=..."
    }
  ]
}
  • outputs è vuoto finché l'attività non riesce.
  • url è un URL firmato. Si scarica senza chiave API, quindi trattalo come un link bearer.
  • L'URL ha una scadenza. Il parametro di query exp è il suo momento di scadenza. Scarica il file e conservalo nel tuo bucket o filesystem; l'attività non è un archivio permanente.
  • Se interroghi di nuovo dopo la scadenza dell'URL, ottieni lo stesso URL scaduto. Non ne viene emesso uno nuovo.
  • La risposta non include dati immagine in base64.
for index, output in enumerate(outputs):
    image = requests.get(output["url"], timeout=60)
    image.raise_for_status()
    with open(f"image-{index}.png", "wb") as file:
        file.write(image.content)

Modificare un'immagine

Passa le immagini di riferimento in input_references. Il modello le usa come contesto; il prompt descrive comunque la modifica.

curl -X POST "https://openapi.felo.ai/api/v1/images/generations" \
  -H "Authorization: Bearer ${FELO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3-pro-image",
    "prompt": "Keep the product and framing. Replace the background with a sunlit marble countertop.",
    "resolution": "2K",
    "aspect_ratio": "4:3",
    "input_references": [
      {
        "type": "image_url",
        "image_url": {"url": "https://example.com/product.png"}
      }
    ]
  }'

Ogni riferimento è un URL HTTP(S) o un URL di dati base64. L'ordine dei riferimenti viene conservato; quando conta, fai riferimento alle immagini per posizione nel prompt. I modelli attuali accettano fino a 14 riferimenti.

Campi della richiesta

CampoObbligatorioDescrizione
modelSìID del modello nel catalogo, per esempio gemini-3-pro-image. Non usare l'ID upstream google/...
promptSìIstruzione testuale. Per una modifica, descrivi il cambiamento e cosa deve restare uguale
resolutionNoLivello di output. I modelli attuali accettano 1K, 2K o 4K
aspect_ratioNoRapporto d'aspetto dell'output. I valori accettati dipendono dal modello
nNoNumero di immagini. I modelli attuali accettano 1
input_referencesNoImmagini di riferimento per modifiche o composizioni

Modelli di immagine attuali:

ID modelloRisoluzioniRapporti d'aspettoImmagini per attivitàRiferimenti
gemini-3-pro-image1K, 2K, 4K1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:91Fino a 14
gemini-nano-banana-2.11K, 2K, 4K1:1, 1:4, 1:8, 2:3, 3:2, 3:4, 4:1, 4:3, 4:5, 5:4, 8:1, 9:16, 16:9, 21:91Fino a 14

Per vincolare un fornitore, invia l'header X-Felo-Channel con un codice canale dall'elenco channels del modello. Vedi Canali e routing dei provider.

Trovare un modello di immagine

Non esiste un endpoint separato per l'elenco dei modelli di immagine. Interroga il catalogo generale e filtra per model_kind:

curl "https://openapi.felo.ai/api/v1/models" \
  -H "Authorization: Bearer ${FELO_API_KEY}" \
  | jq '.data[] | select(.model_kind == "image_generation") | {id, name}'

GET /api/v1/models/{model_id} restituisce i canali del modello e le tariffe pubblicate.

supported_parameters nel catalogo generale è un elenco a livello di protocollo. Per i modelli di immagine non enumera in modo affidabile i campi immagine sopra, quindi non costruire la richiesta partendo da lì. Usa la tabella dei campi in questa guida e conferma l'ID del modello dal catalogo.

Prezzi

La generazione di immagini viene fatturata secondo le tariffe pubblicate del modello. Il catalogo espone input_image e output_image accanto alle tariffe di testo prompt e completion. Le tariffe immagine sono tariffe per token: resolution cambia quanti token immagine di output consuma un'immagine, quindi un'immagine 4K costa più di una 1K. Le immagini di riferimento aggiungono token immagine di input.

La risposta dell'attività non include un oggetto usage. Controlla l'addebito in Console Billing.

Un'attività che termina failed o interrupted non produce output e non viene fatturata. Un invio rifiutato con 402 non ha creato alcuna attività.

Errori

Gli errori a livello di endpoint della route immagini usano la struttura di errore OpenAI:

{
  "error": {
    "message": "Model kind does not match this generation endpoint",
    "type": "invalid_request_error",
    "param": null,
    "code": "model_kind_mismatch"
  }
}

Il request ID si trova nell'header di risposta X-Request-Id. Registralo insieme all'ID dell'attività.

HTTPerror.codeSignificato
400invalid_request_errormodel manca oppure il corpo non è un oggetto JSON
400model_not_configuredL'ID del modello non è nel catalogo abilitato
400chat_model_not_allowedÈ stato inviato un modello di chat all'endpoint immagini
400model_kind_mismatchÈ stato inviato un modello video o un altro modello non di immagine
402insufficient_balanceCrediti insufficienti; nessuna attività è stata creata
404generation_task_not_foundL'ID dell'attività è sconosciuto o appartiene a un altro account
429daily_spend_limit_exceededÈ stato raggiunto il limite di spesa giornaliero dell'account
503generation_unavailableLa generazione è temporaneamente non disponibile; riprova più tardi

Gli errori di autenticazione sono descritti in Errori, limiti e retry.

Correlati