Chuyển tới nội dung
Sursa Developers

Đồ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 path củ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óaBắt đầu bằngLàm được gì
Khóa nguồnkbsrc_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:writekb_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ườngBắt buộcMô tả
external_idcó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.
titlecóTiêu đề thẻ, tối đa 500 ký tự. Với tệp, mặc định là tên tệp.
contentcó, trừ khi có tệpTối đa 5 MB.
content_typekhônghtml (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.
urlkhôngLiên kết tới tài liệu trong hệ thống của bạn, hiển thị trên thẻ.
pathkhôngThư mục, dạng mảng (["Support", "Billing"]) hoặc chuỗi ("Support/Billing"), tối đa 10 cấp.
permissionskhông{"everyone": true}, hoặc {"emails": [...], "groups": [...]}. Được dùng khi quyền của nguồn là “như trong nguồn”.
tagskhôngTối đa 50 nhãn, được thêm vào các nhãn của nguồn.
author_emailkhôngNếu đây là người dùng của tổ chức, người đó trở thành người phụ trách thẻ.
updated_atkhôngThời điểm tài liệu thay đổi trong hệ thống của bạn (RFC 3339).
metadatakhôngCác cặp khóa-giá trị của bạn trên thẻ. Xem Siêu dữ liệu.
categorykhôngDanh mục của thẻ: khóa của một danh mục của tổ chức.
verifiers, verify_interval_dayskhôngAi 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_idkhôngTệp của tài liệu từ một lượt tải lên theo từng phần, thay cho content.
attachmentskhôngTố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ầuChức năng
POST /v1/push/sources/{source_id}/documentsTạo hoặc thay thế một tài liệu.
POST /v1/push/sources/{source_id}/documents/batchTạ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}
  • type là initial cho lần đồng bộ đầu tiên của nguồn, và incremental khi đã có một lần đồng bộ hoàn tất. Đồng bộ incremental trướ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ề 409 sources.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).
statusTà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_idThẻ của tài liệu, khi thẻ đã tồn tại.
versionGiá 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, reasonVì 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"}'
statusTá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ì.
failedKhô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:

  1. Mở với "type": "incremental".
  2. Đẩ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).
  3. Đó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-Key với mỗi yêu cầu POST. 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_id không bao giờ trở thành thẻ thứ hai: nó là unchanged hoặc updated.
  • 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 failed nế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ạnGiá trị
Nội dung của một tài liệu5 MB
Tệp trong yêu cầu một tài liệu100 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 touch1000
Số tài liệu mỗi nguồnTù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ờiNguyên nhânCách xử lý
401 sources.push_key_invalidKhó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_invalidThiế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_openMộ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_closedPhiê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_disabledNguồn không thuộc gói của tổ chức.Liên hệ quản trị viên.
429Quá nhiều yêu cầu.Chờ hết Retry-After; gửi ít lô hơn nhưng lớn hơn.