Schnellstart

Dein erster FFmpeg-Job auf FFHub in 3 Minuten.

Diese Anleitung führt dich durch den ersten API-Call: API-Key holen, Transkodierungs-Job einreichen und Ergebnis abholen.

1. API-Key holen

Auf ffhub.io registrieren und unter Dashboard / API Keys einen Key erstellen. Format: sk_xxxxx — geheim halten.

Bei der Registrierung gibt's kostenloses Guthaben, die Schritte hier kosten dich also nichts.

Prüfe den API-Schlüssel mit GET /v1/me und dem Header Authorization: Bearer YOUR_API_KEY. Ein gültiger Schlüssel liefert HTTP 200 mit Kontoinformationen, ein ungültiger HTTP 401. Verwende diesen Endpunkt zur Verbindungsprüfung statt des Task-Abfrageendpunkts.

2. Job einreichen

Beliebiger FFmpeg-Befehl an POST /v1/tasks. Eingaben müssen öffentliche URLs sein — lokale Pfade lehnt der Cloud-Worker ab.

curl -X POST https://api.ffhub.io/v1/tasks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "ffmpeg -i https://storage.ffhub.io/Sample_Video_File_100MB.mp4 -c:v libx264 -preset fast output.mp4"
  }'
const res = await fetch("https://api.ffhub.io/v1/tasks", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FFHUB_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    command:
      "ffmpeg -i https://storage.ffhub.io/Sample_Video_File_100MB.mp4 -c:v libx264 -preset fast output.mp4",
  }),
});
const { task_id } = await res.json();
import os, requests

res = requests.post(
    "https://api.ffhub.io/v1/tasks",
    headers={"Authorization": f"Bearer {os.environ['FFHUB_API_KEY']}"},
    json={
        "command": "ffmpeg -i https://storage.ffhub.io/Sample_Video_File_100MB.mp4 -c:v libx264 -preset fast output.mp4",
    },
)
task_id = res.json()["task_id"]

Die Antwort enthält eine task_id, mit der du den Status abfragst:

{
  "task_id": "01abcd…"
}

3. Bis zum Abschluss pollen

curl https://api.ffhub.io/v1/tasks/TASK_ID \
  -H "Authorization: Bearer YOUR_API_KEY"

Frage alle 2–5 Sekunden ab, solange status pending oder running ist. Beende das Polling bei succeeded oder failed. Lade Dateien aus outputs nur bei succeeded herunter. Lies bei failed das Feld error und melde den Fehler, ohne einen Download zu versuchen. Eine erfolgreiche HTTP-Abfrage bedeutet nicht, dass die Verarbeitung erfolgreich war. Hier ein Auszug aus einer erfolgreichen Antwort:

{
  "task_id": "01abcd…",
  "status": "succeeded",
  "progress": 100,
  "outputs": [
    {
      "filename": "output.mp4",
      "url": "https://storage.ffhub.io/outputs/01abcd…/output.mp4",
      "size": 10485760
    }
  ]
}

Die Task-Antwort enthält außerdem created_at und nach Abschluss finished_at. Dies sind ISO-8601-Zeitstempel mit Zeitzone und optionalen Sekundenbruchteilen. Zum Beispiel sind 2026-05-10T12:00:00Z und 2026-05-10T12:00:00.123Z beide gültig. Vor Abschluss kann finished_at fehlen; parse keinen fehlenden Wert und behandle ihn nicht als Abschlusszeit.

Ausgabedateien werden 7 Tage nach Abschluss der Aufgabe gelöscht — lade herunter, was du behalten willst.

Lokale Dateien hochladen

Wenn deine Eingabe noch keine öffentliche URL ist, lad sie zuerst hoch, um eine zu bekommen. Zwei Schritte:

# 1. Eine einmalige signierte PUT-URL anfordern
SIGNED=$(curl -s -X POST https://api.ffhub.io/v1/uploads/sign \
  -H "Authorization: Bearer $FFHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename":"input.mp4","size":12345678,"content_type":"video/mp4"}')

# 2. Datei direkt per PUT nach R2 — dein Server sieht die Bytes nie
curl -fsS -X PUT "$(echo "$SIGNED" | jq -r '.upload_url')" \
  -H "Content-Type: video/mp4" \
  --data-binary "@./input.mp4" || { echo "Upload fehlgeschlagen"; exit 1; }

# Das Feld .public_url ist das, was du im Task-Befehl an `-i` übergibst.

Komplette Anleitung in Dateien hochladen.

Wie es weitergeht