本文へスキップ
Sursa Developers

カスタムソースで自社のシステムを同期する

カスタムソースは、組み込みのコネクターがないシステムをつなぎます。自社のWiki、チケット管理ツール、データベース、あらゆる場所からのエクスポートなどです。コードがドキュメントをSursaに送信すると、Sursaはそれを、ソースに設定されたコレクションとフォルダーのカードにします。カードには、他のソースのカードと同じ検索、回答、検証、権限が適用されます。

カードを直接書き込む場合と違い、カスタムソースは送信済みのものを記録します。完全同期の最後に、Sursaは送信されなかったすべてのドキュメントをアーカイブするので、自社のシステムでの削除が、追加の作業なしにSursaに反映されます。

ソースを設定する

管理者は、SursaのSources → New source → Custom source(ソース → 新しいソース → カスタムソース)でソースを作成し、次を選びます。

  • カードを入れるコレクションと、必要に応じてフォルダー。
  • フォルダーモード:選んだフォルダーにすべてのカードを入れるか、各ドキュメントのpathを反映したサブフォルダーを作るか。
  • 権限:コレクションの権限を使うか、各ドキュメントで参照できる人を指定する「ソースと同じ」にするか。

ソースのページにはそのIDが表示されます。例では42を使います。

キーを選ぶ

キー先頭の文字できること
ソースキーkbsrc_この1つのソースへのドキュメントの書き込み。それ以外は何もできず、読み込みも検索もできません。ソースのページのAPI keys(APIキー)で作成します。
import:writeスコープを持つ組織のキーkb_組織のすべてのカスタムソースへの書き込みと、その状態の読み取り。ソースとそのキーの作成にはadminスコープが必要です。

1つの連携システム、特に第三者のプラットフォームで動く連携システムには、ソースキーが最も安全です。複数のソースにデータを送るサービスには、import:writeを持つ組織のキーが適しています。

どちらのキーも同じ方法で送信し、プッシュ用エンドポイントはすべて/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はいドキュメントの、自社での安定したID。512文字まで。同じIDをもう一度送信すると、ドキュメントが置き換えられます。
titleはいカードのタイトル。500文字まで。ファイルの場合、デフォルトはファイル名です。
contentはい(ファイルがない場合)5MBまで。
content_typeいいえhtml(デフォルト)、markdown、text。HTMLからは、スクリプト、スタイル、フォーム、埋め込みオブジェクトが取り除かれます。
urlいいえ自社のシステムでのドキュメントへのリンク。カードに表示されます。
pathいいえフォルダー。配列(["Support", "Billing"])または文字列("Support/Billing")で、10階層まで。
permissionsいいえ{"everyone": true}、または{"emails": [...], "groups": [...]}。ソースの権限が「ソースと同じ」の場合に使われます。
tagsいいえ50個までのタグ。ソースのタグに追加されます。
author_emailいいえ組織のユーザーであれば、カードの担当者になります。
updated_atいいえ自社のシステムでドキュメントが変更された日時(RFC 3339)。
metadataいいえカードに付ける独自のキーと値のペア。メタデータを参照してください。
categoryいいえカードのカテゴリ。組織のカテゴリのキーで指定します。
verifiers、verify_interval_daysいいえカードを検証する人(メールアドレスで指定するユーザーとグループ)と、その頻度(日数)。
upload_idいいえパートに分けたアップロードによるドキュメントのファイル。contentの代わりに使います。
attachmentsいいえドキュメントの追加のファイル(最大20個)。upload_idのリストで指定します。それぞれがソースの個別のカードになります。

1件のドキュメントなら、contentの代わりに、multipart/form-dataのリクエストで最大100MBのファイルを送ることもできます。ファイルはfileパートに、上のフィールドはJSONとしてdocumentパートに入れます。upload_idとattachmentsのためのパートに分けたアップロードは、import:writeスコープを持つ組織のキーで、用途import_attachmentを指定して作成します。ソースキーでは作成できません。

2つの送信方法

直接更新は、ヘルプデスクからのWebhookやZapierのステップのように、変更を1件ずつ知らせるシステムに向いています。ドキュメントが作成または変更されたら送信し、削除されたら削除します。

リクエスト処理
POST /v1/push/sources/{source_id}/documents1件のドキュメントを作成または置換します。
POST /v1/push/sources/{source_id}/documents/batch多数のドキュメントを一度に作成または置換します。
DELETE /v1/push/sources/{source_id}/documents/{external_id}1件のドキュメントを削除します。IDはURLエンコードしてください。

変更は1分ほどでカードになります。続けて行われた複数の変更は、まとめて処理されます。

同期は、定期的なエクスポートに向いています。すべて、または変更されたものすべてを送信すると、Sursaが照合します。このガイドの残りでは、同期について説明します。

完全同期を実行する

同期は、開始、送信、終了の3つの手順からなります。

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が返ります。
  • 同時に開ける同期は1つだけです。2つ目を開こうとすると409 sources.push_sync_openが返ります。
  • 同期はmax_minutes(デフォルトは60、最大1440)のあいだ開いたままになります。その後は期限切れになり、何もアーカイブされず、その番号は受け付けられなくなります。エクスポートにかかる時間より十分に長い時間を選んでください。

2. ドキュメントを送信

ドキュメントは、同期の番号を付けて、最大500件のバッチで送信します。バッチのボディは50MiBまでです。バッチの中のファイルは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(アトミックバッチの別のドキュメントが失敗した)。

デフォルトでは、バッチの各ドキュメントは個別に適用されます。1件の不正なドキュメントが他を止めることはありません。

前回の同期から変わっていないドキュメントは、もう一度送信する必要はありません。完全な照合でそれらが残るように、POST /v1/push/sources/{source_id}/syncs/{sync_number}/touchで、1回のリクエストで最大1000件のIDを指定して、再送せずに確認します。

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は1分ほどでドキュメントをカードにします。ソースのページには、各同期が、送信されたドキュメントとアーカイブされたドキュメントの数とともに表示され、GET /v1/push/sources/{source_id}/syncs/{sync_number}も同じカウンターを返します。

増分同期

完全同期のあいだには、変更されたものだけを送信します。

  1. "type": "incremental"で開始します。
  2. 変更されたドキュメントを送信し、削除されたドキュメントのIDをdeletesに入れます(下記)。
  3. complete_incrementalで終了します。

増分同期で漏れたものを拾うために、ときどき(たとえば毎週)完全同期を実行してください。

ドキュメントを一括で削除する

バッチでは、書き込むドキュメントと一緒にドキュメントを削除できます。そのIDをdeletesに並べます。

{
  "sync_number": 8,
  "documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
  "deletes": ["faq-old-returns", "faq-fax"]
}

削除した各IDはresultsにそれぞれの項目を持ち、resultはdeleted、ソースにそのドキュメントがなければnot_foundになります。同じIDをもう一度削除しても害はありません。

アトミックバッチ

ドキュメントと、それを置き換えるドキュメントのように、まとめて行わないと意味のない変更もあります。"atomic": trueを送信すると、バッチは完全に適用されるか、まったく適用されないかのどちらかになります。どれか1件のドキュメントが確認に失敗すると、バッチは何も適用されず、レスポンスはコードsources.push_batch_rejectedとともに422になり、error.details.resultsにすべてのドキュメントの結果が含まれます。失敗したドキュメントにはerrorが、それ以外にはskippedが入ります。

{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}

atomicがなければ、バッチはドキュメントごとに適用されます。関連する変更にはアトミックバッチを、1件の不正なドキュメントで残りを止めるべきではない大量のロードには通常のバッチを使ってください。

ドキュメントごとの結果を確認する

バッチのレスポンスは、各ドキュメントがどのように書き込まれたかを示します。カードになるのはその後なので、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が含まれる)が、Webhookとイベントフィードに届きます。

再試行

  • すべてのPOSTでIdempotency-Keyを送信してください。同じキーで繰り返したバッチは、最初の結果を返します。
  • キーがなくても、同じexternal_idのドキュメントが2枚目のカードになることはありません。結果はunchangedまたはupdatedになります。
  • 同期の途中でプロセスが止まった場合は、古い同期の期限が切れてから新しい同期を開始するか、番号がわかっていれば古い同期をfailedで終了して、同期をもう一度実行してください。

上限

上限値
1件のドキュメントの内容5MB
1件のドキュメントのリクエストでのファイル100MB
バッチあたりのドキュメント数500
バッチのリクエストボディ50MiB
touchリクエストあたりのID数1000
ソースあたりのドキュメント数プランによる:100,000から
開いている同期デフォルトで60分、最大24時間

ソースのドキュメント数の上限を超えたドキュメントは、バッチでは理由limit_reachedで失敗します。1件のドキュメントのリクエストには、コードsources.push_too_many_documentsとともに409が返ります。他のリクエストと同じくレート制限が適用されます。レート制限とクォータを参照してください。

よくあるエラー

応答原因対処
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の時間だけ待ってください。より大きなバッチで、送信の回数を減らしてください。