Đồng bộ hệ thống của bạn bằng nguồn tùy chỉnh
Nguồn tùy chỉnh kết nối một hệ thống không có trình kết nối dựng sẵn: wiki của bạn, công cụ quản lý phiếu yêu cầu, một cơ sở dữ liệu, một bản xuất từ bất kỳ đâu. Mã của bạn đẩy tài liệu tới Sursa, và Sursa biến chúng thành thẻ trong bộ sưu tập và thư mục mà nguồn được thiết lập, với cùng khả năng tìm kiếm, câu trả lời, kiểm chứng và quyền như thẻ từ mọi nguồn khác.
Khác với ghi thẻ trực tiếp, nguồn tùy chỉnh theo dõi những gì bạn đã gửi. Khi kết thúc một lần đồng bộ toàn bộ, Sursa lưu trữ mọi tài liệu mà bạn không gửi, nên các thao tác xóa trong hệ thống của bạn tới được Sursa mà không cần làm thêm gì.
Thiết lập nguồn
Quản trị viên tạo nguồn trong Sursa tại Sources → New source → Custom source (Nguồn → Nguồn mới → Nguồn tùy chỉnh), và chọn:
- bộ sưu tập và, nếu muốn, một thư mục cho các thẻ của nguồn;
- chế độ thư mục: mọi thẻ trong thư mục đã chọn, hoặc các thư mục con phản ánh
pathcủa từng tài liệu; - quyền: quyền của bộ sưu tập, hoặc “như trong nguồn”, khi mỗi tài liệu liệt kê những ai được xem nó.
Trang của nguồn hiển thị ID của nó; các ví dụ dùng 42.
Chọn khóa
| Khóa | Bắt đầu bằng | Làm được gì |
|---|---|---|
| Khóa nguồn | kbsrc_ | Ghi tài liệu vào đúng nguồn này. Không gì khác: khóa không thể đọc hay tìm kiếm. Tạo khóa trên trang của nguồn tại API keys (khóa API của nguồn). |
Khóa của tổ chức có phạm vi quyền import:write | kb_ | Ghi vào bất kỳ nguồn tùy chỉnh nào của tổ chức và đọc trạng thái của nguồn. Việc tạo nguồn và khóa của nguồn cần phạm vi admin. |
Khóa nguồn là lựa chọn an toàn nhất cho một tích hợp đơn lẻ, đặc biệt là tích hợp chạy trên nền tảng của bên thứ ba.
Khóa của tổ chức có import:write phù hợp với một dịch vụ cấp dữ liệu cho nhiều nguồn.
Cả hai khóa được gửi theo cùng một cách, và mọi endpoint đẩy dữ liệu đều nằm dưới /v1/push/sources/{source_id}. Hãy
kiểm tra khóa và trạng thái của nguồn bằng 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}
Tài liệu
| Trường | Bắt buộc | Mô tả |
|---|---|---|
external_id | có | ID ổn định của tài liệu trong hệ thống của bạn, tối đa 512 ký tự. Gửi lại cùng ID sẽ thay thế tài liệu. |
title | có | Tiêu đề thẻ, tối đa 500 ký tự. Với tệp, mặc định là tên tệp. |
content | có, trừ khi có tệp | Tối đa 5 MB. |
content_type | không | html (mặc định), markdown hoặc text. HTML được làm sạch khỏi script, style, biểu mẫu và đối tượng nhúng. |
url | không | Liên kết tới tài liệu trong hệ thống của bạn, hiển thị trên thẻ. |
path | không | Thư mục, dạng mảng (["Support", "Billing"]) hoặc chuỗi ("Support/Billing"), tối đa 10 cấp. |
permissions | không | {"everyone": true}, hoặc {"emails": [...], "groups": [...]}. Được dùng khi quyền của nguồn là “như trong nguồn”. |
tags | không | Tối đa 50 nhãn, được thêm vào các nhãn của nguồn. |
author_email | không | Nếu đây là người dùng của tổ chức, người đó trở thành người phụ trách thẻ. |
updated_at | không | Thời điểm tài liệu thay đổi trong hệ thống của bạn (RFC 3339). |
metadata | không | Các cặp khóa-giá trị của bạn trên thẻ. Xem Siêu dữ liệu. |
category | không | Danh mục của thẻ: khóa của một danh mục của tổ chức. |
verifiers, verify_interval_days | không | Ai kiểm chứng thẻ (người dùng theo email và nhóm) và bao lâu một lần, tính bằng ngày. |
upload_id | không | Tệp của tài liệu từ một lượt tải lên theo từng phần, thay cho content. |
attachments | không | Tối đa 20 tệp bổ sung của tài liệu, dạng danh sách upload_id. Mỗi tệp trở thành một thẻ riêng của nguồn. |
Thay cho content, một tài liệu đơn lẻ có thể mang một tệp tới 100 MB trong yêu cầu multipart/form-data: tệp trong
phần file, các trường ở trên dạng JSON trong phần document. Lượt tải lên theo từng phần cho upload_id và
attachments được tạo bằng khóa của tổ chức có phạm vi import:write và mục đích import_attachment; khóa của nguồn
không thể tạo chúng.
Hai cách đẩy dữ liệu
Cập nhật trực tiếp phù hợp với hệ thống báo cho bạn về từng thay đổi, chẳng hạn webhook từ hệ thống hỗ trợ khách hàng hoặc một bước trong Zapier. Gửi tài liệu khi nó được tạo hoặc thay đổi, và xóa nó khi nó bị loại bỏ:
| Yêu cầu | Chức năng |
|---|---|
POST /v1/push/sources/{source_id}/documents | Tạo hoặc thay thế một tài liệu. |
POST /v1/push/sources/{source_id}/documents/batch | Tạo hoặc thay thế nhiều tài liệu cùng lúc. |
DELETE /v1/push/sources/{source_id}/documents/{external_id} | Xóa một tài liệu. Hãy mã hóa URL cho ID. |
Thay đổi trở thành thẻ trong khoảng một phút; nhiều thay đổi liên tiếp được xử lý cùng nhau.
Đồng bộ phù hợp với các lần xuất định kỳ: bạn gửi mọi thứ, hoặc mọi thứ đã thay đổi, và Sursa đối soát. Phần còn lại của hướng dẫn này nói về đồng bộ.
Chạy đồng bộ toàn bộ
Một lần đồng bộ có ba bước: mở, đẩy, đóng.
1. Mở
POST /v1/push/sources/{source_id}/syncs mở một phiên đồng bộ và trả về số của
nó:
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}
typelàinitialcho lần đồng bộ đầu tiên của nguồn, vàincrementalkhi đã có một lần đồng bộ hoàn tất. Đồng bộincrementaltrước khi có lần nào hoàn tất trả vềsources.push_initial_required.- Mỗi lúc chỉ có thể mở một phiên đồng bộ: phiên thứ hai trả về
409sources.push_sync_open. - Phiên đồng bộ mở trong
max_minutes(mặc định 60, tối đa 1440). Sau đó nó hết hạn: không có gì được lưu trữ và số của nó không còn được chấp nhận. Hãy chọn thời gian dài hơn khá nhiều so với thời gian bản xuất của bạn cần.
2. Đẩy tài liệu
Gửi tài liệu theo lô tối đa 500, kèm số của phiên đồng bộ. Phần thân của một lô tối đa 50 MiB; tệp trong lô được
truyền dưới dạng 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"}}
]
}'Phản hồi có kết quả cho từng tài liệu, theo đúng thứ tự bạn đã gửi:
{
"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…"}
]
}
| Trường | Ý nghĩa |
|---|---|
result | Điều gì đã xảy ra với tài liệu lúc này: created, updated, unchanged, deleted, not_found, error, hoặc skipped (trong một lô nguyên tử không được áp dụng). |
status | Tài liệu đang ở đâu trên đường trở thành thẻ: pending, processing (thẻ đã được ghi và đang được lập chỉ mục), indexed, failed hoặc removed. |
card_id | Thẻ của tài liệu, khi thẻ đã tồn tại. |
version | Giá trị băm của nội dung và các trường. Cùng tài liệu được gửi lại có cùng phiên bản và là unchanged. |
error, reason | Vì sao tài liệu thất bại. reason là mã ổn định: content_invalid, file_rejected, too_large, limit_reached, index_failed, hoặc batch_rejected (một tài liệu khác của lô nguyên tử thất bại). |
Theo mặc định, mỗi tài liệu của một lô được áp dụng riêng: một tài liệu lỗi không làm dừng các tài liệu khác.
Những tài liệu không thay đổi kể từ lần đồng bộ trước không cần gửi lại. Hãy xác nhận chúng theo ID bằng
POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch, tối đa 1000
ID mỗi yêu cầu, để lần đối soát toàn bộ giữ lại chúng:
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. Đóng
POST /v1/push/sources/{source_id}/syncs/{sync_number}/close kết thúc phiên
đồng bộ:
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 | Tác dụng |
|---|---|
complete | Đối soát toàn bộ. Mọi tài liệu của nguồn không được đẩy cũng không được xác nhận trong phiên đồng bộ này đều bị lưu trữ. Chỉ dùng khi bạn đã gửi mọi thứ. |
complete_incremental | Áp dụng những gì bạn đã gửi và không lưu trữ gì. |
failed | Không lưu trữ gì và giữ những gì đã được đẩy. Thêm reason (ví dụ API_ERROR) và error_details để ghi nhật ký. |
Hãy đóng với failed bất cứ khi nào bản xuất của bạn dừng giữa chừng: complete sau một bản xuất dở dang sẽ lưu trữ
mọi tài liệu mà bạn chưa kịp gửi. Lặp lại cùng thao tác đóng trả về cùng kết quả.
Sau khi đóng, Sursa biến tài liệu thành thẻ trong khoảng một phút. Trang của nguồn hiển thị từng phiên đồng bộ cùng số
tài liệu đã đẩy và đã lưu trữ, và GET /v1/push/sources/{source_id}/syncs/{sync_number}
trả về cùng các bộ đếm đó.
Đồng bộ gia tăng
Giữa các lần đồng bộ toàn bộ, chỉ gửi những gì đã thay đổi:
- Mở với
"type": "incremental". - Đẩy các tài liệu đã thay đổi, và đặt ID của các tài liệu đã bị xóa vào
deletes(bên dưới). - Đóng với
complete_incremental.
Thỉnh thoảng hãy chạy đồng bộ toàn bộ, ví dụ hằng tuần, để bắt được những gì một lần chạy gia tăng đã bỏ sót.
Xóa tài liệu trong một lô
Một lô có thể xóa tài liệu cùng lúc với việc ghi các tài liệu khác. Hãy liệt kê ID của chúng trong deletes:
{
"sync_number": 8,
"documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
"deletes": ["faq-old-returns", "faq-fax"]
}
Mỗi ID bị xóa có mục riêng trong results, với result là deleted, hoặc not_found nếu nguồn không có tài liệu
đó. Xóa lại cùng ID không gây hại.
Lô nguyên tử
Một số thay đổi chỉ có nghĩa khi đi cùng nhau, ví dụ một tài liệu và tài liệu thay thế nó. Hãy gửi "atomic": true,
và lô được áp dụng toàn bộ hoặc không áp dụng gì: nếu bất kỳ tài liệu nào không vượt qua kiểm tra, không phần nào của
lô được áp dụng, và phản hồi là 422 với mã sources.push_batch_rejected cùng kết quả của mọi tài liệu trong
error.details.results: tài liệu thất bại có error, các tài liệu còn lại có skipped.
{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}
Khi không có atomic, lô được áp dụng theo từng tài liệu. Hãy dùng lô nguyên tử cho các thay đổi liên quan với nhau,
và lô thông thường cho việc nạp khối lượng lớn, khi một tài liệu lỗi không nên kìm giữ phần còn lại.
Kiểm tra kết quả của từng tài liệu
Phản hồi của lô cho bạn biết từng tài liệu đã được ghi như thế nào. Việc biến tài liệu thành thẻ diễn ra sau đó, nên
status vẫn có thể là pending. Để tìm các tài liệu của một phiên đồng bộ chưa trở thành thẻ:
curl "https://api.sursa.com/v1/push/sources/42/syncs/7/documents?status=failed" \
-H "Authorization: Bearer $SURSA_SOURCE_KEY"Mỗi mục có external_id, title, status, card_id, version và reason, và danh sách được phân trang bằng
cursor. status cũng nhận pending, processing, indexed và removed.
Bạn cũng có thể được thông báo thay vì phải hỏi: các sự kiện import.sync_completed (một phiên đồng bộ đã được đóng
và xử lý, kèm các tổng số) và import.document_failed (một tài liệu không trở thành thẻ, kèm reason) được gửi qua
webhook và có trong nguồn cấp sự kiện.
Thử lại
- Gửi
Idempotency-Keyvới mỗi yêu cầuPOST. Lô được lặp lại với cùng khóa trả về kết quả đầu tiên. - Ngay cả khi không có khóa, một tài liệu có cùng
external_idkhông bao giờ trở thành thẻ thứ hai: nó làunchangedhoặcupdated. - Nếu tiến trình dừng giữa một phiên đồng bộ, hãy mở phiên mới sau khi phiên cũ hết hạn, hoặc đóng phiên cũ với
failednếu bạn vẫn còn số của nó, rồi chạy lại đồng bộ.
Giới hạn
| Giới hạn | Giá trị |
|---|---|
| Nội dung của một tài liệu | 5 MB |
| Tệp trong yêu cầu một tài liệu | 100 MB |
| Số tài liệu mỗi lô | 500 |
| Phần thân yêu cầu của lô | 50 MiB |
Số ID mỗi yêu cầu touch | 1000 |
| Số tài liệu mỗi nguồn | Tùy theo gói: từ 100.000 |
| Phiên đồng bộ mở | Mặc định 60 phút, tối đa 24 giờ |
Trong một lô, tài liệu vượt giới hạn số tài liệu của nguồn thất bại với lý do limit_reached; yêu cầu gửi một tài liệu
đơn lẻ trả về 409 với mã sources.push_too_many_documents. Giới hạn tốc
độ áp dụng như với mọi yêu cầu khác; xem Giới hạn tốc độ và hạn mức.
Lỗi thường gặp
| Câu trả lời | Nguyên nhân | Cách xử lý |
|---|---|---|
401 sources.push_key_invalid | Khóa sai, đã bị thu hồi hoặc thuộc về nguồn khác. | Kiểm tra khóa và ID nguồn trong đường dẫn. |
400 sources.push_document_invalid | Thiếu một trường bắt buộc hoặc vượt một giới hạn. | Sửa tài liệu; trong lô thông thường, chỉ tài liệu đó thất bại. |
409 sources.push_sync_open | Một phiên đồng bộ khác vẫn đang mở. | Đóng phiên đó, hoặc chờ tới khi nó hết hạn. |
409 sources.push_sync_closed | Phiên đồng bộ đã đóng hoặc đã hết hạn. | Mở phiên đồng bộ mới; tăng max_minutes cho các bản xuất dài. |
403 sources.feature_disabled | Nguồn không thuộc gói của tổ chức. | Liên hệ quản trị viên. |
429 | Quá nhiều yêu cầu. | Chờ hết Retry-After; gửi ít lô hơn nhưng lớn hơn. |