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
pathal 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 cu | Ce 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:write | kb_ | 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âmp | Obligatoriu | Descriere |
|---|---|---|
external_id | da | Identificatorul stabil al documentului în sistemul propriu, cel mult 512 caractere. Trimiterea din nou a aceluiași identificator înlocuiește documentul. |
title | da | Titlul fișei, cel mult 500 de caractere. Pentru un fișier, implicit numele fișierului. |
content | da, dacă nu există un fișier | Cel mult 5 MB. |
content_type | nu | html (implicit), markdown sau text. Din HTML sunt eliminate scripturile, stilurile, formularele și obiectele inserate. |
url | nu | Linkul către document în sistemul propriu, afișat pe fișă. |
path | nu | Dosarele, ca tablou (["Support", "Billing"]) sau ca șir ("Support/Billing"), cel mult 10 niveluri. |
permissions | nu | {"everyone": true} sau {"emails": [...], "groups": [...]}. Se folosește când permisiunile sursei sunt „ca în sursă”. |
tags | nu | Cel mult 50 de etichete, adăugate la etichetele sursei. |
author_email | nu | Dacă este un utilizator al organizației, acesta devine responsabilul fișei. |
updated_at | nu | Momentul în care documentul s-a schimbat în sistemul propriu (RFC 3339). |
metadata | nu | Perechile cheie–valoare proprii pe fișă. Vedeți Metadate. |
category | nu | Categoria fișei: cheia unei categorii a organizației. |
verifiers, verify_interval_days | nu | Cine verifică fișa (utilizatori după e-mail și grupuri) și cât de des, în zile. |
upload_id | nu | Fișierul documentului, dintr-o încărcare în părți, în locul lui content. |
attachments | nu | Cel 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:
| Cerere | Ce face |
|---|---|
POST /v1/push/sources/{source_id}/documents | Creează sau înlocuiește un document. |
POST /v1/push/sources/{source_id}/documents/batch | Creează 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}
typeesteinitialpentru prima sincronizare a sursei șiincrementaldupă ce o sincronizare s-a finalizat. O sincronizareincrementalînainte de orice sincronizare finalizată returneazăsources.push_initial_required.- Poate fi deschisă o singură sincronizare odată: a doua returnează
409sources.push_sync_open. - O sincronizare rămâne deschisă
max_minutesminute (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âmp | Semnificație |
|---|---|
result | Ce 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). |
status | Unde se află documentul pe drumul spre o fișă: pending, processing (fișa este scrisă și se indexează), indexed, failed sau removed. |
card_id | Fișa documentului, după ce există. |
version | Un hash al conținutului și al câmpurilor. Același document trimis din nou are aceeași versiune și este unchanged. |
error, reason | De 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"}'status | Efect |
|---|---|
complete | Reconciliere 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_incremental | Aplică ce ați trimis și nu arhivează nimic. |
failed | Nu 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:
- Deschideți cu
"type": "incremental". - Trimiteți documentele modificate și puneți identificatorii celor eliminate în
deletes(mai jos). - Î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-Keycu fiecarePOST. Un lot repetat cu aceeași cheie returnează primul rezultat. - Chiar și fără cheie, un document cu același
external_idnu devine niciodată o a doua fișă: esteunchangedsauupdated. - 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 document | 5 MB |
| Fișier într-o cerere cu un singur document | 100 MB |
| Documente pe lot | 500 |
| Corpul cererii unui lot | 50 MiB |
Identificatori pe cerere touch | 1.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ăspuns | Cauză | Ce trebuie făcut |
|---|---|---|
401 sources.push_key_invalid | Cheia este greșită, revocată sau aparține altei surse. | Verificați cheia și identificatorul sursei din cale. |
400 sources.push_document_invalid | Lipseș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_open | O altă sincronizare este încă deschisă. | Închideți-o sau așteptați să expire. |
409 sources.push_sync_closed | Sincronizarea este închisă sau a expirat. | Deschideți o sincronizare nouă; măriți max_minutes pentru exporturile lungi. |
403 sources.feature_disabled | Sursele nu fac parte din planul organizației. | Contactați administratorul. |
429 | Prea multe cereri. | Așteptați cât indică Retry-After; trimiteți mai puține loturi, dar mai mari. |