Імпортуйте документи
Цей посібник показує, як розмістити ваші документи в 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} приймає ідентифікатор запису у вашій системі. Якщо жодна картка не має
цього 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 МБ). Більші файли, а також файли в ненадійних мережах спершу завантажуйте частинами.
Замініть вміст картки
Коли ви вже маєте ідентифікатор картки в 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 | Ключ не бачить жодної колекції з таким ідентифікатором чи назвою. | Перевірте 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 порушує ліміт. | Див. Метадані. |