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
pathde 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
| Clau | Comença per | Pot fer |
|---|---|---|
| Clau de la font | kbsrc_ | 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:write | kb_ | 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
| Camp | Obligatori | Descripció |
|---|---|---|
external_id | sí | El vostre ID estable del document, fins a 512 caràcters. Si torneu a enviar el mateix ID, el document se substitueix. |
title | sí | Títol de l’entrada, fins a 500 caràcters. Per a un fitxer, per defecte, el nom del fitxer. |
content | sí, tret que hi hagi un fitxer | Fins a 5 MB. |
content_type | no | html (per defecte), markdown o text. De l’HTML se n’eliminen els scripts, els estils, els formularis i els objectes incrustats. |
url | no | Enllaç al document al vostre sistema, que es mostra a l’entrada. |
path | no | Carpetes, com a matriu (["Support", "Billing"]) o com a cadena ("Support/Billing"), fins a 10 nivells. |
permissions | no | {"everyone": true} o {"emails": [...], "groups": [...]}. S’usa quan els permisos de la font són «com a la font». |
tags | no | Fins a 50 etiquetes, que s’afegeixen a les etiquetes de la font. |
author_email | no | Si és un usuari de l’organització, passa a ser el responsable de l’entrada. |
updated_at | no | Quan va canviar el document al vostre sistema (RFC 3339). |
metadata | no | Les vostres parelles clau-valor a l’entrada. Vegeu Metadades. |
category | no | Categoria de l’entrada: la clau d’una categoria de l’organització. |
verifiers, verify_interval_days | no | Qui verifica l’entrada (usuaris per correu electrònic i grups) i cada quants dies. |
upload_id | no | El fitxer del document d’una pujada per parts, en lloc de content. |
attachments | no | Fins 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·licitud | Fa |
|---|---|
POST /v1/push/sources/{source_id}/documents | Crea o substitueix un document. |
POST /v1/push/sources/{source_id}/documents/batch | Crea 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ésinitialper a la primera sincronització de la font, iincrementalun cop s’ha completat una sincronització. Una sincronitzacióincrementalabans que se n’hagi completat cap retornasources.push_initial_required.- Només hi pot haver una sincronització oberta alhora: una segona retorna
409sources.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…"}
]
}
| Camp | Significat |
|---|---|
result | Què 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). |
status | En 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_id | L’entrada del document, un cop existeix. |
version | Un hash del contingut i dels camps. El mateix document enviat de nou té la mateixa versió i és unchanged. |
error, reason | Per 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"}'status | Efecte |
|---|---|
complete | Conciliació 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_incremental | Aplica el que heu enviat i no arxiva res. |
failed | No 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:
- Obriu amb
"type": "incremental". - Envieu els documents canviats i poseu els ID dels eliminats a
deletes(vegeu més avall). - 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-Keyamb cadaPOST. Un lot repetit amb la mateixa clau retorna el primer resultat. - Fins i tot sense la clau, un document amb el mateix
external_idno es converteix mai en una segona entrada: ésunchangedoupdated. - Si el procés s’atura enmig d’una sincronització, obriu-ne una de nova quan caduqui l’antiga, o tanqueu l’antiga amb
failedsi encara en teniu el número, i torneu a executar la sincronització.
Límits
| Límit | Valor |
|---|---|
| Contingut d’un document | 5 MB |
| Fitxer en una sol·licitud d’un sol document | 100 MB |
| Documents per lot | 500 |
| Cos de la sol·licitud d’un lot | 50 MiB |
ID per sol·licitud touch | 1000 |
| Documents per font | Depèn del pla: a partir de 100.000 |
| Sincronització oberta | 60 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
| Resposta | Causa | Què cal fer |
|---|---|---|
401 sources.push_key_invalid | La 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_invalid | Falta 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_open | Encara hi ha una altra sincronització oberta. | Tanqueu-la o espereu que caduqui. |
409 sources.push_sync_closed | La sincronització està tancada o ha caducat. | Obriu una sincronització nova; augmenteu max_minutes per a exportacions llargues. |
403 sources.feature_disabled | Les fonts no formen part del pla de l’organització. | Contacteu amb qui administra l’organització. |
429 | Massa sol·licituds. | Espereu el temps de Retry-After; envieu menys lots i més grans. |