Импорт на документи
Това ръководство показва как да поставите документите си в Sursa с API за карти: няколко документа от скрипт или всички документи на дадена система чрез редовно задание. Всеки документ става карта в колекция. Хората я намират при търсене, асистентът отговаря въз основа на нея и тя има отговорник, етикети, проверка и права като всяка друга карта.
Ако искате Sursa сама да установява кои документи са изтрити във вашата система или изпращате документи от платформа за интеграции, използвайте вместо това собствен източник. Той е създаден за пълни и инкрементални синхронизации. Това ръководство описва директния запис в колекция.
Нужен ви е API ключ с обхвата cards:write и роля, която може да записва в целевата колекция (editor или
admin). Примерите използват помощната функция от Бърз старт.
Изберете подходящата операция
| Имате | Използвайте |
|---|---|
| Запис със стабилен идентификатор във вашата система | PUT /v1/cards-by-external-id/{external_id}: създаване или замяна по вашия идентификатор. |
| Текст, който добавяте веднъж, без собствен идентификатор | POST /v1/cards/text |
| Файл, който добавяте веднъж | POST /v1/cards |
| ZIP архив с много файлове | POST /v1/cards/archive |
| Файл, по-голям от лимита за една заявка | Качване на части, а след това някоя от операциите по-горе. |
| Ново съдържание за карта, която вече имате | PUT /v1/cards/{card_id}/content |
За всичко, което импортирате повече от веднъж, използвайте external_id. С него всеки импорт може да се повтаря:
повторното му изпълнение обновява създадените от него карти, вместо да добавя копия.
Създаване или замяна на карта по вашия идентификатор
PUT /v1/cards-by-external-id/{external_id} приема ID на записа във вашата система. Ако няма карта с този
external_id, операцията създава карта (201). Ако има такава карта, операцията заменя съдържанието и данните ѝ
(200).
curl -X PUT https://api.sursa.com/v1/cards-by-external-id/kb-article-1042 \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"collection_id": 3,
"folder_id": "0f8e2d7c-4b6a-4e1f-9c3d-2a5b8e7f1c40",
"title": "Returning a damaged item",
"content_type": "html",
"body": "<h2>Damaged items</h2><p>Send a photo within 7 days and we ship a replacement.</p>",
"tags": ["returns", "shipping"],
"metadata": {"source": "helpdesk", "article_id": "1042"}
}'Какво се случва при повторение:
- Съдържанието не се е променило: не се създава нова версия. Отговорът е
200с"status": "skipped"и"reason": "unchanged". Повтарянето на заявката винаги е безопасно, дори безIdempotency-Key. - Съдържанието се е променило: картата получава нова версия и се индексира повторно. Заглавието, етикетите,
отговорникът, категорията и
metadataполучават изпратените от вас стойности;metadataсе заменя изцяло. - Колекцията и папката се прилагат само при създаването на картата. За да преместите карта по-късно, променете я
с
PATCH /v1/cards/{card_id}.
Новата версия премахва проверката на картата, както всяка промяна на съдържанието: проверяващият я потвърждава отново.
Текстови формати
content_type | Тялото е |
|---|---|
markdown (по подразбиране) | Markdown. |
html | HTML. Изчиства се до проста маркировка: заглавия, абзаци, списъци, таблици и връзки http, https и mailto. Скриптовете, стиловете, рамките, формулярите и изображенията се премахват заедно със съдържанието си. |
text | Обикновен текст. Абзаците се разделят с празни редове. |
Изчакване на картата – или не
По подразбиране заявката връща отговор, когато картата е готова да бъде намирана, с "status": "ready" и картата в
card. Това отнема от част от секундата за кратък текст до минута или повече за дълъг файл.
При масов импорт изпращайте "async": true. Отговорът идва веднага с "status": "queued" и заданието за индексиране
в job (с неговия job_id). Проверявайте заданието с GET /v1/jobs/{job_id} или
следете всички задания в GET /v1/jobs/stream. Заданието завършва със status
done, error или canceled.
curl https://api.sursa.com/v1/jobs/48213 \
-H "Authorization: Bearer $SURSA_API_KEY"Качване на файл
Файловете се изпращат в заявка multipart/form-data, в полето file. Sursa чете PDF, Word, Excel, PowerPoint,
електронни таблици OpenDocument, CSV, Markdown, HTML, AsciiDoc, имейли (.eml), обикновен текст и разпространените
формати на изображения. Тя проверява дали името на файла, обявеният тип и съдържанието му си съответстват и
отхвърля несъответствие с 415.
За да създадете или замените карта с файл по вашия идентификатор, изпратете файла до същата
PUT /v1/cards-by-external-id/{external_id}:
curl -X PUT https://api.sursa.com/v1/cards-by-external-id/handbook-2026 \
-H "Authorization: Bearer $SURSA_API_KEY" \
-F "file=@employee-handbook.pdf" \
-F "collection_id=3" \
-F "tags=hr,policies" \
-F 'metadata={"owner_team":"people"}'Във формуляр tags е низ, разделен със запетаи, а metadata е JSON обект, записан като низ. Нова карта без title
получава за заглавие името на файла.
За да добавите файл веднъж, без собствен идентификатор, използвайте POST /v1/cards
със същия формуляр и Idempotency-Key. Качването на файл, който колекцията вече има, връща "status": "skipped" с
"duplicate": true и съществуващия card_id, освен ако не подадете external_id.
Размерът на един файл се ограничава от инсталацията (по подразбиране 200 MB). За по-големи файлове или за ненадеждни мрежи първо качете файла на части.
Замяна на съдържанието на карта
Когато вече имате идентификатора на картата в Sursa, PUT /v1/cards/{card_id}/content
заменя текста или файла ѝ и запазва всичко останало: отговорника, етикетите, проверяващите, интервала на проверка и
ръчно зададената категория.
curl -X PUT https://api.sursa.com/v1/cards/3f2c9a7e-5b1d-4c8e-9f0a-1b2c3d4e5f60/content \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content_type": "markdown", "body": "# Refund policy\n\nRefunds are processed within 10 days."}'- Същото съдържание отново връща
"status": "skipped"с"reason": "unchanged". - Карта, която се индексира в момента, връща
409с кодаcards.indexing_in_progress. Опитайте отново след няколко секунди. - Карта, която идва от източник, например от конектор или собствен източник, се променя само в своя източник:
cards.managed_by_source. - Ключът трябва да има право да вижда цялата карта; частично видима карта връща
cards.content_whole_access.
Импорт на много документи
Цикъл по записите ви с PUT /v1/cards-by-external-id/… е най-простият масов импорт и може безопасно да бъде спрян и
пуснат отново във всеки момент. За да е бърз и да щади лимита на честотата:
- Изпращайте
"async": true, за да връща всяка заявка отговор веднага щом картата бъде поставена в опашката. - Изпълнявайте няколко заявки паралелно (от 4 до 8) и забавяйте темпото, когато заглавката
RateLimitпоказва, че остават малко заявки. Вж. Лимити на честотата и квоти. - При
429изчаквайтеRetry-After; при мрежова грешка или5xxповтаряйте същата заявка. Повторенията са безвредни. - Записвайте
external_idна всеки запис, който завършва с грешка, и опитайте отново с тях накрая.
import { api } from "./sursa.mjs";
async function importAll(records, concurrency = 6) {
const failed = [];
const queue = [...records];
async function worker() {
for (let record = queue.shift(); record; record = queue.shift()) {
try {
await api("PUT", `/v1/cards-by-external-id/${encodeURIComponent(record.id)}`, {
collection_id: 3,
title: record.title,
content_type: "html",
body: record.html,
metadata: { source: "helpdesk" },
async: true,
});
} catch (error) {
failed.push({ id: record.id, error: String(error) });
}
}
}
await Promise.all(Array.from({ length: concurrency }, worker));
return failed;
}За ZIP архив с файлове POST /v1/cards/archive превръща всеки поддържан
файл в него в карта с една заявка. Операцията отговаря веднага с плана (кои файлове стават карти, кои се пропускат и
защо) и задание; GET /v1/archives/{job_id} съобщава резултата.
Намиране и премахване на импортирани карти
- Прочетете карта по вашия идентификатор с
GET /v1/cards-by-external-id/{external_id}. - Изброете картите от един импорт с филтър по метаданни:
GET /v1/cards?metadata[source]=helpdesk. Вж. Метаданни. - Изтрийте карта с
DELETE /v1/cards/{card_id}.
Чести грешки
| Код | Причина | Какво да направите |
|---|---|---|
collections.not_found | За ключа не е видима колекция с това ID или име. | Проверете collection_id с GET /v1/collections. |
collections.no_write_access | Ключът няма право да записва в тази колекция. | Използвайте ключ с ролята editor и достъп до колекцията. |
cards.external_id_taken | POST с external_id, който вече има друга карта. | Използвайте PUT /v1/cards-by-external-id/…, за да я замените. |
cards.managed_by_source | Картата принадлежи на източник. | Променете документа в неговия източник. |
files.type_mismatch | Името, типът и съдържанието на файла не си съответстват. | Изпратете файла с истинското му разширение. |
files.too_large | Файлът надвишава лимита за качване или мястото в хранилището на организацията. | Използвайте качване на части или освободете място. |
limits.cards | Организацията е достигнала лимита на картите в плана си. | Изтрийте картите, които вече не са нужни, или сменете плана. |
api.metadata_invalid | metadata нарушава лимит. | Вж. Метаданни. |