Afbeeldingen, video, muziek en spraak
De sleutel die je voor tekst gebruikt, maakt ook afbeeldingen, video's, muziek en spraak, en zet opnames om in tekst, allemaal van hetzelfde saldo. Kies een model in de modellenoverzicht (of ?type=image, ?type=music, ?type=audio); de pagina van elk model toont de prijs, het type en een werkend verzoek.
| Je wilt | Route | Bronafbeelding gaat in |
|---|---|---|
| Een nieuwe afbeelding van een prompt | POST /v1/images/generations |
(geen) |
| Een bewerkte afbeelding | POST /v1/images/edits |
image (of image_url, input_images, images) |
| Een video van een prompt | POST /v1/video/generations |
(geen) |
| Een video die begint met een afbeelding | POST /v1/video/generations |
image_url (eerste frame); end_image_url voor het laatste frame |
| Een video van referentieafbeeldingen | POST /v1/video/generations |
input_images met "role": "reference" |
| Een tekstantwoord over een afbeelding | POST /v1/chat/completions |
een image_url deel in messages[].content |
| Muziek | POST /v1/music/generations |
(geen) |
| Spraak van tekst | POST /v1/audio/speech |
(geen) |
| Tekst van een opname | POST /v1/audio/transcriptions |
(geen; de opname gaat in file) |
Een bronafbeelding is een https:// link, een data: URI (data:image/png;base64,iVBORw0…) of platte base64 van een PNG, JPEG of WebP, tot 8 per verzoek. De afbeeldingsroutes accepteren ook een multipart upload (zie hieronder). Links moeten openbare https:// links zijn; http:// links worden geweigerd. Een link die doorverwijst (bijvoorbeeld https://picsum.photos/640/360) wordt gevolgd, tot 5 keer en alleen naar andere openbare https:// links, en het model krijgt de link waar het op terechtkomt. Een link die niet naar een afbeelding leidt, of doorverwijst naar een plek die we niet kunnen gebruiken, wordt geweigerd met 400 invalid_image_url voordat er iets wordt vastgehouden of in rekening gebracht. Afbeeldingen die inline worden verzonden, maken het verzoek groter: houd het onder 10 MB, of stuur links.
In een chatbericht (image_url in messages[].content) wordt een link (https:// of http://) geopend door UberLLM en naar het model gestuurd als een data: URL, omdat de meeste vision modellen alleen dat accepteren. Elke afbeelding kan tot 20 MB zijn (40 MB per verzoek), en doorverwijzingen worden tot 5 keer gevolgd, alleen naar openbare adressen. Gemini modellen krijgen de link zoals deze is. Een link die niet naar een afbeelding leidt, wordt geweigerd met 400 invalid_image_url, en er wordt niets in rekening gebracht.
Maak een afbeelding
Afbeeldingen komen terug in het antwoord.
curl https://api.uberllm.dev/v1/images/generations \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "venice/z-image-turbo", "prompt": "a red apple on a white table", "n": 1, "size": "1024x1024"}'
{ "created": 1792429247, "data": [{ "url": "https://api.uberllm.dev/v1/media/artifacts/<id>/0" }],
"usage": { "cost_usd": 0.0099, "max_cost_usd": 0.0109 } }
usage.cost_usd zijn de kosten van de afbeelding (ook in de X-UberLLM-Cost-USD
header). In het zeldzame antwoord waar de prijs nog niet bekend is, is het null. Je
betaalt wat de provider in rekening bracht, nooit meer dan max_cost_usd, wat ervoor
gereserveerd was.
response_format is standaard url, voor zowel /v1/images/generations als
/v1/images/edits. Stuur "response_format": "b64_json" om de afbeelding
in het antwoord te krijgen. Wanneer het model de afbeelding zelf teruggeeft, bewaart UberLLM
deze als een bestand van je account voor 24 uur en antwoordt met de link
ernaartoe (https://api.uberllm.dev/v1/files/file_…/content), die ook werkt als de
bronafbeelding voor een latere bewerking. Download een url met dezelfde key:
curl -L -o image.png -H "Authorization: Bearer $UBERLLM_API_KEY" \
"https://api.uberllm.dev/v1/media/artifacts/<id>/0"
n is 1 tot 10.
Een afbeelding bewerken
Gebruik een model dat bewerkt (de ID eindigt meestal op -edit) en stuur de bronafbeelding in image:
curl https://api.uberllm.dev/v1/images/edits \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "google/nano-banana-pro-edit", "prompt": "make the sky a sunset",
"image": "https://example.com/skyline.png"}'
Dezelfde afbeelding kan worden ingevoerd als:
"image": "data:image/png;base64,iVBORw0…""image_url": "https://…""input_images": ["https://…", "https://…"]: de eerste is de te bewerken afbeelding, de rest zijn referenties. Een invoer kan ook{"url": "…", "role": "reference"}zijn."images": [{"image_url": "https://…"}], de vorm die de OpenAI SDK's versturen
Gewone base64 werkt ook, en "input_image" wordt gelezen als "image".
Of upload het bestand, net als bij OpenAI's afbeeldingsbewerking:
curl https://api.uberllm.dev/v1/images/edits \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-F model=google/nano-banana-pro-edit -F prompt="make the sky a sunset" \
-F [email protected]
Een bewerking zonder bronafbeelding wordt geweigerd met 400 image_required. Maskers (inpainting) worden niet ondersteund.
Upload één keer een afbeelding
Upload een afbeelding naar /v1/files en gebruik deze zo vaak als je wilt in verzoeken gedurende 24 uur, in plaats van deze bij elk verzoek mee te sturen:
curl https://api.uberllm.dev/v1/files \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-F [email protected]
{ "id": "file_3f9c…", "object": "file", "bytes": 482113, "content_type": "image/png",
"filename": "skyline.png", "created_at": 1792540800, "expires_at": 1792627200,
"url": "https://api.uberllm.dev/v1/files/file_3f9c…/content" }
Plaats vervolgens de id, of de url, overal waar een bronafbeelding hoort: "image": "file_3f9c…",
"image": {"file_id": "file_3f9c…"}, "image_url": "file_3f9c…", een invoer van
input_images, of een startframe van een video. Alleen jouw account kan de bestanden ervan gebruiken.
- PNG, JPEG, WebP, GIF, HEIC of AVIF, tot 10 MB per stuk, maximaal 500 tegelijk per account bewaard.
- Bewaard gedurende 24 uur, daarna verwijderd.
GET /v1/files/{id}beschrijft er één,GET /v1/files/{id}/contentdownloadt deze,DELETE /v1/files/{id}verwijdert deze nu.
Maak een video
Een video duurt een minuut of langer, dus het is een klus: start hem, controleer hem, download hem.
1. Start hem
curl https://api.uberllm.dev/v1/video/generations \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"model": "fal-ai/vidu/q3/text-to-video/turbo", "prompt": "a red ball bouncing on green grass",
"duration_seconds": 5, "models": ["fal-ai/kling-video/v3/standard/text-to-video"]}'
models is optioneel: backupmodellen worden alleen in volgorde geprobeerd als de eerste op dit moment geen vrije provider heeft, zodat een druk moment je verzoek niet laat mislukken (zie Fallbackmodellen). De video hierboven duurt ongeveer een minuut en kost ongeveer $0.33.
Om te starten vanuit een afbeelding, gebruik een image-to-video model en voeg image_url toe:
-d '{"model": "bytedance/seedance-2-0-image-to-video", "prompt": "slow push-in as the waves roll",
"image_url": "https://example.com/first-frame.png", "duration_seconds": 5}'
Een model dat twee afbeeldingen combineert, neemt ook end_image_url (het laatste frame). Een image-to-video of reference-to-video model dat geen video kan maken van alleen tekst, wordt geweigerd met 400 image_required wanneer het verzoek geen afbeelding bevat, voordat er iets in rekening wordt gebracht. Een reference-to-video model neemt de afbeeldingen in input_images:
-d '{"model": "pixverse/pixverse-c1-reference-to-video", "prompt": "the cat walks across the room",
"input_images": [{"url": "https://example.com/cat.png", "role": "reference"}],
"aspect_ratio": "16:9", "duration_seconds": 5}'
Andere velden, waar het model ze aanbiedt: resolution (480p, 720p, 1080p…), aspect_ratio (16:9, 9:16, 1:1…) en audio (true / false; een model zonder geluidsinstelling krijgt deze niet toegestuurd en maakt de clip zoals het altijd doet). Een reference-to-video model heeft een vorm nodig, dus wanneer je aspect_ratio weglaat, wordt het verzonden als 16:9 (of de eerste vorm van het model als het geen 16:9 maakt); het schema van het model toont die standaardwaarde. De keuzes van elk model worden vermeld door GET /v1/models/<model id> (zie Opties van elk model).
Elk model maakt slechts bepaalde cliplengtes, resoluties en vormen. Een verzoek voor een die het niet maakt, wordt geweigerd met een bericht dat de beschikbare opties vermeldt, voordat er iets in rekening wordt gebracht.
HTTP 202:
{
"id": "6f1c…",
"object": "media.job",
"kind": "video",
"status": "queued",
"model": "fal-ai/vidu/q3/text-to-video/turbo",
"estimated_cost_usd": 0.32725,
"estimated_cost_usdc": "327250",
"max_cost_usd": 0.359975,
"max_cost_usdc": "359975",
"poll_url": "/v1/video/generations/6f1c…",
"cancel_url": "/v1/video/generations/6f1c…"
}
model is het model dat de klus heeft aangenomen (een backup van models toen de eerste dat niet kon). Kosten die eindigen op _usdc zijn in miljoensten van een dollar (327250 = $0.33). estimated_cost_usd is de vermelde prijs van wat je hebt gevraagd: hetzelfde nummer validate en POST /v1/quote antwoord als cost_usd. Het is de huidige prijs van het model vermenigvuldigd met de seconden (bij de gevraagde resolutie), afbeeldingen of andere eenheden. De klus wordt gefactureerd voor wat de provider ervoor in rekening bracht, wat meer of minder kan zijn. max_cost_usd is wat van je saldo wordt gereserveerd voor de klus: hetzelfde bedrag terwijl het loopt en nadat het eindigt, en het maximale bedrag dat voor de klus in rekening wordt gebracht. Een videomodel waarvan de prijs per second is, wordt per seconde van de clip gefactureerd; een model geprijsd per job kost dat per video.
2. Controleer hem elke 5–10 seconden:
curl -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/video/generations/<job id>
HTTP 202 terwijl de klus loopt, HTTP 200 zodra deze eindigt:
{
"id": "6f1c…",
"status": "succeeded",
"results": [{ "artifact_index": 0, "url": "https://api.uberllm.dev/v1/media/artifacts/6f1c…/0",
"content_type": "video/mp4", "duration_seconds": 5 }],
"usage": { "cost_usdc": "40000", "cost_usd": 0.04 }
}
Het model rapporteert de exacte kosten van een klus iets nadat het bestand klaar is, meestal binnen 30 seconden. Tot die tijd toont een succeeded klus "usage": { "cost_usd": null, "cost_pending": true }; vraag het een paar seconden later opnieuw. Als de kosten niet binnen 30 minuten zijn binnengekomen, wordt de klus gefactureerd tegen de vermelde prijs (estimated_cost_usd) en usage.cost_note vermeldt dit.
3. Download hem
curl -L -o video.mp4 -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/media/artifacts/<job id>/0
Vraag om een klus te stoppen die je niet langer nodig hebt: DELETE /v1/video/generations/<job id>. We vragen de provider om deze te stoppen; een klus die al was gemaakt, wordt zoals gewoonlijk gefactureerd, en een die wordt gestopt, eindigt canceled en kost niets.
Fal videomodellen
De modellen waarvan de ID begint met fal-ai/ draaien op Fal, onder Fal's eigen prijs: je betaalt Fal's prijs min de korting van de goedkoopste Fal-verkoper op de marktplaats op dit moment (15% korting op 30 oktober 2026; 25% korting wanneer die verkoper verkoopt). De prijs wordt bepaald door wat je aanvraagt — seconden × het tarief voor de resolutie, en of de clip geluid heeft — dus de kosten van de taak zijn bekend wanneer deze begint en estimated_cost_usd is precies wat er in rekening wordt gebracht. Een mislukte taak kost niets. Het stoppen van een taak is een 'best effort': als Fal de clip al heeft gemaakt, wordt deze in rekening gebracht.
curl https://api.uberllm.dev/v1/video/generations \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "fal-ai/wan/v2.7/text-to-video", "prompt": "a woman twirls at a garden party at night",
"duration_seconds": 15, "resolution": "720p", "aspect_ratio": "9:16"}'
Fal's eigen prijs per seconde (de jouwe is dit min de live korting; de pagina van elk model, GET /v1/models en POST /v1/quote, tonen de exacte prijs nu):
| Model | Lengtes (s) | Fal's prijs per seconde, vanaf |
|---|---|---|
fal-ai/wan/v2.7/text-to-video, …/image-to-video |
2–15 | 720p $0.10 · 1080p $0.15 |
fal-ai/kling-video/v3/standard/text-to-video, …/image-to-video |
3–15 | $0.084 · met geluid $0.126 |
fal-ai/kling-video/v3/pro/text-to-video, …/image-to-video |
3–15 | $0.112 · met geluid $0.168 |
fal-ai/kling-video/o3/standard/text-to-video, …/image-to-video |
3–15 | $0.084 · met geluid $0.112 |
fal-ai/kling-video/v2.6/pro/text-to-video, …/image-to-video |
5, 10 | $0.07 · met geluid $0.14 |
fal-ai/veo3.1/fast, fal-ai/veo3.1/fast/image-to-video |
4, 6, 8 | 720p/1080p $0.10 · met geluid $0.15 · 4k $0.30 |
fal-ai/veo3.1, fal-ai/veo3.1/image-to-video |
4, 6, 8 | 720p/1080p $0.20 · met geluid $0.40 · 4k $0.40 |
fal-ai/veo3.1/lite |
4, 6, 8 | 720p $0.03 · met geluid $0.05 · 1080p $0.05 |
fal-ai/ltx-2.3/text-to-video/fast, …/image-to-video/fast |
6, 8, 10 | 1080p $0.06 · 1440p $0.12 · 2160p $0.24 |
fal-ai/ltx-2.3/text-to-video |
6, 8, 10 | 1080p $0.08 |
fal-ai/minimax/hailuo-02/standard/text-to-video, …/image-to-video |
6, 10 | 768P $0.045 · 512P (afbeelding) $0.017 |
fal-ai/vidu/q3/text-to-video/turbo, …/image-to-video/turbo |
1–16 | 360p/540p $0.035 · 720p/1080p $0.077 |
fal-ai/vidu/q3/text-to-video, …/image-to-video |
1–16 | 360p/540p $0.07 · 720p/1080p $0.154 |
Elke prijs is Fal's eigen prijs; de korting gaat ervan af wanneer de taak begint. Als de goedkoopste verkoper een taak weigert, voert een duurdere deze uit en wordt de taak gefactureerd tegen de prijs van die verkoper, nooit meer dan estimated_cost_usd op het antwoord.
Sommige modellen kosten ons minder dan de korting van de verkoper aangeeft. Elke 6 uur vergelijken we wat de marktplaats ons in rekening heeft gebracht voor elk model gedurende de laatste 7 dagen met Fal's prijs voor dezelfde taken. Een model met ten minste 20 taken in die periode wordt dan geprijsd op dat werkelijke aandeel plus 5%, wanneer dat lager is. De modelpagina, /v1/models en de factuur gebruiken allemaal dezelfde prijs. Als dat cijfer ouder is dan 3 dagen, is de korting van de verkoper opnieuw van toepassing.
De velden zijn van ons: duration_seconds, resolution, aspect_ratio, audio en image_url (of input_images). Fal's eigen spelling (duration, generate_audio, start_image_url) werkt ook. Kling, Veo en Kling 2.6 voegen geluid toe, tenzij je "audio": false stuurt.
Taakstatus
status |
HTTP | Betekenis |
|---|---|---|
queued |
202 | Geaccepteerd, wacht op een model om te beginnen |
running |
202 | Wordt gemaakt; progress gaat van 0 naar 1 wanneer het model dit meldt |
succeeded |
200 | Klaar; download results[].url |
failed |
200 | Niet gemaakt. error.message zegt waarom; error.retryable zegt of opnieuw proberen kan werken |
canceled |
200 | Gestopt voordat het gemaakt was |
expired |
200 | Niet op tijd afgerond |
Dit zijn de enige zes waarden. failed, canceled en expired kosten niets. Een
DELETE is een verzoek om te stoppen, geen belofte: een taak die de provider toch afmaakt,
eindigt succeeded en wordt gefactureerd.
Een druk moment wordt voor u opnieuw geprobeerd. Wanneer geen provider vrij is om uw video te maken,
of er een te druk is op dit moment, start UberLLM de taak zelf opnieuw, tot twee keer extra
binnen 10 minuten. Het behoudt dezelfde job id en dezelfde maximale kosten. De
taak duurt dan alleen iets langer. U ziet failed alleen wanneer elke poging is mislukt, en een
mislukte taak kost niets.
Wachten. Stuur callback_url en wij vertellen u wanneer de taak eindigt (zie
Callbacks), of vraag de poll URL elke 5–10 seconden op. De meeste video's duren
1–5 minuten; sommige lange of 4K taken duren langer. U hoeft niet te blijven vragen om
de rekening te vereffenen: een taak die niemand controleert, wordt nog steeds afgerond en gefactureerd (of
terugbetaald) door UberLLM, en verschijnt in
Dashboard → Activiteit.
Callbacks
Voeg callback_url toe aan een video- of muziektaak: een https:// link op een openbare host.
Wanneer de taak definitief is beëindigd, stuurt UberLLM er een POST naartoe met dezelfde JSON
die GET op de taak retourneert.
{ "model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5,
"callback_url": "https://your-app.example/uberllm/jobs" }
- Wanneer. Eenmalig, wanneer de taak is beëindigd en de factuur definitief is:
succeededmetusage.cost_usdingesteld (nooitcost_pending), offailed,canceledofexpired(kosten 0). Het wordt niet opnieuw verzonden wanneer de kosten arriveren, omdat het pas daarna wordt verzonden. Ook bijoutput_upload_urlkomt de callback nadat de upload is voltooid, dusoutput_upload.statusis aldeliveredoffailed. - Headers.
Content-Type: application/json,UberLLM-Event: job.succeeded(ofjob.failed,job.canceled,job.expired),UberLLM-Event-Id: <job id>:<status>enUberLLM-Signature: t=<unix seconds>,v1=<hex>. - Opnieuw proberen. Antwoord met een 2xx binnen 15 seconden. Elk ander antwoord, of geen antwoord, wordt opnieuw geprobeerd na 30 seconden, 2 minuten, 10 minuten, 30 minuten en 2 uur, waarna het wordt opgegeven. U kunt de taak op elk moment nog steeds poll.
- Herhalingen. Een bericht kan meer dan eens arriveren (bijvoorbeeld wanneer uw antwoord verloren gaat). De event id blijft hetzelfde, dus negeer een bericht dat u al hebt verwerkt.
- Status. De taak toont hoe het is gegaan:
"callback": { "status": "delivered", "attempts": 1, "http_status": 200, "delivered_at": 1792540990 }.statusispending,deliveredoffailed(meterrorin gewone taal). - De link moet
https://zijn op een openbare host, zonder gebruikersnaam of wachtwoord erin. Het wordt nooit teruggestuurd en wordt verwijderd zodra de callback eindigt.webhook_urlwordt gelezen als hetzelfde veld. Afbeeldingen en spraak nemen het niet aan: ze komen terug in het antwoord zelf.
Controleer de handtekening
Elk bericht is ondertekend met het webhook secret van uw account. U vindt het in Dashboard → API keys → Webhook signing secret; het wordt aangemaakt de eerste keer dat u het opent, en Replace secret wisselt het direct.
v1 is de hex HMAC-SHA256 van <t>.<raw body>, gesleuteld met het volledige secret
(whsec_…). Bereken het over de ruwe bytes die u hebt ontvangen (voordat u de JSON parseert),
vergelijk in constante tijd, en weiger een t die ouder is dan 5 minuten.
Node.js (Express):
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.UBERLLM_WEBHOOK_SECRET; // whsec_…
app.post("/uberllm/jobs", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("UberLLM-Signature") || "";
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const expected = crypto.createHmac("sha256", SECRET)
.update(`${parts.t}.`).update(req.body).digest("hex");
const ok = parts.v1 && parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected)) &&
Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
if (!ok) return res.status(400).send("bad signature");
const job = JSON.parse(req.body);
// Drop a repeat: req.get("UberLLM-Event-Id") is the same each time.
console.log(job.id, job.status, job.usage?.cost_usd);
res.sendStatus(204);
});
Python (Flask):
import hashlib, hmac, os, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["UBERLLM_WEBHOOK_SECRET"].encode() # whsec_…
@app.post("/uberllm/jobs")
def uberllm_job():
raw = request.get_data() # the raw bytes, before any JSON parsing
parts = dict(p.split("=", 1) for p in request.headers.get("UberLLM-Signature", "").split(",") if "=" in p)
expected = hmac.new(SECRET, parts.get("t", "").encode() + b"." + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(parts.get("v1", ""), expected) or abs(time.time() - int(parts.get("t", "0"))) > 300:
abort(400)
job = request.get_json()
# Drop a repeat: request.headers["UberLLM-Event-Id"] is the same each time.
print(job["id"], job["status"], job.get("usage", {}).get("cost_usd"))
return "", 204
Meldingen naar een webhook
De waarschuwings-e-mails kunnen ook naar een webhook gaan: stel een link in onder
Dashboard → Credits → Voor ontwikkelaars: stuur meldingen ook naar een webhook,
of PUT /api/v1/billing/alerts {"alerts_webhook_url": "https://…"} (null schakelt het uit).
De berichten worden ondertekend, opnieuw geprobeerd en op dezelfde manier geïdentificeerd als callbacks. De
body is:
{ "id": "evt_…", "object": "event", "type": "balance.low", "created": 1792540990,
"data": { "balance_usd": 4.2, "threshold_usd": 5, "message": "Your balance is $4.20, below the $5.00 you set. Requests stop once it runs out.",
"add_credits_url": "https://uberllm.dev/dashboard/credits" } }
balance.low: het saldo is onder het bedrag gedaald dat u hebt ingesteld voor de e-mail voor laag saldo. Eenmalig verzonden elke keer dat het eronder zakt; er wordt niets verzonden totdat u een bedrag instelt.hold.not_released: geld dat voor een taak was gereserveerd, werd nog steeds vastgehouden meer dan 15 minuten nadat de taak was beëindigd.data.jobssomt ze op (id,kind,model,ended_at,held_usd) endata.held_usdis het totaal. Het geld is nog steeds van u en ons team is op de hoogte gebracht.
Hoe lang bestanden worden bewaard
Download een resultaat snel nadat het is gemaakt:
- Video- en muziekbestanden worden ongeveer 3 uur bewaard nadat de taak is voltooid.
- Afbeeldingslinks naar
/v1/media/artifacts/…worden ongeveer 15 minuten bewaard; afbeeldingslinks naar/v1/files/…voor 24 uur. Vraag om"response_format": "b64_json"om de afbeelding in het antwoord te krijgen en zelf te bewaren. - Afbeeldingen die je uploadt naar
/v1/filesworden 24 uur bewaard.
Daarna antwoordt de download 404 artifact_expired.
Stuur resultaten naar je eigen opslag
Voeg output_upload_url toe aan een video- of muziektaak: een https:// link die een HTTP PUT accepteert, zoals een presigned S3, R2 of Google Cloud Storage upload link. Wanneer de taak slaagt, uploadt UberLLM het bestand daarheen met zijn content type. Voor een taak die meerdere bestanden maakt, stuur output_upload_urls, één link per bestand in volgorde (maximaal 4).
{ "model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5,
"output_upload_url": "https://my-bucket.s3.amazonaws.com/ball.mp4?X-Amz-Signature=…" }
De status van de taak heeft dan output_upload:
"output_upload": { "status": "delivered", "attempts": 1, "delivered_at": 1792540990,
"files": [{ "artifact_index": 0, "http_status": 200, "bytes": 5242880 }] }
statusispendingtotdat de upload is voltooid, daarnadeliveredoffailed(meterrorin gewone woorden).- Een mislukte upload wordt opnieuw geprobeerd na 30 seconden, 2, 10 en 30 minuten, en wordt dan gemarkeerd als
failed; het bestand kan nog steeds worden gedownload vanresults[].urlzolang het wordt bewaard. Maak de link minstens een uur geldig. - De link moet
https://zijn op een openbare host, zonder gebruikersnaam of wachtwoord erin. Deze wordt nooit terug getoond en wordt verwijderd zodra de upload eindigt. - Afbeeldingen accepteren dit niet: een afbeelding komt terug in het antwoord zelf.
Muziek
Dezelfde drie stappen op /v1/music/generations. curl -OJ slaat het nummer op onder de bestandsnaam die we meesturen.
Spraak
Tekst gaat erin, een audiobestand komt terug als antwoord.
curl https://api.uberllm.dev/v1/audio/speech \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "x-ai/tts-xai-v1", "input": "Hello from UberLLM."}' \
-o speech.mp3
Je kunt ook voice, response_format (bijvoorbeeld mp3 of wav) en speed meesturen.
Elk model heeft zijn eigen stemmen (GET /v1/models/{id} somt ze op). Met
best-price:speech of fastest:speech weet je van tevoren niet welk model wordt gebruikt,
dus de stem wordt daarop aangepast: een stem die het model heeft, wordt behouden, de namen van OpenAI worden gekoppeld aan de
overeenkomstige stem van het model waar het die heeft (alloy → af_alloy), en elke andere stem, of
geen, krijgt de eerste stem van het model. Wanneer je een model benoemt, wordt je stem zoals hij is meegestuurd.
Het wordt gefactureerd per begonnen 1K tekens van input. Het antwoord is het audiobestand; de
X-UberLLM-Cost-USD header ervan vermeldt wat het kostte, en X-Request-Id is de ID van het verzoek
zoals vermeld in Activiteit. "validate": true, max_cost, metadata, models en
provider.max_price werken net als bij afbeeldingen (zie Wat je betaalt).
Zet een opname om in tekst
Stuur de opname als een formulier met file en model:
curl https://api.uberllm.dev/v1/audio/transcriptions \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-F model=venice/whisper-large-v3 \
-F [email protected]
{ "text": "Hello from UberLLM.", "duration": 4.2,
"usage": { "type": "duration", "seconds": 5, "cost_usd": 0.00055, "max_cost_usd": 0.00726 } }
Dit zijn de kosten: usage.cost_usd (ook in de X-UberLLM-Cost-USD header, de enige
plek voor text, srt en vtt antwoorden). Onze eigen velden gaan ook in het formulier en worden
nooit naar het model gestuurd: -F max_cost=0.10, -F "metadata[project]=podcast",
-F validate=true.
Je kunt ook language, prompt, temperature en response_format meesturen: json
(de standaard), of text, srt of vtt om platte tekst terug te krijgen. Er wordt gefactureerd per minuut
audio. Bestanden kunnen tot 40 MB groot zijn. Het formaat (mp3, wav, ogg, flac, m4a/mp4,
webm, aac) wordt gelezen uit de opname zelf, niet uit de bestandsnaam, dus een upload
genaamd tmp123.out werkt.
Met de OpenAI SDK
from openai import OpenAI
client = OpenAI(base_url="https://api.uberllm.dev/v1", api_key="<your UberLLM key>")
speech = client.audio.speech.create(model="x-ai/tts-xai-v1", voice="eve", input="Hello from UberLLM.")
speech.write_to_file("speech.mp3")
with open("speech.mp3", "rb") as f:
text = client.audio.transcriptions.create(model="venice/whisper-large-v3", file=f)
print(text.text)
Wat je betaalt
- De prijs van wat is gemaakt: wat de provider in rekening bracht, zonder UberLLM-kosten. Een afbeelding of transcriptieantwoord en een voltooide taak dragen dit als
usage.cost_usd(Amerikaanse dollars); elk antwoord dat iets heeft gemaakt, draagt het ook in deX-UberLLM-Cost-USDresponse header (voor spraak is de header de enige plek, aangezien het antwoord het audiobestand is). Het verschijnt in Dashboard → Activiteit. De rest van de reservering komt terug. - Niets voor een taak die
failed,canceledofexpiredwas, of voor een afbeelding-, spraak- of transcriptieverzoek dat mislukt. - De goedkoopste verkoper die precies maakt wat je hebt gevraagd. Veel afbeelding- en videomodellen hebben meer dan één verkoper; elk verzoek gaat naar de goedkoopste die het met jouw instellingen kan maken, en naar een andere als die het niet kan verwerken. De modellijst en elke modelpagina tonen de prijs bij de goedkoopste verkoper die nu live is.
- Bekijk je saldo en wat is gereserveerd met
GET /v1/balance(hieronder).
Controleer de prijs voordat je uitgeeft
Voeg "validate": true toe aan elk afbeelding-, video-, muziek- of spraakverzoek (voor een transcriptie, stuur validate=true als een form field met de opname). Het verzoek wordt gecontroleerd alsof het echt was (model, opties, bronafbeeldingen), er wordt niets gemaakt en niets in rekening gebracht, en HTTP 200 geeft aan wat het kost tegen de vermelde prijs (cost_usd, de prijs die op de modelpagina wordt getoond; je betaalt wat de provider in rekening bracht, wat kan verschillen) en wat wordt gereserveerd terwijl het draait (max_cost_usd, het maximale dat wordt gefactureerd):
{ "object": "quote", "model": "bytedance/seedance-2-0-image-to-video", "kind": "video",
"valid": true, "cost_usd": 0.2117, "max_cost_usd": 0.4235, "unit": "second", "units": 5, "duration_seconds": 5,
"note": "Nothing was charged. …" }
Als de verkoper van het model een instelling nodig heeft die je hebt weggelaten (een reference-to-video model heeft aspect_ratio nodig), wordt de standaardwaarde waarmee het wordt verzonden getoond op het schema van het model en in de offerte als defaults_applied, bijv. "defaults_applied": {"aspect_ratio": "16:9"}.
Een verzoek dat zou worden geweigerd, wordt op dezelfde manier geweigerd, met de reden.
Reserveer een prijs voor 15 minuten
POST /v1/quote gebruikt dezelfde body als het afbeelding-, video-, muziek- of spraakverzoek en antwoordt met de vermelde kosten (cost_usd), wat wordt gereserveerd terwijl het draait (max_cost_usd, het maximale dat wordt gefactureerd) en een quote_id (voor een transcriptie, stuur model en duration_seconds; een transcriptie zelf neemt geen quote_id, gebruik max_cost om het te begrenzen):
curl https://api.uberllm.dev/v1/quote \
-H "Authorization: Bearer $UBERLLM_API_KEY" -H "Content-Type: application/json" \
-d '{"model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5}'
{ "object": "quote", "id": "6f1c…", "quote_id": "6f1c…", "model": "kling/kling-o3",
"kind": "video", "cost_usd": 0.225, "max_cost_usd": 0.495, "unit": "job", "units": 1,
"expires_at": 1792541700, "note": "Nothing was charged. …" }
Stuur hetzelfde verzoek met "quote_id": "6f1c…" binnen 15 minuten en het wordt gefactureerd wat de provider in rekening bracht, maximaal max_cost_usd; als wat moet worden gereserveerd wanneer het start boven max_cost_usd is, wordt het kosteloos geannuleerd. Er wordt niets in rekening gebracht of gereserveerd voor de offerte zelf.
- Eén offerte start één verzoek. Het opnieuw gebruiken ervan antwoordt
409 quote_used; een taak die nooit een model heeft bereikt, geeft de offerte terug. - Het verzoek moet om hetzelfde vragen: hetzelfde model en dezelfde instellingen (prompt, size, clip length, source pictures …). Iets anders wordt geweigerd met
400 quote_mismatch.max_cost,metadataenoutput_upload_urlmogen verschillen. - Na 15 minuten antwoordt het
400 quote_expired. Chatmodellen worden per token gefactureerd en hebben geen offerte: begrens ze metprovider.max_price.
Fallback modellen en een prijsplafond
"models": ["model-b", "model-c"] noemt modellen om in volgorde te proberen wanneer de eerste nu niet kan worden geleverd (no_available_provider) of boven je provider.max_price is. Elke andere weigering wordt direct beantwoord. De model van het antwoord noemt het model dat het heeft gemaakt (een spraakantwoord is het audiobestand zelf: Activiteit toont het model). Een verzoek met quote_id neemt geen models, en een transcriptie neemt geen van beide.
"provider": {"max_price": 0.05} is het maximale dat één eenheid (de pricing unit van het model: image, second, megapixel, minute, 1K characters of request) mag kosten, in Amerikaanse dollars. Een model daarboven wordt geweigerd met 400 max_price_exceeded, en het verzoek wordt nooit meer gefactureerd dan max_price keer zijn eenheden. Andere provider opties worden geweigerd met 400 unsupported_routing_option, omdat de verkoperskeuze voor mediaverzoeken niet per verzoek kan worden gestuurd.
"model": "best-price:image" (of image-edit, text-to-video, image-to-video, music, speech, transcription) kiest het goedkoopste live model voor de taak; fastest: de snelst gemeten. Zie Model aliassen.
Tags
"metadata": {"project": "spring-ads"} (maximaal 16 tekstwaarden) wordt opgeslagen bij de taak, geretourneerd bij de status, getoond in Activiteit en in de CSV-export, en nooit naar een model gestuurd. Bij een transcriptie, stuur ze als form fields: -F "metadata[project]=spring-ads". Zie Tags.
Stel een plafond in
Stuur "max_cost" (Amerikaanse dollars, bijv. 0.50) mee met elk afbeelding-, video-, muziek- of spraakverzoek (een form field bij een transcriptie). Als het meer kan kosten dan dat, wordt het geweigerd met 400 max_cost_too_low en wordt er niets in rekening gebracht. Voor een video- of muziektaak wordt het exacte plafond ingesteld wanneer de taak start; als het dan boven je max_cost uitkomt, wordt de taak kosteloos geannuleerd. Met "validate": true, voegt de offerte within_max_cost toe.
Opnieuw proberen zonder twee keer te betalen
Stuur een Idempotency-Key header (elke unieke string tot 255 characters, zoals een UUID) wanneer je een video- of muziektaak start. Als je verbinding wegvalt en je stuurt hetzelfde verzoek opnieuw met dezelfde key binnen 24 uur, krijg je dezelfde taak terug in plaats van een tweede. Dezelfde key met een ander verzoek wordt geweigerd met 409 idempotency_key_reused. Afbeelding-, spraak- en transcriptieverzoeken nemen geen key: een mislukte werd niet in rekening gebracht, dus stuur het opnieuw.
Je saldo
curl -H "Authorization: Bearer $UBERLLM_API_KEY" https://api.uberllm.dev/v1/balance
{ "balance_usd": 12.40, "held_usd": 0.35, "available_usd": 12.05 }
held_usd is gereserveerd voor lopende verzoeken; het komt terug (minus de werkelijke
kosten) wanneer ze zijn voltooid. available_usd is wat nieuwe verzoeken kunnen gebruiken.
Opties van elk model
GET /v1/models?type=image (of video, music, speech, transcription,
audio voor beide, chat, all; meerdere samengevoegd met komma's; zonder
type is de lijst alleen chatmodellen) toont de modellen die je nu kunt aanroepen, elk met zijn type, de
endpoints om het naartoe te sturen en zijn pricing. GET /v1/models/<model id> geeft één
model, en voor een mediamodel een parameters object: een JSON Schema van de request
body met de clip lengtes, resoluties, beeldverhoudingen en groottes die het accepteert, en
welke bronafbeelding het nodig heeft.
curl -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/models/pixverse/pixverse-c1-reference-to-video
pricing heeft usd (het meeste wat één unit nu kost) en list_usd (de
eigen prijs van de modelmaker); een chatmodel heeft input_usd, output_usd en hun
list_ prijzen per 1M tokens.
Fouten
| HTTP | code | betekenis |
|---|---|---|
| 400 | wrong_endpoint |
bijv. een afbeeldingsmodel verzonden naar /v1/video/generations, een chatmodel verzonden naar een afbeeldingsroute, of een spraakmodel verzonden naar /v1/audio/transcriptions; het bericht noemt het juiste pad. Er wordt niets in rekening gebracht, en Activiteit vermeldt het als geweigerd |
| 400 | invalid_request |
het verzoek is fout (het bericht zegt waarom, bijv. een duur die het model niet aanbiedt of een ontbrekende bronafbeelding) |
| 400 | image_required |
een bewerking, of een afbeelding-naar-video- of referentie-naar-video-model, zonder bronafbeelding |
| 400 | max_cost_too_low |
het kan meer kosten dan uw max_cost; er werd niets in rekening gebracht |
| 409 | idempotency_key_reused |
die Idempotency-Key werd gebruikt voor een ander verzoek |
| 400 | quote_mismatch / quote_expired |
het verzoek is niet het geciteerde, of de offerte is ouder dan 15 minuten |
| 404 | quote_not_found |
geen dergelijke offerte op uw account |
| 409 | quote_used |
die offerte heeft al een verzoek gestart |
| 400 | max_price_exceeded |
het model kost meer per eenheid dan uw provider.max_price |
| 400 | unsupported_routing_option |
een provider optie anders dan max_price |
| 404 | file_not_found |
geen dergelijk geüpload bestand op uw account, of het is verlopen |
| 413 | file_too_large |
een upload van meer dan 10 MB |
| 429 | too_many_files |
500 uploads worden al bewaard; verwijder er enkele of wacht tot ze verlopen |
| 503 | files_unavailable |
uploads zijn momenteel niet beschikbaar |
| 413 | request_too_large |
het verzoek overschrijdt de groottelimiet (40 MB); stuur afbeeldingen als https:// links en splits lange opnames |
| 402 | insufficient_credits |
uw saldo kan de maximale kosten van de taak niet dekken; het bericht zegt hoeveel er nodig is |
| 404 | model_not_found / not_found |
geen dergelijk model, of geen dergelijke taak op uw account |
| 404 | artifact_expired |
het bestand wordt niet langer bewaard (zie hierboven) |
| 429 | rate_limited |
wacht de seconden in Retry-After (een paar seconden als het afwezig is), probeer het dan opnieuw; X-RateLimit-Remaining toont hoeveel verzoeken er deze minuut nog over zijn |
| 503 | no_available_provider |
geen enkele verkoper kan het nu maken; UberLLM heeft de anderen al geprobeerd. Het bericht noemt de modellen van dezelfde soort die nu werken |