Zum Inhalt springen
Sursa Developers

Dokumente importieren

Diese Anleitung zeigt, wie Sie Ihre Dokumente mit der Karten-API in Sursa übertragen: ein paar Dokumente aus einem Skript oder alle Dokumente eines Systems über einen regelmäßigen Job. Jedes Dokument wird zu einer Karte in einer Sammlung. Menschen finden sie in der Suche, der Assistent antwortet daraus, und sie hat wie jede andere Karte eine verantwortliche Person, Tags, eine Prüfung und Berechtigungen.

Wenn Sursa selbst ermitteln soll, welche Dokumente in Ihrem System gelöscht wurden, oder wenn Sie Dokumente aus einer Integrationsplattform senden, verwenden Sie stattdessen eine benutzerdefinierte Quelle. Eine solche Quelle ist für vollständige und inkrementelle Synchronisierungen gebaut. Diese Anleitung behandelt das direkte Schreiben in eine Sammlung.

Sie brauchen einen API-Schlüssel mit dem Scope cards:write und einer Rolle, die in die Zielsammlung schreiben darf (editor oder admin). Die Beispiele verwenden die Hilfsfunktion aus dem Schnellstart.

Den richtigen Endpunkt wählen

Sie habenVerwenden Sie
Einen Datensatz mit stabiler ID in Ihrem SystemPUT /v1/cards-by-external-id/{external_id}: über Ihre ID erstellen oder ersetzen.
Text, den Sie einmalig hinzufügen, ohne eigene IDPOST /v1/cards/text
Eine Datei, die Sie einmalig hinzufügenPOST /v1/cards
Ein ZIP-Archiv mit vielen DateienPOST /v1/cards/archive
Eine Datei über dem Limit einer einzelnen AnfrageEin Upload in Teilen, danach einer der Endpunkte oben.
Neuen Inhalt für eine vorhandene KartePUT /v1/cards/{card_id}/content

Für alles, was Sie mehr als einmal importieren, verwenden Sie external_id. Damit lässt sich jeder Import wiederholen: Ein erneuter Lauf aktualisiert die Karten, die er erstellt hat, statt Kopien hinzuzufügen.

Karte über Ihre ID erstellen oder ersetzen

PUT /v1/cards-by-external-id/{external_id} erwartet die ID des Datensatzes in Ihrem System. Hat keine Karte diese external_id, wird eine erstellt (201). Hat eine Karte sie, werden Inhalt und Angaben der Karte ersetzt (200).

curl -X PUT https://api.sursa.com/v1/cards-by-external-id/kb-article-1042 \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "collection_id": 3,
    "folder_id": "0f8e2d7c-4b6a-4e1f-9c3d-2a5b8e7f1c40",
    "title": "Returning a damaged item",
    "content_type": "html",
    "body": "<h2>Damaged items</h2><p>Send a photo within 7 days and we ship a replacement.</p>",
    "tags": ["returns", "shipping"],
    "metadata": {"source": "helpdesk", "article_id": "1042"}
  }'

Was bei einer Wiederholung geschieht:

  • Der Inhalt hat sich nicht geändert: Es entsteht keine neue Version. Die Antwort ist 200 mit "status": "skipped" und "reason": "unchanged". Die Anfrage zu wiederholen ist immer unbedenklich, auch ohne Idempotency-Key.
  • Der Inhalt hat sich geändert: Die Karte erhält eine neue Version und wird erneut indexiert. Titel, Tags, verantwortliche Person, Kategorie und metadata übernehmen die gesendeten Werte; metadata wird als Ganzes ersetzt.
  • Sammlung und Ordner gelten nur beim Erstellen der Karte. Um eine Karte später zu verschieben, ändern Sie sie mit PATCH /v1/cards/{card_id}.

Wie jede Änderung des Inhalts hebt eine neue Version die Prüfung der Karte auf: Die Karte muss erneut geprüft und bestätigt werden.

Textformate

content_typeDer Body ist
markdown (Standard)Markdown.
htmlHTML. Es wird auf einfaches Markup reduziert: Überschriften, Absätze, Listen, Tabellen und Links mit http, https und mailto. Skripte, Styles, Frames, Formulare und Bilder werden samt Inhalt entfernt.
textReiner Text. Absätze werden durch Leerzeilen getrennt.

Auf die Karte warten – oder nicht

Standardmäßig kehrt die Anfrage zurück, sobald die Karte gefunden werden kann, mit "status": "ready" und der Karte in card. Das dauert von Sekundenbruchteilen für einen kurzen Text bis zu einer Minute oder länger für eine lange Datei.

Für Massenimporte senden Sie "async": true. Die Antwort kommt sofort mit "status": "queued" und dem Indexierungsjob in job (mit seiner job_id). Prüfen Sie den Job mit GET /v1/jobs/{job_id} oder verfolgen Sie alle Jobs über GET /v1/jobs/stream. Ein Job endet mit status done, error oder canceled.

curl https://api.sursa.com/v1/jobs/48213 \
  -H "Authorization: Bearer $SURSA_API_KEY"

Datei hochladen

Dateien werden in einer Anfrage mit multipart/form-data im Feld file gesendet. Sursa liest PDF, Word, Excel, PowerPoint, OpenDocument-Tabellen, CSV, Markdown, HTML, AsciiDoc, E-Mails (.eml), reinen Text und gängige Bildformate. Sursa prüft, ob Dateiname, angegebener Typ und Inhalt zusammenpassen, und lehnt Abweichungen mit 415 ab.

Um eine Dateikarte über Ihre ID zu erstellen oder zu ersetzen, senden Sie die Datei an denselben Endpunkt PUT /v1/cards-by-external-id/{external_id}:

curl -X PUT https://api.sursa.com/v1/cards-by-external-id/handbook-2026 \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -F "file=@employee-handbook.pdf" \
  -F "collection_id=3" \
  -F "tags=hr,policies" \
  -F 'metadata={"owner_team":"people"}'

In einem Formular ist tags eine kommagetrennte Zeichenkette und metadata ein als Zeichenkette geschriebenes JSON-Objekt. Eine neue Karte ohne title erhält den Dateinamen als Titel.

Um eine Datei einmalig ohne eigene ID hinzuzufügen, verwenden Sie POST /v1/cards mit demselben Formular und einem Idempotency-Key. Laden Sie eine Datei hoch, die die Sammlung bereits enthält, ergibt das "status": "skipped" mit "duplicate": true und der vorhandenen card_id – es sei denn, Sie übergeben eine external_id.

Die Größe einer Datei ist durch die Installation begrenzt (standardmäßig 200 MB). Laden Sie größere Dateien oder Dateien über unzuverlässige Netzwerke zuerst in Teilen hoch.

Inhalt einer Karte ersetzen

Wenn Sie die Sursa-ID einer Karte bereits haben, ersetzt PUT /v1/cards/{card_id}/content ihren Text oder ihre Datei und behält alles andere bei: verantwortliche Person, Tags, Prüfende, Prüfintervall und eine von Hand gesetzte Kategorie.

curl -X PUT https://api.sursa.com/v1/cards/3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60/content \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content_type": "markdown", "body": "# Refund policy\n\nRefunds are processed within 10 days."}'
  • Derselbe Inhalt ergibt erneut "status": "skipped" mit "reason": "unchanged".
  • Eine Karte, die gerade indexiert wird, ergibt 409 mit dem Code cards.indexing_in_progress. Versuchen Sie es nach einigen Sekunden erneut.
  • Eine Karte, die aus einer Quelle stammt, etwa aus einem Connector oder einer benutzerdefinierten Quelle, wird nur in ihrer Quelle geändert: cards.managed_by_source.
  • Der Schlüssel muss die ganze Karte sehen dürfen; eine nur teilweise sichtbare Karte ergibt cards.content_whole_access.

Viele Dokumente importieren

Eine Schleife über Ihre Datensätze mit PUT /v1/cards-by-external-id/… ist der einfachste Massenimport, und Sie können ihn jederzeit anhalten und erneut starten. So wird er schnell und schont das Ratenlimit:

  1. Senden Sie "async": true, damit jede Anfrage zurückkehrt, sobald die Karte in der Warteschlange steht.
  2. Führen Sie einige Anfragen parallel aus (4 bis 8) und werden Sie langsamer, wenn der Header RateLimit nur noch wenige verbleibende Anfragen zeigt. Siehe Ratenlimits und Kontingente.
  3. Warten Sie bei 429 die Zeit aus Retry-After ab; wiederholen Sie bei einem Netzwerkfehler oder 5xx dieselbe Anfrage. Wiederholungen schaden nicht.
  4. Notieren Sie die external_id jedes Datensatzes, der mit einem Fehler endet, und wiederholen Sie diese am Schluss.
import { api } from "./sursa.mjs";

async function importAll(records, concurrency = 6) {
  const failed = [];
  const queue = [...records];
  async function worker() {
    for (let record = queue.shift(); record; record = queue.shift()) {
      try {
        await api("PUT", `/v1/cards-by-external-id/${encodeURIComponent(record.id)}`, {
          collection_id: 3,
          title: record.title,
          content_type: "html",
          body: record.html,
          metadata: { source: "helpdesk" },
          async: true,
        });
      } catch (error) {
        failed.push({ id: record.id, error: String(error) });
      }
    }
  }
  await Promise.all(Array.from({ length: concurrency }, worker));
  return failed;
}

Für ein ZIP-Archiv mit Dateien macht POST /v1/cards/archive mit einer einzigen Anfrage aus jeder unterstützten Datei darin eine Karte. Der Endpunkt antwortet sofort mit dem Plan (welche Dateien zu Karten werden, welche übersprungen werden und warum) und einem Job; GET /v1/archives/{job_id} meldet das Ergebnis.

Importierte Karten finden und entfernen

Häufige Fehler

CodeUrsacheWas zu tun ist
collections.not_foundFür den Schlüssel ist keine Sammlung mit dieser ID oder diesem Namen sichtbar.Prüfen Sie collection_id mit GET /v1/collections.
collections.no_write_accessDer Schlüssel darf nicht in diese Sammlung schreiben.Verwenden Sie einen Schlüssel mit der Rolle editor und Zugriff auf die Sammlung.
cards.external_id_takenPOST mit einer external_id, die bereits eine andere Karte hat.Verwenden Sie PUT /v1/cards-by-external-id/…, um sie zu ersetzen.
cards.managed_by_sourceDie Karte gehört zu einer Quelle.Ändern Sie das Dokument in seiner Quelle.
files.type_mismatchName, Typ und Inhalt der Datei passen nicht zusammen.Senden Sie die Datei mit ihrer tatsächlichen Endung.
files.too_largeDie Datei überschreitet das Upload-Limit oder den Speicherplatz der Organisation.Verwenden Sie einen Upload in Teilen oder geben Sie Speicherplatz frei.
limits.cardsDie Organisation hat das Kartenlimit ihres Tarifs erreicht.Löschen Sie nicht mehr benötigte Karten oder wechseln Sie den Tarif.
api.metadata_invalidmetadata verletzt ein Limit.Siehe Metadaten.