Salt la conținut
Sursa Developers

Sincronizați sistemul propriu cu o sursă personalizată

O sursă personalizată conectează un sistem care nu are un conector predefinit: wikiul intern, instrumentul de tichete, o bază de date, un export de oriunde. Codul dumneavoastră trimite documente în Sursa, iar Sursa le transformă în fișe în colecția și în dosarele pentru care este configurată sursa, cu aceeași căutare, aceleași răspunsuri, aceeași verificare și aceleași permisiuni ca fișele din orice altă sursă.

Spre deosebire de scrierea directă a fișelor, o sursă personalizată ține evidența a ce ați trimis. La sfârșitul unei sincronizări complete, Sursa arhivează fiecare document pe care nu l-ați trimis, așa că ștergerile din sistemul dumneavoastră ajung în Sursa fără efort suplimentar.

Configurarea sursei

Un administrator creează sursa în Sursa, în Sources → New source → Custom source (surse → sursă nouă → sursă personalizată), și alege:

  • colecția și, opțional, un dosar pentru fișele ei;
  • modul dosarelor: toate fișele în dosarul ales sau subdosare care reproduc path al fiecărui document;
  • permisiunile: permisiunile colecției sau „ca în sursă”, caz în care fiecare document indică cine îl poate vedea.

Pagina sursei arată identificatorul ei; exemplele folosesc 42.

Alegerea cheii

CheieÎncepe cuCe poate face
Cheie de sursăkbsrc_Scrie documente în această singură sursă. Nimic altceva: nu poate citi și nu poate căuta. Creați-o pe pagina sursei, în API keys.
Cheia organizației cu domeniul import:writekb_Scrie în orice sursă personalizată a organizației și îi citește starea. Crearea unei surse și a cheilor ei necesită domeniul admin.

Cheia de sursă este cea mai sigură alegere pentru o singură integrare, mai ales pentru una care rulează pe o platformă terță. O cheie a organizației cu import:write se potrivește unui serviciu care alimentează mai multe surse.

Ambele chei se trimit la fel, iar fiecare endpoint de trimitere se află sub /v1/push/sources/{source_id}. Verificați cheia și starea sursei cu 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}

Documentul

CâmpObligatoriuDescriere
external_iddaIdentificatorul stabil al documentului în sistemul propriu, cel mult 512 caractere. Trimiterea din nou a aceluiași identificator înlocuiește documentul.
titledaTitlul fișei, cel mult 500 de caractere. Pentru un fișier, implicit numele fișierului.
contentda, dacă nu există un fișierCel mult 5 MB.
content_typenuhtml (implicit), markdown sau text. Din HTML sunt eliminate scripturile, stilurile, formularele și obiectele inserate.
urlnuLinkul către document în sistemul propriu, afișat pe fișă.
pathnuDosarele, ca tablou (["Support", "Billing"]) sau ca șir ("Support/Billing"), cel mult 10 niveluri.
permissionsnu{"everyone": true} sau {"emails": [...], "groups": [...]}. Se folosește când permisiunile sursei sunt „ca în sursă”.
tagsnuCel mult 50 de etichete, adăugate la etichetele sursei.
author_emailnuDacă este un utilizator al organizației, acesta devine responsabilul fișei.
updated_atnuMomentul în care documentul s-a schimbat în sistemul propriu (RFC 3339).
metadatanuPerechile cheie–valoare proprii pe fișă. Vedeți Metadate.
categorynuCategoria fișei: cheia unei categorii a organizației.
verifiers, verify_interval_daysnuCine verifică fișa (utilizatori după e-mail și grupuri) și cât de des, în zile.
upload_idnuFișierul documentului, dintr-o încărcare în părți, în locul lui content.
attachmentsnuCel mult 20 de fișiere suplimentare ale documentului, ca listă de upload_id. Fiecare devine o fișă separată a sursei.

În locul lui content, un singur document poate conține un fișier de cel mult 100 MB într-o cerere multipart/form-data: fișierul în partea file, câmpurile de mai sus ca JSON în partea document. Încărcările în părți pentru upload_id și attachments se creează cu o cheie a organizației care are domeniul import:write și scopul încărcării import_attachment; o cheie de sursă nu le poate crea.

Două moduri de trimitere

Actualizările directe se potrivesc sistemelor care vă anunță fiecare modificare, de exemplu un webhook din sistemul de asistență sau un pas din Zapier. Trimiteți un document când este creat sau modificat și ștergeți-l când este eliminat:

CerereCe face
POST /v1/push/sources/{source_id}/documentsCreează sau înlocuiește un document.
POST /v1/push/sources/{source_id}/documents/batchCreează sau înlocuiește multe documente deodată.
DELETE /v1/push/sources/{source_id}/documents/{external_id}Elimină un document. Codificați identificatorul pentru URL.

Modificările devin fișe în aproximativ un minut; mai multe modificări succesive sunt prelucrate împreună.

Sincronizările se potrivesc exporturilor regulate: trimiteți totul sau tot ce s-a schimbat, iar Sursa face reconcilierea. Restul acestui ghid este despre sincronizări.

Rularea unei sincronizări complete

O sincronizare are trei pași: deschidere, trimitere, închidere.

1. Deschiderea

POST /v1/push/sources/{source_id}/syncs deschide o sincronizare și returnează numărul ei:

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 este initial pentru prima sincronizare a sursei și incremental după ce o sincronizare s-a finalizat. O sincronizare incremental înainte de orice sincronizare finalizată returnează sources.push_initial_required.
  • Poate fi deschisă o singură sincronizare odată: a doua returnează 409 sources.push_sync_open.
  • O sincronizare rămâne deschisă max_minutes minute (implicit 60, cel mult 1.440). După aceea expiră: nu se arhivează nimic, iar numărul ei nu mai este acceptat. Alegeți un timp mult mai lung decât durează exportul.

2. Trimiterea documentelor

Trimiteți documentele în loturi de cel mult 500, cu numărul sincronizării. Corpul unui lot are cel mult 50 MiB; fișierele dintr-un lot se transmit ca 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"}}
    ]
  }'

Răspunsul conține un rezultat pentru fiecare document, în ordinea în care le-ați trimis:

{
  "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…"}
  ]
}
CâmpSemnificație
resultCe s-a întâmplat acum cu documentul: created, updated, unchanged, deleted, not_found, error sau skipped (într-un lot atomic care nu a fost aplicat).
statusUnde se află documentul pe drumul spre o fișă: pending, processing (fișa este scrisă și se indexează), indexed, failed sau removed.
card_idFișa documentului, după ce există.
versionUn hash al conținutului și al câmpurilor. Același document trimis din nou are aceeași versiune și este unchanged.
error, reasonDe ce a eșuat documentul. reason este un cod stabil: content_invalid, file_rejected, too_large, limit_reached, index_failed sau batch_rejected (alt document al unui lot atomic a eșuat).

În mod implicit, fiecare document dintr-un lot se aplică separat: un document greșit nu le oprește pe celelalte.

Documentele care nu s-au schimbat de la ultima sincronizare nu trebuie trimise din nou. Confirmați-le după identificator cu POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch, cel mult 1.000 de identificatori pe cerere, astfel încât reconcilierea completă să le păstreze:

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. Închiderea

POST /v1/push/sources/{source_id}/syncs/{sync_number}/close încheie sincronizarea:

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"}'
statusEfect
completeReconciliere completă. Fiecare document al sursei care nu a fost nici trimis, nici confirmat în această sincronizare este arhivat. Folosiți-l doar când ați trimis totul.
complete_incrementalAplică ce ați trimis și nu arhivează nimic.
failedNu arhivează nimic și păstrează ce a fost deja trimis. Adăugați reason (de exemplu API_ERROR) și error_details pentru jurnal.

Închideți cu failed ori de câte ori exportul se oprește la jumătate: un complete după un export parțial ar arhiva fiecare document la care nu ați ajuns. Repetarea aceleiași închideri returnează același rezultat.

După închidere, Sursa transformă documentele în fișe în aproximativ un minut. Pagina sursei arată fiecare sincronizare, cu numărul de documente trimise și arhivate, iar GET /v1/push/sources/{source_id}/syncs/{sync_number} returnează aceleași contoare.

Sincronizări incrementale

Între sincronizările complete, trimiteți doar ce s-a schimbat:

  1. Deschideți cu "type": "incremental".
  2. Trimiteți documentele modificate și puneți identificatorii celor eliminate în deletes (mai jos).
  3. Închideți cu complete_incremental.

Rulați din când în când o sincronizare completă, de exemplu săptămânal, ca să prindeți tot ce a scăpat unei rulări incrementale.

Ștergerea documentelor într-un lot

Un lot poate elimina documente odată cu cele pe care le scrie. Enumerați identificatorii lor în deletes:

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

Fiecare identificator șters primește propria intrare în results, cu result deleted sau not_found dacă sursa nu are un astfel de document. Ștergerea din nou a aceluiași identificator nu face rău.

Loturi atomice

Unele modificări au sens doar împreună, de exemplu un document și cel care îl înlocuiește. Trimiteți "atomic": true, iar lotul se aplică fie complet, fie deloc: dacă vreun document nu trece verificările, nu se aplică nimic din lot, iar răspunsul este 422 cu codul sources.push_batch_rejected și rezultatul fiecărui document în error.details.results: documentele care au eșuat au error, celelalte skipped.

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

Fără atomic, un lot se aplică document cu document. Folosiți loturi atomice pentru modificările legate între ele și loturi obișnuite pentru încărcările în volum mare, unde un document greșit nu trebuie să le rețină pe celelalte.

Verificarea rezultatului fiecărui document

Răspunsul la lot vă spune cum a fost scris fiecare document. Transformarea în fișă are loc după aceea, așa că status poate fi încă pending. Pentru a găsi documentele unei sincronizări care nu au devenit fișe:

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

Fiecare intrare are external_id, title, status, card_id, version și reason, iar lista se paginează cu cursor. status acceptă și pending, processing, indexed și removed.

Puteți fi și anunțați, în loc să întrebați: evenimentele import.sync_completed (o sincronizare este închisă și prelucrată, cu totalurile ei) și import.document_failed (un document nu a devenit fișă, cu reason al lui) sosesc prin webhook și în fluxul de evenimente.

Reîncercări

  • Trimiteți un Idempotency-Key cu fiecare POST. Un lot repetat cu aceeași cheie returnează primul rezultat.
  • Chiar și fără cheie, un document cu același external_id nu devine niciodată o a doua fișă: este unchanged sau updated.
  • Dacă procesul se oprește în mijlocul unei sincronizări, deschideți una nouă după ce cea veche expiră sau închideți-o pe cea veche cu failed, dacă îi mai aveți numărul, și rulați din nou sincronizarea.

Limite

LimităValoare
Conținutul unui document5 MB
Fișier într-o cerere cu un singur document100 MB
Documente pe lot500
Corpul cererii unui lot50 MiB
Identificatori pe cerere touch1.000
Documente pe sursăDepinde de plan: de la 100.000
Sincronizare deschisăImplicit 60 de minute, cel mult 24 de ore

Un document peste limita de documente a sursei eșuează cu motivul limit_reached într-un lot; o cerere cu un singur document răspunde 409 cu codul sources.push_too_many_documents. Limitele de frecvență se aplică la fel ca pentru orice altă cerere; vedeți Limite de frecvență și cote.

Erori frecvente

RăspunsCauzăCe trebuie făcut
401 sources.push_key_invalidCheia este greșită, revocată sau aparține altei surse.Verificați cheia și identificatorul sursei din cale.
400 sources.push_document_invalidLipsește un câmp obligatoriu sau este depășită o limită.Corectați documentul; într-un lot obișnuit eșuează doar acel document.
409 sources.push_sync_openO altă sincronizare este încă deschisă.Închideți-o sau așteptați să expire.
409 sources.push_sync_closedSincronizarea este închisă sau a expirat.Deschideți o sincronizare nouă; măriți max_minutes pentru exporturile lungi.
403 sources.feature_disabledSursele nu fac parte din planul organizației.Contactați administratorul.
429Prea multe cereri.Așteptați cât indică Retry-After; trimiteți mai puține loturi, dar mai mari.