Felo API PlatformFelo API Platform

Handleidingen

Beeldgeneratie

Genereer en bewerk afbeeldingen asynchroon: dien een taak in, poll op voltooiing en download ondertekende uitvoer-URL's.

De Felo image-API genereert en bewerkt afbeeldingen met modellen uit de Felo-modelcatalogus. De API is asynchroon: het indienverzoek retourneert direct een taak-ID en je pollt de taak totdat die een definitieve status bereikt.

Deze pagina behandelt het contractspecifieke deel voor afbeeldingen. Zie Asynchrone taken voor de gedeelde taaklevenscyclus.

Voordat je begint

Hoe dit verschilt van de OpenAI Images API

Het pad lijkt op dat van de Images API van OpenAI. De respons niet:

OpenAI Images APIFelo Image API
Indienrespons200 met de afbeeldingsgegevens202 met task_id, status: "queued"
Wanneer de afbeelding bestaatIn de indienresponsNadat het pollen succeeded bereikt
Afbeeldingspayloadb64_json of urlEen ondertekende url met beperkte geldigheid
Fouten in het verzoekHTTP-fout bij het indienenMeestal status: "failed" bij de taak

Stuur openai.images.generate() niet naar dit endpoint. De SDK verwacht een synchrone data-array en kan een taak niet pollen. Roep het endpoint aan via HTTP en poll de taak, of schrijf een kleine wrapper voor beide stappen.

Een taak indienen

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"
  }'

Een geslaagde indiening retourneert HTTP 202:

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

202 betekent dat het platform de taak heeft geaccepteerd. Het betekent niet dat de prompt, parameters of referentieafbeeldingen geldig zijn. De aanroep naar de upstream gebeurt na de respons, dus de meeste problemen met het verzoek verschijnen later als een mislukte taak. De uitzondering is modelroutering: een chat- of videomodel wordt bij het indienen geweigerd.

Pollen tot de taak definitief is

curl "https://openapi.felo.ai/api/v1/images/generations/${TASK_ID}" \
  -H "Authorization: Bearer ${FELO_API_KEY}"
StatusBetekenisWat je moet doen
queuedGeaccepteerd; wacht op de startBlijf pollen
runningHet model genereertBlijf pollen
succeededDefinitief; outputs is gevuldDownload de uitvoer
failedDefinitief; lees error.messageCorrigeer het verzoek; probeer niet ongewijzigd opnieuw
interruptedDefinitief; het resultaat kon niet worden hersteldDien de taak opnieuw in

Bij mislukte taken blijft de HTTP-status 200. Controleer status in de body, niet alleen de HTTP-status.

Begin met een interval van 2–5 seconden en verhoog dat geleidelijk. De meeste afbeeldingen zijn binnen een minuut klaar; 4K-uitvoer en bewerkingen met veel referentieafbeeldingen duren langer. Stel altijd je eigen deadline in.

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")

De uitvoer lezen en opslaan

Als de taak slaagt, bevat outputs één vermelding per gegenereerde afbeelding:

{
  "task_id": "6d1f0c9a-...",
  "status": "succeeded",
  "kind": "image",
  "outputs": [
    {
      "media_type": "image/png",
      "url": "https://openapi.felo.ai/api/v1/media/...?exp=...&sig=..."
    }
  ]
}
  • outputs is leeg totdat de taak slaagt.
  • url is een ondertekende URL. De URL kan zonder API-sleutel worden gedownload, dus behandel hem als een bearer-link.
  • De URL is tijdelijk geldig. De queryparameter exp is het vervaltijdstip. Download het bestand en sla het op in je eigen bucket of bestandssysteem; de taak is geen permanente opslag.
  • Als je na het verlopen van de URL opnieuw pollt, krijg je dezelfde verlopen URL. Er wordt geen nieuwe uitgegeven.
  • De respons bevat geen base64-afbeeldingsgegevens.
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)

Een afbeelding bewerken

Geef referentieafbeeldingen mee in input_references. Het model gebruikt ze als context; de prompt beschrijft nog steeds de wijziging.

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"}
      }
    ]
  }'

Elke referentie is een HTTP(S)-URL of een base64-data-URL. De volgorde van de referenties blijft behouden; verwijs in de prompt naar afbeeldingen op basis van hun positie wanneer dat uitmaakt. De huidige modellen accepteren maximaal 14 referenties.

Verzoekvelden

VeldVerplichtBeschrijving
modelJaModel-ID uit de catalogus, bijvoorbeeld gemini-3-pro-image. Gebruik niet het upstream-ID google/...
promptJaTekstinstructie. Beschrijf bij een bewerking de wijziging en wat gelijk moet blijven
resolutionNeeUitvoerstaffel. De huidige modellen accepteren 1K, 2K of 4K
aspect_ratioNeeUitvoerverhouding. De geaccepteerde waarden hangen af van het model
nNeeAantal afbeeldingen. De huidige modellen accepteren 1
input_referencesNeeReferentieafbeeldingen voor bewerken of compositie

Huidige beeldmodellen:

Model-IDResolutiesBeeldverhoudingenAfbeeldingen per taakReferenties
gemini-3-pro-image1K, 2K, 4K1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:91Maximaal 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:91Maximaal 14

Als je een leverancier wilt vastzetten, stuur je de X-Felo-Channel-header mee met een kanaalcode uit de channels-lijst van het model. Zie Kanalen en providerroutering.

Een beeldmodel vinden

Er is geen apart lijst-endpoint voor beeldmodellen. Doorzoek de algemene catalogus en filter op 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} retourneert de kanalen en gepubliceerde tarieven van het model.

supported_parameters in de algemene catalogus is een lijst op protocolniveau. Voor beeldmodellen geeft die niet betrouwbaar de bovenstaande beeldvelden weer, dus bouw je verzoek er niet op. Gebruik de veldentabel in deze handleiding en controleer het model-ID in de catalogus.

Prijzen

Beeldgeneratie wordt gefactureerd op basis van de gepubliceerde tarieven van het model. De catalogus bevat input_image en output_image naast de teksttarieven voor prompt en completion. De beeldtarieven zijn tokentarieven: resolution bepaalt hoeveel uitvoerbeeldtokens een afbeelding verbruikt, dus een 4K-afbeelding kost meer dan een 1K-afbeelding. Referentieafbeeldingen voegen invoerbeeldtokens toe.

De taakrespons bevat geen usage-object. Controleer de kosten in Console Billing.

Een taak die eindigt met failed of interrupted levert geen uitvoer op en wordt niet gefactureerd. Een indiening die met 402 wordt geweigerd, heeft geen taak aangemaakt.

Fouten

Fouten op endpointniveau van de beeldroute gebruiken het OpenAI-foutformaat:

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

De request-ID staat in de X-Request-Id-responsheader. Log deze samen met het taak-ID.

HTTPerror.codeBetekenis
400invalid_request_errormodel ontbreekt, of de body is geen JSON-object
400model_not_configuredHet model-ID staat niet in de ingeschakelde catalogus
400chat_model_not_allowedEr is een chatmodel naar het beeld-endpoint gestuurd
400model_kind_mismatchEr is een videomodel of een ander niet-beeldmodel gestuurd
402insufficient_balanceOnvoldoende service-tegoed; er is geen taak aangemaakt
404generation_task_not_foundHet taak-ID is onbekend of hoort bij een ander account
429daily_spend_limit_exceededDe dagelijkse uitgavelimiet van het account is bereikt
503generation_unavailableGeneratie is tijdelijk niet beschikbaar; probeer het later opnieuw

Authenticatiefouten worden beschreven in Fouten, limieten en nieuwe pogingen.

Gerelateerd