कस्टम स्रोत से अपने सिस्टम का सिंक
कस्टम स्रोत ऐसे सिस्टम को जोड़ता है, जिसके लिए कोई बिल्ट-इन कनेक्टर नहीं है: आपकी विकी, आपका टिकटिंग टूल, कोई डेटाबेस, कहीं से भी किया गया एक्सपोर्ट। आपका कोड दस्तावेज़ Sursa में भेजता है, और Sursa उन्हें उस कलेक्शन और उन फ़ोल्डर में कार्ड बना देता है, जिनके लिए स्रोत सेट किया गया है, उसी खोज, जवाबों, सत्यापन और अनुमतियों के साथ, जो किसी भी दूसरे स्रोत के कार्ड के लिए हैं।
सीधे कार्ड लिखने से अलग, कस्टम स्रोत याद रखता है कि आपने क्या भेजा है। पूरे सिंक के आख़िर में Sursa हर वह दस्तावेज़ आर्काइव कर देता है, जो आपने नहीं भेजा, इसलिए आपके सिस्टम में हुए डिलीशन बिना अतिरिक्त काम के Sursa तक पहुँच जाते हैं।
स्रोत सेट करें
एडमिन Sursa में Sources → New source → Custom source (स्रोत → नया स्रोत → कस्टम स्रोत) में स्रोत बनाता है, और चुनता है:
- कलेक्शन और, चाहें तो, उसके कार्ड के लिए एक फ़ोल्डर;
- फ़ोल्डर मोड: सभी कार्ड चुने गए फ़ोल्डर में, या ऐसे सब-फ़ोल्डर, जो हर दस्तावेज़ के
pathको दोहराते हैं; - अनुमतियाँ: कलेक्शन की अनुमतियाँ, या “स्रोत की तरह”, जहाँ हर दस्तावेज़ बताता है कि उसे कौन देख सकता है।
स्रोत के पेज पर उसकी ID दिखती है; उदाहरण 42 इस्तेमाल करते हैं।
कुंजी चुनें
| कुंजी | किससे शुरू होती है | क्या कर सकती है |
|---|---|---|
| स्रोत कुंजी | kbsrc_ | इसी एक स्रोत में दस्तावेज़ लिखना। और कुछ नहीं: यह न पढ़ सकती है, न खोज सकती है। इसे स्रोत के पेज पर API keys (स्रोत की API कुंजियाँ) में बनाएँ। |
import:write स्कोप वाली संगठन की कुंजी | kb_ | संगठन के किसी भी कस्टम स्रोत में लिखना और उसकी स्थिति पढ़ना। स्रोत और उसकी कुंजियाँ बनाने के लिए स्कोप admin चाहिए। |
एक इंटीग्रेशन के लिए स्रोत कुंजी सबसे सुरक्षित विकल्प है, ख़ास तौर पर ऐसे इंटीग्रेशन के लिए, जो तीसरे पक्ष के
प्लैटफ़ॉर्म पर चलता है। 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 | हाँ, अगर फ़ाइल नहीं है | 5 MB तक। |
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 की सूची के रूप में। हर फ़ाइल स्रोत का अपना अलग कार्ड बनती है। |
content के बजाय एक अकेला दस्तावेज़ multipart/form-data रिक्वेस्ट में 100 MB तक की फ़ाइल ले जा सकता है: फ़ाइल
file हिस्से में, ऊपर के फ़ील्ड JSON के रूप में document हिस्से में। upload_id और attachments के लिए हिस्सों
में अपलोड स्कोप import:write वाली संगठन की कुंजी से, उद्देश्य import_attachment के साथ बनाए जाते हैं; स्रोत कुंजी
उन्हें नहीं बना सकती।
भेजने के दो तरीक़े
सीधे अपडेट उन सिस्टम के लिए ठीक हैं, जो हर बदलाव के बारे में बताते हैं, जैसे आपके हेल्पडेस्क का वेबहुक या Zapier में कोई स्टेप। दस्तावेज़ बनने या बदलने पर उसे भेजें, और हटाए जाने पर उसे डिलीट करें:
| रिक्वेस्ट | क्या करती है |
|---|---|
POST /v1/push/sources/{source_id}/documents | एक दस्तावेज़ बनाती या बदलती है। |
POST /v1/push/sources/{source_id}/documents/batch | एक साथ कई दस्तावेज़ बनाती या बदलती है। |
DELETE /v1/push/sources/{source_id}/documents/{external_id} | एक दस्तावेज़ हटाती है। ID को URL-एनकोड करें। |
बदलाव लगभग एक मिनट के अंदर कार्ड बन जाते हैं; लगातार कई बदलाव एक साथ प्रोसेस होते हैं।
सिंक नियमित एक्सपोर्ट के लिए ठीक हैं: आप सब कुछ, या जो कुछ बदला है वह सब, भेजते हैं, और Sursa मिलान करता है। इस गाइड का बाक़ी हिस्सा सिंक के बारे में है।
पूरा सिंक चलाएँ
सिंक के तीन स्टेप हैं: खोलें, भेजें, बंद करें।
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लौटाता है। - एक समय पर सिर्फ़ एक सिंक खुला रह सकता है: दूसरा सिंक
409sources.push_sync_openलौटाता है। - सिंक
max_minutesतक खुला रहता है (डिफ़ॉल्ट रूप से 60, ज़्यादा से ज़्यादा 1440)। उसके बाद उसकी मियाद ख़त्म हो जाती है: कुछ भी आर्काइव नहीं होता और उसका नंबर अब स्वीकार नहीं होता। ऐसा समय चुनें, जो आपके एक्सपोर्ट में लगने वाले समय से काफ़ी ज़्यादा हो।
2. दस्तावेज़ भेजें
दस्तावेज़ 500 तक के बैच में, सिंक नंबर के साथ भेजें। बैच की बॉडी 50 MiB तक होती है; बैच के अंदर फ़ाइलें
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 (एटॉमिक बैच का कोई दूसरा दस्तावेज़ असफल हुआ)। |
डिफ़ॉल्ट रूप से बैच का हर दस्तावेज़ अलग से लागू होता है: एक ख़राब दस्तावेज़ बाक़ी को नहीं रोकता।
जो दस्तावेज़ पिछले सिंक के बाद नहीं बदले, उन्हें फिर से भेजने की ज़रूरत नहीं है। उनकी पुष्टि ID से
POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch से करें, हर
रिक्वेस्ट में 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 लगभग एक मिनट के अंदर दस्तावेज़ों को कार्ड बना देता है। स्रोत का पेज हर सिंक को भेजे गए और
आर्काइव किए गए दस्तावेज़ों की संख्या के साथ दिखाता है, और GET /v1/push/sources/{source_id}/syncs/{sync_number}
यही काउंटर लौटाता है।
इंक्रीमेंटल सिंक
पूरे सिंक के बीच में सिर्फ़ वही भेजें, जो बदला है:
"type": "incremental"के साथ खोलें।- बदले गए दस्तावेज़ भेजें, और हटाए गए दस्तावेज़ों की ID
deletesमें डालें (नीचे देखें)। 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 भेजें, और बैच या तो पूरा लागू होता है या बिल्कुल नहीं: अगर कोई भी दस्तावेज़ अपनी जाँच में असफल होता
है, तो बैच का कुछ भी लागू नहीं होता, और रिस्पॉन्स कोड sources.push_batch_rejected के साथ 422 होता है, और
error.details.results में हर दस्तावेज़ का नतीजा होता है: असफल दस्तावेज़ों में error, बाक़ी में skipped।
{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}
atomic के बिना बैच दस्तावेज़-दर-दस्तावेज़ लागू होता है। जुड़े हुए बदलावों के लिए एटॉमिक बैच इस्तेमाल करें, और बड़े
लोड के लिए सामान्य बैच, जहाँ एक ख़राब दस्तावेज़ को बाक़ी को नहीं रोकना चाहिए।
हर दस्तावेज़ का नतीजा जाँचें
बैच का रिस्पॉन्स बताता है कि हर दस्तावेज़ कैसे लिखा गया। कार्ड बाद में बनता है, इसलिए 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 के साथ)
वेबहुक से और इवेंट फ़ीड में आते हैं।
रीट्राई
- हर
POSTके साथIdempotency-Keyभेजें। उसी कुंजी के साथ दोहराया गया बैच पहला नतीजा लौटाता है। - कुंजी के बिना भी उसी
external_idवाला दस्तावेज़ कभी दूसरा कार्ड नहीं बनता: वहunchangedयाupdatedहोता है। - अगर प्रोसेस सिंक के बीच में रुक जाए, तो पुराने सिंक की मियाद ख़त्म होने के बाद नया खोलें, या अगर आपके पास पुराने का
नंबर है, तो उसे
failedसे बंद करें, और सिंक फिर से चलाएँ।
सीमाएँ
| सीमा | मान |
|---|---|
| एक दस्तावेज़ का कंटेंट | 5 MB |
| एक दस्तावेज़ वाली रिक्वेस्ट में फ़ाइल | 100 MB |
| हर बैच में दस्तावेज़ | 500 |
| बैच रिक्वेस्ट की बॉडी | 50 MiB |
हर touch रिक्वेस्ट में ID | 1000 |
| हर स्रोत में दस्तावेज़ | प्लान पर निर्भर: 100,000 से |
| खुला सिंक | डिफ़ॉल्ट रूप से 60 मिनट, ज़्यादा से ज़्यादा 24 घंटे |
स्रोत की दस्तावेज़ सीमा से ऊपर का दस्तावेज़ बैच में limit_reached कारण के साथ असफल होता है; एक दस्तावेज़ वाली
रिक्वेस्ट कोड 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 तक इंतज़ार करें; कम, पर बड़े बैच भेजें। |