Je systeem synchroniseren met een eigen bron
Een eigen bron koppelt een systeem waarvoor geen ingebouwde connector bestaat: je wiki, je ticketsysteem, een database, een export van waar dan ook. Je code verstuurt documenten naar Sursa, en Sursa maakt er kaarten van in de collectie en de mappen waarvoor de bron is ingesteld, met hetzelfde zoeken, dezelfde antwoorden, verificatie en rechten als kaarten uit elke andere bron.
Anders dan bij rechtstreeks kaarten schrijven houdt een eigen bron bij wat je hebt verstuurd. Aan het eind van een volledige synchronisatie archiveert Sursa elk document dat je niet hebt verstuurd, zodat verwijderingen in je systeem zonder extra werk in Sursa aankomen.
De bron instellen
Een beheerder maakt de bron in Sursa onder Sources → New source → Custom source (bronnen → nieuwe bron → eigen bron) en kiest:
- de collectie en, optioneel, een map voor de kaarten;
- de mapmodus: alle kaarten in de gekozen map, of submappen die het
pathvan elk document volgen; - de rechten: de rechten van de collectie, of “zoals in de bron”, waarbij elk document vermeldt wie het mag zien.
De pagina van de bron toont de ID ervan; de voorbeelden gebruiken 42.
Een sleutel kiezen
| Sleutel | Begint met | Kan |
|---|---|---|
| Bronsleutel | kbsrc_ | Documenten naar deze ene bron schrijven. Verder niets: hij kan niet lezen of zoeken. Maak hem op de pagina van de bron onder API keys. |
Sleutel van de organisatie met de scope import:write | kb_ | Naar elke eigen bron van de organisatie schrijven en de toestand ervan lezen. Voor het maken van een bron en de sleutels ervan is de scope admin nodig. |
De bronsleutel is de veiligste keuze voor één integratie, vooral een die op een platform van derden draait. Een
sleutel van de organisatie met import:write past bij een dienst die meerdere bronnen voedt.
Beide sleutels worden op dezelfde manier meegestuurd, en elk push-endpoint staat onder /v1/push/sources/{source_id}.
Controleer de sleutel en de toestand van de bron met 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}
Het document
| Veld | Verplicht | Beschrijving |
|---|---|---|
external_id | ja | Je stabiele ID van het document, maximaal 512 tekens. Dezelfde ID opnieuw versturen vervangt het document. |
title | ja | Titel van de kaart, maximaal 500 tekens. Voor een bestand standaard de bestandsnaam. |
content | ja, tenzij er een bestand is | Maximaal 5 MB. |
content_type | nee | html (standaard), markdown of text. HTML wordt opgeschoond: scripts, stijlen, formulieren en ingesloten objecten worden verwijderd. |
url | nee | Link naar het document in je systeem, getoond op de kaart. |
path | nee | Mappen, als array (["Support", "Billing"]) of als string ("Support/Billing"), maximaal 10 niveaus. |
permissions | nee | {"everyone": true}, of {"emails": [...], "groups": [...]}. Gebruikt als de rechten van de bron “zoals in de bron” zijn. |
tags | nee | Maximaal 50 tags, toegevoegd aan de tags van de bron. |
author_email | nee | Is dit een gebruiker van de organisatie, dan wordt die de eigenaar van de kaart. |
updated_at | nee | Wanneer het document in je systeem is gewijzigd (RFC 3339). |
metadata | nee | Je sleutel-waardeparen op de kaart. Zie Metadata. |
category | nee | Categorie van de kaart: de sleutel van een categorie van de organisatie. |
verifiers, verify_interval_days | nee | Wie de kaart verifieert (gebruikers op e-mailadres en groepen) en hoe vaak, in dagen. |
upload_id | nee | Het bestand van het document uit een upload in delen, in plaats van content. |
attachments | nee | Maximaal 20 extra bestanden van het document, als lijst van upload_id. Elk bestand wordt een eigen kaart van de bron. |
In plaats van content kan één document een bestand tot 100 MB meenemen in een multipart/form-data-request: het
bestand in het deel file, de velden hierboven als JSON in het deel document. Uploads in delen voor upload_id en
attachments worden gemaakt met een sleutel van de organisatie die de scope import:write heeft, met het doel
import_attachment; een bronsleutel kan ze niet maken.
Twee manieren om te versturen
Directe updates passen bij systemen die je over elke wijziging informeren, zoals een webhook van je helpdesk of een stap in Zapier. Stuur een document als het wordt gemaakt of gewijzigd, en verwijder het als het wordt weggehaald:
| Request | Doet |
|---|---|
POST /v1/push/sources/{source_id}/documents | Maakt of vervangt één document. |
POST /v1/push/sources/{source_id}/documents/batch | Maakt of vervangt veel documenten tegelijk. |
DELETE /v1/push/sources/{source_id}/documents/{external_id} | Verwijdert één document. Codeer de ID voor de URL. |
Wijzigingen worden binnen ongeveer een minuut kaarten; meerdere wijzigingen achter elkaar worden samen verwerkt.
Synchronisaties passen bij regelmatige exports: je stuurt alles, of alles wat is gewijzigd, en Sursa stemt af. De rest van deze handleiding gaat over synchronisaties.
Een volledige synchronisatie uitvoeren
Een synchronisatie heeft drie stappen: openen, versturen, sluiten.
1. Openen
POST /v1/push/sources/{source_id}/syncs opent een synchronisatie en geeft het
nummer ervan terug:
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}
typeisinitialvoor de eerste synchronisatie van de bron, enincrementalzodra er een synchronisatie is voltooid. Eenincremental-synchronisatie vóór een voltooide synchronisatie geeftsources.push_initial_required.- Er kan maar één synchronisatie tegelijk open zijn: een tweede geeft
409sources.push_sync_open. - Een synchronisatie blijft
max_minutesopen (standaard 60, maximaal 1440). Daarna verloopt ze: er wordt niets gearchiveerd en haar nummer wordt niet meer geaccepteerd. Kies een tijd die ruim langer is dan je export duurt.
2. Documenten versturen
Stuur de documenten in batches van maximaal 500, met het nummer van de synchronisatie. De body van een batch is
maximaal 50 MiB; bestanden in een batch worden meegegeven als 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"}}
]
}'De response bevat een resultaat voor elk document, in de volgorde waarin je ze hebt verstuurd:
{
"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…"}
]
}
| Veld | Betekenis |
|---|---|
result | Wat er nu met het document is gebeurd: created, updated, unchanged, deleted, not_found, error of skipped (in een atomaire batch die niet is verwerkt). |
status | Waar het document is op weg naar een kaart: pending, processing (de kaart is geschreven en wordt geïndexeerd), indexed, failed of removed. |
card_id | De kaart van het document, zodra die bestaat. |
version | Een hash van de inhoud en de velden. Hetzelfde document opnieuw versturen geeft dezelfde versie en is unchanged. |
error, reason | Waarom het document is mislukt. reason is een stabiele code: content_invalid, file_rejected, too_large, limit_reached, index_failed of batch_rejected (een ander document van een atomaire batch is mislukt). |
Standaard wordt elk document van een batch afzonderlijk verwerkt: één slecht document houdt de andere niet tegen.
Documenten die sinds de vorige synchronisatie niet zijn veranderd, hoef je niet opnieuw te versturen. Bevestig ze op
ID met POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch,
maximaal 1000 ID’s per request, zodat de volledige afstemming ze behoudt:
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. Sluiten
POST /v1/push/sources/{source_id}/syncs/{sync_number}/close beëindigt de
synchronisatie:
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 | Effect |
|---|---|
complete | Volledige afstemming. Elk document van de bron dat in deze synchronisatie niet is verstuurd en niet is bevestigd, wordt gearchiveerd. Gebruik dit alleen als je alles hebt verstuurd. |
complete_incremental | Verwerkt wat je hebt verstuurd en archiveert niets. |
failed | Archiveert niets en behoudt wat al is verstuurd. Voeg reason (bijvoorbeeld API_ERROR) en error_details toe voor het log. |
Sluit met failed zodra je export halverwege stopt: een complete na een gedeeltelijke export zou elk document
archiveren waaraan je niet bent toegekomen. Dezelfde sluiting herhalen geeft hetzelfde resultaat.
Na het sluiten maakt Sursa binnen ongeveer een minuut kaarten van de documenten. De pagina van de bron toont elke
synchronisatie met het aantal verstuurde en gearchiveerde documenten, en
GET /v1/push/sources/{source_id}/syncs/{sync_number} geeft dezelfde tellers
terug.
Incrementele synchronisaties
Stuur tussen volledige synchronisaties alleen wat er is gewijzigd:
- Open met
"type": "incremental". - Verstuur de gewijzigde documenten en zet de ID’s van verwijderde documenten in
deletes(zie hieronder). - Sluit met
complete_incremental.
Voer af en toe een volledige synchronisatie uit, bijvoorbeeld wekelijks, om op te vangen wat een incrementele run heeft gemist.
Documenten verwijderen in een batch
Een batch kan documenten verwijderen samen met de documenten die hij schrijft. Zet hun ID’s in deletes:
{
"sync_number": 8,
"documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
"deletes": ["faq-old-returns", "faq-fax"]
}
Elke verwijderde ID krijgt een eigen item in results, met result deleted, of not_found als de bron zo’n
document niet heeft. Dezelfde ID nog een keer verwijderen kan geen kwaad.
Atomaire batches
Sommige wijzigingen hebben alleen samen zin, bijvoorbeeld een document en het document dat het vervangt. Stuur
"atomic": true mee, en de batch wordt volledig of helemaal niet verwerkt: als een document de controles niet
doorstaat, wordt er niets van de batch verwerkt, en de response is 422 met de code sources.push_batch_rejected en
het resultaat van elk document in error.details.results: de mislukte documenten hebben error, de andere skipped.
{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}
Zonder atomic wordt een batch document voor document verwerkt. Gebruik atomaire batches voor samenhangende
wijzigingen, en gewone batches voor grote ladingen, waarbij één slecht document de rest niet mag ophouden.
Het resultaat van elk document controleren
De response op een batch vertelt je hoe elk document is geschreven. Het omzetten in een kaart gebeurt daarna, dus
status kan nog pending zijn. Zo vind je de documenten van een synchronisatie die geen kaart zijn geworden:
curl "https://api.sursa.com/v1/push/sources/42/syncs/7/documents?status=failed" \
-H "Authorization: Bearer $SURSA_SOURCE_KEY"Elk item heeft external_id, title, status, card_id, version en reason, en de lijst pagineert met cursor.
status accepteert ook pending, processing, indexed en removed.
Je kunt het ook laten melden in plaats van het te vragen: de events import.sync_completed (een synchronisatie is
gesloten en verwerkt, met de totalen) en import.document_failed (een document is geen kaart geworden, met de
reason) komen binnen via een webhook en in de
eventfeed.
Nieuwe pogingen
- Stuur bij elke
POSTeenIdempotency-Keymee. Een herhaalde batch met dezelfde sleutel geeft het eerste resultaat terug. - Ook zonder de sleutel wordt een document met dezelfde
external_idnooit een tweede kaart: het isunchangedofupdated. - Stopt het proces midden in een synchronisatie, open dan een nieuwe zodra de oude is verlopen, of sluit de oude met
failedals je het nummer nog hebt, en voer de synchronisatie opnieuw uit.
Limieten
| Limiet | Waarde |
|---|---|
| Inhoud van één document | 5 MB |
| Bestand in een request met één document | 100 MB |
| Documenten per batch | 500 |
| Body van een batchrequest | 50 MiB |
ID’s per touch-request | 1000 |
| Documenten per bron | Afhankelijk van het abonnement: vanaf 100.000 |
| Open synchronisatie | Standaard 60 minuten, maximaal 24 uur |
Een document boven de documentlimiet van de bron mislukt in een batch met de reden limit_reached; een request met één document
geeft 409 met de code sources.push_too_many_documents.
Snelheidslimieten gelden net als voor elk ander request; zie Snelheidslimieten en quota.
Veelvoorkomende fouten
| Antwoord | Oorzaak | Wat je doet |
|---|---|---|
401 sources.push_key_invalid | De sleutel is onjuist, ingetrokken of hoort bij een andere bron. | Controleer de sleutel en de ID van de bron in het pad. |
400 sources.push_document_invalid | Er ontbreekt een verplicht veld of een limiet is overschreden. | Corrigeer het document; in een gewone batch mislukt alleen dat document. |
409 sources.push_sync_open | Er is nog een andere synchronisatie open. | Sluit die, of wacht tot ze verloopt. |
409 sources.push_sync_closed | De synchronisatie is gesloten of verlopen. | Open een nieuwe synchronisatie; verhoog max_minutes voor lange exports. |
403 sources.feature_disabled | Bronnen maken geen deel uit van het abonnement van de organisatie. | Neem contact op met de beheerder. |
429 | Te veel requests. | Wacht de tijd uit Retry-After af; stuur minder, grotere batches. |