Anar al contingut
Sursa Developers

Importar documents

Aquesta guia mostra com posar els vostres documents a Sursa amb l’API d’entrades: uns quants documents des d’un script, o tots els documents d’un sistema amb un treball periòdic. Cada document es converteix en una entrada d’una col·lecció. La gent la troba a la cerca, l’assistent respon a partir del seu contingut, i té responsable, etiquetes, verificació i permisos com qualsevol altra entrada.

Si voleu que Sursa determini quins documents s’han eliminat al vostre sistema, o si envieu documents des d’una plataforma d’integració, feu servir una font personalitzada. Està pensada per a sincronitzacions completes i incrementals. Aquesta guia tracta de l’escriptura directa en una col·lecció.

Necessiteu una clau d’API amb l’àmbit cards:write i un rol que pugui escriure a la col·lecció de destinació (editor o admin). Els exemples fan servir la funció auxiliar de l’Inici ràpid.

Triar el punt final adequat

TeniuFeu servir
Un element amb un ID estable al vostre sistemaPUT /v1/cards-by-external-id/{external_id}: crear o substituir pel vostre ID.
Un text per afegir una sola vegada, sense ID propiPOST /v1/cards/text
Un fitxer per afegir una sola vegadaPOST /v1/cards
Un arxiu comprimit ZIP amb molts fitxersPOST /v1/cards/archive
Un fitxer més gran que el límit d’una sola sol·licitudUna pujada per parts i després qualsevol dels punts finals anteriors.
Contingut nou per a una entrada que ja teniuPUT /v1/cards/{card_id}/content

Per a qualsevol cosa que importeu més d’una vegada, feu servir external_id. Fa que cada importació es pugui repetir: si la torneu a executar, actualitza les entrades que va crear en lloc d’afegir-ne còpies.

Crear o substituir una entrada pel vostre ID

PUT /v1/cards-by-external-id/{external_id} rep l’ID de l’element al vostre sistema. Si cap entrada no té aquest external_id, en crea una (201). Si una entrada el té, en substitueix el contingut i les dades (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"}
  }'

Què passa en una repetició:

  • El contingut no ha canviat: no es crea cap versió nova. La resposta és 200 amb "status": "skipped" i "reason": "unchanged". Repetir la sol·licitud no comporta mai cap risc, fins i tot sense Idempotency-Key.
  • El contingut ha canviat: l’entrada rep una versió nova i es torna a indexar. El títol, les etiquetes, el responsable, la categoria i metadata prenen els valors que heu enviat; metadata se substitueix sencer.
  • La col·lecció i la carpeta només s’apliquen quan es crea l’entrada. Per moure una entrada més endavant, canvieu-la amb PATCH /v1/cards/{card_id}.

Una versió nova retira la verificació de l’entrada, com qualsevol canvi de contingut: un verificador l’ha de tornar a confirmar.

Formats de text

content_typeEl cos és
markdown (per defecte)Markdown.
htmlHTML. Es redueix a un marcatge senzill: títols, paràgrafs, llistes, taules i enllaços http, https i mailto. Els scripts, els estils, els marcs, els formularis i les imatges s’eliminen amb el seu contingut.
textText pla. Els paràgrafs se separen amb línies en blanc.

Esperar l’entrada o no

Per defecte, la sol·licitud retorna quan l’entrada ja es pot trobar, amb "status": "ready" i l’entrada a card. Això triga des d’una fracció de segon, per a un text curt, fins a un minut o més, per a un fitxer llarg.

Per a les importacions massives, envieu "async": true. La resposta arriba immediatament amb "status": "queued" i el treball d’indexació a job (amb el seu job_id). Comproveu el treball amb GET /v1/jobs/{job_id}, o seguiu tots els treballs a GET /v1/jobs/stream. Un treball acaba amb status igual a done, error o canceled.

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

Pujar un fitxer

Els fitxers van en una sol·licitud multipart/form-data, al camp file. Sursa llegeix PDF, Word, Excel, PowerPoint, fulls de càlcul d’OpenDocument, CSV, Markdown, HTML, AsciiDoc, correu electrònic (.eml), text pla i els formats d’imatge habituals. Comprova que el nom, el tipus declarat i el contingut del fitxer concordin, i rebutja una discrepància amb 415.

Per crear o substituir una entrada de fitxer pel vostre ID, envieu el fitxer al mateix 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"}'

En un formulari, tags és una cadena separada per comes i metadata és un objecte JSON escrit com a cadena. Una entrada nova sense title rep el nom del fitxer com a títol.

Per afegir un fitxer una sola vegada, sense ID propi, feu servir POST /v1/cards amb el mateix formulari i una Idempotency-Key. Si pugeu un fitxer que la col·lecció ja té, es retorna "status": "skipped" amb "duplicate": true i el card_id existent, tret que passeu un external_id.

La mida d’un fitxer la limita la instal·lació (200 MB per defecte). Per a fitxers més grans, o per a xarxes poc fiables, pugeu primer el fitxer per parts.

Substituir el contingut d’una entrada

Quan ja teniu l’ID de Sursa d’una entrada, PUT /v1/cards/{card_id}/content en substitueix el text o el fitxer i conserva tota la resta: el responsable, les etiquetes, els verificadors, l’interval de verificació i una categoria definida a mà.

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."}'
  • Si torneu a enviar el mateix contingut, es retorna "status": "skipped" amb "reason": "unchanged".
  • Una entrada que s’està indexant en aquest moment retorna 409 amb el codi cards.indexing_in_progress. Torneu-ho a provar d’aquí a uns segons.
  • Una entrada que prové d’una font, com ara un connector o una font personalitzada, només es canvia a la seva font: cards.managed_by_source.
  • La clau ha de poder veure tota l’entrada; una entrada visible només en part retorna cards.content_whole_access.

Importar molts documents

Un bucle sobre els vostres elements amb PUT /v1/cards-by-external-id/… és la importació massiva més senzilla, i la podeu aturar i tornar a executar en qualsevol moment sense risc. Per fer-la ràpida i respectuosa amb el límit de freqüència:

  1. Envieu "async": true, perquè cada sol·licitud retorni tan bon punt l’entrada és a la cua.
  2. Executeu unes quantes sol·licituds en paral·lel (de 4 a 8) i aneu més a poc a poc quan la capçalera RateLimit mostri que en queden poques. Vegeu Límits de freqüència i quotes.
  3. Amb un 429, espereu el temps de Retry-After; amb un error de xarxa o un 5xx, reintenteu la mateixa sol·licitud. Les repeticions no fan cap mal.
  4. Anoteu l’external_id de cada element que acabi en error i reintenteu-los al final.
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;
}

Per a un arxiu comprimit ZIP de fitxers, POST /v1/cards/archive converteix en una entrada cada fitxer compatible que conté, amb una sola sol·licitud. Respon immediatament amb la previsió (quins fitxers es converteixen en entrades i quins s’ometen, i per què) i un treball; GET /v1/archives/{job_id} informa del resultat.

Trobar i eliminar les entrades importades

Errors habituals

CodiCausaQuè cal fer
collections.not_foundLa clau no veu cap col·lecció amb aquest ID o aquest nom.Comproveu collection_id amb GET /v1/collections.
collections.no_write_accessLa clau no pot escriure en aquesta col·lecció.Feu servir una clau amb el rol editor i accés a la col·lecció.
cards.external_id_takenPOST amb un external_id que ja té una altra entrada.Feu servir PUT /v1/cards-by-external-id/… per substituir-la.
cards.managed_by_sourceL’entrada pertany a una font.Canvieu el document a la seva font.
files.type_mismatchEl nom, el tipus i el contingut del fitxer no concorden.Envieu el fitxer amb la seva extensió real.
files.too_largeEl fitxer supera el límit de pujada o l’emmagatzematge de l’organització.Feu servir una pujada per parts o allibereu espai d’emmagatzematge.
limits.cardsL’organització ha arribat al límit d’entrades del seu pla.Elimineu les entrades que ja no calguin o canvieu de pla.
api.metadata_invalidmetadata supera un límit.Vegeu Metadades.