Przejdź do treści
Sursa Developers

Synchronizuj swój system przez własne źródło

Własne źródło łączy system, który nie ma wbudowanego konektora: Twoją wiki, system zgłoszeń, bazę danych, eksport z dowolnego miejsca. Twój kod wysyła dokumenty do Sursy, a Sursa zamienia je w karty w kolekcji i folderach, dla których skonfigurowano źródło, z takim samym wyszukiwaniem, odpowiedziami, weryfikacją i uprawnieniami jak w przypadku kart z każdego innego źródła.

W odróżnieniu od bezpośredniego zapisu kart własne źródło śledzi, co zostało wysłane. Na koniec pełnej synchronizacji Sursa archiwizuje każdy dokument, którego nie wysłano, więc usunięcia w Twoim systemie docierają do Sursy bez dodatkowej pracy.

Skonfiguruj źródło

Administrator tworzy źródło w Sursie w sekcji Sources → New source → Custom source (źródła → nowe źródło → własne źródło) i wybiera:

  • kolekcję i opcjonalnie folder dla kart źródła;
  • tryb folderów: wszystkie karty w wybranym folderze albo podfoldery odwzorowujące path każdego dokumentu;
  • uprawnienia: uprawnienia kolekcji albo „jak w źródle”, gdzie każdy dokument wymienia, kto może go widzieć.

Strona źródła pokazuje jego ID; przykłady używają 42.

Wybierz klucz

KluczZaczyna się odMoże
Klucz źródłakbsrc_Zapisywać dokumenty w tym jednym źródle. Nic więcej: nie może odczytywać ani wyszukiwać. Utwórz go na stronie źródła w sekcji API keys.
Klucz organizacji z zakresem import:writekb_Zapisywać dane w dowolnym własnym źródle organizacji i odczytywać jego stan. Utworzenie źródła i jego kluczy wymaga zakresu admin.

Klucz źródła to najbezpieczniejszy wybór dla pojedynczej integracji, zwłaszcza działającej na platformie zewnętrznej. Klucz organizacji z import:write pasuje do usługi, która zasila kilka źródeł.

Oba klucze wysyła się w ten sam sposób, a wszystkie operacje push znajdują się pod /v1/push/sources/{source_id}. Sprawdź klucz i stan źródła za pomocą 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}

Dokument

PoleWymaganeOpis
external_idtakTwój stały identyfikator dokumentu, do 512 znaków. Ponowne wysłanie tego samego identyfikatora zastępuje dokument.
titletakTytuł karty, do 500 znaków. W przypadku pliku domyślnie nazwa pliku.
contenttak, chyba że jest plikDo 5 MB.
content_typeniehtml (domyślnie), markdown lub text. Z HTML usuwane są skrypty, style, formularze i osadzone obiekty.
urlnieLink do dokumentu w Twoim systemie, wyświetlany na karcie.
pathnieFoldery jako tablica (["Support", "Billing"]) lub ciąg znaków ("Support/Billing"), do 10 poziomów.
permissionsnie{"everyone": true} lub {"emails": [...], "groups": [...]}. Używane, gdy uprawnienia źródła są ustawione na „jak w źródle”.
tagsnieDo 50 tagów, dodawanych do tagów źródła.
author_emailnieJeśli to użytkownik organizacji, staje się właścicielem karty.
updated_atnieKiedy dokument zmienił się w Twoim systemie (RFC 3339).
metadatanieTwoje pary klucz–wartość w karcie. Zob. Metadane.
categorynieKategoria karty: klucz jednej z kategorii organizacji.
verifiers, verify_interval_daysnieKto weryfikuje kartę (użytkownicy według adresu e-mail i grupy) i jak często, w dniach.
upload_idniePlik dokumentu z przesyłania w częściach, zamiast content.
attachmentsnieDo 20 dodatkowych plików dokumentu jako lista upload_id. Każdy z nich staje się osobną kartą źródła.

Zamiast content pojedynczy dokument może zawierać plik do 100 MB w żądaniu multipart/form-data: plik w części file, a powyższe pola jako JSON w części document. Przesyłania w częściach dla upload_id i attachments tworzy się kluczem organizacji, który ma zakres import:write, z przeznaczeniem import_attachment; klucz źródła nie może ich tworzyć.

Dwa sposoby wysyłania

Bezpośrednie aktualizacje pasują do systemów, które informują o każdej zmianie, np. webhook z Twojego systemu pomocy technicznej lub krok w Zapier. Wysyłaj dokument, gdy zostanie utworzony lub zmieniony, i usuwaj go, gdy zniknie z Twojego systemu:

ŻądanieDziałanie
POST /v1/push/sources/{source_id}/documentsTworzy lub zastępuje jeden dokument.
POST /v1/push/sources/{source_id}/documents/batchTworzy lub zastępuje wiele dokumentów naraz.
DELETE /v1/push/sources/{source_id}/documents/{external_id}Usuwa jeden dokument. Zakoduj identyfikator do postaci URL.

Zmiany stają się kartami w ciągu około minuty; kilka kolejnych zmian jest przetwarzanych razem.

Synchronizacje pasują do regularnych eksportów: wysyłasz wszystko lub wszystko, co się zmieniło, a Sursa uzgadnia stan. Dalsza część przewodnika dotyczy synchronizacji.

Uruchom pełną synchronizację

Synchronizacja ma trzy kroki: otwarcie, wysyłanie, zamknięcie.

1. Otwórz

POST /v1/push/sources/{source_id}/syncs otwiera synchronizację i zwraca jej numer:

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 ma wartość initial przy pierwszej synchronizacji źródła i incremental po zakończeniu którejkolwiek synchronizacji. Synchronizacja incremental przed pierwszą zakończoną zwraca sources.push_initial_required.
  • Naraz może być otwarta tylko jedna synchronizacja: druga zwraca 409 sources.push_sync_open.
  • Synchronizacja pozostaje otwarta przez max_minutes (domyślnie 60, maksymalnie 1440). Potem wygasa: nic nie jest archiwizowane, a jej numer przestaje być akceptowany. Wybierz czas wyraźnie dłuższy niż czas trwania eksportu.

2. Wyślij dokumenty

Wysyłaj dokumenty w pakietach do 500 z numerem synchronizacji. Treść pakietu może mieć do 50 MiB; pliki w pakiecie przekazuje się jako 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"}}
    ]
  }'

Odpowiedź zawiera wynik dla każdego dokumentu, w kolejności wysłania:

{
  "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…"}
  ]
}
PoleZnaczenie
resultCo teraz stało się z dokumentem: created, updated, unchanged, deleted, not_found, error lub skipped (w pakiecie atomowym, który nie został zastosowany).
statusNa jakim etapie drogi do karty jest dokument: pending, processing (karta jest zapisana i trwa jej indeksowanie), indexed, failed lub removed.
card_idKarta dokumentu, gdy już istnieje.
versionSkrót (hash) treści i pól. Ten sam dokument wysłany ponownie ma tę samą wersję i wynik unchanged.
error, reasonDlaczego dokument nie został przetworzony. reason to stały kod: content_invalid, file_rejected, too_large, limit_reached, index_failed lub batch_rejected (inny dokument pakietu atomowego nie przeszedł kontroli).

Domyślnie każdy dokument pakietu jest stosowany osobno: jeden błędny dokument nie zatrzymuje pozostałych.

Dokumentów, które nie zmieniły się od ostatniej synchronizacji, nie trzeba wysyłać ponownie. Potwierdź je według identyfikatora za pomocą POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch, do 1000 identyfikatorów na żądanie, aby pełne uzgadnianie je zachowało:

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. Zamknij

POST /v1/push/sources/{source_id}/syncs/{sync_number}/close kończy synchronizację:

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"}'
statusSkutek
completePełne uzgadnianie. Każdy dokument źródła, który w tej synchronizacji nie został ani wysłany, ani potwierdzony, jest archiwizowany. Używaj tego statusu tylko wtedy, gdy wysłano wszystko.
complete_incrementalStosuje to, co wysłano, i niczego nie archiwizuje.
failedNiczego nie archiwizuje i zachowuje to, co już wysłano. Dodaj reason (np. API_ERROR) i error_details do dziennika.

Zamykaj z failed zawsze, gdy eksport zatrzyma się w połowie: complete po częściowym eksporcie zarchiwizowałoby każdy dokument, do którego eksport nie dotarł. Powtórzenie tego samego zamknięcia zwraca ten sam wynik.

Po zamknięciu Sursa w ciągu około minuty zamienia dokumenty w karty. Strona źródła pokazuje każdą synchronizację z liczbą wysłanych i zarchiwizowanych dokumentów, a GET /v1/push/sources/{source_id}/syncs/{sync_number} zwraca te same liczniki.

Synchronizacje przyrostowe

Między pełnymi synchronizacjami wysyłaj tylko to, co się zmieniło:

  1. Otwórz synchronizację z "type": "incremental".
  2. Wyślij zmienione dokumenty, a identyfikatory usuniętych umieść w deletes (poniżej).
  3. Zamknij synchronizację z complete_incremental.

Od czasu do czasu, np. co tydzień, uruchamiaj pełną synchronizację, aby wyłapać wszystko, co pominęło uruchomienie przyrostowe.

Usuwaj dokumenty w pakiecie

Pakiet może usuwać dokumenty razem z tymi, które zapisuje. Wymień ich identyfikatory w deletes:

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

Każdy usunięty identyfikator otrzymuje własny wpis w results, z result równym deleted lub not_found, jeśli źródło nie ma takiego dokumentu. Ponowne usunięcie tego samego identyfikatora jest nieszkodliwe.

Pakiety atomowe

Niektóre zmiany mają sens tylko razem, np. dokument i ten, który go zastępuje. Wyślij "atomic": true, a pakiet zostanie zastosowany w całości albo wcale: jeśli którykolwiek dokument nie przejdzie kontroli, nic z pakietu nie zostanie zastosowane, a odpowiedź to 422 z kodem sources.push_batch_rejected i wynikiem każdego dokumentu w error.details.results: dokumenty, które nie przeszły kontroli, mają error, a pozostałe skipped.

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

Bez atomic pakiet jest stosowany dokument po dokumencie. Używaj pakietów atomowych do powiązanych zmian, a zwykłych pakietów do ładowań masowych, w których jeden błędny dokument nie powinien wstrzymywać reszty.

Sprawdź wynik każdego dokumentu

Odpowiedź pakietu informuje, jak każdy dokument został zapisany. Zamiana w kartę następuje później, więc status może jeszcze mieć wartość pending. Aby znaleźć dokumenty synchronizacji, które nie stały się kartami:

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

Każdy wpis ma external_id, title, status, card_id, version i reason, a lista jest stronicowana za pomocą cursor. status przyjmuje też pending, processing, indexed i removed.

Możesz też otrzymywać powiadomienia, zamiast pytać: zdarzenia import.sync_completed (synchronizacja została zamknięta i przetworzona, z jej sumami) i import.document_failed (dokument nie stał się kartą, z jego reason) przychodzą przez webhook i w kanale zdarzeń.

Ponowienia

  • Wysyłaj Idempotency-Key z każdym żądaniem POST. Powtórzony pakiet z tym samym kluczem zwraca pierwszy wynik.
  • Nawet bez klucza dokument z tym samym external_id nigdy nie stanie się drugą kartą: ma wynik unchanged lub updated.
  • Jeśli proces zatrzyma się w trakcie synchronizacji, otwórz nową po wygaśnięciu starej albo zamknij starą z failed, jeśli nadal znasz jej numer, i uruchom synchronizację ponownie.

Limity

LimitWartość
Treść jednego dokumentu5 MB
Plik w żądaniu z jednym dokumentem100 MB
Dokumenty w pakiecie500
Treść żądania z pakietem50 MiB
Identyfikatory w żądaniu touch1000
Dokumenty w źródleZależnie od planu: od 100 000
Otwarta synchronizacjaDomyślnie 60 minut, maksymalnie 24 godziny

Dokument przekraczający limit dokumentów źródła kończy się w pakiecie błędem z przyczyną limit_reached; na żądanie z pojedynczym dokumentem API odpowiada 409 z kodem sources.push_too_many_documents. Limity częstotliwości obowiązują tak samo jak przy każdym innym żądaniu; zob. Limity częstotliwości i przydziały.

Typowe błędy

OdpowiedźPrzyczynaCo zrobić
401 sources.push_key_invalidKlucz jest błędny, unieważniony lub należy do innego źródła.Sprawdź klucz i ID źródła w ścieżce.
400 sources.push_document_invalidBrakuje wymaganego pola lub przekroczono limit.Popraw dokument; w zwykłym pakiecie błędem kończy się tylko ten dokument.
409 sources.push_sync_openInna synchronizacja jest wciąż otwarta.Zamknij ją lub poczekaj, aż wygaśnie.
409 sources.push_sync_closedSynchronizacja jest zamknięta lub wygasła.Otwórz nową synchronizację; przy długich eksportach zwiększ max_minutes.
403 sources.feature_disabledŹródła nie są częścią planu organizacji.Skontaktuj się z administratorem.
429Zbyt wiele żądań.Odczekaj czas z Retry-After; wysyłaj mniej pakietów, ale większych.