← Entwickler-Anleitungen

Node.js-Server-Integration

Zwei Muster für ein Node.js-Backend: Session-Tokens für ein Browser-Frontend erstellen, oder die API direkt aus reinem Server-Code aufrufen.

Node.js auf dem Backend deckt zwei verschiedene Aufgaben ab, beide auf dieser Seite: (1) Session-Tokens erstellen, damit ein Browser-Frontend (einfache Webseite oder React) die API sicher aufrufen kann, und (2) die API direkt aus reinem Server-Code aufrufen — ein Cron-Job, ein Webhook-Handler, eine CLI, alles ohne Browser-Beteiligung. Wählen Sie den Abschnitt, der zu Ihrem Vorhaben passt.

Tokens für ein Browser-Frontend erstellen

Dies ist das Muster aus Wählen Sie Ihren Auth-Modus, konkret umgesetzt: ein Token-Erstellungs-Endpunkt auf Ihrem Server, und eine Browser-Seite (siehe Integration für einfache Webseiten oder React-SPA-Integration für die Browser-Seite), die ihn aufruft, bevor sie das SDK aufruft.

1. Einen Token-Endpunkt zu Ihrem Backend hinzufügen

Der empfohlene Weg, ein Session-JWT zu erstellen, ist, dass Ihr backend den eigenen POST /auth/token-Endpunkt der Plattform aufruft und sich dabei mit dem client_id/client_secret-Paar aus Holen Sie sich Ihren API-Schlüssel authentifiziert. Ihr backend signiert selbst nichts — es leitet die Anfrage nur weiter und gibt das zurückgegebene Token an den Browser weiter.

const CLIENT_ID = process.env.QURAVIN_CLIENT_ID;         // aus der Console
const CLIENT_SECRET = process.env.QURAVIN_CLIENT_SECRET; // aus der Console, einmalige Anzeige

app.get("/ai-token", requireUserLogin, async (req, res) => {
  const basic = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64");

  const r = await fetch("https://api.quravin.com/auth/token", {
    method: "POST",
    headers: {
      Authorization: `Basic ${basic}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      subject: req.user.id,     // die Nutzer-ID Ihrer Anwendung — wird zum JWT-`sub`
      ttl_seconds: 900,         // optional; 60-3600, Standard 900 (15 Min)
      // pipelines: ["translate-string"],  // optional — weglassen für die volle Erlaubnisliste Ihrer Anwendung
    }),
  });
  if (!r.ok) return res.status(502).json({ error: "token_mint_failed" });

  const { token, expires_in } = await r.json();
  res.json({ token, expires_in });
});

POST /auth/token antwortet mit:

{ "token": "eyJhbGciOi...", "token_type": "Bearer", "expires_in": 900 }

Die von Ihnen angeforderten pipelines werden mit allowed_pipelines Ihrer Anwendung geschnitten (in der Console festgelegt — siehe Holen Sie sich Ihren API-Schlüssel); lassen Sie das Feld weg, um alles zu erhalten, was Ihre Anwendung aufrufen darf. requireUserLogin ist Ihre eigene Auth-Middleware — das Token geht nur an einen Nutzer, den Ihr Server bereits authentifiziert hat.

Alternative: ein JWT selbst signieren (veraltet)

Manche Anwendungen halten stattdessen ihr eigenes anwendungsbezogenes Signing-Secret (AI_PLATFORM_SIGNING_SECRET) und erstellen das JWT lokal mit einer Bibliothek wie jsonwebtoken, anstatt POST /auth/token aufzurufen. Das ist ein echter, unterstützter Mechanismus, aber der veraltete Pfad — bevorzugen Sie POST /auth/token oben, es sei denn, Sie haben einen konkreten Grund zum Selbst-Signieren (z. B. Sie arbeiten bereits so und möchten das nicht ändern).

import jwt from "jsonwebtoken";

const SECRET = process.env.AI_PLATFORM_SIGNING_SECRET;   // NICHT das client_secret — siehe unten
const APP_ID = "your-app-id";                             // die registrierte ID Ihrer Anwendung

app.get("/ai-token", requireUserLogin, (req, res) => {
  const token = jwt.sign(
    {
      iss: APP_ID,
      sub: req.user.id,                    // die Nutzer-ID Ihrer Anwendung
      aud: "ai-platform",
      pipelines: ["translate-string"],     // welche Pipelines dieser Nutzer aufrufen darf
      rate_limit: { rpm: 30 },
    },
    SECRET,
    { algorithm: "HS256", expiresIn: "15m" },
  );
  res.json({ token, expires_in: 15 * 60 });
});

Dies verwendet ein anderes Credential als client_id/client_secret. Das Signing-Secret wird nicht von der Console ausgestellt — es wird außerhalb dieses Flusses vom Plattformbetreiber über einen sicheren Kanal bereitgestellt, speziell für Anwendungen, die selbst signieren müssen. Wenn Sie noch keins haben, verwenden Sie stattdessen den POST /auth/token-Pfad oben, anstatt eins anzufordern.

iss unterscheidet sich zwischen den beiden Erstellungspfaden — gehen Sie nicht davon aus, dass ein JWT-Payload, den Sie debuggen, immer denselben Aussteller hat. Ein über POST /auth/token erstelltes Token hat immer iss: "ai-platform" (die Plattform selbst signiert es). Ein selbst signiertes Token (dieser Abschnitt) hat stattdessen iss: <your-app-id> — die Plattform akzeptiert es weiterhin, verschlüsselt über das Signing-Secret der registrierten App-ID. Beide verwenden aud: "ai-platform".

Welches Secret welches ist

Drei verschiedene Secrets tauchen in diesen Auth-Dokumenten auf, und ihre Namen überschneiden sich genug, um Verwechslungen zu verursachen. Dies ist die vollständige Liste:

SecretEnv-VariableWer es besitztWofür verwendet
Client secretQURAVIN_CLIENT_SECRET (frei benennbar)Ihr backendAuthorization: Basic client_id:client_secret bei POST /auth/token — der oben empfohlene Pfad.
Anwendungsbezogenes Signing-SecretAI_PLATFORM_SIGNING_SECRETIhr backend (nur beim Selbst-Signieren)JWTs lokal selbst signieren, unter Umgehung von POST /auth/token — der veraltete Pfad in diesem Abschnitt.
Platform-JWT-Signing-Secret(plattforminterne, nicht offengelegt)Nur der Plattformbetreiber, niemals SieWas die Plattform selbst verwendet, um Tokens zu signieren, die sie über POST /auth/token erstellt. Sie sehen oder konfigurieren dies nie.

Wenn Sie ausschließlich POST /auth/token aufrufen (der empfohlene Pfad), müssen Sie nur an das Client-Secret denken — die anderen beiden sind interne/veraltete Angelegenheiten.

2. Ihr Frontend holt das Token und ruft das SDK auf

fetch("/ai-token", { credentials: "include" }) ist ein same-origin-Aufruf an Ihre eigene Backend-Route (Schritt 1) — kein CORS involviert, nur Ihre gewohnte Cookie-basierte Session. Der eigene Aufruf des SDK an unsere API ist eine separate, Cross-Origin-Anfrage, die das SDK selbst abwickelt; Sie konfigurieren dafür kein CORS. Der vollständige Browser-seitige Code (einfache Webseite oder React) befindet sich in Integration für einfache Webseiten und React-SPA-Integration — dieser Endpunkt ist das Stück, das diese beiden Anleitungen als bereits vorhanden voraussetzen.

Das ist der ganze Kreislauf: Ihr Server erstellt Tokens, der Browser sieht nie ein Secret, und jeder Aufruf wird dem Nutzer zugeordnet, der ihn getätigt hat.

Die API direkt aus reinem Server-Code aufrufen

Kein Browser involviert — ein Cron-Job, ein Webhook-Handler, eine CLI, ein Batch-Script. Verwenden Sie direkt den apiKey-Modus; es gibt kein Token zu erstellen, keinen Pro-Anfrage-Roundtrip zu POST /auth/token.

Es gibt hier kein window, an das ein <script>-Tag andocken könnte, und die eigene import { Quravin } from "@quravin/sdk"-Ergonomie des SDK ist noch nicht im öffentlichen npm-Registry verfügbar (fragen Sie Ihren Plattformbetreiber, falls Sie diesen Pfad benötigen) — rufen Sie die API für reinen Server-Code auf Node.js heute also direkt über HTTP auf. Node 18+ liefert fetch global mit, keine zusätzliche Abhängigkeit nötig:

const API_BASE = process.env.QURAVIN_API_BASE;
const API_KEY = process.env.QURAVIN_API_KEY; // aus der Console — siehe „Holen Sie sich Ihren API-Schlüssel"

async function runPipeline(pipelineId, inputs) {
  const submit = await fetch(`${API_BASE}/tickets`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
    body: JSON.stringify({ mode: "pipeline", pipeline_id: pipelineId, inputs }),
  });
  const { ticket_id } = await submit.json();

  while (true) {
    await new Promise((r) => setTimeout(r, 1000));
    const poll = await fetch(`${API_BASE}/tickets/${ticket_id}`, {
      headers: { "x-api-key": API_KEY },
    });
    const ticket = await poll.json();
    if (ticket.status === "DONE") return ticket.result;
    if (ticket.status === "FAILED") throw new Error(ticket.error);
  }
}

const out = await runPipeline("translate-string", { text: "Hello", target_language: "de" });
console.log(out.translation); // "Hallo"

Siehe Direct API integration für die vollständigen Request-/Response-Formen und Fehlertabellen, auf denen diese Schleife aufbaut.

Dies ist derselbe x-api-key aus dem Abschnitt „Was ist mit einem statischen x-api-key?” von Holen Sie sich Ihren API-Schlüssel — sicher aufzubewahren in reinem Server-Code (eine Env-Variable, ein Secrets-Speicher), da er nie an einen Browser ausgeliefert wird. Jeder Aufruf wird der Anwendung zugeordnet, nicht einem bestimmten Nutzer; wenn Sie eine Zuordnung pro Nutzer auch bei reinem Server-Code benötigen, erstellen Sie stattdessen ein Session-JWT pro Nutzer (derselbe POST /auth/token-Aufruf wie oben, nur ausgelöst durch Ihre eigene Serverlogik statt durch eine eingehende Browser-Anfrage — senden Sie es dann als Authorization: Bearer <jwt> statt als x-api-key).

Fehler behandeln

Ein erreichtes Kontingent oder Rate-Limit gibt einen typisierten Fehler zurück — zeigen Sie ihn passend zu Ihrem Kontext an (eine Nutzermeldung in einem Browser-Flow, ein Retry/Alert in einem Batch-Job):

try {
  const out = await runPipeline("translate-string", { text: "Hello", target_language: "de" });
} catch (err) {
  console.error("Translation failed:", err.message);
}

Siehe den Errors-Abschnitt der Tool-Referenz für die vollständige Liste der Statuscodes und was jeder davon für den authentifizierten Pfad bedeutet.

Weiterführend

Das SDK unterstützt außerdem einige Muster, die oben nicht gezeigt werden:

ai.runMany(...), ai.button(...) und die Troubleshooting-Tabelle sind im ausführlicheren Integration Guide des SDK dokumentiert — er ist nicht öffentlich, fragen Sie also Ihren Plattformbetreiber nach einer Kopie, falls Sie ihn benötigen.