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
- Een API-sleutel. Zie Authenticatie.
- Een model waarvan
model_kindimage_generationis. Zie Een beeldmodel vinden. - De base-URL
https://openapi.felo.ai.
Hoe dit verschilt van de OpenAI Images API
Het pad lijkt op dat van de Images API van OpenAI. De respons niet:
| OpenAI Images API | Felo Image API | |
|---|---|---|
| Indienrespons | 200 met de afbeeldingsgegevens | 202 met task_id, status: "queued" |
| Wanneer de afbeelding bestaat | In de indienrespons | Nadat het pollen succeeded bereikt |
| Afbeeldingspayload | b64_json of url | Een ondertekende url met beperkte geldigheid |
| Fouten in het verzoek | HTTP-fout bij het indienen | Meestal 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}"| Status | Betekenis | Wat je moet doen |
|---|---|---|
queued | Geaccepteerd; wacht op de start | Blijf pollen |
running | Het model genereert | Blijf pollen |
succeeded | Definitief; outputs is gevuld | Download de uitvoer |
failed | Definitief; lees error.message | Corrigeer het verzoek; probeer niet ongewijzigd opnieuw |
interrupted | Definitief; het resultaat kon niet worden hersteld | Dien 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=..."
}
]
}outputsis leeg totdat de taak slaagt.urlis 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
expis 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
| Veld | Verplicht | Beschrijving |
|---|---|---|
model | Ja | Model-ID uit de catalogus, bijvoorbeeld gemini-3-pro-image. Gebruik niet het upstream-ID google/... |
prompt | Ja | Tekstinstructie. Beschrijf bij een bewerking de wijziging en wat gelijk moet blijven |
resolution | Nee | Uitvoerstaffel. De huidige modellen accepteren 1K, 2K of 4K |
aspect_ratio | Nee | Uitvoerverhouding. De geaccepteerde waarden hangen af van het model |
n | Nee | Aantal afbeeldingen. De huidige modellen accepteren 1 |
input_references | Nee | Referentieafbeeldingen voor bewerken of compositie |
Huidige beeldmodellen:
| Model-ID | Resoluties | Beeldverhoudingen | Afbeeldingen per taak | Referenties |
|---|---|---|---|---|
gemini-3-pro-image | 1K, 2K, 4K | 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9 | 1 | Maximaal 14 |
gemini-nano-banana-2.1 | 1K, 2K, 4K | 1: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:9 | 1 | Maximaal 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.
| HTTP | error.code | Betekenis |
|---|---|---|
| 400 | invalid_request_error | model ontbreekt, of de body is geen JSON-object |
| 400 | model_not_configured | Het model-ID staat niet in de ingeschakelde catalogus |
| 400 | chat_model_not_allowed | Er is een chatmodel naar het beeld-endpoint gestuurd |
| 400 | model_kind_mismatch | Er is een videomodel of een ander niet-beeldmodel gestuurd |
| 402 | insufficient_balance | Onvoldoende service-tegoed; er is geen taak aangemaakt |
| 404 | generation_task_not_found | Het taak-ID is onbekend of hoort bij een ander account |
| 429 | daily_spend_limit_exceeded | De dagelijkse uitgavelimiet van het account is bereikt |
| 503 | generation_unavailable | Generatie is tijdelijk niet beschikbaar; probeer het later opnieuw |
Authenticatiefouten worden beschreven in Fouten, limieten en nieuwe pogingen.