Bilder, Video, Musik und Sprache
Der Schlüssel, den Sie für Text verwenden, erstellt auch Bilder, Videos, Musik und Sprache und wandelt Aufnahmen in Text um, vom selben Guthaben. Wählen Sie ein Modell in der Modelltabelle (oder ?type=image, ?type=music, ?type=audio); auf jeder Modellseite werden Preis, Typ und eine funktionierende Anfrage angezeigt.
| Sie möchten | Route | Quellbild geht in |
|---|---|---|
| Ein neues Bild aus einem Prompt | POST /v1/images/generations |
(keine) |
| Ein bearbeitetes Bild | POST /v1/images/edits |
image (oder image_url, input_images, images) |
| Ein Video aus einem Prompt | POST /v1/video/generations |
(keine) |
| Ein Video, das mit einem Bild beginnt | POST /v1/video/generations |
image_url (erstes Frame); end_image_url für das letzte Frame |
| Ein Video aus Referenzbildern | POST /v1/video/generations |
input_images mit "role": "reference" |
| Eine Textantwort zu einem Bild | POST /v1/chat/completions |
ein image_url part in messages[].content |
| Musik | POST /v1/music/generations |
(keine) |
| Sprache aus Text | POST /v1/audio/speech |
(keine) |
| Text aus einer Aufnahme | POST /v1/audio/transcriptions |
(keine; die Aufnahme geht in file) |
Ein Quellbild ist ein https:// Link, ein data: URI (data:image/png;base64,iVBORw0…) oder einfaches base64 eines PNG, JPEG oder WebP, bis zu 8 pro Anfrage. Die Bild-Routen akzeptieren auch einen Multipart-Upload (siehe unten). Links müssen öffentliche https:// Links sein; http:// Links werden abgelehnt. Ein Link, der weiterleitet (zum Beispiel https://picsum.photos/640/360), wird bis zu 5 Mal verfolgt und nur zu anderen öffentlichen https:// Links, und das Modell erhält den Link, auf dem es landet. Ein Link, der nicht zu einem Bild führt oder an einen Ort weiterleitet, den wir nicht verwenden können, wird mit 400 invalid_image_url abgelehnt, bevor etwas reserviert oder berechnet wird. Inline gesendete Bilder machen die Anfrage größer: Halten Sie sie unter 10 MB, oder senden Sie Links.
In einer Chat-Nachricht (image_url in messages[].content) wird ein Link (https:// oder http://) von UberLLM geöffnet und als data: URL an das Modell gesendet, da die meisten Vision-Modelle nur dies akzeptieren. Jedes Bild kann bis zu 20 MB groß sein (40 MB pro Anfrage), und Weiterleitungen werden bis zu 5 Mal verfolgt, nur zu öffentlichen Adressen. Gemini-Modelle erhalten den Link, wie er ist. Ein Link, der nicht zu einem Bild führt, wird mit 400 invalid_image_url abgelehnt, und es wird nichts berechnet.
Bild erstellen
Bilder kommen in der Antwort zurück.
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 ist, was das Bild gekostet hat (auch im X-UberLLM-Cost-USD Header). In der seltenen Antwort, wo der Preis noch nicht bekannt ist, ist er null. Sie zahlen, was der Anbieter berechnet hat, nie mehr als max_cost_usd, was dafür reserviert wurde.
response_format ist standardmäßig url, für /v1/images/generations und /v1/images/edits gleichermaßen. Senden Sie "response_format": "b64_json", um das Bild stattdessen in der Antwort zu erhalten. Wenn das Modell das Bild selbst zurückgibt, speichert UberLLM es als Datei Ihres Kontos für 24 Stunden und antwortet mit seinem Link (https://api.uberllm.dev/v1/files/file_…/content), der auch als Quellbild einer späteren Bearbeitung dient. Laden Sie eine url mit demselben Schlüssel herunter:
curl -L -o image.png -H "Authorization: Bearer $UBERLLM_API_KEY" \
"https://api.uberllm.dev/v1/media/artifacts/<id>/0"
n ist 1 bis 10.
Bild bearbeiten
Nutzen Sie ein Modell, das bearbeitet (dessen ID normalerweise auf -edit endet), und senden Sie das Quellbild 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"}'
Dasselbe Bild kann als Folgendes übermittelt werden:
"image": "data:image/png;base64,iVBORw0…""image_url": "https://…""input_images": ["https://…", "https://…"]: das erste ist das zu bearbeitende Bild, der Rest sind Referenzen. Ein Eintrag kann auch{"url": "…", "role": "reference"}sein."images": [{"image_url": "https://…"}], das Format, das die OpenAI SDKs senden
Einfaches base64 funktioniert auch, und "input_image" wird als "image" gelesen.
Oder laden Sie die Datei hoch, wie bei der Bildbearbeitung von OpenAI:
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]
Eine Bearbeitung ohne Quellbild wird mit 400 image_required abgelehnt. Masken (Inpainting) werden nicht unterstützt.
Ein Bild einmal hochladen
Laden Sie ein Bild auf /v1/files hoch und verwenden Sie es für 24 Stunden in so vielen Anfragen, wie Sie möchten, anstatt es in jeder Anfrage erneut zu senden:
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" }
Platzieren Sie dann die ID oder das url überall dort, wo ein Quellbild hingehört: "image": "file_3f9c…",
"image": {"file_id": "file_3f9c…"}, "image_url": "file_3f9c…", ein Eintrag von
input_images oder der Startframe eines Videos. Nur Ihr Konto kann seine Dateien verwenden.
- PNG, JPEG, WebP, GIF, HEIC oder AVIF, jeweils bis zu 10 MB, maximal 500 pro Konto gleichzeitig gespeichert.
- Für 24 Stunden gespeichert, dann gelöscht.
GET /v1/files/{id}beschreibt eines,GET /v1/files/{id}/contentlädt es herunter,DELETE /v1/files/{id}löscht es jetzt.
Ein Video erstellen
Ein Video dauert eine Minute oder länger, es ist also ein Auftrag: starten, prüfen, herunterladen.
1. Starten
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 ist optional: Backup-Modelle werden der Reihe nach nur dann versucht, wenn das erste Modell gerade keinen freien Anbieter hat, damit ein ausgelasteter Moment Ihre Anfrage nicht fehlschlagen lässt (siehe Fallback-Modelle). Das obige Video dauert etwa eine Minute und kostet etwa $0.33.
Um von einem Bild aus zu starten, verwenden Sie ein Image-to-Video-Modell und fügen Sie image_url hinzu:
-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}'
Ein Modell, das zwei Bilder mischt, nimmt auch end_image_url (den letzten Frame).
Ein Image-to-Video- oder Reference-to-Video-Modell, das kein Video nur aus Text erstellen kann, wird mit 400 image_required abgelehnt, wenn die Anfrage kein Bild enthält, bevor etwas berechnet wird. Ein Reference-to-Video-Modell nimmt die Bilder 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}'
Weitere Felder, sofern das Modell sie anbietet: resolution (480p, 720p, 1080p…), aspect_ratio (16:9, 9:16, 1:1…) und audio (true / false; ein Modell ohne Toneinstellung erhält diese nicht und erstellt den Clip wie immer). Ein Reference-to-Video-Modell benötigt eine Form, daher wird, wenn Sie aspect_ratio weglassen, 16:9 gesendet (oder die erste Form des Modells, wenn es 16:9 nicht erstellt); das Schema des Modells zeigt diese Standardeinstellung. Die Optionen jedes Modells werden von GET /v1/models/<model id> aufgelistet (siehe Optionen jedes Modells).
Jedes Modell erstellt nur bestimmte Clip-Längen, Auflösungen und Formen. Eine Anfrage für eine, die es nicht erstellt, wird mit einer Nachricht abgelehnt, die die verfügbaren auflistet, bevor etwas berechnet wird.
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 ist das Modell, das den Auftrag übernommen hat (ein Backup von models, wenn das erste nicht konnte). Kosten, die auf _usdc enden, sind in Millionstel eines Dollars (327250 = $0.33). estimated_cost_usd ist der gelistete Preis dessen, was Sie angefragt haben: dieselbe Zahl validate und POST /v1/quote antworten wie cost_usd. Es ist der aktuelle Preis des Modells multipliziert mit den Sekunden (in der angefragten Auflösung), Bildern oder anderen Einheiten. Der Auftrag wird mit dem berechnet, was der Anbieter dafür verlangt hat, was mehr oder weniger sein kann. max_cost_usd ist der Betrag, der von Ihrem Guthaben für den Auftrag einbehalten wird: derselbe Betrag, während er läuft und nachdem er beendet ist, und der Höchstbetrag, der für den Auftrag berechnet wird. Ein Videomodell, dessen Preis pro second ist, wird pro Sekunde des Clips abgerechnet; eines, das pro job bepreist ist, kostet das pro Video.
2. Prüfen alle 5–10 Sekunden:
curl -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/video/generations/<job id>
HTTP 202 während der Auftrag läuft, HTTP 200 sobald er endet:
{
"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 }
}
Das Modell meldet die genaue Gebühr eines Auftrags kurz nachdem die Datei fertig ist, normalerweise innerhalb von 30 Sekunden. Bis dahin zeigt ein succeeded Auftrag "usage": { "cost_usd": null, "cost_pending": true }; fragen Sie ein paar Sekunden später erneut an. Wenn die Gebühr nicht innerhalb von 30 Minuten eingegangen ist, wird der Auftrag zum gelisteten Preis (estimated_cost_usd) abgerechnet und usage.cost_note gibt dies an.
3. Herunterladen
curl -L -o video.mp4 -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/media/artifacts/<job id>/0
Bitten Sie darum, einen Auftrag zu stoppen, den Sie nicht mehr benötigen: DELETE /v1/video/generations/<job id>. Wir bitten den Anbieter, ihn zu stoppen; ein Auftrag, den er bereits erstellt hatte, wird wie gewohnt abgerechnet, und einer, den er stoppt, endet canceled und kostet nichts.
Fal Videomodelle
Die Modelle, deren ID mit fal-ai/ beginnt, laufen auf Fal, unter Fal's eigenem Preis:
Sie zahlen Fal's Preis abzüglich des Rabatts des günstigsten Fal-Verkäufers auf dem
Marktplatz im Moment (15% Rabatt auf 30. Oktober 2026; 25% Rabatt, wann immer dieser Verkäufer
verkauft). Der Preis wird durch Ihre Anfrage festgelegt – Sekunden × den Tarif für die
Auflösung und ob der Clip Ton hat – so sind die Kosten des Auftrags bekannt, wenn er
beginnt, und estimated_cost_usd ist genau das, was abgerechnet wird. Ein fehlgeschlagener Auftrag
kostet nichts. Das Stoppen eines Auftrags ist ein Best-Effort-Versuch: Wenn Fal den Clip bereits erstellt hat,
wird er abgerechnet.
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 eigener Preis pro Sekunde (Ihr Preis ist dieser abzüglich des Live-Rabatts; die
Seite jedes Modells, GET /v1/models und POST /v1/quote, zeigen den genauen Preis jetzt):
| Modell | Längen (s) | Fal's Preis pro Sekunde, ab |
|---|---|---|
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 · mit Ton $0.126 |
fal-ai/kling-video/v3/pro/text-to-video, …/image-to-video |
3–15 | $0.112 · mit Ton $0.168 |
fal-ai/kling-video/o3/standard/text-to-video, …/image-to-video |
3–15 | $0.084 · mit Ton $0.112 |
fal-ai/kling-video/v2.6/pro/text-to-video, …/image-to-video |
5, 10 | $0.07 · mit Ton $0.14 |
fal-ai/veo3.1/fast, fal-ai/veo3.1/fast/image-to-video |
4, 6, 8 | 720p/1080p $0.10 · mit Ton $0.15 · 4k $0.30 |
fal-ai/veo3.1, fal-ai/veo3.1/image-to-video |
4, 6, 8 | 720p/1080p $0.20 · mit Ton $0.40 · 4k $0.40 |
fal-ai/veo3.1/lite |
4, 6, 8 | 720p $0.03 · mit Ton $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 (Bild) $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 |
Jeder Preis ist Fal's eigener; der Rabatt wird abgezogen, wenn der Auftrag beginnt. Wenn der
günstigste Verkäufer einen Auftrag ablehnt, übernimmt ihn ein teurerer, und der Auftrag wird zu
dessen Preis abgerechnet, niemals mehr als estimated_cost_usd in der Antwort.
Einige Modelle kosten uns weniger, als der Verkäuferrabatt angibt. Alle 6 Stunden
vergleichen wir, was uns der Marktplatz für jedes Modell in den letzten 7 Tagen
berechnet hat, mit Fal's Preis für dieselben Aufträge. Ein Modell mit mindestens 20 Aufträgen in dieser Zeit
wird dann zu diesem realen Anteil plus 5% bepreist, wenn dieser niedriger ist. Die Modellseite,
/v1/models und die Rechnung verwenden alle denselben Preis. Wenn dieser Wert älter als
3 Tage ist, gilt der Verkäuferrabatt erneut.
Die Felder sind unsere: duration_seconds, resolution, aspect_ratio, audio
und image_url (oder input_images). Fal's eigene Schreibweise (duration,
generate_audio, start_image_url) funktioniert auch. Kling, Veo und Kling 2.6 fügen Ton
hinzu, es sei denn, Sie senden "audio": false.
Job-Status
status |
HTTP | Bedeutung |
|---|---|---|
queued |
202 | Akzeptiert, wartet darauf, dass ein Modell ihn startet |
running |
202 | Wird erstellt; progress wechselt von 0 zu 1, wenn das Modell es meldet |
succeeded |
200 | Fertig; results[].url herunterladen |
failed |
200 | Nicht erstellt. error.message erklärt warum; error.retryable sagt, ob ein erneuter Versuch funktionieren kann |
canceled |
200 | Gestoppt, bevor er erstellt wurde |
expired |
200 | Nicht rechtzeitig fertiggestellt |
Dies sind die einzigen sechs Werte. failed, canceled und expired kosten nichts. Ein
DELETE ist eine Anfrage zum Stoppen, kein Versprechen: ein Auftrag, den der Anbieter
trotzdem beendet, endet succeeded und wird abgerechnet.
Ein ausgelasteter Zeitpunkt wird für Sie wiederholt. Wenn kein Anbieter frei ist, um Ihr Video zu erstellen,
oder einer gerade zu beschäftigt ist, startet UberLLM den Auftrag von selbst erneut, bis zu zwei weitere
Male innerhalb von 10 Minuten. Dabei behält er dieselbe job id und dieselben maximalen Kosten. Der
Auftrag dauert dann einfach etwas länger. Sie sehen failed nur, wenn jeder Versuch fehlgeschlagen ist, und ein
fehlgeschlagener Auftrag kostet nichts.
Warten. Senden Sie callback_url und wir sagen Ihnen, wann der Auftrag endet (siehe
Callbacks), oder fragen Sie die poll URL alle 5–10 Sekunden ab. Die meisten Videos dauern
1–5 Minuten; einige lange oder 4K Aufträge dauern länger. Sie müssen nicht ständig nach
der Abrechnung fragen: ein Auftrag, den niemand überprüft, wird von UberLLM trotzdem abgeschlossen
und abgerechnet (oder erstattet), und erscheint unter
Dashboard → Activity.
Callbacks
Fügen Sie callback_url zu einem Video- oder Musik-Job hinzu: einen https:// Link auf einem öffentlichen Host.
Wenn der Job endgültig abgeschlossen ist, sendet UberLLM eine POST dorthin mit demselben JSON,
das GET für den Job zurückgibt.
{ "model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5,
"callback_url": "https://your-app.example/uberllm/jobs" }
- Wann. Einmal, wenn der Job beendet und seine Abrechnung final ist:
succeededmit gesetztemusage.cost_usd(niemalscost_pending), oderfailed,canceledoderexpired(Kosten 0). Sie wird nicht erneut gesendet, wenn die Kosten eintreffen, da sie erst danach gesendet wird. Auch beioutput_upload_urlkommt der Callback, nachdem der Upload abgeschlossen ist, sodassoutput_upload.statusbereitsdeliveredoderfailedist. - Header.
Content-Type: application/json,UberLLM-Event: job.succeeded(oderjob.failed,job.canceled,job.expired),UberLLM-Event-Id: <job id>:<status>undUberLLM-Signature: t=<unix seconds>,v1=<hex>. - Wiederholungen. Antworten Sie mit einem beliebigen 2xx innerhalb von 15 Sekunden. Jede andere Antwort oder keine Antwort wird nach 30 Sekunden, 2 Minuten, 10 Minuten, 30 Minuten und 2 Stunden erneut versucht und dann aufgegeben. Sie können den Job jederzeit abfragen.
- Wiederholungen. Eine Nachricht kann mehr als einmal ankommen (zum Beispiel, wenn Ihre Antwort verloren geht). Die Event-ID bleibt gleich, also verwerfen Sie eine, die Sie bereits bearbeitet haben.
- Status. Der Job zeigt, wie es gelaufen ist:
"callback": { "status": "delivered", "attempts": 1, "http_status": 200, "delivered_at": 1792540990 }.statusistpending,deliveredoderfailed(miterrorin einfachen Worten). - Der Link muss
https://auf einem öffentlichen Host sein, ohne Benutzernamen oder Passwort. Er wird niemals zurück angezeigt und gelöscht, sobald der Callback endet.webhook_urlwird als dasselbe Feld gelesen. Bilder und Sprache nehmen ihn nicht an: Sie kommen in der Antwort selbst zurück.
Signatur prüfen
Jede Nachricht ist mit dem Webhook-Secret Ihres Kontos signiert. Sie finden es unter Dashboard → API keys → Webhook signing secret; es wird erstellt, wenn Sie es zum ersten Mal öffnen, und Secret ersetzen tauscht es sofort aus.
v1 ist der hex HMAC-SHA256 von <t>.<raw body>, verschlüsselt mit dem gesamten Secret
(whsec_…). Berechnen Sie ihn über die empfangenen Rohbytes (bevor Sie das JSON parsen),
vergleichen Sie in konstanter Zeit und lehnen Sie einen t ab, der älter als 5 Minuten ist.
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
Benachrichtigungen an einen Webhook
Die Benachrichtigungs-E-Mails können auch an einen Webhook gesendet werden: setzen Sie einen Link unter
Dashboard → Credits → For developers: also send alerts to a webhook,
oder PUT /api/v1/billing/alerts {"alerts_webhook_url": "https://…"} (null schaltet es aus).
Die Nachrichten werden auf dieselbe Weise wie Callbacks signiert, wiederholt und identifiziert. Der
Body ist:
{ "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: der Kontostand ist unter den Betrag gefallen, den Sie für die E-Mail bei niedrigem Kontostand festgelegt haben. Wird einmal gesendet, jedes Mal, wenn er darunter fällt; es wird nichts gesendet, bis Sie einen Betrag festlegen.hold.not_released: für einen Job zurückgelegtes Geld wurde mehr als 15 Minuten nach Beendigung des Jobs immer noch gehalten.data.jobslistet sie auf (id,kind,model,ended_at,held_usd) unddata.held_usdist die Summe. Das Geld gehört Ihnen immer noch und unser Team wurde benachrichtigt.
Wie lange Dateien aufbewahrt werden
Laden Sie ein Ergebnis bald nach seiner Erstellung herunter:
- Video- und Musikdateien werden nach Beendigung des Jobs für etwa 3 Stunden aufbewahrt.
- Bildlinks zu
/v1/media/artifacts/…werden für etwa 15 Minuten aufbewahrt; Bildlinks zu/v1/files/…für 24 Stunden. Fragen Sie nach"response_format": "b64_json", um das Bild in der Antwort zu erhalten und selbst zu speichern. - Bilder, die Sie auf
/v1/fileshochladen, werden für 24 Stunden aufbewahrt.
Danach antwortet der Download 404 artifact_expired.
Ergebnisse an Ihren eigenen Speicher senden
Fügen Sie output_upload_url zu einem Video- oder Musik-Job hinzu: einen https:// Link, der einen HTTP PUT akzeptiert, wie einen vorab signierten S3, R2 oder Google Cloud Storage Upload-Link. Wenn der Job erfolgreich ist, lädt UberLLM die Datei mit ihrem Content-Type dorthin hoch. Für einen Job, der mehrere Dateien erstellt, senden Sie output_upload_urls, einen Link pro Datei in der richtigen Reihenfolge (maximal 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=…" }
Der Status des Jobs enthält dann output_upload:
"output_upload": { "status": "delivered", "attempts": 1, "delivered_at": 1792540990,
"files": [{ "artifact_index": 0, "http_status": 200, "bytes": 5242880 }] }
statusistpending, bis der Upload abgeschlossen ist, danndeliveredoderfailed(miterrorin einfachen Worten).- Ein fehlgeschlagener Upload wird nach 30 Sekunden, 2, 10 und 30 Minuten erneut versucht und dann als
failedmarkiert; die Datei kann weiterhin vonresults[].urlheruntergeladen werden, solange sie aufbewahrt wird. Machen Sie den Link für mindestens eine Stunde gültig. - Der Link muss
https://auf einem öffentlichen Host sein, ohne Benutzernamen oder Passwort. Er wird niemals zurück angezeigt und gelöscht, sobald der Upload beendet ist. - Bilder akzeptieren dies nicht: Ein Bild kommt in der Antwort selbst zurück.
Musik
Die gleichen drei Schritte unter /v1/music/generations. curl -OJ speichert den Track unter dem Dateinamen, den wir senden.
Sprache
Text wird eingegeben, eine Audiodatei kommt als Antwort zurück.
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
Sie können auch voice, response_format (zum Beispiel mp3 oder wav) und speed senden.
Jedes Modell hat seine eigenen Stimmen (GET /v1/models/{id} listet sie auf). Mit
best-price:speech oder fastest:speech wissen Sie im Voraus nicht, welches Modell verwendet wird,
daher wird die Stimme daran angepasst: Eine Stimme, die das Modell hat, wird beibehalten, OpenAIs Namen werden der
passenden Stimme des Modells zugeordnet, wo es eine gibt (alloy → af_alloy), und jede andere Stimme, oder
keine, erhält die erste Stimme des Modells. Wenn Sie ein Modell benennen, wird Ihre Stimme unverändert gesendet.
Es wird pro angefangene 1K Zeichen von input abgerechnet. Die Antwort ist die Audiodatei; ihr
X-UberLLM-Cost-USD Header gibt an, was sie gekostet hat, und X-Request-Id ist die ID der Anfrage,
wie in der Aktivität aufgeführt. "validate": true, max_cost, metadata, models und
provider.max_price funktionieren wie bei Bildern (siehe Was Sie bezahlen).
Eine Aufnahme in Text umwandeln
Senden Sie die Aufnahme als Formular zusammen mit file und 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 } }
usage.cost_usd sind die Kosten (auch im X-UberLLM-Cost-USD Header, dem einzigen Ort für text, srt und vtt Antworten). Unsere eigenen Felder werden ebenfalls im Formular übermittelt und niemals an das Modell gesendet: -F max_cost=0.10, -F "metadata[project]=podcast", -F validate=true.
Sie können auch language, prompt, temperature und response_format senden: json (die Standardeinstellung), oder text, srt oder vtt, um reinen Text zurückzuerhalten. Die Abrechnung erfolgt pro Audiominute. Dateien können bis zu 40 MB groß sein. Das Format (mp3, wav, ogg, flac, m4a/mp4, webm, aac) wird aus der Aufnahme selbst gelesen, nicht aus ihrem Dateinamen, sodass ein Upload namens tmp123.out funktioniert.
Mit dem 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)
Was Sie zahlen
- Der Preis dessen, was erstellt wurde: was der Anbieter berechnet hat, ohne UberLLM-Gebühr. Eine Bild- oder Transkriptionsantwort und ein abgeschlossener Auftrag tragen ihn als
usage.cost_usd(US-Dollar); jede Antwort, die etwas erstellt hat, trägt ihn auch imX-UberLLM-Cost-USDResponse Header (bei Sprache ist der Header der einzige Ort, da die Antwort die Audiodatei ist). Er wird im Dashboard → Aktivität angezeigt. Der Rest des gehaltenen Betrags kommt zurück. - Nichts für einen Auftrag, der
failed,canceledoderexpiredwar, oder für eine Bild-, Sprach- oder Transkriptionsanfrage, die fehlschlägt. - Der günstigste Anbieter, der genau das erstellt, was Sie angefragt haben. Viele Bild- und Videomodelle haben mehr als einen Anbieter; jede Anfrage geht an den günstigsten, der sie mit Ihren Einstellungen erstellen kann, und an einen anderen, falls dieser sie nicht annehmen kann. Die Modellliste und jede Modellseite zeigen den Preis beim aktuell günstigsten Anbieter live an.
- Sehen Sie Ihr Guthaben und was gehalten wird unter
GET /v1/balance(unten).
Preis prüfen, bevor Sie ausgeben
Fügen Sie "validate": true zu jeder Bild-, Video-, Musik- oder Sprachanfrage hinzu (für eine Transkription senden Sie validate=true als Formularfeld mit der Aufnahme). Die Anfrage wird geprüft, als wäre sie echt (Modell, Optionen, Quellbilder), nichts wird erstellt und nichts berechnet, und HTTP 200 gibt an, was es zum gelisteten Preis kostet (cost_usd, der auf der Modellseite angezeigte Preis; Sie zahlen, was der Anbieter berechnet hat, was abweichen kann) und was während der Ausführung gehalten wird (max_cost_usd, der Höchstbetrag, der abgerechnet wird):
{ "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. …" }
Wenn der Anbieter des Modells eine Einstellung benötigt, die Sie weggelassen haben (ein Referenz-zu-Video-Modell benötigt aspect_ratio), wird der Standardwert, mit dem es gesendet wird, im Schema des Modells und im Angebot als defaults_applied angezeigt, z.B. "defaults_applied": {"aspect_ratio": "16:9"}.
Eine Anfrage, die abgelehnt würde, wird auf die gleiche Weise abgelehnt, mit Angabe des Grundes.
Preis für 15 Minuten halten
POST /v1/quote nimmt denselben Body wie die Bild-, Video-, Musik- oder Sprachanfrage und antwortet mit den gelisteten Kosten (cost_usd), dem Betrag, der während der Ausführung gehalten wird (max_cost_usd, der Höchstbetrag, der abgerechnet wird) und einem quote_id (für eine Transkription senden Sie model und duration_seconds; eine Transkription selbst benötigt kein quote_id, verwenden Sie max_cost, um sie zu 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. …" }
Senden Sie dieselbe Anfrage mit "quote_id": "6f1c…" innerhalb von 15 Minuten, und es wird Ihnen berechnet, was der Anbieter in Rechnung gestellt hat, höchstens max_cost_usd; wenn der Betrag, der beim Start gehalten werden muss, über max_cost_usd liegt, wird sie kostenlos storniert. Für das Angebot selbst wird nichts berechnet oder gehalten.
- Ein Angebot startet eine Anfrage. Eine erneute Verwendung antwortet
409 quote_used; ein Auftrag, der nie ein Modell erreicht hat, gibt das Angebot zurück. - Die Anfrage muss dasselbe verlangen: dasselbe Modell und dieselben Einstellungen (prompt, Größe, Clip-Länge, Quellbilder …). Alles andere wird mit
400 quote_mismatchabgelehnt.max_cost,metadataundoutput_upload_urlkönnen abweichen. - Nach 15 Minuten antwortet es
400 quote_expired. Chat-Modelle werden pro token abgerechnet und haben kein Angebot: begrenzen Sie sie mitprovider.max_price.
Fallback-Modelle und eine Preisobergrenze
"models": ["model-b", "model-c"] benennt Modelle, die der Reihe nach versucht werden, wenn das erste gerade nicht bedient werden kann (no_available_provider) oder über Ihrem provider.max_price liegt. Jede andere Ablehnung wird sofort beantwortet. Das model der Antwort benennt das Modell, das sie erstellt hat (eine Sprachantwort ist die Audiodatei selbst: Aktivität zeigt ihr Modell). Eine Anfrage mit quote_id benötigt kein models, und eine Transkription benötigt keines von beidem.
"provider": {"max_price": 0.05} ist der Höchstbetrag, den eine Einheit (die Preisgestaltung des Modells unit: Bild, Sekunde, Megapixel, Minute, 1K characters oder Anfrage) in US-Dollar kosten darf. Ein Modell, das darüber liegt, wird mit 400 max_price_exceeded abgelehnt, und die Anfrage wird niemals über max_price mal ihren Einheiten abgerechnet. Andere provider Optionen werden mit 400 unsupported_routing_option abgelehnt, da die Anbieterwahl für Medienanfragen nicht pro Anfrage gesteuert werden kann.
"model": "best-price:image" (oder image-edit, text-to-video, image-to-video, music, speech, transcription) wählt das günstigste verfügbare Modell für den Auftrag; fastest: das schnellste gemessene. Siehe Modell-Aliase.
Tags
"metadata": {"project": "spring-ads"} (bis zu 16 Textwerte) wird mit dem Auftrag gespeichert, in dessen Status zurückgegeben, in der Aktivität und im CSV-Export angezeigt und niemals an ein Modell gesendet. Bei einer Transkription senden Sie sie als Formularfelder: -F "metadata[project]=spring-ads". Siehe Tags.
Eine Obergrenze festlegen
Senden Sie "max_cost" (US-Dollar, z.B. 0.50) mit jeder Bild-, Video-, Musik- oder Sprachanfrage (ein Formularfeld bei einer Transkription). Wenn es mehr kosten kann, wird es mit 400 max_cost_too_low abgelehnt und nichts berechnet. Für einen Video- oder Musikauftrag wird die genaue Obergrenze beim Start des Auftrags festgelegt; wenn er dann über Ihrem max_cost liegt, wird der Auftrag kostenlos storniert. Mit "validate": true fügt das Angebot within_max_cost hinzu.
Wiederholen ohne doppelte Zahlung
Senden Sie einen Idempotency-Key Header (eine beliebige eindeutige Zeichenfolge von bis zu 255 Zeichen, wie z.B. eine UUID), wenn Sie einen Video- oder Musikauftrag starten. Wenn Ihre Verbindung abbricht und Sie dieselbe Anfrage mit demselben Schlüssel innerhalb von 24 Stunden erneut senden, erhalten Sie denselben Auftrag zurück, anstatt eines zweiten. Derselbe Schlüssel mit einer anderen Anfrage wird mit 409 idempotency_key_reused abgelehnt. Bild-, Sprach- und Transkriptionsanfragen benötigen keinen Schlüssel: eine fehlgeschlagene wurde nicht berechnet, senden Sie sie also erneut.
Ihr Guthaben
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 ist für noch laufende Anfragen vorgemerkt; es kommt (abzüglich der tatsächlichen Kosten) zurück, wenn sie beendet sind. available_usd steht neuen Anfragen zur Verfügung.
Optionen jedes Modells
GET /v1/models?type=image (oder video, music, speech, transcription,
audio für beide, chat, all; mehrere mit Kommas verbunden; ohne
type ist die Liste nur Chat-Modelle) listet die Modelle auf, die Sie jetzt aufrufen können, jedes mit seinem type, dem
endpoints, an das es gesendet werden soll, und seinem pricing. GET /v1/models/<model id> gibt ein
Modell an, und für ein Medienmodell ein parameters Objekt: ein JSON Schema des Anfrage-Bodys mit den akzeptierten Clip-Längen, Auflösungen, Seitenverhältnissen und Größen und welchem Quellbild es bedarf.
curl -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/models/pixverse/pixverse-c1-reference-to-video
pricing hat usd (der höchste Preis, den ein unit jetzt kostet) und list_usd (der
eigene Preis des Modellherstellers); ein Chat-Modell hat input_usd, output_usd und deren
list_ Preise pro 1M tokens.
Fehler
| HTTP | Code | Bedeutung |
|---|---|---|
| 400 | wrong_endpoint |
z.B. ein Bildmodell an /v1/video/generations gesendet, ein Chatmodell an eine Bildroute gesendet oder ein Sprachmodell an /v1/audio/transcriptions gesendet; die Nachricht nennt den richtigen Pfad. Es wird nichts berechnet, und die Aktivität listet es als abgelehnt auf |
| 400 | invalid_request |
die Anfrage ist falsch (die Nachricht sagt, warum, z.B. eine Dauer, die das Modell nicht anbietet, oder ein fehlendes Quellbild) |
| 400 | image_required |
eine Bearbeitung oder ein Bild-zu-Video- oder Referenz-zu-Video-Modell ohne Quellbild |
| 400 | max_cost_too_low |
es kann mehr kosten als Ihre max_cost; es wurde nichts berechnet |
| 409 | idempotency_key_reused |
diese Idempotency-Key wurde für eine andere Anfrage verwendet |
| 400 | quote_mismatch / quote_expired |
die Anfrage ist nicht die zitierte, oder das Angebot ist älter als 15 Minuten |
| 404 | quote_not_found |
kein solches Angebot in Ihrem Konto |
| 409 | quote_used |
dieses Angebot hat bereits eine Anfrage gestartet |
| 400 | max_price_exceeded |
das Modell kostet pro Einheit mehr als Ihre provider.max_price |
| 400 | unsupported_routing_option |
eine provider-Option außer max_price |
| 404 | file_not_found |
keine solche hochgeladene Datei in Ihrem Konto, oder sie ist abgelaufen |
| 413 | file_too_large |
ein Upload über 10 MB |
| 429 | too_many_files |
500 Uploads werden bereits gespeichert; löschen Sie einige oder warten Sie, bis sie ablaufen |
| 503 | files_unavailable |
Uploads sind derzeit nicht verfügbar |
| 413 | request_too_large |
die Anfrage überschreitet das Größenlimit (40 MB); senden Sie Bilder als https://-Links und teilen Sie lange Aufnahmen auf |
| 402 | insufficient_credits |
Ihr Guthaben kann die maximalen Kosten des Auftrags nicht decken; die Nachricht sagt, wie viel benötigt wird |
| 404 | model_not_found / not_found |
kein solches Modell oder kein solcher Auftrag in Ihrem Konto |
| 404 | artifact_expired |
die Datei wird nicht mehr gespeichert (siehe oben) |
| 429 | rate_limited |
warten Sie die Sekunden in Retry-After (ein paar Sekunden, falls es fehlt), versuchen Sie es dann erneut; X-RateLimit-Remaining zeigt an, wie viele Anfragen in dieser Minute noch übrig sind |
| 503 | no_available_provider |
kein Anbieter kann es derzeit erstellen; UberLLM hat die anderen bereits versucht. Die Nachricht nennt die Modelle derselben Art, die jetzt funktionieren |