Direct naar de inhoud
Sursa Developers

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 path van 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

SleutelBegint metKan
Bronsleutelkbsrc_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:writekb_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

VeldVerplichtBeschrijving
external_idjaJe stabiele ID van het document, maximaal 512 tekens. Dezelfde ID opnieuw versturen vervangt het document.
titlejaTitel van de kaart, maximaal 500 tekens. Voor een bestand standaard de bestandsnaam.
contentja, tenzij er een bestand isMaximaal 5 MB.
content_typeneehtml (standaard), markdown of text. HTML wordt opgeschoond: scripts, stijlen, formulieren en ingesloten objecten worden verwijderd.
urlneeLink naar het document in je systeem, getoond op de kaart.
pathneeMappen, als array (["Support", "Billing"]) of als string ("Support/Billing"), maximaal 10 niveaus.
permissionsnee{"everyone": true}, of {"emails": [...], "groups": [...]}. Gebruikt als de rechten van de bron “zoals in de bron” zijn.
tagsneeMaximaal 50 tags, toegevoegd aan de tags van de bron.
author_emailneeIs dit een gebruiker van de organisatie, dan wordt die de eigenaar van de kaart.
updated_atneeWanneer het document in je systeem is gewijzigd (RFC 3339).
metadataneeJe sleutel-waardeparen op de kaart. Zie Metadata.
categoryneeCategorie van de kaart: de sleutel van een categorie van de organisatie.
verifiers, verify_interval_daysneeWie de kaart verifieert (gebruikers op e-mailadres en groepen) en hoe vaak, in dagen.
upload_idneeHet bestand van het document uit een upload in delen, in plaats van content.
attachmentsneeMaximaal 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:

RequestDoet
POST /v1/push/sources/{source_id}/documentsMaakt of vervangt één document.
POST /v1/push/sources/{source_id}/documents/batchMaakt 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}
  • type is initial voor de eerste synchronisatie van de bron, en incremental zodra er een synchronisatie is voltooid. Een incremental-synchronisatie vóór een voltooide synchronisatie geeft sources.push_initial_required.
  • Er kan maar één synchronisatie tegelijk open zijn: een tweede geeft 409 sources.push_sync_open.
  • Een synchronisatie blijft max_minutes open (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…"}
  ]
}
VeldBetekenis
resultWat er nu met het document is gebeurd: created, updated, unchanged, deleted, not_found, error of skipped (in een atomaire batch die niet is verwerkt).
statusWaar het document is op weg naar een kaart: pending, processing (de kaart is geschreven en wordt geïndexeerd), indexed, failed of removed.
card_idDe kaart van het document, zodra die bestaat.
versionEen hash van de inhoud en de velden. Hetzelfde document opnieuw versturen geeft dezelfde versie en is unchanged.
error, reasonWaarom 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"}'
statusEffect
completeVolledige 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_incrementalVerwerkt wat je hebt verstuurd en archiveert niets.
failedArchiveert 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:

  1. Open met "type": "incremental".
  2. Verstuur de gewijzigde documenten en zet de ID’s van verwijderde documenten in deletes (zie hieronder).
  3. 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 POST een Idempotency-Key mee. Een herhaalde batch met dezelfde sleutel geeft het eerste resultaat terug.
  • Ook zonder de sleutel wordt een document met dezelfde external_id nooit een tweede kaart: het is unchanged of updated.
  • Stopt het proces midden in een synchronisatie, open dan een nieuwe zodra de oude is verlopen, of sluit de oude met failed als je het nummer nog hebt, en voer de synchronisatie opnieuw uit.

Limieten

LimietWaarde
Inhoud van één document5 MB
Bestand in een request met één document100 MB
Documenten per batch500
Body van een batchrequest50 MiB
ID’s per touch-request1000
Documenten per bronAfhankelijk van het abonnement: vanaf 100.000
Open synchronisatieStandaard 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

AntwoordOorzaakWat je doet
401 sources.push_key_invalidDe 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_invalidEr ontbreekt een verplicht veld of een limiet is overschreden.Corrigeer het document; in een gewone batch mislukt alleen dat document.
409 sources.push_sync_openEr is nog een andere synchronisatie open.Sluit die, of wacht tot ze verloopt.
409 sources.push_sync_closedDe synchronisatie is gesloten of verlopen.Open een nieuwe synchronisatie; verhoog max_minutes voor lange exports.
403 sources.feature_disabledBronnen maken geen deel uit van het abonnement van de organisatie.Neem contact op met de beheerder.
429Te veel requests.Wacht de tijd uit Retry-After af; stuur minder, grotere batches.