Перейти до вмісту
Sursa Developers

Синхронізуйте свою систему через власне джерело

Власне джерело підключає систему, для якої немає вбудованого конектора: вашу wiki, систему заявок, базу даних, експорт звідки завгодно. Ваш код надсилає документи до Sursa, а Sursa перетворює їх на картки в колекції та папках, на які налаштовано джерело, — з тими самими пошуком, відповідями, верифікацією та дозволами, що й у карток із будь-якого іншого джерела.

На відміну від прямого запису карток, власне джерело відстежує, що ви вже надіслали. Наприкінці повної синхронізації Sursa архівує кожен документ, якого ви не надіслали, тож видалення у вашій системі доходять до Sursa без додаткової роботи.

Налаштуйте джерело

Адміністратор створює джерело в Sursa в розділі Sources → New source → Custom source (джерела → нове джерело → власне джерело) і вибирає:

  • колекцію і, за потреби, папку для його карток;
  • режим папок: усі картки у вибраній папці або вкладені папки, що відтворюють path кожного документа;
  • дозволи: дозволи колекції або «як у джерелі», коли кожен документ перелічує, хто може його бачити.

Сторінка джерела показує його ID; у прикладах це 42.

Виберіть ключ

КлючПочинається зЩо може
Ключ джерелаkbsrc_Записувати документи в це одне джерело. І нічого більше: він не може читати чи шукати. Створіть його на сторінці джерела в розділі API keys (ключі API джерела).
Ключ організації з областю доступу import:writekb_Записувати в будь-яке власне джерело організації та читати його стан. Для створення джерела та його ключів потрібна область доступу admin.

Ключ джерела — найбезпечніший вибір для окремої інтеграції, особливо такої, що працює на сторонній платформі. Ключ організації з import:write підходить для сервісу, який наповнює кілька джерел.

Обидва ключі надсилають однаково, а всі push-операції розміщено в /v1/push/sources/{source_id}. Перевірте ключ і стан джерела через 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}

Документ

ПолеОбов’язковеОпис
external_idтакВаш стабільний ідентифікатор документа, до 512 символів. Повторне надсилання з тим самим ідентифікатором замінює документ.
titleтакЗаголовок картки, до 500 символів. Для файлу типово — назва файлу.
contentтак, якщо немає файлуДо 5 МБ.
content_typeніhtml (типово), markdown або text. З HTML вилучаються скрипти, стилі, форми й вбудовані об’єкти.
urlніПосилання на документ у вашій системі, показане на картці.
pathніПапки — масивом (["Support", "Billing"]) або рядком ("Support/Billing"), до 10 рівнів.
permissionsні{"everyone": true} або {"emails": [...], "groups": [...]}. Використовується, коли дозволи джерела — «як у джерелі».
tagsніДо 50 тегів, що додаються до тегів джерела.
author_emailніЯкщо це користувач організації, він стає відповідальним за картку.
updated_atніКоли документ змінився у вашій системі (RFC 3339).
metadataніВаші пари «ключ — значення» в картці. Див. Метадані.
categoryніКатегорія картки: ключ однієї з категорій організації.
verifiers, verify_interval_daysніХто верифікує картку (користувачі за електронною поштою та групи) і як часто, у днях.
upload_idніФайл документа із завантаження частинами, замість content.
attachmentsніДо 20 додаткових файлів документа — список upload_id. Кожен файл стає окремою карткою джерела.

Замість content окремий документ може містити файл до 100 МБ у запиті multipart/form-data: файл — у частині file, поля, наведені вище, — у форматі JSON у частині document. Завантаження частинами для upload_id і attachments створюють ключем організації з областю доступу import:write і метою import_attachment; ключ джерела створити їх не може.

Два способи надсилання

Прямі оновлення підходять для систем, які повідомляють про кожну зміну, як-от вебхук від вашої служби підтримки або крок у Zapier. Надсилайте документ, коли його створено чи змінено, і видаляйте, коли його прибрано:

ЗапитЩо робить
POST /v1/push/sources/{source_id}/documentsСтворює або замінює один документ.
POST /v1/push/sources/{source_id}/documents/batchСтворює або замінює багато документів одразу.
DELETE /v1/push/sources/{source_id}/documents/{external_id}Видаляє один документ. Закодуйте ідентифікатор для URL.

Зміни стають картками приблизно за хвилину; кілька змін поспіль обробляються разом.

Синхронізації підходять для регулярних експортів: ви надсилаєте все або все, що змінилося, а Sursa звіряє. Решта цього посібника — про синхронізації.

Запустіть повну синхронізацію

Синхронізація має три кроки: відкрити, надіслати, закрити.

1. Відкрийте

POST /v1/push/sources/{source_id}/syncs відкриває синхронізацію й повертає її номер:

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 дорівнює initial для першої синхронізації джерела та incremental після того, як якась синхронізація завершилася. Синхронізація incremental до першої завершеної повертає sources.push_initial_required.
  • Одночасно може бути відкрита лише одна синхронізація: друга повертає 409 sources.push_sync_open.
  • Синхронізація лишається відкритою max_minutes хвилин (типово 60, щонайбільше 1440). Після цього строк її дії спливає: нічого не архівується, а її номер більше не приймається. Вибирайте час із добрим запасом понад тривалість вашого експорту.

2. Надішліть документи

Надсилайте документи пакетами до 500 разом із номером синхронізації. Тіло пакета — до 50 МіБ; файли всередині пакета передаються як 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"}}
    ]
  }'

Відповідь містить результат для кожного документа в тому порядку, в якому ви їх надіслали:

{
  "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…"}
  ]
}
ПолеЗначення
resultЩо зараз сталося з документом: created, updated, unchanged, deleted, not_found, error або skipped (в атомарному пакеті, який не застосовано).
statusНа якому етапі шляху до картки перебуває документ: pending, processing (картку записано, і вона індексується), indexed, failed або removed.
card_idКартка документа, щойно вона з’явиться.
versionХеш вмісту й полів. Той самий документ, надісланий повторно, має ту саму версію й отримує unchanged.
error, reasonЧому документ не вдалося обробити. reason — стабільний код: content_invalid, file_rejected, too_large, limit_reached, index_failed або batch_rejected (інший документ атомарного пакета не пройшов перевірки).

Типово кожен документ пакета застосовується окремо: один хибний документ не зупиняє інших.

Документи, що не змінилися з останньої синхронізації, не треба надсилати знову. Підтвердьте їх за ідентифікатором через POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch, до 1000 ідентифікаторів на запит, щоб повна звірка їх зберегла:

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. Закрийте

POST /v1/push/sources/{source_id}/syncs/{sync_number}/close завершує синхронізацію:

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Дія
completeПовна звірка. Кожен документ джерела, який у цій синхронізації не надіслали й не підтвердили, архівується. Використовуйте цей статус, лише коли надіслали все.
complete_incrementalЗастосовує надіслане й нічого не архівує.
failedНічого не архівує й зберігає вже надіслане. Додайте reason (наприклад, API_ERROR) та error_details для журналу.

Закривайте зі статусом failed щоразу, коли ваш експорт зупиняється на півдорозі: complete після часткового експорту архівував би кожен документ, до якого ви не дійшли. Повторне таке саме закриття повертає той самий результат.

Після закриття Sursa перетворює документи на картки приблизно за хвилину. Сторінка джерела показує кожну синхронізацію з кількістю надісланих та архівованих документів, а GET /v1/push/sources/{source_id}/syncs/{sync_number} повертає ті самі лічильники.

Інкрементні синхронізації

Між повними синхронізаціями надсилайте лише те, що змінилося:

  1. Відкрийте синхронізацію з "type": "incremental".
  2. Надішліть змінені документи, а ідентифікатори видалених додайте в deletes (див. нижче).
  3. Закрийте зі статусом complete_incremental.

Час від часу, наприклад щотижня, запускайте повну синхронізацію, щоб підхопити все, що пропустив інкрементний запуск.

Видаляйте документи в пакеті

Пакет може видаляти документи разом із тими, які він записує. Перелічіть їхні ідентифікатори в deletes:

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

Кожен видалений ідентифікатор отримує власний запис у results із result, що дорівнює deleted, або not_found, якщо в джерелі немає такого документа. Повторне видалення того самого ідентифікатора нічим не шкодить.

Атомарні пакети

Деякі зміни мають сенс лише разом, наприклад документ і той, що його замінює. Надішліть "atomic": true, і пакет буде застосовано повністю або не застосовано зовсім: якщо будь-який документ не пройде перевірки, з пакета не застосовується нічого, а відповідь — 422 з кодом sources.push_batch_rejected і результатом кожного документа в error.details.results: документи, що не пройшли перевірки, мають error, решта — skipped.

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

Без atomic пакет застосовується документ за документом. Використовуйте атомарні пакети для пов’язаних змін, а звичайні — для масових завантажень, де один хибний документ не має затримувати решту.

Перевірте результат кожного документа

Відповідь на пакет повідомляє, як було записано кожен документ. Перетворення на картку відбувається пізніше, тож status може ще бути pending. Щоб знайти документи синхронізації, які не стали картками:

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

Кожен запис має external_id, title, status, card_id, version і reason, а список розбито на сторінки через cursor. status також приймає pending, processing, indexed і removed.

Можна не запитувати, а отримувати сповіщення: події import.sync_completed (синхронізацію закрито й оброблено, з підсумками) та import.document_failed (документ не став карткою, з його reason) надходять через вебхук і в стрічці подій.

Повтори

  • Надсилайте Idempotency-Key з кожним POST. Повторний пакет із тим самим ключем повертає перший результат.
  • Навіть без ключа документ із тим самим external_id ніколи не стане другою карткою: він отримає unchanged або updated.
  • Якщо процес зупинився посеред синхронізації, відкрийте нову після того, як строк дії старої спливе, або закрийте стару зі статусом failed, якщо ще маєте її номер, і запустіть синхронізацію знову.

Ліміти

ЛімітЗначення
Вміст одного документа5 МБ
Файл у запиті з одним документом100 МБ
Документів у пакеті500
Тіло запиту з пакетом50 МіБ
Ідентифікаторів у запиті touch1000
Документів у джереліЗалежить від тарифу: від 100 000
Відкрита синхронізаціяТипово 60 хвилин, щонайбільше 24 години

Документ понад ліміт документів джерела завершується в пакеті помилкою з причиною limit_reached; на запит з одним документом API відповідає 409 з кодом sources.push_too_many_documents. Ліміти частоти діють так само, як для будь-якого іншого запиту; див. Ліміти частоти та квоти.

Поширені помилки

ВідповідьПричинаЩо робити
401 sources.push_key_invalidКлюч неправильний, відкликаний або належить іншому джерелу.Перевірте ключ та ID джерела в шляху.
400 sources.push_document_invalidБракує обов’язкового поля або перевищено ліміт.Виправте документ; у звичайному пакеті помилкою завершується лише цей документ.
409 sources.push_sync_openІнша синхронізація ще відкрита.Закрийте її або дочекайтеся, поки сплине строк її дії.
409 sources.push_sync_closedСинхронізацію закрито, або строк її дії сплив.Відкрийте нову синхронізацію; для довгих експортів збільште max_minutes.
403 sources.feature_disabledДжерела не входять до тарифу організації.Зверніться до адміністратора.
429Забагато запитів.Зачекайте Retry-After; надсилайте менше пакетів більшого розміру.