Anar al contingut
Sursa Developers

Sincronitzar el vostre sistema amb una font personalitzada

Una font personalitzada connecta un sistema que no té cap connector integrat: la vostra wiki, la vostra eina de tiquets, una base de dades, una exportació des d’on sigui. El vostre codi envia documents a Sursa, i Sursa els converteix en entrades a la col·lecció i a les carpetes per a les quals s’ha configurat la font, amb la mateixa cerca, les mateixes respostes, la mateixa verificació i els mateixos permisos que les entrades de qualsevol altra font.

A diferència de l’escriptura directa d’entrades, una font personalitzada porta el compte del que heu enviat. Al final d’una sincronització completa, Sursa arxiva tots els documents que no heu enviat, de manera que les eliminacions al vostre sistema arriben a Sursa sense feina addicional.

Configurar la font

Qui administra l’organització crea la font a Sursa a Sources → New source → Custom source (fonts, font nova, font personalitzada) i tria:

  • la col·lecció i, opcionalment, una carpeta per a les seves entrades;
  • el mode de carpetes: totes les entrades a la carpeta triada, o subcarpetes que reprodueixen el path de cada document;
  • els permisos: els permisos de la col·lecció, o «com a la font», en què cada document indica qui el pot veure.

La pàgina de la font en mostra l’ID; els exemples fan servir 42.

Triar una clau

ClauComença perPot fer
Clau de la fontkbsrc_Escriure documents en aquesta font i prou. Res més: no pot llegir ni cercar. Creeu-la a la pàgina de la font, a API keys (claus d’API de la font).
Clau de l’organització amb l’àmbit import:writekb_Escriure en qualsevol font personalitzada de l’organització i llegir-ne l’estat. Per crear una font i les seves claus cal l’àmbit admin.

La clau de la font és l’opció més segura per a una sola integració, sobretot si s’executa en una plataforma de tercers. Una clau de l’organització amb import:write convé a un servei que alimenta diverses fonts.

Totes dues claus s’envien de la mateixa manera, i tots els punts finals d’enviament són a /v1/push/sources/{source_id}. Comproveu la clau i l’estat de la font amb GET /v1/push/sources/{source_id}:

curl https://api.sursa.com/v1/push/sources/42 \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY"
{"source_id": 42, "name": "Helpdesk articles", "documents": 1840, "open_sync": null}

El document

CampObligatoriDescripció
external_idsíEl vostre ID estable del document, fins a 512 caràcters. Si torneu a enviar el mateix ID, el document se substitueix.
titlesíTítol de l’entrada, fins a 500 caràcters. Per a un fitxer, per defecte, el nom del fitxer.
contentsí, tret que hi hagi un fitxerFins a 5 MB.
content_typenohtml (per defecte), markdown o text. De l’HTML se n’eliminen els scripts, els estils, els formularis i els objectes incrustats.
urlnoEnllaç al document al vostre sistema, que es mostra a l’entrada.
pathnoCarpetes, com a matriu (["Support", "Billing"]) o com a cadena ("Support/Billing"), fins a 10 nivells.
permissionsno{"everyone": true} o {"emails": [...], "groups": [...]}. S’usa quan els permisos de la font són «com a la font».
tagsnoFins a 50 etiquetes, que s’afegeixen a les etiquetes de la font.
author_emailnoSi és un usuari de l’organització, passa a ser el responsable de l’entrada.
updated_atnoQuan va canviar el document al vostre sistema (RFC 3339).
metadatanoLes vostres parelles clau-valor a l’entrada. Vegeu Metadades.
categorynoCategoria de l’entrada: la clau d’una categoria de l’organització.
verifiers, verify_interval_daysnoQui verifica l’entrada (usuaris per correu electrònic i grups) i cada quants dies.
upload_idnoEl fitxer del document d’una pujada per parts, en lloc de content.
attachmentsnoFins a 20 fitxers més del document, com a llista d’upload_id. Cadascun es converteix en una entrada pròpia de la font.

En lloc de content, un sol document pot portar un fitxer de fins a 100 MB en una sol·licitud multipart/form-data: el fitxer a la part file i els camps anteriors en JSON a la part document. Les pujades per parts per a upload_id i attachments es creen amb una clau de l’organització que tingui l’àmbit import:write i la finalitat import_attachment; una clau de la font no les pot crear.

Dues maneres d’enviar

Les actualitzacions directes convenen als sistemes que us informen de cada canvi, com ara un webhook del vostre servei d’assistència o un pas a Zapier. Envieu un document quan es crea o es canvia, i elimineu-lo quan s’esborra:

Sol·licitudFa
POST /v1/push/sources/{source_id}/documentsCrea o substitueix un document.
POST /v1/push/sources/{source_id}/documents/batchCrea o substitueix molts documents alhora.
DELETE /v1/push/sources/{source_id}/documents/{external_id}Elimina un document. Codifiqueu l’ID per a URL.

Els canvis es converteixen en entrades en un minut aproximadament; diversos canvis seguits es processen junts.

Les sincronitzacions convenen a les exportacions periòdiques: ho envieu tot, o tot el que ha canviat, i Sursa ho concilia. La resta d’aquesta guia tracta de les sincronitzacions.

Executar una sincronització completa

Una sincronització té tres passos: obrir, enviar i tancar.

1. Obrir

POST /v1/push/sources/{source_id}/syncs obre una sincronització i en retorna el número:

curl -X POST https://api.sursa.com/v1/push/sources/42/syncs \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Idempotency-Key: sync-2026-10-24" \
  -H "Content-Type: application/json" \
  -d '{"type": "initial", "max_minutes": 180}'
{"sync_number": 7, "type": "initial", "status": "open", "opened_at": "2026-10-24T02:00:00Z",
 "expires_at": "2026-10-24T05:00:00Z", "pushed": 0, "removed": 0}
  • type és initial per a la primera sincronització de la font, i incremental un cop s’ha completat una sincronització. Una sincronització incremental abans que se n’hagi completat cap retorna sources.push_initial_required.
  • Només hi pot haver una sincronització oberta alhora: una segona retorna 409 sources.push_sync_open.
  • Una sincronització es manté oberta durant max_minutes (60 per defecte, fins a 1440). Després caduca: no s’arxiva res i el seu número ja no s’accepta. Trieu un temps clarament més llarg del que triga la vostra exportació.

2. Enviar els documents

Envieu els documents en lots de fins a 500, amb el número de la sincronització. El cos d’un lot pot tenir fins a 50 MiB; els fitxers dins d’un lot es passen com a upload_id.

curl -X POST https://api.sursa.com/v1/push/sources/42/documents/batch \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Idempotency-Key: sync-7-batch-1" \
  -H "Content-Type: application/json" \
  -d '{
    "sync_number": 7,
    "documents": [
      {"external_id": "faq-shipping", "title": "Shipping", "content_type": "markdown",
       "content": "# Shipping\n\nWe ship worldwide within 5 days.", "path": ["Support"]},
      {"external_id": "faq-refunds", "title": "Refunds", "content_type": "html",
       "content": "<p>Refunds take 14 days.</p>", "path": ["Support", "Billing"],
       "permissions": {"groups": ["Support"]}, "metadata": {"article_id": "1042"}}
    ]
  }'

La resposta té un resultat per a cada document, en l’ordre en què els heu enviat:

{
  "results": [
    {"external_id": "faq-shipping", "result": "unchanged", "status": "indexed", "card_id": "8c1d…", "version": "5e0f…"},
    {"external_id": "faq-refunds", "result": "updated", "status": "pending", "card_id": "3f2c…", "version": "a91b…"}
  ]
}
CampSignificat
resultQuè li ha passat ara al document: created, updated, unchanged, deleted, not_found, error o skipped (en un lot atòmic que no s’ha aplicat).
statusEn quin punt és el document en el camí cap a una entrada: pending, processing (l’entrada s’ha escrit i s’està indexant), indexed, failed o removed.
card_idL’entrada del document, un cop existeix.
versionUn hash del contingut i dels camps. El mateix document enviat de nou té la mateixa versió i és unchanged.
error, reasonPer què ha fallat el document. reason és un codi estable: content_invalid, file_rejected, too_large, limit_reached, index_failed o batch_rejected (ha fallat un altre document d’un lot atòmic).

Per defecte, cada document d’un lot s’aplica per separat: un document incorrecte no atura els altres.

Els documents que no han canviat des de l’última sincronització no s’han de tornar a enviar. Confirmeu-los per ID amb POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch, fins a 1000 ID per sol·licitud, perquè la conciliació completa els conservi:

curl -X POST https://api.sursa.com/v1/push/sources/42/syncs/7/touch \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"external_ids": ["faq-contact", "faq-hours"]}'

3. Tancar

POST /v1/push/sources/{source_id}/syncs/{sync_number}/close acaba la sincronització:

curl -X POST https://api.sursa.com/v1/push/sources/42/syncs/7/close \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "complete"}'
statusEfecte
completeConciliació completa. S’arxiva cada document de la font que en aquesta sincronització no s’ha enviat ni confirmat. Feu-lo servir només quan ho hàgiu enviat tot.
complete_incrementalAplica el que heu enviat i no arxiva res.
failedNo arxiva res i conserva el que ja s’ha enviat. Afegiu reason (per exemple, API_ERROR) i error_details per al registre.

Tanqueu amb failed sempre que la vostra exportació s’aturi a mitges: un complete després d’una exportació parcial arxivaria tots els documents als quals no hàgiu arribat. Repetir el mateix tancament retorna el mateix resultat.

Després del tancament, Sursa converteix els documents en entrades en un minut aproximadament. La pàgina de la font mostra cada sincronització amb el nombre de documents enviats i arxivats, i GET /v1/push/sources/{source_id}/syncs/{sync_number} retorna els mateixos comptadors.

Sincronitzacions incrementals

Entre sincronitzacions completes, envieu només el que ha canviat:

  1. Obriu amb "type": "incremental".
  2. Envieu els documents canviats i poseu els ID dels eliminats a deletes (vegeu més avall).
  3. Tanqueu amb complete_incremental.

Executeu de tant en tant una sincronització completa, per exemple cada setmana, per recollir el que una execució incremental s’hagi pogut deixar.

Eliminar documents en un lot

Un lot pot eliminar documents alhora que n’escriu d’altres. Enumereu-ne els ID a deletes:

{
  "sync_number": 8,
  "documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
  "deletes": ["faq-old-returns", "faq-fax"]
}

Cada ID eliminat rep el seu propi element a results, amb result igual a deleted, o not_found si la font no té aquest document. Tornar a eliminar el mateix ID no fa cap mal.

Lots atòmics

Alguns canvis només tenen sentit junts, per exemple un document i el que el substitueix. Envieu "atomic": true i el lot s’aplica sencer o no s’aplica gens: si qualsevol document no supera les comprovacions, no s’aplica res del lot, i la resposta és 422 amb el codi sources.push_batch_rejected i el resultat de cada document a error.details.results: els documents que han fallat tenen error, i els altres, skipped.

{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}

Sense atomic, un lot s’aplica document per document. Feu servir lots atòmics per als canvis relacionats, i lots normals per a les importacions massives, en què un document incorrecte no ha de retenir la resta.

Comprovar el resultat de cada document

La resposta del lot us indica com s’ha escrit cada document. La conversió en entrada es fa després, de manera que status encara pot ser pending. Per trobar els documents d’una sincronització que no s’han convertit en entrades:

curl "https://api.sursa.com/v1/push/sources/42/syncs/7/documents?status=failed" \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY"

Cada element té external_id, title, status, card_id, version i reason, i la llista es pagina amb cursor. status també admet pending, processing, indexed i removed.

També podeu rebre avisos en lloc de preguntar: els esdeveniments import.sync_completed (una sincronització s’ha tancat i processat, amb els seus totals) i import.document_failed (un document no s’ha convertit en entrada, amb el seu reason) arriben per webhook i al canal d’esdeveniments.

Reintents

  • Envieu una Idempotency-Key amb cada POST. Un lot repetit amb la mateixa clau retorna el primer resultat.
  • Fins i tot sense la clau, un document amb el mateix external_id no es converteix mai en una segona entrada: és unchanged o updated.
  • Si el procés s’atura enmig d’una sincronització, obriu-ne una de nova quan caduqui l’antiga, o tanqueu l’antiga amb failed si encara en teniu el número, i torneu a executar la sincronització.

Límits

LímitValor
Contingut d’un document5 MB
Fitxer en una sol·licitud d’un sol document100 MB
Documents per lot500
Cos de la sol·licitud d’un lot50 MiB
ID per sol·licitud touch1000
Documents per fontDepèn del pla: a partir de 100.000
Sincronització oberta60 minuts per defecte, fins a 24 hores

Un document per sobre del límit de documents de la font falla amb el motiu limit_reached en un lot; una sol·licitud d’un sol document respon 409 amb el codi sources.push_too_many_documents. Els límits de freqüència s’hi apliquen com a qualsevol altra sol·licitud; vegeu Límits de freqüència i quotes.

Errors habituals

RespostaCausaQuè cal fer
401 sources.push_key_invalidLa clau és incorrecta, s’ha revocat o pertany a una altra font.Comproveu la clau i l’ID de la font al camí.
400 sources.push_document_invalidFalta un camp obligatori o s’ha superat un límit.Corregiu el document; en un lot normal, només falla aquell document.
409 sources.push_sync_openEncara hi ha una altra sincronització oberta.Tanqueu-la o espereu que caduqui.
409 sources.push_sync_closedLa sincronització està tancada o ha caducat.Obriu una sincronització nova; augmenteu max_minutes per a exportacions llargues.
403 sources.feature_disabledLes fonts no formen part del pla de l’organització.Contacteu amb qui administra l’organització.
429Massa sol·licituds.Espereu el temps de Retry-After; envieu menys lots i més grans.