Синхронизация на вашата система със собствен източник
Собственият източник свързва система, за която няма вграден конектор: вашето уики, системата ви за заявки към поддръжката, база данни, експорт от каквото и да е място. Вашият код изпраща документи до Sursa, а Sursa ги превръща в карти в колекцията и папките, за които е настроен източникът, със същото търсене, отговори, проверка и права като картите от всеки друг източник.
За разлика от директния запис на карти, собственият източник следи какво сте изпратили. В края на пълна синхронизация Sursa архивира всеки документ, който не сте изпратили, така че изтриванията във вашата система стигат до Sursa без допълнителна работа.
Настройка на източника
Администраторът създава източника в Sursa в Sources → New source → Custom source (източници, нов източник, собствен източник) и избира:
- колекцията и по желание папка за картите му;
- режима на папките: всички карти в избраната папка или подпапки, които повтарят
pathна всеки документ; - правата: правата на колекцията или „as in the source“ (както в източника), при което всеки документ посочва кой може да го вижда.
Страницата на източника показва неговото ID; примерите използват 42.
Избор на ключ
| Ключ | Започва с | Може да прави |
|---|---|---|
| Ключ на източника | kbsrc_ | Запис на документи в този един източник. Нищо друго: не може да чете и да търси. Създайте го на страницата на източника в раздела API keys. |
Ключ на организацията с обхвата import:write | kb_ | Запис във всеки собствен източник на организацията и четене на състоянието му. За създаване на източник и ключовете му е нужен обхватът 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 MB. |
content_type | не | html (по подразбиране), markdown или text. HTML се изчиства от скриптове, стилове, формуляри и вградени обекти. |
url | не | Връзка към документа във вашата система, показвана в картата. |
path | не | Папки, като масив (["Support", "Billing"]) или низ ("Support/Billing"), до 10 нива. |
permissions | не | {"everyone": true} или {"emails": [...], "groups": [...]}. Използва се, когато правата на източника са „as in the source“. |
tags | не | До 50 етикета, добавяни към етикетите на източника. |
author_email | не | Ако това е потребител на организацията, той става отговорник на картата. |
updated_at | не | Кога е променен документът във вашата система (RFC 3339). |
metadata | не | Вашите двойки ключ–стойност върху картата. Вж. Метаданни. |
category | не | Категория на картата: ключът на категория на организацията. |
verifiers, verify_interval_days | не | Кой проверява картата (потребители по имейл и групи) и колко често, в дни. |
upload_id | не | Файлът на документа от качване на части, вместо content. |
attachments | не | До 20 допълнителни файла на документа като списък от upload_id. Всеки от тях става отделна карта на източника. |
Вместо content единичен документ може да носи файл до 100 MB в заявка 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.- Само една синхронизация може да е отворена в даден момент: втора връща
409sources.push_sync_open. - Синхронизацията остава отворена
max_minutes(по подразбиране 60, до 1440). След това тя изтича: нищо не се архивира и номерът ѝ вече не се приема. Изберете време, което е с достатъчен запас по-дълго от продължителността на експорта ви.
2. Изпратете документите
Изпращайте документите на пакети до 500, с номера на синхронизацията. Тялото на пакета е до 50 MiB; файловете в
пакета се подават като 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} връща същите броячи.
Инкрементални синхронизации
Между пълните синхронизации изпращайте само промененото:
- Отворете с
"type": "incremental". - Изпратете променените документи, а идентификаторите на премахнатите поставете в
deletes(вж. по-долу). - Затворете с
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 MB |
| Файл в заявка с един документ | 100 MB |
| Документи в един пакет | 500 |
| Тяло на заявката с пакет | 50 MiB |
Идентификатори в една заявка touch | 1000 |
| Документи в един източник | Зависи от плана: от 100 000 |
| Отворена синхронизация | По подразбиране 60 минути, до 24 часа |
Документ над лимита на документите на източника в пакет е неуспешен с причина limit_reached; заявка с единичен
документ отговаря с 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; изпращайте по-малко и по-големи пакети. |