Authentifizierung#

EnConvert kennt zwei Arten von API-Schlüsseln, und wo dein Code läuft, entscheidet darüber, welchen du verwendest. Ein privater Schlüssel (sk_) gehört in den X-API-Key-Header und wird von einem Server gesendet, den du kontrollierst; ein öffentlicher Schlüssel (pk_) wird gegen ein kurzlebiges JWT getauscht, das Browser-Code als Authorization: Bearer <token> sendet.


Den Schlüsseltyp wählen#

Privater Schlüssel Öffentlicher Schlüssel + JWT
Präfix sk_ pk_
Gesendet als X-API-Key: sk_your_private_key Authorization: Bearer <token>
Läuft in Servern, Skripten, CI-Jobs, Containern Browsern, eingebetteten Widgets, allem, was an einen Client ausgeliefert wird
Abgelehnt, wenn die Anfrage einen Origin-Header trägt (403) er etwas anderes als /v1/auth/token oder /v1/auth/branding aufruft (403)
Reichweite jeder Endpunkt: synchron, asynchron, Batch, Webhooks ein Element pro Anfrage, synchron, Download per Presigned URL
Geltungsbereich optional allowed_endpoints allowed_domains plus allowed_endpoints
Lebensdauer Schlüssel gültig bis zum Widerruf Schlüssel gültig bis zum Widerruf, Access-Token 1 Stunde, Refresh-Cookie 7 Tage

Entscheide nach Deployment-Ziel. Ein Backend-Service, ein Skript, ein Cron-Job oder ein internes Tool bekommt einen privaten Schlüssel. Eine browserbasierte App oder ein eingebettetes Widget bekommt einen öffentlichen Schlüssel mit JWT. Es gibt keine Möglichkeit, einen privaten Schlüssel in Frontend-Code zu verstecken: Das Gateway lehnt ihn allein aufgrund des Vorhandenseins eines Origin-Headers ab, bevor es überhaupt etwas anderes prüft.

Ein Schlüssel besteht aus seinem Präfix, gefolgt von einem zufälligen Token, insgesamt 46 Zeichen. Die Platzhalternamen in den folgenden Beispielen (sk_your_private_key, pk_your_public_key) stehen für dieses Token; ein echter Schlüssel enthält kein Umgebungssegment wie live oder test. Alles, was kürzer als 45 Zeichen ist, wird mit 401 Invalid API Key format abgelehnt, noch bevor das Präfix überhaupt gelesen wird.

Auf dem Server wird nur ein SHA-256-Hash jedes Schlüssels gespeichert, dazu ein sieben Zeichen langer Präfix-Stub, damit du deine Schlüssel im Dashboard auseinanderhalten kannst.


Private Schlüssel#

Private Schlüssel sind für serverseitige Anwendungen gedacht, bei denen dein API-Schlüssel geheim gehalten werden kann. Sie gewähren vollen Zugriff auf alle API-Endpunkte und -Funktionen.

  • Header: X-API-Key: sk_your_private_key
  • Zugriff: Voller Zugriff auf alle Endpunkte, einschließlich synchroner und asynchroner Operationen, Stapelverarbeitung und aller Konvertierungstypen.
  • Sicherheit: Schlüssel werden auf dem Server als SHA-256-Hashes gespeichert. Der Klartextschlüssel wird nur einmal bei der Erstellung angezeigt.

Ein Token-Austausch oder Session-Management ist nicht erforderlich. Füge den Schlüssel in jede Anfrage ein:

curl -X POST https://api.enconvert.com/v1/convert/url-to-pdf \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

Header-Format#

Füge deinen privaten Schlüssel bei jeder Anfrage in den X-API-Key-Header ein:

X-API-Key: sk_your_private_key

Private Schlüssel beginnen immer mit dem Präfix sk_. Du kannst deine Schlüssel im EnConvert-Dashboard generieren und verwalten.

Beispiel: Dateikonvertierung#

Konvertiere eine JSON-Datei mit einem privaten Schlüssel in XML:

curl -X POST https://api.enconvert.com/v1/convert/json-to-xml \
  -H "X-API-Key: sk_your_private_key" \
  -F "[email protected]"

Antwort:

{
  "presigned_url": "https://econverter.nyc3.cdn.digitaloceanspaces.com/...",
  "object_key": "live/files/12345/json-to-xml/data_20250202_120530123.xml",
  "filename": "data_20250202_120530123.xml",
  "file_size": 1024,
  "conversion_time_seconds": 0.45
}
  • presigned_url: eine temporäre, herunterladbare URL zum Abrufen der konvertierten Datei.
  • object_key: der Speicherpfad der konvertierten Datei (z. B. live/files/12345/json-to-xml/...). Dies ist keine URL.
  • filename: der generierte Dateiname der konvertierten Datei.
  • file_size: die Größe der Ausgabedatei in Bytes.
  • conversion_time_seconds: die Zeit, die die Konvertierung benötigt hat.

Diese Download-URLs sind kurzlebig. Ihre Ablauf- und Aufbewahrungsregeln stehen unter Signierte URLs.

Endpunkt-Beschränkungen#

Standardmäßig hat ein privater Schlüssel Zugriff auf alle API-Endpunkte. Du kannst einen Schlüssel optional über die Einstellung allowed_endpoints bei der Erstellung auf bestimmte Endpunkte beschränken.

Wenn allowed_endpoints konfiguriert ist, kann der Schlüssel nur die aufgeführten Endpunkte aufrufen. Anfragen an jeden anderen Endpunkt werden mit einem 403 Forbidden-Fehler abgelehnt: Endpoint '{path}' not allowed for this API key.

Beispielkonfiguration:

{
  "allowed_endpoints": [
    "/v1/convert/url-to-pdf",
    "/v1/convert/json-to-xml",
    "/v1/convert/html-to-pdf"
  ]
}

Das ist nützlich, wenn du einen Schlüssel mit eingeschränktem Umfang ausstellen möchtest, zum Beispiel einen Schlüssel, der nur PDF-Konvertierungen durchführen kann.

Eine Handvoll Pfade bleibt erreichbar, egal was in der Liste steht, denn ein Schlüssel, der einen Job starten kann, muss ihn auch abschließen können:

  • /v1/auth/token, /v1/auth/verify und /v1/whoami
  • /v1/convert/status/{job_id}, /v1/convert/batch/{batch_id} und /v1/convert/download/{object_key}
  • /v1/extension/*, für JWT-authentifizierte Anfragen
  • die jobspezifischen V2-Pfade für perceive, ingest und watch

Ein Schlüssel, der mit dem einzelnen Eintrag ["*"] erstellt wurde, meint jeden Endpunkt, auch solche, die erst nach der Erstellung des Schlüssels ausgeliefert werden.

Die Liste wird bei der Erstellung festgelegt. Es gibt keinen Aufruf, der die Beschränkungen eines bestehenden Schlüssels bearbeitet; den Geltungsbereich eines Schlüssels einzuschränken oder zu erweitern bedeutet also, einen neuen Schlüssel zu erstellen und den alten zu widerrufen. Siehe Schlüssel sicher aufbewahren.

Verwende private Schlüssel nicht in clientseitigem Code. Die API erkennt den von Browsern gesendeten Origin-Header und lehnt Anfragen mit einem privaten Schlüssel aus einer Browser-Umgebung mit 403 Private API keys cannot be used from browsers ab. Verwende für clientseitige Integrationen stattdessen einen öffentlichen Schlüssel mit JWT.

Öffentliche Schlüssel und JWT#

Die Public-Key-JWT-Authentifizierung ermöglicht es clientseitigen (Browser-)Apps, die EnConvert-API aufzurufen: Du tauschst deinen öffentlichen Schlüssel (pk_) über POST /v1/auth/token gegen ein kurzlebiges JWT-Access-Token ein und sendest dieses Token dann bei API-Anfragen im Header Authorization: Bearer <token>. Da ein öffentlicher Schlüssel für Endnutzer sichtbar ist, kann er die API nicht direkt aufrufen. Für sich allein erreicht er genau zwei Pfade: /v1/auth/token und /v1/auth/branding. Alles andere liefert 403 mit einer Meldung, die dir sagt, dass du den Schlüssel zuerst gegen ein Token tauschen musst.

  1. Tausche deinen öffentlichen Schlüssel (pk_) über POST /v1/auth/token gegen ein JWT-Access-Token.
  2. Verwende das JWT-Token bei API-Anfragen im Header Authorization: Bearer <token>.
  3. Erneuere das Token automatisch vor Ablauf über POST /v1/auth/refresh.
  4. Domain-Whitelisting stellt sicher, dass nur Anfragen von deinen genehmigten Domains akzeptiert werden.

Schritt 1: Öffentlichen Schlüssel gegen JWT tauschen#

POST /v1/auth/token
Header Wert Beschreibung
X-API-Key pk_your_public_key Dein öffentlicher API-Schlüssel

Der Endpunkt erwartet ein JSON-Body-Objekt. Wird gar kein Body gesendet, kommt 422 mit {"type":"missing","loc":["body"],"msg":"Field required"} zurück; sende also {}, wenn du nichts zu übergeben hast. Das einzige optionale Feld ist turnstile_token, das nur bei Anfragen vom Widget-Origin von EnConvert geprüft und überall sonst ignoriert wird.

async function getToken() {
  const response = await fetch("https://api.enconvert.com/v1/auth/token", {
    method: "POST",
    headers: {
      "X-API-Key": "pk_your_public_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({}),
    credentials: "include",
  });

  if (!response.ok) {
    throw new Error(`Token exchange failed: ${response.status}`);
  }

  const data = await response.json();
  return data.token;
}
Wichtig: Du musst credentials: "include" in den fetch-Optionen angeben. Das stellt sicher, dass das Refresh-Token-Cookie vom Browser gespeichert wird, was für die automatische Token-Erneuerung erforderlich ist.

Antwort:

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Die Antwort setzt außerdem ein HttpOnly-Cookie, das das Refresh-Token enthält. Dieses Cookie wird automatisch vom Browser verwaltet und beim Erneuern des Access-Tokens verwendet.

Ein privater Schlüssel, der an diesen Endpunkt gesendet wird, wird mit 400 Only public API keys can exchange for tokens. Private keys should be used directly. abgelehnt. Das ist die API, die dir sagt, dass du den Austauschschritt weglassen sollst, und kein defekter Schlüssel.

Schritt 2: Das JWT-Token verwenden#

Füge das JWT-Token bei allen nachfolgenden API-Anfragen als Bearer-Token in den Authorization-Header ein.

async function convertUrlToPdf(token, url) {
  const response = await fetch("https://api.enconvert.com/v1/convert/url-to-pdf", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ url }),
  });

  return await response.json();
}

// Usage
const token = await getToken();
const result = await convertUrlToPdf(token, "https://example.com");
console.log(result.presigned_url);

Schritt 3: Automatische Token-Erneuerung#

Access-Tokens laufen nach einer Stunde ab. Verwende den Refresh-Endpunkt, um ein neues Access-Token zu erhalten, ohne dass sich der Nutzer erneut authentifizieren muss.

POST /v1/auth/refresh

Das Refresh-Token wird automatisch über das HttpOnly-Cookie gesendet, das beim ursprünglichen Token-Austausch gesetzt wurde. Es sind kein Request-Body und keine zusätzlichen Header erforderlich.

class EnconvertClient {
  constructor(publicKey) {
    this.publicKey = publicKey;
    this.token = null;
    this.tokenExpiry = null;
  }

  async getToken() {
    const response = await fetch("https://api.enconvert.com/v1/auth/token", {
      method: "POST",
      headers: {
        "X-API-Key": this.publicKey,
        "X-Parent-Origin": window.location.origin,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({}),
      credentials: "include",
    });

    const data = await response.json();
    this.token = data.token;
    // Set expiry to 55 minutes (refresh before the 1-hour expiry)
    this.tokenExpiry = Date.now() + 55 * 60 * 1000;
    return this.token;
  }

  async refreshToken() {
    const response = await fetch("https://api.enconvert.com/v1/auth/refresh", {
      method: "POST",
      credentials: "include",
    });

    if (!response.ok) {
      // Refresh token expired, re-authenticate
      return await this.getToken();
    }

    const data = await response.json();
    this.token = data.token;
    this.tokenExpiry = Date.now() + 55 * 60 * 1000;
    return this.token;
  }

  async getValidToken() {
    if (!this.token || Date.now() >= this.tokenExpiry) {
      if (this.token) {
        return await this.refreshToken();
      }
      return await this.getToken();
    }
    return this.token;
  }

  async convert(endpoint, body) {
    const token = await this.getValidToken();
    const response = await fetch(`https://api.enconvert.com${endpoint}`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${token}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    return await response.json();
  }
}

// Usage
const client = new EnconvertClient("pk_your_public_key");
const result = await client.convert("/v1/convert/url-to-pdf", {
  url: "https://example.com",
});

Vier Dinge, die du wissen solltest, bevor du eine fehlschlagende Erneuerung debuggst:

  • Die Erneuerung ermittelt dein Projekt aus dem Cookie und sucht dann nach irgendeinem aktiven öffentlichen Schlüssel in diesem Projekt. Widerrufst du jeden öffentlichen Schlüssel, liefert die Erneuerung 401, selbst wenn das Cookie noch innerhalb seiner sieben Tage liegt.
  • Die Refresh-Route prüft die Domain-Whitelist nicht erneut. Diese Prüfung findet statt, wenn das Token ausgestellt wird.
  • Die Erneuerung bindet das neue Token nicht erneut an den Schlüssel, den du ursprünglich verwendet hast. Hält das Projekt mehrere öffentliche Schlüssel, kann das erneuerte Token mit den Beschränkungen eines anderen Schlüssels zurückkommen.
  • Ausstellung und Erneuerung von Tokens haben eine eigene Drosselung pro IP, getrennt von den Rate-Limits deines Tarifs. Ein Client, der in einer Refresh-Schleife feststeckt, wird das merken.

Token-Lebensdauer#

Token Lebensdauer Speicherung
Access-Token 1 Stunde Wird im JSON-Antwortkörper zurückgegeben; im Speicher (memory) halten
Refresh-Token 7 Tage Wird als HttpOnly-Cookie gesetzt; vom Browser verwaltet

Domain-Whitelisting#

Öffentliche Schlüssel sind auf bestimmte Domains beschränkt, die du in deinem Dashboard konfigurierst.

Der Abgleich vergleicht nur Host und Port. Das Schema wird zuvor auf beiden Seiten entfernt, https://example.com und http://example.com sind für die Whitelist also derselbe Origin. Der Port wird nicht entfernt und ist Teil des Abgleichs.

  • Exakte Übereinstimmung: https://example.com stimmt mit dem reinen Host example.com unter jedem Schema überein.
  • Wildcard-Subdomains: https://*.example.com stimmt mit https://app.example.com, https://staging.example.com und auch mit der Apex-Domain https://example.com überein.
  • Portspezifisch: http://localhost:3000 stimmt nur mit genau diesem Host und Port überein.
Whitelist-Eintrag Stimmt überein mit Stimmt nicht überein mit
https://example.com https://example.com, http://example.com https://www.example.com
https://*.example.com https://app.example.com, https://dev.example.com, https://example.com https://example.net
http://localhost:3000 http://localhost:3000 http://localhost:8080

Eine Anfrage von einem Origin, der nicht auf der Liste steht, erhält 403 Domain {origin} not authorized, und der Projektinhaber wird per E-Mail darüber informiert (höchstens einmal pro Schlüssel und 24 Stunden). Füllt sich dein Postfach, ist meist ein veralteter Whitelist-Eintrag die Ursache.

Zwei Origins überspringen die Domain-Prüfung vollständig: ein chrome-extension://...-Origin, damit Browser-Erweiterungen die API aufrufen können, und der eigene Widget-Origin von EnConvert, bei dem die Prüfung stattdessen auf die X-Parent-Origin-Validierung des Widgets übergeht.

Sicherheitsfunktionen#

  • Kurzlebige Tokens: Access-Tokens laufen nach 1 Stunde ab, wodurch das Zeitfenster im Falle eines kompromittierten Tokens begrenzt wird.
  • HttpOnly-Refresh-Cookies: Refresh-Tokens werden in HttpOnly-Cookies gespeichert, wodurch sie für JavaScript unzugänglich und resistent gegen XSS-Angriffe sind.
  • Domain-Beschränkungen: Tokens werden nur ausgestellt, wenn die Anfrage von einer whitelisteten Domain stammt.
  • Kein direkter API-Zugriff: Öffentliche Schlüssel allein können keine Konvertierungsendpunkte aufrufen. Ein gültiges JWT ist immer erforderlich.

Einschränkungen öffentlicher Schlüssel#

Die Public-Key-Authentifizierung hat im Vergleich zu privaten Schlüsseln folgende Einschränkungen:

  • Nur synchron: Es sind nur synchrone Konvertierungsendpunkte verfügbar. Der Async-Modus und Webhook-Callbacks sind es nicht; notification_email und callback_url werden bei Konvertierungen mit einem Browser-Schlüssel geleert.
  • Ein Element pro Anfrage: Jede Anfrage darf nur eine URL oder Datei konvertieren. Das Senden eines Arrays liefert 400 Public keys only support a single URL input.
  • Direkter Download: Antworten liefern eine presigned_url zum sofortigen Download. Es gibt keine Option für benutzerdefinierte Speicherziele.
  • Job-Status ja, Batch-Status nein: GET /v1/convert/status/{job_id} funktioniert mit einem Browser-Token; so holt sich das Widget ein Ergebnis nach einer abgebrochenen Verbindung zurück. GET /v1/convert/batch/{batch_id} wird mit 403 Batch status requires a private API key abgelehnt.

Das Einreichen von Batches selbst wird durch das Batch-Limit deines Tarifs geregelt und nicht durch den Schlüsseltyp; da ein Browser-Schlüssel aber auf ein Element pro Anfrage begrenzt ist, brauchen Batches in der Praxis einen privaten Schlüssel. Siehe Stapelverarbeitung.

Best Practices:
  • Speichere Access-Tokens ausschließlich im Arbeitsspeicher. Persistiere sie niemals in localStorage oder sessionStorage.
  • Implementiere eine automatische Token-Erneuerung, um Unterbrechungen während Nutzersitzungen zu vermeiden.
  • Halte deine Liste whitelisteter Domains so spezifisch wie möglich. Vermeide breite Wildcards.
  • Verwende credentials: "include" bei allen fetch-Anfragen, damit Cookies korrekt gesendet und empfangen werden.
  • Behandle fehlgeschlagene Token-Erneuerungen elegant, indem du auf eine vollständige Neuauthentifizierung mit dem öffentlichen Schlüssel zurückfällst.

Wenn du den Browser-Flow willst, ohne ihn selbst zu schreiben: Das einbettbare Widget stellt seine Tokens selbst aus und erneuert sie. Siehe Web-Widgets.


Deine Credentials prüfen#

GET /v1/auth/verify prüft, ob deine aktuelle Authentifizierung gültig ist, und meldet, wofür die API sie hält. Der Endpunkt funktioniert mit privaten Schlüsseln, die im X-API-Key-Header gesendet werden, und mit JWT-Bearer-Tokens im Authorization-Header. Eine gültige Anfrage liefert deine project_id, tier, key_type sowie etwaige Domain- oder Endpunkt-Beschränkungen; ein ungültiger oder abgelaufener Schlüssel bzw. Token liefert 401 Unauthorized.

GET /v1/auth/verify
Header Wert Beschreibung
X-API-Key sk_your_private_key Authentifizierung mit einem privaten Schlüssel
Authorization Bearer <token> Authentifizierung mit einem JWT-Token

Verwende einen der beiden obigen Header, nicht beide.

Einen öffentlichen Schlüssel kannst du nicht direkt prüfen. Sendest du X-API-Key: pk_... an diesen Endpunkt, kommt 403 zurück, denn ein öffentlicher Schlüssel darf nur /v1/auth/token und /v1/auth/branding aufrufen. Stelle zuerst ein Token aus und prüfe dann das Token. Das ist der eine Fall, in dem ein 403 hier nicht bedeutet, dass dein Schlüssel defekt ist.

Mit einem privaten Schlüssel:

curl https://api.enconvert.com/v1/auth/verify \
  -H "X-API-Key: sk_your_private_key"

Mit einem JWT-Token:

curl https://api.enconvert.com/v1/auth/verify \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Antwort:

{
  "authenticated": true,
  "project_id": "12345",
  "tier": "pro",
  "key_type": "public",
  "allowed_domains": ["https://example.com", "https://*.example.com"],
  "allowed_endpoints": ["/v1/convert/url-to-pdf", "/v1/convert/jpeg-to-png"]
}
Feld Typ Beschreibung
authenticated boolean Immer true bei einer gültigen Anfrage
project_id string Deine Projekt-ID
tier string Dein Abonnement-Tarif (z. B. free, starter, pro, business)
key_type string private, public oder dashboard
allowed_domains Array oder null Whitelistete Domains (nur öffentliche Schlüssel, sonst null)
allowed_endpoints Array oder null Eingeschränkte Endpunkte (nur öffentliche Schlüssel, sonst null)

Zwei Details, über die viele stolpern. key_type hat einen dritten Wert, dashboard: Den stellt das Backend für eine angemeldete Dashboard- oder Playground-Sitzung aus; wie bei einem privaten Schlüssel sind beide Listen null. Und tier ist der Plan-Slug, nicht der Name auf der Preisseite: Ein Studio-Abonnement meldet "tier": "pro". Die Slugs free, starter, pro, business und enterprise entsprechen Founding, Indie, Studio, Production und Enterprise.

Ist der Schlüssel oder das Token ungültig oder abgelaufen, liefert die API stattdessen einen 401 Unauthorized-Fehler. Die vollständige Liste der Authentifizierungs-Fehlermeldungen steht unter Fehler.

GET /v1/whoami#

Es gibt einen zweiten, kleineren Identitäts-Endpunkt. Er erfordert einen privaten Schlüssel:

curl https://api.enconvert.com/v1/whoami \
  -H "X-API-Key: sk_your_private_key"
{
  "project_id": "12345",
  "plan_slug": "pro"
}

Er liefert bewusst nichts weiter: keinen Schlüsseltyp, keine Domains, keine Limits. Ein JWT oder ein öffentlicher Schlüssel erhält 403 GET /v1/whoami requires a private API key (sk_...). Mehrere Integrationen nutzen ihn als Credential-Test, darunter der n8n-Node.

Anwendungsfälle#

  • API-Schlüssel testen: Bestätige, dass ein neu erstellter Schlüssel aktiv und korrekt konfiguriert ist.
  • Domain-Beschränkungen prüfen: Überprüfe, welche Domains für einen öffentlichen Schlüssel whitelistet sind.
  • Authentifizierungsprobleme debuggen: Ermittle, ob ein Anfragefehler durch die Authentifizierung oder etwas anderes verursacht wird.

Schlüssel sicher aufbewahren#

  • Gehashte Speicherung: Private Schlüssel werden auf dem Server als SHA-256-Hashes gespeichert. Der Klartextschlüssel wird nur einmal bei der Erstellung angezeigt. Wenn du ihn verlierst, musst du einen neuen Schlüssel generieren.
  • Umgebungsvariablen: Speichere deinen Schlüssel in einer Umgebungsvariable (z. B. ENCONVERT_API_KEY), statt ihn fest in deinem Quellcode zu hinterlegen.
  • Geltungsbereich bei der Erstellung: allowed_endpoints und allowed_domains werden bei der Erstellung des Schlüssels festgelegt und lassen sich danach nicht mehr bearbeiten. Entscheide über den Geltungsbereich, bevor du auf Erstellen klickst.

Einen Schlüssel rotieren#

Rotation heißt erst erstellen, dann widerrufen; in dieser Reihenfolge kostet sie keine Downtime:

  1. Erstelle den neuen Schlüssel im Dashboard mit dem gewünschten Geltungsbereich.
  2. Deploye ihn und bestätige dann mit GET /v1/auth/verify, dass der neue Schlüssel aktiv ist.
  3. Widerrufe den alten Schlüssel.

Während Schritt 2 funktionieren beide Schlüssel, es gibt also kein Zeitfenster, in dem dein Service nicht authentifiziert ist. Da Beschränkungen unveränderlich sind, ist das Ändern des Geltungsbereichs eines Schlüssels dasselbe Verfahren wie eine Rotation.

Wenn ein Schlüssel durchsickert#

Widerrufe ihn zuerst, ermittle danach das Schadensausmaß. Der Widerruf ist der einzige Notausschalter, denn der Geltungsbereich eines aktiven Schlüssels lässt sich nicht nachträglich einschränken; ein widerrufener Schlüssel wird mit 401 API Key revoked abgelehnt.

  • Ein durchgesickerter privater Schlüssel kann jeden Endpunkt aufrufen, für den er freigegeben war, und verbraucht deine monatlichen Ops. Widerrufe ihn, erstelle einen Ersatz und prüfe deine Nutzung im Dashboard auf Aufrufe, die nicht von dir stammen.
  • Ein durchgesickerter öffentlicher Schlüssel ist per Design weniger dringend. Er kann Konvertierungsendpunkte überhaupt nicht aufrufen und stellt Tokens nur für Origins auf seiner Whitelist aus. Diese Whitelist zu verschärfen bedeutet, einen enger gefassten Schlüssel zu erstellen und den durchgesickerten zu widerrufen, denn die Liste eines bestehenden Schlüssels lässt sich nicht bearbeiten.
  • Ein durchgesickertes Access-Token stirbt innerhalb einer Stunde und lässt sich nicht von einem anderen Origin aus verwenden als dem, für den es ausgestellt wurde. Das längerlebige Problem ist sein Refresh-Cookie: Die Erneuerung gelingt, solange das Projekt irgendeinen aktiven öffentlichen Schlüssel hat. Den Schlüssel zu widerrufen, aus dem das Token stammt, beendet das Cookie also nicht, es sei denn, es war dein letzter öffentlicher Schlüssel.
Ein nach git gepushter Schlüssel ist bereits öffentlich. Widerrufe ihn im Dashboard, bevor du die History umschreibst. Den Commit zu löschen macht die Veröffentlichung des Schlüssels nicht rückgängig.

Häufig gestellte Fragen#

Wie authentifiziere ich mich bei einer REST-API mit einem X-API-Key-Header?#

Sende deinen privaten Schlüssel bei jeder Anfrage im Header X-API-Key, zum Beispiel X-API-Key: sk_your_private_key. Private Schlüssel gewähren ganz ohne Token-Austausch vollen Zugriff auf alle Endpunkte (einschließlich synchroner und asynchroner Operationen, Stapelverarbeitung und aller Konvertierungstypen).

Was ist der Unterschied zwischen sk_ und pk_ API-Schlüsseln?#

Schlüssel mit dem Präfix sk_ sind private Schlüssel für die Server-zu-Server-Nutzung und gewähren vollen API-Zugriff über den Header X-API-Key. Schlüssel mit dem Präfix pk_ sind öffentliche Schlüssel für clientseitige (Browser-)Apps: Sie können die API nicht direkt aufrufen und müssen zuerst über POST /v1/auth/token gegen ein kurzlebiges JWT getauscht werden.

Kann ich meinen privaten API-Schlüssel (sk_) in einem Browser oder einer mobilen App verwenden?#

Nein. Die API erkennt den von Browsern gesendeten Origin-Header und lehnt Anfragen mit privaten Schlüsseln aus Browser-Umgebungen mit 403 Private API keys cannot be used from browsers ab. Nutze stattdessen einen öffentlichen Schlüssel (pk_) mit dem JWT-Flow für clientseitige Integrationen.

Wie bekomme ich ein JWT-Bearer-Token für die clientseitige API-Authentifizierung?#

Tausche deinen öffentlichen Schlüssel (pk_) gegen ein JWT, indem du POST /v1/auth/token mit dem Schlüssel im Header X-API-Key und {} als JSON-Body aufrufst. Nutze das zurückgegebene Token im Header Authorization: Bearer <token> für API-Anfragen und erneuere es vor Ablauf über POST /v1/auth/refresh.

Kann ich einen privaten API-Schlüssel auf bestimmte Endpunkte beschränken?#

Ja. Setze allowed_endpoints bei der Erstellung des Schlüssels und liste Pfade wie /v1/convert/url-to-pdf auf. Anfragen an Endpunkte, die nicht auf der Liste stehen, werden mit einem 403 Forbidden-Fehler abgelehnt, abgesehen von den Auth-, Status-, Download- und jobspezifischen Pfaden, die für jeden Schlüssel erreichbar bleiben.

Was passiert, wenn ich meinen privaten API-Schlüssel verliere?#

Private Schlüssel werden auf dem Server als SHA-256-Hashes gespeichert, und der Klartextschlüssel wird nur einmal bei der Erstellung angezeigt. Wenn du ihn verlierst, musst du einen neuen Schlüssel generieren. Du kannst mehrere Schlüssel erstellen und alte im Dashboard ohne Downtime widerrufen.

Wie lange sind Access-Tokens und Refresh-Tokens gültig?#

Access-Tokens laufen nach 1 Stunde ab und sollten ausschließlich im Arbeitsspeicher gehalten werden. Refresh-Tokens sind 7 Tage gültig und werden als HttpOnly-Cookie gesetzt, das vom Browser verwaltet wird.

Warum schlägt meine Token-Erneuerung ohne credentials: "include" fehl?#

Das Refresh-Token wird in einem HttpOnly-Cookie gespeichert, das beim ursprünglichen Token-Austausch gesetzt wird, und POST /v1/auth/refresh verlässt sich darauf, dass der Browser dieses Cookie automatisch sendet. Wenn du credentials: "include" in deinen fetch-Anfragen weglässt, wird das Cookie nicht gespeichert oder gesendet. Falle bei einer fehlgeschlagenen Erneuerung auf eine vollständige Neuauthentifizierung mit deinem öffentlichen Schlüssel zurück.

Kann ich Wildcard-Subdomains in der Domain-Whitelist verwenden?#

Ja. https://*.example.com stimmt mit https://app.example.com, https://staging.example.com und der Apex-Domain https://example.com überein. Exakte Hosts und portspezifische Origins wie http://localhost:3000 werden ebenfalls unterstützt. Der Abgleich ignoriert das Schema, nicht aber den Port.

Kann ich einen öffentlichen Schlüssel für asynchrone oder Batch-Konvertierungen verwenden?#

Nein. Die Public-Key-Authentifizierung unterstützt nur synchrone Konvertierungsendpunkte mit einer einzelnen URL oder Datei pro Anfrage; der Async-Modus, Webhooks und das Polling des Batch-Status erfordern einen privaten Schlüssel. Antworten liefern eine presigned_url zum sofortigen Download.

Wie teste ich, ob mein API-Schlüssel gültig ist?#

Sende eine Anfrage an GET /v1/auth/verify mit einem privaten Schlüssel im Header X-API-Key oder einem JWT im Header Authorization. Ein gültiges Credential liefert authenticated: true zusammen mit deiner project_id und tier; ein ungültiges oder abgelaufenes liefert 401 Unauthorized. Ein öffentlicher Schlüssel lässt sich so nicht prüfen und liefert 403.

Warum sind allowed_domains und allowed_endpoints in der verify-Antwort null?#

Beide Felder werden nur für öffentliche Schlüssel befüllt und liefern null für private Schlüssel und für Dashboard-Sitzungen. Bei öffentlichen Schlüsseln listet allowed_domains die whitelisteten Domains auf, und allowed_endpoints listet etwaige Endpunkt-Beschränkungen auf.

Welche Authentifizierungsmethode sollte ich für meine Integration wählen?#

Nutze einen privaten Schlüssel (sk_) für Backend-Services, Skripte oder interne Tools, denn er ist einfacher und gewährt vollen Zugriff. Nutze einen öffentlichen Schlüssel (pk_) mit JWT für browserbasierte Apps oder Widgets, da er Credentials sicher hält und den Zugriff auf zugelassene Domains beschränkt.