Zurück zur Übersicht
Für Entwickler

API-Integration

Diese Anleitung führt Sie vom ersten authentifizierten Request bis zum fertig eingebetteten Video — Schritt für Schritt und mit Beispielen, die Sie direkt kopieren können.

Überblick

Über unsere REST-API können Sie alles automatisieren, was Sie auch in der Oberfläche machen: Libraries anlegen, Videos hochladen, den Encoding-Status abfragen und fertige Videos einbetten. Das ist ideal für Shop-Systeme, Headless-CMS und eigene Workflows.

Jeder Request ist an Ihre Organisation gebunden. Sie sehen und verändern ausschließlich Daten innerhalb Ihrer eigenen Organisation — die Berechtigungen entsprechen Ihrer Rolle.

Basis-URL

https://api.videooptimizer.eu/api/v1

Authentifizierung

Alle Requests (außer dem öffentlichen Embed-Endpoint) werden mit einem Bearer-Token authentifiziert. So kommen Sie an Ihren Token:

  1. Melden Sie sich in der App an und öffnen Sie „Account → API-Tokens“.
  2. Erstellen Sie einen neuen Token und vergeben Sie einen sprechenden Namen.
  3. Kopieren Sie den Token sofort — er wird nur einmal vollständig angezeigt.

Senden Sie den Token bei jedem Request im Authorization-Header mit:

HTTP-Header
http
Authorization: Bearer vp_your_token_here

Behandeln Sie Ihren Token wie ein Passwort. Nutzen Sie ihn nur serverseitig, nie im öffentlichen Frontend-Code, und widerrufen Sie ihn sofort, falls er offengelegt wurde.

Ihr erster Request

Prüfen Sie mit einem einfachen GET, ob Ihr Token funktioniert. Dieser Request gibt alle Libraries Ihrer Organisation zurück.

cURL
bash
curl https://api.videooptimizer.eu/api/v1/libraries \
  -H "Authorization: Bearer vp_your_token_here"
JavaScript
javascript
const res = await fetch("https://api.videooptimizer.eu/api/v1/libraries", {
  headers: { Authorization: "Bearer vp_your_token_here" },
});
const { data } = await res.json();
console.log(data); // -> array of your libraries

Komplett-Ablauf: vom Upload bis zum Embed

Die folgenden vier Schritte zeigen den typischen Ablauf einer Integration: eine Library anlegen, ein Video hochladen, auf das Encoding warten und schließlich die Embed-Daten abrufen.

1 Library anlegen

Eine Library bündelt Ihre Videos und legt die Encoding-Einstellungen fest (Codecs und Auflösungen). In der Antwort finden Sie die Library-UUID (`id`), in die Sie anschließend hochladen.

cURL
bash
curl -X POST https://api.videooptimizer.eu/api/v1/libraries \
  -H "Authorization: Bearer vp_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My first library",
    "codec": "h264,h265",
    "resolutions": "360p,720p,1080p"
  }'
JavaScript
javascript
const res = await fetch("https://api.videooptimizer.eu/api/v1/libraries", {
  method: "POST",
  headers: {
    Authorization: "Bearer vp_your_token_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "My first library",
    codec: "h264,h265",
    resolutions: "360p,720p,1080p",
  }),
});
const { data: library } = await res.json();
console.log(library.id); // the library UUID you'll upload into

2 Video hochladen

Der Upload ist ein Multipart-Request. Die Ziel-Library wird über den Header `x-library-id` gewählt, der Titel optional über `x-title`. Die Antwort enthält die Video-UUID und den Status `processing`.

cURL
bash
curl -X POST https://api.videooptimizer.eu/api/v1/videos \
  -H "Authorization: Bearer vp_your_token_here" \
  -H "x-library-id: <LIBRARY_UUID>" \
  -H "x-title: My product video" \
  -F "file=@/path/to/video.mp4"
JavaScript
javascript
const form = new FormData();
form.append("file", fileInput.files[0]);

const res = await fetch("https://api.videooptimizer.eu/api/v1/videos", {
  method: "POST",
  headers: {
    Authorization: "Bearer vp_your_token_here",
    "x-library-id": "<LIBRARY_UUID>",
    "x-title": "My product video",
  },
  body: form, // do NOT set Content-Type manually — the browser adds the boundary
});
const { data } = await res.json();
console.log(data); // { uuid: "...", status: "processing" }

3 Auf das Encoding warten

Das Encoding läuft asynchron. Fragen Sie den Video-Status in Intervallen ab, bis er `ready` ist. Erst dann ist das Video abspielbar.

cURL
bash
curl https://api.videooptimizer.eu/api/v1/videos/<VIDEO_UUID> \
  -H "Authorization: Bearer vp_your_token_here"
JavaScript
javascript
async function waitUntilReady(uuid) {
  while (true) {
    const res = await fetch(`https://api.videooptimizer.eu/api/v1/videos/${uuid}`, {
      headers: { Authorization: "Bearer vp_your_token_here" },
    });
    const { data } = await res.json();
    if (data.status === "ready") return data;
    await new Promise(r => setTimeout(r, 5000)); // poll every 5s
  }
}

4 Video einbetten

Sobald das Video bereit ist, liefert der öffentliche Embed-Endpoint alle nötigen Daten für den Player. Dieser Endpoint benötigt keinen Token und kann direkt aus dem Browser aufgerufen werden.

cURL
bash
curl https://api.videooptimizer.eu/api/v1/embed/<VIDEO_UUID>
JavaScript
javascript
// Public endpoint — no token required.
const res = await fetch("https://api.videooptimizer.eu/api/v1/embed/<VIDEO_UUID>");
const { data } = await res.json();
// data contains the player sources, poster and embed URL you can render.

Wenn Sie den fertigen HTML-Embed-Code lieber per Copy-and-paste verwenden möchten, sehen Sie sich den Embed-Guide für Content-Teams.

Erweiterte Funktionen

Für den produktiven Einsatz bietet die API noch mehr: Sie können große Listen seitenweise abrufen, sehr große Dateien zuverlässig hochladen, Videos direkt von einer URL importieren lassen und sich per Webhook statt per Polling benachrichtigen lassen.

Pagination

Die Listen-Endpunkte `GET /api/v1/libraries` und `GET /api/v1/libraries/:id/videos` liefern ihre Ergebnisse seitenweise (Cursor-basiert, keine Seitenzahlen). Steuern Sie die Seitengröße über `?limit=` (Standard 50, maximal 100) und blättern Sie mit `?cursor=` weiter. Die Antwort enthält zusätzlich ein `pagination`-Objekt mit `next_cursor` und `has_more` — reichen Sie `next_cursor` als nächsten `cursor`-Wert weiter, bis `has_more` `false` ist.

cURL
bash
curl "https://api.videooptimizer.eu/api/v1/libraries?limit=20" \
  -H "Authorization: Bearer vp_your_token_here"
JavaScript
javascript
let cursor;
do {
  const url = new URL("https://api.videooptimizer.eu/api/v1/libraries");
  url.searchParams.set("limit", "20");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, {
    headers: { Authorization: "Bearer vp_your_token_here" },
  });
  const { data, pagination } = await res.json();
  // ...process this page of results...
  cursor = pagination.next_cursor;
} while (cursor);

Große Dateien & Resumable Upload

Für kleinere Dateien reicht der einfache Multipart-Upload aus Schritt 2 oben. Bei sehr großen Dateien laden Sie stattdessen in Teilen direkt zu unserem Storage hoch: `POST /api/v1/videos/upload/initiate` liefert eine vorsignierte URL pro Teil, die Sie einzeln per `PUT` hochladen; anschließend meldet `POST /api/v1/videos/upload/complete` die hochgeladenen Teile, um das Video zusammenzusetzen.

cURL
bash
# 1. Initiate — get one presigned PUT URL per part
curl -X POST https://api.videooptimizer.eu/api/v1/videos/upload/initiate \
  -H "Authorization: Bearer vp_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "libraryId": "<LIBRARY_UUID>",
    "filename": "movie.mp4",
    "fileSize": 524288000
  }'

# 2. PUT each part straight to its presigned URL (repeat per part —
#    read the ETag from each PUT response, you need it for step 3)
curl -X PUT "<PRESIGNED_PART_URL>" --data-binary @part-1.bin

# 3. Complete — hand back the part ETags to assemble the video
curl -X POST https://api.videooptimizer.eu/api/v1/videos/upload/complete \
  -H "Authorization: Bearer vp_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "libraryId": "<LIBRARY_UUID>",
    "uuid": "<VIDEO_UUID_FROM_INITIATE>",
    "key": "<KEY_FROM_INITIATE>",
    "uploadId": "<UPLOAD_ID_FROM_INITIATE>",
    "title": "My product video",
    "parts": [{ "partNumber": 1, "etag": "<ETAG_FROM_STEP_2>" }]
  }'
JavaScript
javascript
const { data: init } = await fetch("https://api.videooptimizer.eu/api/v1/videos/upload/initiate", {
  method: "POST",
  headers: {
    Authorization: "Bearer vp_your_token_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ libraryId, filename: file.name, fileSize: file.size }),
}).then(r => r.json());

const parts = [];
for (const part of init.parts) {
  const chunk = file.slice((part.partNumber - 1) * init.partSize, part.partNumber * init.partSize);
  const putRes = await fetch(part.url, { method: "PUT", body: chunk });
  parts.push({ partNumber: part.partNumber, etag: putRes.headers.get("ETag") });
}

await fetch("https://api.videooptimizer.eu/api/v1/videos/upload/complete", {
  method: "POST",
  headers: {
    Authorization: "Bearer vp_your_token_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    libraryId, uuid: init.uuid, key: init.key, uploadId: init.uploadId, parts,
  }),
});

Video per URL importieren

Statt die Datei selbst hochzuladen, können Sie `POST /api/v1/videos` auch mit JSON aufrufen und eine öffentlich erreichbare `https`-URL angeben (`source_url`) — die Plattform lädt die Datei dann selbstständig herunter.

cURL
bash
curl -X POST https://api.videooptimizer.eu/api/v1/videos \
  -H "Authorization: Bearer vp_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "library_id": "<LIBRARY_UUID>",
    "source_url": "https://example.com/videos/movie.mp4",
    "title": "My product video"
  }'
JavaScript
javascript
const res = await fetch("https://api.videooptimizer.eu/api/v1/videos", {
  method: "POST",
  headers: {
    Authorization: "Bearer vp_your_token_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    library_id: "<LIBRARY_UUID>",
    source_url: "https://example.com/videos/movie.mp4",
    title: "My product video",
  }),
});
const { data } = await res.json();
console.log(data); // { uuid: "...", status: "processing" }

Webhooks statt Polling

Statt den Video-Status per Polling abzufragen, können Sie sich per Webhook benachrichtigen lassen, sobald ein Video fertig ist (`video.ready`) oder das Encoding fehlgeschlagen ist (`video.failed`). Webhooks werden in der App unter „Organisation → Webhooks“ konfiguriert (nur für Owner/Admin) — nicht über die API.

Jede Zustellung ist signiert. Prüfen Sie den Header `X-VideoOptimizer-Signature` (`sha256=` + HMAC-SHA256 über Zeitstempel + Rohtext-Body, siehe Beispiel unten, mit Ihrem Endpoint-Secret) gegen den mitgesendeten `X-VideoOptimizer-Timestamp`, bevor Sie der Nutzlast vertrauen. Jede Zustellung trägt außerdem eine eindeutige `X-VideoOptimizer-Delivery-Id`.

JavaScript
javascript
import crypto from "crypto";

function isValidWebhook(rawBody, timestamp, signatureHeader, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  return signatureHeader === expected;
}

// Inside your webhook route handler:
const timestamp = req.headers["x-videooptimizer-timestamp"];
const signature = req.headers["x-videooptimizer-signature"];
if (!isValidWebhook(rawBody, timestamp, signature, process.env.WEBHOOK_SECRET)) {
  return res.status(401).send("Invalid signature");
}

Limits & Hosts

  • Rate-Limit: 120 Requests pro Minute je Token bzw. IP.
  • Die API ist nur über ihre eigene API-Subdomain erreichbar — andere Hosts antworten mit 404.
  • Jeder Token ist auf genau eine Organisation beschränkt; Berechtigungen werden bei jedem Request live geprüft.

Nächste Schritte