अपने ग्राहकों के लिए कैप्चा API कुंजियाँ कैसे जारी करें

अगर आप CapSkip दूसरों के लिए चलाते हैं, तो ग्राहक के भुगतान करते ही, सीधे अपने बिलिंग webhook से कैप्चा API कुंजियाँ जारी की जा सकती हैं। Remote Key Management तीन POST एंडपॉइंट देता है जो चल रहे इंस्टेंस पर कुंजियाँ जोड़ते, दिखाते और मिटाते हैं, और नई कुंजी एकदम अगली हल करने वाली रिक्वेस्ट पर ही चालू हो जाती है। न रीस्टार्ट, न कोई मैनुअल कदम, और भुगतान पूरा होने तथा ग्राहक के हल करना शुरू करने के बीच अब कुछ भी नहीं बचता। इस पोस्ट में सदस्यता लेते समय कुंजी देना, रद्द करते समय वापस लेना, कुंजी सूची को बिलिंग सिस्टम से मिलाकर रखना, और वह एक नेटवर्क गलती जो यह सेटअप बहुत आसान बना देता है, सब शामिल है।
आपको क्या चाहिए
- आपके अपने नियंत्रण वाली एक Windows मशीन पर चलता हुआ CapSkip। यही मशीन आपकी हल करने वाली सेवा है, और यही अकेली मशीन है जिस पर ऐप्लिकेशन इंस्टॉल होना ज़रूरी है। आपके ग्राहक कुछ भी इंस्टॉल नहीं करते।
- और Server मोड, ताकि वे ग्राहक असल में इस तक पहुँच सकें। Local मोड लूपबैक पते पर सुनता है और सिर्फ़ उसी डिवाइस को सेवा देता है, जबकि Server मोड आपके नेटवर्क या पब्लिक IP पर सुनता है, ताकि दूसरी मशीनें जुड़ सकें। दोनों मोड यहाँ बताए गए हैं: कनेक्शन सेटिंग्स. और पता किसी को देने से पहले एक स्टैटिक पब्लिक IP रखना बेहतर है।
- एडमिन token बनाने के लिए CapSkip विंडो पर एक बार जाना। इंटरफ़ेस में होने वाला यही अकेला कदम है, और इसे दोबारा दोहराना नहीं पड़ता।
- इन कॉल को चलाने के लिए कोई जगह: आपका बिलिंग webhook हैंडलर, आपके डैशबोर्ड का बैकएंड, या जब तक आप जाँच रहे हैं तब तक एक टर्मिनल।
कोड से पहले एक बात साफ़ कह देना ठीक रहेगा, क्योंकि यही वह चीज़ है जिस पर यह पूरा मॉडल टिका है। जो कुंजियाँ आप बाँट रहे हैं, वे आपकी अपनी बनाई हुई हैं। ये खरीदे हुए क्रेडिट नहीं हैं जिन्हें आप आगे बेच रहे हों, और इनके पीछे प्रति-हल कोई मीटर नहीं चलता। CapSkip आपके अपने हार्डवेयर पर चलता है, इसलिए सौ ग्राहक कुंजियों की लागत ठीक उतनी ही है जितनी एक की।
चरण 1: Remote Key Management चालू करें
यह स्विच Settings में है, API Key Validation के नीचे, फिर Advanced, फिर Remote Key Management। इसे चालू कीजिए और Generate बटन दबाइए।
token सिर्फ़ एक बार दिखता है और सिर्फ़ साल्टेड हैश के रूप में सहेजा जाता है, इसलिए बाद में उसे कहीं से पढ़ा नहीं जा सकता। खो जाए तो नया बना लीजिए, पुराना उसी क्षण बेकार हो जाता है। इसी को रद्द करने का बटन मानिए, क्योंकि अलग से कोई बटन है ही नहीं। इसे वहीं रखिए जहाँ आपका बिलिंग सिस्टम अपने बाकी गोपनीय मान रखता है, अपने ऐप्लिकेशन कोड में नहीं।
ये एंडपॉइंट उसी होस्ट और उसी पोर्ट पर रहते हैं जो पहले से आपकी हल करने वाली रिक्वेस्ट का जवाब देता है। अगर आपके ग्राहक पोर्ट 8080 से बात करते हैं तो एडमिन API भी वहीं है। यह सुविधाजनक है और यही वह चीज़ भी है जिससे सावधान रहना पड़ता है; नीचे इसके लिए अलग खंड है।
जब तक यह सुविधा बंद है, हर एडमिन पथ बिना बॉडी वाला सादा 404 लौटाता है। अनजान पथ को भी ठीक यही जवाब मिलता है, और यह जानबूझकर ऐसा रखा गया है: पोर्ट टटोलने वाला यह नहीं बता सकता कि यह सुविधा बंद किए हुए इंस्टेंस है या ऐसा इंस्टेंस जिसने इस सुविधा का नाम भी नहीं सुना।
चरण 2: ग्राहक के सदस्यता लेते ही कुंजी बनाइए
तीनों एंडपॉइंट POST हैं, JSON बॉडी लेते हैं, और एक Authorization हेडर माँगते हैं जिसमें token, Bearer क्रेडेंशियल के रूप में हो। जोड़ने वाली कॉल को एक नाम चाहिए। सिर्फ़ नाम भेजिए और कुंजी का मान CapSkip को बनाने दीजिए, यहाँ यही सही है: ग्राहक को अपना क्रेडेंशियल खुद नहीं चुनना चाहिए।
# No install needed. Name the key after the customer, not after the plan.
curl -X POST http://YOUR_SERVER:8080/admin/keys/add \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" -d '{"name":"cust_10482"}'
# Response carries the value to show the customer once:
# {"errorId":0,"key":{"name":"cust_10482","key":"..."}}नाम अपने ही सिस्टम की किसी स्थिर चीज़ पर रखिए, जैसे ग्राहक ID या सदस्यता ID। नाम अद्वितीय होते हैं और यह नियम जोड़ते समय ही लागू होता है, इसलिए नाम आगे के हर काम के लिए एक भरोसेमंद पकड़ बन जाता है। इसके बजाय प्लान या तारीख के नाम पर कुंजियाँ रखना ही वह गलती है जो रद्द करने वाले दिन को तकलीफ़देह बना देती है।
यही अद्वितीयता का नियम आपकी दोहराव-सुरक्षा भी है। भुगतान सेवाएँ webhook दोबारा भेजती हैं, और दोबारा आया सदस्यता इवेंट उसी ग्राहक के लिए चुपचाप दूसरी कुंजी बनाने के बजाय 409 और ERROR_KEY_EXISTS लौटाता है। अपने हैंडलर में इस 409 को सफलता मानिए, दोहराव की समस्या खत्म।
मान ठीक एक बार, उसी जवाब में लौटता है। उसे ग्राहक को दिखाइए या वहाँ सहेजिए जहाँ से आपका डैशबोर्ड पढ़ता है, क्योंकि बाद में कुंजियाँ सूचीबद्ध करना एक एडमिन काम है और किसी एक ग्राहक का क्रेडेंशियल वापस पाने के लिए उसे चलाना आप नहीं चाहेंगे।
चरण 3: रद्द करने पर कुंजी वापस लीजिए
मिटाने के लिए ठीक एक ही पहचान चाहिए, या तो कुंजी का मान या फिर नाम। चूँकि आपने कुंजियों के नाम ग्राहकों पर रखे हैं, इसलिए नाम ही सही विकल्प है:
# By name, which is unambiguous because names are unique.
curl -X POST http://YOUR_SERVER:8080/admin/keys/delete \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" -d '{"name":"cust_10482"}'
# By value works too, if that is what your records hold:
# -d '{"key":"the-old-value"}'वापसी अगली हल करने वाली रिक्वेस्ट पर लागू होती है, इसलिए कॉल लौटते ही पहुँच खत्म हो जाती है। उसके बाद से उस ग्राहक की कॉल इस त्रुटि के साथ विफल होंगी: ERROR_KEY_DOES_NOT_EXIST। यह संकेत काफ़ी साफ़ है, उनका इंटीग्रेशन इसे किसी खराबी के बजाय समाप्त हो चुकी सदस्यता के रूप में दिखा सकता है।
यह कब चलाना है, सोच-समझकर तय कीजिए। रद्द होने वाले इवेंट पर मिटाने से पहुँच तुरंत कट जाती है, जबकि ग्राहक ने आमतौर पर अवधि के अंत तक का भुगतान किया होता है। अवधि समाप्त होने वाले इवेंट पर मिटाना ही वह है जो ज़्यादातर लोग असल में चाहते हैं। भुगतान विफल होना तीसरी स्थिति है: वापसी से पहले थोड़ी रियायत अवधि देना, कार्ड दोबारा चार्ज होते समय गायब हो जाने वाली कुंजी के मुकाबले कहीं कम शिकायतें पैदा करता है।
चरण 4: सूची को अपने बिलिंग सिस्टम से मिलाइए
सूची वाली कॉल एक खाली ऑब्जेक्ट लेती है और वह हर कुंजी लौटाती है जिसे इंस्टेंस इस समय स्वीकार करता है।
# The audit: exactly who can solve right now.
curl -X POST http://YOUR_SERVER:8080/admin/keys/list \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" -d '{}'{
"errorId": 0,
"keys": [
{ "name": "cust_10482", "key": "..." },
{ "name": "cust_10515", "key": "..." }
]
}errorId का 0 होना सफलता है, यही परिपाटी हल करने वाले एंडपॉइंट भी इस्तेमाल करते हैं। इसे नियमित अंतराल पर चलाइए और नामों की तुलना अपनी सक्रिय सदस्यताओं से कीजिए। जिस कुंजी की कोई सदस्यता नहीं है, उसका मतलब है कोई अब भी मुफ़्त में हल करा रहा है; और जिस सदस्यता की कोई कुंजी नहीं है, उसका मतलब है ऐसा ग्राहक जिसका कुंजी जारी करने वाला webhook गिर गया और जो शायद अभी शिकायत दर्ज करने वाला है। दोनों तब तक चुप रहते हैं जब तक आप देखें नहीं, और सच सिर्फ़ इसी कॉल में रहता है।
इसे सदस्यता webhook में जोड़ना
सब मिलाकर पूरा इंटीग्रेशन दो हैंडलर और एक दोहराव नियम भर है:
# pip install requests
import requests
BASE = "http://YOUR_SERVER:8080"
AUTH = {"Authorization": "Bearer YOUR_TOKEN"}
def admin(path, body):
r = requests.post(f"{BASE}/admin/keys/{path}", json=body,
headers=AUTH, timeout=10)
# 409 on add means the key already exists, which is what a
# retried webhook looks like. Treat it as success, not failure.
if r.status_code == 409:
return None
r.raise_for_status()
return r.json()
def on_subscription_active(customer_id):
created = admin("add", {"name": f"cust_{customer_id}"})
return created["key"]["key"] if created else None
def on_subscription_ended(customer_id):
admin("delete", {"name": f"cust_{customer_id}"})दोहराए गए सदस्यता इवेंट से आने वाले None को ध्यान से संभालिए। इसका मतलब है कि कुंजी मौजूद है पर उसका मान अब आपको दिखाई नहीं देगा, इसलिए अगर आपने पहली बार उसे सहेजा नहीं था, तो उपाय सूची देखना नहीं बल्कि मिटाकर दोबारा बनाना है। पहली बार मिलते ही मान सहेज लेने से यह स्थिति आती ही नहीं।
एडमिन API को ग्राहकों वाले पोर्ट पर मत छोड़िए
इस सेटअप के लिए यही सबसे अहम खंड है, क्योंकि एक ही होस्ट और एक ही पोर्ट की सुविधा दोनों तरफ़ काटती है। आपके ग्राहकों को हल करने वाले एंडपॉइंट तक पहुँचना ही है। एडमिन एंडपॉइंट उसी पोर्ट पर हैं, उनकी सुरक्षा सिर्फ़ Bearer token से है, और कोई ट्रांसपोर्ट जाँच है ही नहीं, इसलिए किसी अलग पोर्ट पर यह token सादे HTTP में जाता है। जो कोई भी उस ट्रैफ़िक को देख सकता है वह उसे पढ़ लेगा, और जिसके हाथ वह लग गया वह अपने लिए कुंजी बना लेगा।
इंस्टेंस के आगे एक रिवर्स प्रॉक्सी लगाइए और दोनों तरह के लोगों को अलग कीजिए:
- इंटरनेट पर सिर्फ़ हल करने वाले पथ प्रकाशित कीजिए, प्रॉक्सी पर समाप्त होने वाले HTTPS के ज़रिए, और एडमिन पथ के नीचे की हर चीज़ के लिए 404 लौटाइए।
- एडमिन एंडपॉइंट तक अपने ही बैकएंड से किसी निजी रास्ते से पहुँचिए: अगर बिलिंग सेवा उसी Windows मशीन पर चलती है तो लूपबैक पता, वरना कोई निजी नेटवर्क, कोई VPN, या कोई SSH टनल।
मोटा नियम यह है कि एडमिन token को कभी आपके ढाँचे से बाहर नहीं जाना चाहिए, और वह जिस पोर्ट से बात करता है वह कभी ऐसा पोर्ट नहीं होना चाहिए जहाँ ग्राहक पहुँच सके। सुविधा चालू हो या बंद, एडमिन पथ को कभी खुले इंटरनेट पर मत लाइए।
एक और सीमा जानने लायक है, क्योंकि यहाँ सबसे पहले दिमाग में ग्राहक डैशबोर्ड बनाने का ही खयाल आता है। ब्राउज़र इन एंडपॉइंट को बुला ही नहीं सकते, क्योंकि एडमिन प्रतिक्रियाएँ डिज़ाइन के हिसाब से कोई CORS हेडर नहीं भेजतीं। आपके डैशबोर्ड को आपके ही बैकएंड से होकर जाना होगा, और token की सही जगह भी वही है।
कुंजियाँ असल में लिखी कहाँ जाती हैं
कुंजियाँ वहीं जाती हैं जहाँ आपकी कुंजियाँ पहले से रहती हैं। Direct Input और From File अलग-अलग दो सूचियाँ हैं, और API उसी को पढ़ता और लिखता है जो इस समय चुनी हुई है। सेटिंग्स विंडो में स्रोत बदलने से एंडपॉइंट को दिखने वाली चीज़ भी बदल जाती है, इसलिए अभी-अभी जारी की कुंजी सूची में क्यों नहीं है, यह सोचने से पहले पुष्टि कर लीजिए कि आप किस मोड में हैं।
फ़ाइल मोड का एक व्यवहार पहले से जान लेना ठीक रहेगा: पहली ही लिखाई सादे टेक्स्ट वाली कुंजी फ़ाइल को JSON के रूप में दोबारा लिख देती है। कुछ खोता नहीं, लेकिन प्रारूप हमेशा के लिए बदल जाता है, इसलिए अगर उस फ़ाइल को कोई और चीज़ भी पढ़ती है तो पहले बैकअप ले लीजिए। और अगर कोई फ़ाइल चुनी ही नहीं गई है तो लिखाई कहीं टिक ही नहीं सकती, और आपको 500 के साथ ERROR_ADMIN_STORE_FAILURE मिलेगा। यहाँ 500 का मतलब लगभग हमेशा यही होता है।
इस सुविधा से पहले बनी सूचियों में अब भी दोहराए हुए नाम हो सकते हैं, क्योंकि अद्वितीयता सिर्फ़ जोड़ते समय जाँची जाती है। ऐसे में नाम से मिटाने पर ERROR_KEY_NAME_AMBIGUOUS मिलता है और कुछ भी नहीं बदलता। इसके बजाय मान से मिटाइए, दुविधा खत्म हो जाती है।
Windows शेल में उद्धरण चिह्न, अगर आप उसी मशीन से जाँच रहे हैं
CapSkip एक Windows ऐप्लिकेशन है, इसलिए जिस मशीन से आप जाँच रहे हैं वह भी अक्सर Windows ही होती है। कमांड प्रॉम्प्ट एकल उद्धरण को उद्धरण चिह्न मानता ही नहीं। नकल किया हुआ कमांड उद्धरण चिह्नों को JSON बॉडी का हिस्सा बनाकर भेज देता है, पार्सर उसे ठुकरा देता है, और बिल्कुल सही दिखने वाले कमांड पर आपको ERROR_ADMIN_BAD_REQUEST मिल जाता है।
| शेल | खाली body | फ़ील्ड के साथ |
|---|---|---|
| कमांड प्रॉम्प्ट | -d "{}" | -d "{\"name\":\"prod\"}" |
| PowerShell, curl.exe के साथ | -d '{}' | -d '{\"name\":\"prod\"}' |
| Git Bash, macOS, Linux | -d '{}' | -d '{"name":"prod"}' |
PowerShell में curl.exe को पूरे नाम से बुलाइए। वहाँ सादा curl दरअसल Invoke-WebRequest का उपनाम है, जो बिल्कुल अलग आर्ग्युमेंट लेता है और ऐसी गड़बड़ी दिखाएगा जिसका इस API से कोई लेना-देना नहीं।
एरर कोड
| स्थिति | कोड | कारण |
|---|---|---|
| 404 | सादा टेक्स्ट | सुविधा बंद है, या पथ अनजान है। दोनों को जानबूझकर एक जैसा रखा गया है। |
| 401 | ERROR_ADMIN_UNAUTHORIZED | token नहीं है, बिगड़ा हुआ है, या गलत है। |
| 405 | ERROR_ADMIN_METHOD_NOT_ALLOWED | आपने POST के अलावा कुछ भेजा है। |
| 400 | ERROR_ADMIN_BAD_REQUEST | बॉडी वैध JSON नहीं है, जोड़ने में नाम नहीं है, या मिटाने में दोनों पहचान दी गई हैं या एक भी नहीं। |
| 409 | ERROR_KEY_EXISTS | वह नाम या वह मान पहले से इस्तेमाल में है। सदस्यता हैंडलर में इसका मतलब आमतौर पर दोबारा भेजा गया webhook होता है। |
| 409 | ERROR_KEY_NAME_AMBIGUOUS | नाम से मिटाने पर कई कुंजियाँ मिलीं। इसके बजाय मान से मिटाइए। |
| 404 | ERROR_KEY_NOT_FOUND | मिटाने पर कुछ भी नहीं मिला। आमतौर पर यह पहले ही निपटाई जा चुकी रद्दीकरण होती है। |
| 500 | ERROR_ADMIN_STORE_FAILURE | सहेजा नहीं जा सका। आमतौर पर फ़ाइल मोड में कोई फ़ाइल चुनी नहीं गई होती। |
ये कोड हल करने वाले एरर कोड की जगह नहीं लेते, उनके साथ ही रहते हैं, और पूरी सूची यहाँ है: CapSkip API दस्तावेज़.
FAQ
नई कुंजी असल में कितनी जल्दी काम करने लगती है?
अगली हल करने वाली रिक्वेस्ट पर। कुछ भी कैश नहीं होता और कुछ भी दोबारा लोड करने की ज़रूरत नहीं, इसलिए जिस ग्राहक को आपके चेकआउट पेज से कुंजी मिली है वह उसी मिनट उसका इस्तेमाल कर सकता है। दूसरी दिशा में वापसी भी उतनी ही तत्काल है, और इसीलिए आपके रद्दीकरण हैंडलर का समय एक नीतिगत फ़ैसला है, तकनीकी बंदिश नहीं।
हर अतिरिक्त ग्राहक कुंजी पर मुझे कुछ खर्च होता है?
नहीं। CapSkip आपके अपने हार्डवेयर पर चलता है और उसमें प्रति-हल कोई कोटा नहीं है, इसलिए कुंजी बिलिंग की पहचान नहीं, बल्कि कॉल करने वाले पर लगा एक लेबल भर है। हर ग्राहक के लिए एक बना लीजिए, या उनके अलग-अलग एनवायरनमेंट बाँटने हों तो कई बना लीजिए, और उतनी ही आसानी से मिटा भी दीजिए। कैप्चा हल करने वाला SDK आप उसे जो कुंजी देते हैं वही पढ़ता है, इसलिए बँटवारा कैसे करना है यह पूरी तरह आपका डिज़ाइन है।
क्या मैं इस API से किसी ग्राहक की गिनती या दर सीमा तय कर सकता हूँ?
इस API से नहीं। यह कुंजियाँ जोड़ता, दिखाता और मिटाता है, और कोई दूसरी सेटिंग इससे न पढ़ी जा सकती है न बदली जा सकती है। अगर आपके प्लान इस्तेमाल की मात्रा से अलग होते हैं, तो जिस रिवर्स प्रॉक्सी को आप वैसे भी इंस्टेंस के आगे लगा रहे हैं, वहीं ग्राहक द्वारा भेजी गई API कुंजी के आधार पर रिक्वेस्ट गिनिए। कुंजी बताती है कि कॉल कौन कर रहा है, और प्रॉक्सी तय करता है कि उसे क्या करने की इजाज़त है।
मेरा एडमिन token खो गया है। अब क्या करूँ?
उसी सेटिंग्स पैनल में जाकर नया बना लीजिए। पुराना token तुरंत काम करना बंद कर देता है, इसलिए कोई सफ़ाई का चरण नहीं है और ऐसा कोई अंतराल भी नहीं जिसमें दोनों चलें। आपके ग्राहकों पर इसका असर नहीं पड़ता: उनकी कुंजियाँ अछूती रहती हैं और वे हल कराते रहते हैं। सिर्फ़ आपकी अपनी कुंजी जारी करने की प्रक्रिया रुकती है, जब तक आप अपने webhook हैंडलर द्वारा पढ़े जाने वाले गोपनीय मान को अपडेट न कर दें।
सबसे छोटा जवाब
Remote Key Management एक बार चालू कीजिए और token को अपने बाकी बिलिंग गोपनीय मानों के साथ रखिए। ग्राहक की सदस्यता सक्रिय होने पर उसके नाम वाली एक कुंजी जोड़िए, दोहराव पर आने वाले 409 को सफलता मानिए, और सदस्यता खत्म होने पर उसी नाम से मिटा दीजिए। नियमित अंतराल पर सूची लेकर सक्रिय सदस्यों से मिलाइए, क्योंकि असली जवाब सिर्फ़ वहीं रहता है। फिर आगे एक प्रॉक्सी लगाइए और एडमिन पथ को उस पोर्ट से दूर रखिए जो आपके ग्राहक देख सकते हैं। इतना कर लीजिए, तो कैप्चा बायपास ऐसी चीज़ बन जाती है जिसे आप अपने ही हार्डवेयर पर आगे बेच सकते हैं, और जारी करने की रफ़्तार उतनी ही होगी जितनी तेज़ी से आपका चेकआउट webhook चला देता है।
