Synchroniser votre système avec une source personnalisée
Une source personnalisée connecte un système qui n’a pas de connecteur intégré : votre wiki, votre outil de tickets, une base de données, un export d’où que ce soit. Votre code envoie des documents à Sursa, et Sursa en fait des fiches dans la collection et les dossiers pour lesquels la source est configurée, avec la même recherche, les mêmes réponses, la même validation et les mêmes permissions que les fiches de n’importe quelle autre source.
Contrairement à l’écriture directe de fiches, une source personnalisée garde la trace de ce que vous avez envoyé. À la fin d’une synchronisation complète, Sursa archive chaque document que vous n’avez pas envoyé : les suppressions faites dans votre système parviennent ainsi à Sursa sans travail supplémentaire.
Configurer la source
Un administrateur crée la source dans Sursa sous Sources → New source → Custom source et choisit :
- la collection et, éventuellement, un dossier pour ses fiches ;
- le mode des dossiers : toutes les fiches dans le dossier choisi, ou des sous-dossiers qui reproduisent le
pathde chaque document ; - les permissions : celles de la collection, ou « comme dans la source », où chaque document indique qui peut le voir.
La page de la source affiche son identifiant ; les exemples utilisent 42.
Choisir une clé
| Clé | Commence par | Peut |
|---|---|---|
| Clé de source | kbsrc_ | Écrire des documents dans cette seule source. Rien d’autre : elle ne peut ni lire ni rechercher. Créez-la sur la page de la source, sous API keys. |
Clé de l’organisation dotée de la portée import:write | kb_ | Écrire dans n’importe quelle source personnalisée de l’organisation et lire son état. La création d’une source et de ses clés exige la portée admin. |
La clé de source est le choix le plus sûr pour une intégration unique, surtout si elle tourne sur une plateforme
tierce. Une clé de l’organisation dotée de import:write convient à un service qui alimente plusieurs sources.
Les deux clés s’envoient de la même façon, et tous les points de terminaison d’envoi se trouvent sous
/v1/push/sources/{source_id}. Vérifiez la clé et l’état de la source avec
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}
Le document
| Champ | Obligatoire | Description |
|---|---|---|
external_id | oui | Votre identifiant stable du document, jusqu’à 512 caractères. Renvoyer le même identifiant remplace le document. |
title | oui | Titre de la fiche, jusqu’à 500 caractères. Pour un fichier, le nom du fichier par défaut. |
content | oui, sauf s’il y a un fichier | Jusqu’à 5 Mo. |
content_type | non | html (par défaut), markdown ou text. Le HTML est nettoyé des scripts, des styles, des formulaires et des objets intégrés. |
url | non | Lien vers le document dans votre système, affiché sur la fiche. |
path | non | Dossiers, sous forme de tableau (["Support", "Billing"]) ou de chaîne ("Support/Billing"), jusqu’à 10 niveaux. |
permissions | non | {"everyone": true}, ou {"emails": [...], "groups": [...]}. Utilisé quand les permissions de la source sont « comme dans la source ». |
tags | non | Jusqu’à 50 étiquettes, ajoutées aux étiquettes de la source. |
author_email | non | S’il s’agit d’un utilisateur de l’organisation, il devient le responsable de la fiche. |
updated_at | non | Date de modification du document dans votre système (RFC 3339). |
metadata | non | Vos paires clé-valeur sur la fiche. Voir Métadonnées. |
category | non | Catégorie de la fiche : la clé d’une catégorie de l’organisation. |
verifiers, verify_interval_days | non | Qui valide la fiche (utilisateurs par adresse e-mail et groupes) et à quelle fréquence, en jours. |
upload_id | non | Le fichier du document issu d’un téléversement en plusieurs parties, à la place de content. |
attachments | non | Jusqu’à 20 fichiers supplémentaires du document, sous forme de liste d’upload_id. Chacun devient une fiche distincte de la source. |
À la place de content, un document seul peut porter un fichier d’au plus 100 Mo dans une requête
multipart/form-data : le fichier dans la partie file, les champs ci-dessus en JSON dans la partie document. Les
téléversements en plusieurs parties pour upload_id et attachments se créent avec une clé de l’organisation dotée de
la portée import:write et de la destination import_attachment ; une clé de source ne peut pas les créer.
Deux façons d’envoyer
Les mises à jour directes conviennent aux systèmes qui vous signalent chaque modification, comme un webhook de votre outil de support ou une étape dans Zapier. Envoyez un document quand il est créé ou modifié, et supprimez-le quand il est retiré :
| Requête | Effet |
|---|---|
POST /v1/push/sources/{source_id}/documents | Crée ou remplace un document. |
POST /v1/push/sources/{source_id}/documents/batch | Crée ou remplace plusieurs documents à la fois. |
DELETE /v1/push/sources/{source_id}/documents/{external_id} | Supprime un document. Encodez l’identifiant pour l’URL. |
Les modifications deviennent des fiches en une minute environ ; plusieurs modifications successives sont traitées ensemble.
Les synchronisations conviennent aux exports réguliers : vous envoyez tout, ou tout ce qui a changé, et Sursa fait le rapprochement. La suite de ce guide porte sur les synchronisations.
Lancer une synchronisation complète
Une synchronisation compte trois étapes : ouvrir, envoyer, fermer.
1. Ouvrir
POST /v1/push/sources/{source_id}/syncs ouvre une synchronisation et renvoie
son numéro :
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}
typevautinitialpour la première synchronisation de la source, puisincrementaldès qu’une synchronisation s’est terminée. Une synchronisationincrementalavant toute synchronisation terminée renvoiesources.push_initial_required.- Une seule synchronisation peut être ouverte à la fois : une deuxième renvoie
409sources.push_sync_open. - Une synchronisation reste ouverte pendant
max_minutes(60 par défaut, jusqu’à 1440). Ensuite, elle expire : rien n’est archivé et son numéro n’est plus accepté. Choisissez une durée nettement plus longue que celle de votre export.
2. Envoyer les documents
Envoyez les documents par lots d’au plus 500, avec le numéro de la synchronisation. Le corps d’un lot fait au plus
50 Mio ; les fichiers d’un lot sont transmis sous forme d'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 réponse contient un résultat pour chaque document, dans l’ordre d’envoi :
{
"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…"}
]
}
| Champ | Signification |
|---|---|
result | Ce qui vient d’arriver au document : created, updated, unchanged, deleted, not_found, error ou skipped (dans un lot atomique qui n’a pas été appliqué). |
status | L’étape où se trouve le document sur le chemin qui le mène à une fiche : pending, processing (la fiche est écrite et en cours d’indexation), indexed, failed ou removed. |
card_id | La fiche du document, une fois qu’elle existe. |
version | Une empreinte du contenu et des champs. Le même document renvoyé a la même version et vaut unchanged. |
error, reason | Pourquoi le document a échoué. reason est un code stable : content_invalid, file_rejected, too_large, limit_reached, index_failed ou batch_rejected (un autre document d’un lot atomique a échoué). |
Par défaut, chaque document d’un lot est appliqué séparément : un document défectueux n’arrête pas les autres.
Les documents qui n’ont pas changé depuis la dernière synchronisation n’ont pas besoin d’être renvoyés. Confirmez-les
par identifiant avec POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch,
jusqu’à 1000 identifiants par requête, pour que le rapprochement complet les conserve :
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. Fermer
POST /v1/push/sources/{source_id}/syncs/{sync_number}/close termine la
synchronisation :
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 | Effet |
|---|---|
complete | Rapprochement complet. Chaque document de la source qui n’a été ni envoyé ni confirmé pendant cette synchronisation est archivé. Ne l’utilisez que si vous avez tout envoyé. |
complete_incremental | Applique ce que vous avez envoyé et n’archive rien. |
failed | N’archive rien et conserve ce qui a déjà été envoyé. Ajoutez reason (par exemple API_ERROR) et error_details pour le journal. |
Fermez avec failed chaque fois que votre export s’arrête en cours de route : un complete après un export partiel
archiverait tous les documents que vous n’avez pas eu le temps d’envoyer. Répéter la même fermeture renvoie le même
résultat.
Après la fermeture, Sursa transforme les documents en fiches en une minute environ. La page de la source affiche
chaque synchronisation avec le nombre de documents envoyés et archivés, et
GET /v1/push/sources/{source_id}/syncs/{sync_number} renvoie les mêmes
compteurs.
Synchronisations incrémentales
Entre deux synchronisations complètes, n’envoyez que ce qui a changé :
- Ouvrez avec
"type": "incremental". - Envoyez les documents modifiés et placez les identifiants des documents retirés dans
deletes(voir ci-dessous). - Fermez avec
complete_incremental.
Lancez de temps en temps une synchronisation complète, par exemple chaque semaine, pour rattraper ce qu’une exécution incrémentale aurait manqué.
Supprimer des documents dans un lot
Un lot peut supprimer des documents en même temps qu’il en écrit d’autres. Listez leurs identifiants dans deletes :
{
"sync_number": 8,
"documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
"deletes": ["faq-old-returns", "faq-fax"]
}
Chaque identifiant supprimé reçoit sa propre entrée dans results, avec result égal à deleted, ou à not_found
si la source n’a pas ce document. Supprimer de nouveau le même identifiant est sans conséquence.
Lots atomiques
Certaines modifications n’ont de sens qu’ensemble, par exemple un document et celui qui le remplace. Envoyez
"atomic": true : le lot est alors appliqué entièrement ou pas du tout. Si un document échoue à ses vérifications,
rien du lot n’est appliqué, et la réponse est 422 avec le code sources.push_batch_rejected et le résultat de
chaque document dans error.details.results : les documents qui ont échoué ont error, les autres skipped.
{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}
Sans atomic, un lot est appliqué document par document. Utilisez les lots atomiques pour les modifications liées, et
les lots ordinaires pour les chargements en masse, où un document défectueux ne doit pas retenir les autres.
Vérifier le résultat de chaque document
La réponse au lot vous indique comment chaque document a été écrit. Sa transformation en fiche a lieu ensuite : le
status peut donc encore valoir pending. Pour trouver les documents d’une synchronisation qui ne sont pas devenus
des fiches :
curl "https://api.sursa.com/v1/push/sources/42/syncs/7/documents?status=failed" \
-H "Authorization: Bearer $SURSA_SOURCE_KEY"Chaque entrée a external_id, title, status, card_id, version et reason, et la liste se pagine avec
cursor. status accepte aussi pending, processing, indexed et removed.
Vous pouvez aussi être prévenu au lieu de demander : les événements import.sync_completed (une synchronisation est
fermée et traitée, avec ses totaux) et import.document_failed (un document n’est pas devenu une fiche, avec son
reason) arrivent par webhook et dans le
flux d’événements.
Nouvelles tentatives
- Envoyez un en-tête
Idempotency-Keyavec chaquePOST. Un lot répété avec la même clé renvoie le premier résultat. - Même sans la clé, un document qui porte le même
external_idne devient jamais une seconde fiche : il estunchangedouupdated. - Si le processus s’arrête au milieu d’une synchronisation, ouvrez-en une nouvelle après l’expiration de l’ancienne, ou
fermez l’ancienne avec
failedsi vous avez encore son numéro, puis relancez la synchronisation.
Limites
| Limite | Valeur |
|---|---|
| Contenu d’un document | 5 Mo |
| Fichier dans une requête à document unique | 100 Mo |
| Documents par lot | 500 |
| Corps de la requête d’un lot | 50 Mio |
Identifiants par requête touch | 1000 |
| Documents par source | Selon l’offre : à partir de 100 000 |
| Synchronisation ouverte | 60 minutes par défaut, jusqu’à 24 heures |
Dans un lot, un document qui dépasse la limite de documents de la source échoue avec le motif limit_reached ; une
requête à document unique répond 409 avec le code
sources.push_too_many_documents. Les limites de débit s’appliquent comme à toute autre requête ; voir Limites de débit et quotas.
Erreurs courantes
| Réponse | Cause | Que faire |
|---|---|---|
401 sources.push_key_invalid | La clé est erronée, révoquée ou appartient à une autre source. | Vérifiez la clé et l’identifiant de la source dans le chemin. |
400 sources.push_document_invalid | Un champ obligatoire manque ou une limite est dépassée. | Corrigez le document ; dans un lot ordinaire, seul ce document échoue. |
409 sources.push_sync_open | Une autre synchronisation est encore ouverte. | Fermez-la, ou attendez qu’elle expire. |
409 sources.push_sync_closed | La synchronisation est fermée ou a expiré. | Ouvrez une nouvelle synchronisation ; augmentez max_minutes pour les exports longs. |
403 sources.feature_disabled | Les sources ne font pas partie de l’offre de l’organisation. | Contactez l’administrateur. |
429 | Trop de requêtes. | Attendez la durée de Retry-After ; envoyez moins de lots, mais plus gros. |