डेवलपर
लॉगबुक API
अपनी PingDX लॉगबुक को किसी अन्य लॉगिंग प्रोग्राम, स्क्रिप्ट या अपनी वेबसाइट से पढ़ें और उसमें लिखें।
इस पृष्ठ पर
परिचय
PingDX API किसी सदस्य को अपनी PingDX लॉगबुक को किसी अन्य लॉगिंग प्रोग्राम, स्क्रिप्ट या अपनी वेबसाइट के साथ सिंक रखने देती है: QSO डाउनलोड करना, नए जोड़ना, उन्हें सुधारना या हटाना। यह केवल उसी सदस्य की लॉगबुक तक पहुँच देती है जिसने कुंजी बनाई है।
बेस URL
https://pingdx.org/api/v1अनुरोध और उत्तर JSON (UTF-8) में होते हैं। बॉडी वाले हर अनुरोध के साथ Content-Type: application/json भेजें। तारीखें ISO 8601 स्ट्रिंग होती हैं; सर्वर हमेशा UTC में उत्तर देता है (2026-10-05T18:42:00.000Z)।
कोड जनरेटर और Postman जैसे टूल के लिए मशीन-पठनीय विवरण (OpenAPI 3.1, सार्वजनिक, कुंजी की आवश्यकता नहीं) उपलब्ध है: https://pingdx.org/api/v1/openapi.json
कुंजी प्राप्त करना
हर सदस्य अपनी कुंजियाँ प्रोफ़ाइल → API एक्सेस में बनाता है। प्रत्येक कुंजी को एक नाम दें (वह प्रोग्राम या साइट जो उसका उपयोग करती है) और उसके अधिकार चुनें:
- केवल पढ़ने के लिए (
READ): लॉगबुक पढ़ सकती है (GETअनुरोध) — किसी वेबसाइट पर अपने QSO दिखाने के लिए पर्याप्त। - पढ़ना और लिखना (
WRITE): QSO बना, अपडेट और हटा भी सकती है — लॉगिंग प्रोग्राम के साथ दो-तरफ़ा सिंक के लिए आवश्यक। - पूरी कुंजी बनने के तुरंत बाद केवल एक बार दिखाई जाती है: उसे तुरंत कॉपी कर लें। PingDX उसका केवल फ़िंगरप्रिंट रखता है और उसे दोबारा नहीं दिखा सकता।
- आप किसी भी समय कुंजी रद्द कर सकते हैं: वह तुरंत काम करना बंद कर देती है। प्रति सदस्य अधिकतम 10 सक्रिय कुंजियाँ।
सुरक्षा
- कुंजी को पासवर्ड की तरह मानें। WRITE कुंजी को कभी किसी वेबसाइट के सार्वजनिक कोड में न रखें (आगंतुकों के ब्राउज़र को भेजा गया JavaScript): कोई भी उसे पढ़कर आपकी लॉगबुक बदल सकता है। API को अपने सर्वर से कॉल करें, या READ कुंजी का उपयोग करें।
- कुंजी केवल लॉगबुक API खोलती है: आपके संदेश, प्रोफ़ाइल, पासवर्ड या खाते का बाकी हिस्सा कभी नहीं।
- हर प्रोग्राम के लिए एक कुंजी रखें, ताकि बाकी को बिगाड़े बिना एक को रद्द किया जा सके। कुंजियाँ
pdx_…से शुरू होती हैं: गलती से कोई प्रकाशित हो जाए तो पहचानना आसान है — तब उसे रद्द कर दें।
प्रमाणीकरण
कुंजी को हर अनुरोध के साथ Authorization हेडर (Bearer) में या X-API-Key हेडर में भेजें। आपका PingDX लॉगिन सत्र इस API में स्वीकार नहीं किया जाता, और कुकी का कभी उपयोग नहीं होता।
Authorization: Bearer pdx_…
# या
X-API-Key: pdx_…वैध कुंजी के बिना API 401 लौटाती है; लिखने की कोशिश करने वाली READ कुंजी को 403 मिलता है:
401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।403 API_KEYS.READ_ONLYकुंजी केवल पढ़ने के लिए है: लिखने के लिए WRITE कुंजी बनाएँ।
एंडपॉइंट
सभी पाथ बेस URL के सापेक्ष हैं। हर QSO की पहचान उसके clientId से होती है, जो आपके प्रोग्राम द्वारा चुना गया UUID है।
GET/me
आवश्यक अधिकार: READ या WRITE कुंजी
वह सदस्य जिसकी यह कुंजी है (कॉलसाइन, लोकेटर) और कुंजी के अधिकार। कुंजी जाँचने के लिए उपयोगी।
उत्तर
{
"callsign": "14KM001",
"locator": "JN03ql",
"scope": "WRITE"
}त्रुटियाँ
401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।429 GENERIC.RATE_LIMITEDबहुत अधिक अनुरोध: थोड़ा रुककर फिर कोशिश करें।
GET/logs
आवश्यक अधिकार: READ या WRITE कुंजी
लॉगबुक, सबसे पुराना बदलाव पहले (सर्वर पर अंतिम लेखन के क्रम में), पृष्ठ-दर-पृष्ठ।
updatedSince के बिना आपको पूरी लॉगबुक मिलती है। उसके साथ, केवल वे QSO मिलते हैं जो उस क्षण के बाद बने, बदले या क्रॉस-कन्फ़र्म हुए।
पैरामीटर
updatedSincestring (ISO 8601)क्वेरीवैकल्पिकसमय क्षेत्र सहित ISO 8601 दिनांक-समय (उदा.
2026-10-01T00:00:00Z)। अपने पिछले सिंक काserverTimeदें।limitinteger 1–500 (200)क्वेरीवैकल्पिकप्रति पृष्ठ QSO, 1 से 500 तक। डिफ़ॉल्ट: 200।
cursorstringक्वेरीवैकल्पिकअगला पृष्ठ पाने के लिए पिछले पृष्ठ का
nextCursor। पृष्ठ बदलते समय वहीupdatedSinceरखें।
उत्तर
items: पृष्ठ के QSO (QSO ऑब्जेक्ट देखें)। nextCursor: अगला पृष्ठ पाने के लिए इसे cursor के रूप में दें; अंतिम पृष्ठ पर null। serverTime: अनुरोध शुरू होने के समय का सर्वर समय — आपका अगला updatedSince।
{
"items": [
{
"id": "cmgd4w1x70003s60e8k2v9qhz",
"clientId": "0b9e6c1e-5f3a-4d2b-9c7e-1a2b3c4d5e6f",
"band": "ELEVEN_METERS",
"frequencyMhz": "27.555",
"channel": null,
"ctcssTone": null,
"dcsCode": null,
"mode": "USB",
"callsignWorked": "14KM123",
"operatorCallsign": "14KM001",
"dxLocator": "JN18du",
"dxLat": null,
"dxLng": null,
"txPowerW": 4,
"myLocator": "JN03ql",
"splitKhz": null,
"path": null,
"qsoStatus": null,
"rstSent": "59",
"rstReceived": "57",
"qslSent": false,
"qslReceived": false,
"qslVia": null,
"qsoAt": "2026-10-05T18:42:00.000Z",
"notes": null,
"radio": "President Lincoln II+",
"antenna": "Sirio 827",
"crossConfirmedAt": null,
"spottedAt": null,
"createdAt": "2026-10-05T18:43:10.512Z",
"syncedAt": "2026-10-05T18:43:10.512Z"
}
],
"nextCursor": null,
"serverTime": "2026-10-05T18:45:12.345Z"
}त्रुटियाँ
400 VALIDATION.FAILEDअमान्य अनुरोध: गलत पैरामीटर, UUID न होने वाला clientId, या वैध entries ऐरे (1 से 200) के बिना बैच। details समस्या बताता है।401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।429 GENERIC.RATE_LIMITEDबहुत अधिक अनुरोध: थोड़ा रुककर फिर कोशिश करें।
GET/logs/ids
आवश्यक अधिकार: READ या WRITE कुंजी
लॉगबुक के सभी QSO के id, बिना पृष्ठांकन के। PingDX पर (या किसी अन्य प्रोग्राम से) हटाए गए QSO खोजने के लिए इन्हें अपनी प्रति से मिलाएँ।
उत्तर
सिंक्रनाइज़ेशन आने से पहले बने कुछ बहुत पुराने QSO के लिए clientId null हो सकता है।
{
"items": [
{ "id": "cmgd4w1x70003s60e8k2v9qhz", "clientId": "0b9e6c1e-5f3a-4d2b-9c7e-1a2b3c4d5e6f" },
{ "id": "cmgd51b2c0007s60efq3m1abc", "clientId": "7d1f2a90-3b4c-4e5f-8a6b-9c0d1e2f3a4b" }
]
}त्रुटियाँ
401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।429 GENERIC.RATE_LIMITEDबहुत अधिक अनुरोध: थोड़ा रुककर फिर कोशिश करें।
POST/logs/batch
आवश्यक अधिकार: WRITE कुंजी
एक अनुरोध में अधिकतम 200 QSO बनाता या अपडेट करता है। जिस QSO का clientId अज्ञात है वह बनाया जाता है; मौजूदा clientId उस QSO को अपडेट करता है।
हर QSO की जाँच अलग से होती है: अमान्य QSO की सूचना उसके परिणाम में दी जाती है और वह बाकी को सहेजने से कभी नहीं रोकता। अनुरोध पूरा तभी विफल होता है (400) जब entries अनुपस्थित, खाली या 200 से लंबी हो।
पैरामीटर
entriesQSO[] (1–200)बॉडीआवश्यकबनाए या अपडेट किए जाने वाले QSO (QSO ऑब्जेक्ट देखें)।
अनुरोध बॉडी
{
"entries": [
{
"clientId": "0b9e6c1e-5f3a-4d2b-9c7e-1a2b3c4d5e6f",
"band": "ELEVEN_METERS",
"frequencyMhz": "27.555",
"mode": "USB",
"callsignWorked": "14KM123",
"qsoAt": "2026-10-05T18:42:00Z",
"rstSent": "59",
"rstReceived": "57",
"dxLocator": "JN18DU"
},
{
"clientId": "7d1f2a90-3b4c-4e5f-8a6b-9c0d1e2f3a4b",
"band": "PMR446",
"channel": 8,
"ctcssTone": "67.0",
"mode": "FM",
"callsignWorked": "PMR-ALPHA",
"qsoAt": "2026-10-05T19:05:00+02:00",
"dxLocator": "JN1"
}
]
}उत्तर
प्रति QSO एक परिणाम। id सर्वर id है, या QSO अस्वीकृत होने पर null; तब error कारण बताता है। permanent: true का अर्थ है कि QSO स्वयं अमान्य है: सुधारे जाने तक वह फिर अस्वीकृत होगा — उसे जस का तस दोबारा न भेजें। permanent के बिना अस्वीकृति अस्थायी है: बाद में फिर कोशिश करें।
{
"results": [
{ "clientId": "0b9e6c1e-5f3a-4d2b-9c7e-1a2b3c4d5e6f", "id": "cmgd4w1x70003s60e8k2v9qhz", "spottedAt": null },
{ "clientId": "7d1f2a90-3b4c-4e5f-8a6b-9c0d1e2f3a4b", "id": null, "error": "LOCATOR_INVALID", "permanent": true }
]
}त्रुटियाँ
400 VALIDATION.FAILEDअमान्य अनुरोध: गलत पैरामीटर, UUID न होने वाला clientId, या वैध entries ऐरे (1 से 200) के बिना बैच। details समस्या बताता है।401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।403 API_KEYS.READ_ONLYकुंजी केवल पढ़ने के लिए है: लिखने के लिए WRITE कुंजी बनाएँ।429 GENERIC.RATE_LIMITEDबहुत अधिक अनुरोध: थोड़ा रुककर फिर कोशिश करें।
DELETE/logs/{clientId}
आवश्यक अधिकार: WRITE कुंजी
आपकी लॉगबुक का एक QSO उसके clientId से हटाता है। यदि वह DX क्लस्टर को भेजा गया था, तो स्पॉट भी हटा दिया जाता है।
पैरामीटर
clientIdstring (UUID)पाथआवश्यकQSO का
clientId(एक UUID)।
उत्तर
कोई बॉडी नहीं (204)। यह अनुरोध बिना बॉडी और बिना Content-Type के भेजें।
HTTP/1.1 204 No Contentत्रुटियाँ
400 VALIDATION.FAILEDअमान्य अनुरोध: गलत पैरामीटर, UUID न होने वाला clientId, या वैध entries ऐरे (1 से 200) के बिना बैच। details समस्या बताता है।401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।403 API_KEYS.READ_ONLYकुंजी केवल पढ़ने के लिए है: लिखने के लिए WRITE कुंजी बनाएँ।404 GENERIC.NOT_FOUNDआपकी लॉगबुक में इस clientId वाला कोई QSO नहीं है।429 GENERIC.RATE_LIMITEDबहुत अधिक अनुरोध: थोड़ा रुककर फिर कोशिश करें।
GET/openapi.json
आवश्यक अधिकार: कोई नहीं (सार्वजनिक)
इस API का OpenAPI 3.1 विवरण (JSON)। सार्वजनिक: कुंजी की आवश्यकता नहीं।
QSO ऑब्जेक्ट
यही ऑब्जेक्ट POST /logs/batch को भेजा जाता है और GET /logs द्वारा लौटाया जाता है। band फ़ील्ड दो रूपों में से एक चुनती है:
- 11 m (CB) —
"band": "ELEVEN_METERS":frequencyMhz(वैकल्पिक);channel,ctcssToneऔरdcsCodeअनुपस्थित याnullहोने चाहिए। - PMR446 —
"band": "PMR446":channel(1 से 16) आवश्यक है,ctcssTone/dcsCodeवैकल्पिक;frequencyMhzअनुपस्थित याnullहोनी चाहिए। - अपडेट QSO को बदल देता है: हमेशा पूरा QSO भेजें। छोड़ी गई फ़ील्ड रीसेट हो जाती है (खाली, या
qslSent/qslReceivedके लिएfalse), सिवायoperatorCallsign,dxLat,dxLng,txPowerW,radioऔरantennaके, जो छोड़ने पर अपना संग्रहीत मान बनाए रखती हैं। - टेक्स्ट के आगे-पीछे की खाली जगह हटा दी जाती है, लोकेटर मानकीकृत होते हैं (
jn18DU→JN18du) और अज्ञात फ़ील्ड अनदेखी कर दी जाती हैं। केवल पढ़ने योग्य फ़ील्ड सर्वर सेट करता है: उन्हें भेजने की आवश्यकता नहीं।
clientIdआवश्यकstring (UUID)इस QSO के लिए आपका स्थिर id: एक यादृच्छिक UUID (उदा.
crypto.randomUUID()), जो एक बार बनाकर आपके प्रोग्राम में QSO के साथ सहेजा जाता है। यही सिंक कुंजी है।bandआवश्यक"ELEVEN_METERS" | "PMR446"बैंड:
ELEVEN_METERS(11 m / CB) याPMR446।qsoAtआवश्यकstring (ISO 8601)QSO की तारीख और समय, समय क्षेत्र सहित ISO 8601 (
Zया+02:00)। UTC में सहेजा और लौटाया जाता है।frequencyMhzवैकल्पिकstring "27.555" · 26.000–28.000केवल 11 m: MHz में आवृत्ति, ठीक 3 दशमलव वाली स्ट्रिंग के रूप में, 26.000 और 28.000 के बीच।
channelPMR446 पर आवश्यकinteger 1–16केवल PMR446 (वहाँ आवश्यक): चैनल, 1 से 16।
ctcssToneवैकल्पिकstring "67.0" · ^\d{2,3}\.\d$केवल PMR446: Hz में CTCSS टोन, एक दशमलव (
67.0,103.5)।dcsCodeवैकल्पिकstring "D023N" · ^D?[0-7]{3}[NI]?$केवल PMR446: DCS कोड, 3 अष्टाधारी अंक, वैकल्पिक
Dउपसर्ग औरN/Iध्रुवता के साथ (D023N)।modeवैकल्पिक"FM" | "AM" | "SSB" | "USB" | "LSB" | "CW" | "DIGITAL"मोड।
callsignWorkedवैकल्पिकstring ≤ 20जिस स्टेशन से संपर्क हुआ उसका कॉलसाइन।
operatorCallsignवैकल्पिकstring ≤ 20इस QSO के लिए आपका अपना कॉलसाइन (कई उपयोग करने पर काम आता है)। अपडेट में छोड़ने पर वही बना रहता है।
dxLocatorवैकल्पिकstring "JN18" | "JN18du"संपर्क किए गए स्टेशन का Maidenhead लोकेटर, 4 या 6 अक्षर।
dxLatवैकल्पिकnumber −90…90संपर्क किए गए स्टेशन का सटीक अक्षांश, यदि ज्ञात हो। मानचित्र इसे लोकेटर से प्राथमिकता देते हैं।
dxLngवैकल्पिकnumber −180…180संपर्क किए गए स्टेशन का सटीक देशांतर, यदि ज्ञात हो।
txPowerWवैकल्पिकinteger 0–100000आपकी ट्रांसमिट पावर पूर्ण वॉट में।
myLocatorवैकल्पिकstring "JN03" | "JN03ql"इस QSO के लिए आपका लोकेटर (उदा. पोर्टेबल होने पर), 4 या 6 अक्षर।
splitKhzवैकल्पिकinteger −99999…99999kHz में स्प्लिट (ट्रांसमिट और रिसीव आवृत्तियों का अंतर)।
pathवैकल्पिक"SP" | "LP"प्रसार पथ: शॉर्ट पाथ (
SP) या लॉन्ग पाथ (LP)।qsoStatusवैकल्पिक"HRD" | "WKD" | "CFM"संपर्क की स्थिति: सुना (
HRD), संपर्क हुआ (WKD), पुष्ट (CFM)।rstSentवैकल्पिकstring ≤ 10भेजी गई रिपोर्ट (उदा.
59)।rstReceivedवैकल्पिकstring ≤ 10प्राप्त रिपोर्ट।
qslSentवैकल्पिकboolean (false)QSL कार्ड भेजा गया। डिफ़ॉल्ट:
false।qslReceivedवैकल्पिकboolean (false)QSL कार्ड प्राप्त हुआ। डिफ़ॉल्ट:
false।qslViaवैकल्पिक"DIRECT" | "BUREAU" | "EQSL" | "ECARD"QSL किस माध्यम से आदान-प्रदान हुआ:
DIRECT(डाक),BUREAU,EQSL(eQSL.cc) याECARD(अन्य इलेक्ट्रॉनिक कार्ड)।notesवैकल्पिकstring ≤ 2000खुले नोट्स।
radioवैकल्पिकstring ≤ 80उपयोग किया गया रेडियो (मुक्त टेक्स्ट)।
antennaवैकल्पिकstring ≤ 80उपयोग किया गया एंटीना (मुक्त टेक्स्ट)।
sendSpotवैकल्पिकbooleanकेवल लिखने के लिए, कभी लौटाया नहीं जाता:
trueQSO को PingDX DX क्लस्टर पर स्पॉट के रूप में भी प्रकाशित करता है (प्रति QSO एक बार)। केवल लाइव QSO के लिए, पुराने QSO के आयात के लिए कभी नहीं।idकेवल पढ़ने योग्यstringQSO का सर्वर id।
crossConfirmedAtकेवल पढ़ने योग्यstring (ISO 8601) | nullPingDX तब सेट करता है जब दूसरे स्टेशन ने वही QSO PingDX पर लॉग किया हो (क्रॉस-कन्फ़र्मेशन)।
spottedAtकेवल पढ़ने योग्यstring (ISO 8601) | nullQSO कब क्लस्टर स्पॉट के रूप में प्रकाशित हुआ, या
null।createdAtकेवल पढ़ने योग्यstring (ISO 8601)QSO पहली बार PingDX पर कब सहेजा गया।
syncedAtकेवल पढ़ने योग्यstring (ISO 8601)QSO का सर्वर पर अंतिम लेखन (
GET /logsका क्रम इसी से तय होता है)।
सिंक्रनाइज़ेशन गाइड
आपके प्रोग्राम और PingDX के बीच छह चरणों में एक मज़बूत दो-तरफ़ा सिंक:
- 1
पहला पूर्ण डाउनलोड
updatedSinceके बिनाGET /logs?limit=500कॉल करें, फिरnextCursorकेnullहोने तक उसका अनुसरण करें। पहले पृष्ठ काserverTimeसहेज लें। - 2
वृद्धिशील डाउनलोड
अगली बार, सहेजे गए
serverTimeके साथGET /logs?updatedSince=…कॉल करें, पृष्ठों का उसी तरह अनुसरण करें, फिर सभी पृष्ठ संसाधित होने के बाद ही नयाserverTime(फिर पहले पृष्ठ से) सहेजें। किसी QSO को दो बार पाना हानिरहित है: उसेclientIdके अनुसार लागू करें। - 3
अपने QSO भेजना
अपने प्रोग्राम के हर QSO को एक बार और हमेशा के लिए UUID
clientIdदें, और उसे सहेजें। नए या बदले हुए QSOPOST /logs/batchसे भेजें, प्रति अनुरोध अधिकतम 200। वही QSO दोबारा भेजना सुरक्षित है: डुप्लिकेट बनाने के बजाय वह अपडेट हो जाता है। - 4
अस्वीकृत QSO
हर परिणाम पढ़ें: यदि
idnullहै और साथ मेंpermanent: trueहै, तो दोबारा कोशिश करने के बजाय QSO को सुधार के लिए उपयोगकर्ता को दिखाएँ (errorकारण बताता है)।permanentके बिना, बाद में फिर कोशिश करें। - 5
हटाना
PingDX पर हटाने के लिए:
DELETE /logs/{clientId}। PingDX पर हटाए गए QSO खोजने के लिए:GET /logs/ids, फिर अपनी प्रति से हर वह QSO हटाएँ जिसकाclientIdअब सूची में नहीं है। - 6
टकराव
clientIdके अनुसार अंतिम लेखन जीतता है: फ़ील्ड-दर-फ़ील्ड मर्ज नहीं होता। PingDX ऐप API से लिखे गए QSO को अपने अगले सिंक पर उठा लेता है (खुलते समय, या ऑनलाइन होने पर कुछ ही सेकंड में)।
त्रुटियाँ और सीमाएँ
त्रुटियाँ HTTP स्टेटस कोड और एक स्थिर कोड वाली JSON बॉडी का उपयोग करती हैं (कभी अनुवादित टेक्स्ट नहीं):
{ "error": { "code": "API_KEYS.READ_ONLY" } }400 VALIDATION.FAILEDअमान्य अनुरोध: गलत पैरामीटर, UUID न होने वाला clientId, या वैध entries ऐरे (1 से 200) के बिना बैच। details समस्या बताता है।
401 API_KEYS.INVALIDकुंजी अनुपस्थित, अज्ञात या रद्द है (या खाता अब सक्रिय नहीं)।
403 API_KEYS.READ_ONLYकुंजी केवल पढ़ने के लिए है: लिखने के लिए WRITE कुंजी बनाएँ।
404 GENERIC.NOT_FOUNDआपकी लॉगबुक में इस clientId वाला कोई QSO नहीं है।
429 GENERIC.RATE_LIMITEDबहुत अधिक अनुरोध: थोड़ा रुककर फिर कोशिश करें।
500 GENERIC.INTERNAL_ERRORसर्वर त्रुटि: बाद में फिर कोशिश करें।
प्रति-QSO अस्वीकृति के कारण
POST /logs/batch में, अस्वीकृत QSO में id: null और एक error कोड होता है:
CLIENT_ID_INVALIDclientId वैध UUID नहीं है।DATETIME_INVALIDqsoAt समय क्षेत्र सहित ISO 8601 दिनांक-समय नहीं है।LOCATOR_INVALIDdxLocator या myLocator 4 या 6 अक्षरों का Maidenhead लोकेटर नहीं है।FREQUENCY_FORMAT_INVALIDfrequencyMhz 3 दशमलव वाली स्ट्रिंग होनी चाहिए (27.555)।FREQUENCY_OUT_OF_BAND_11MfrequencyMhz 26.000–28.000 MHz के बाहर है।CHANNEL_OUT_OF_RANGEPMR446 चैनल 1–16 के बाहर है।CTCSS_FORMAT_INVALIDctcssTone 67.0 जैसा दिखना चाहिए।DCS_FORMAT_INVALIDdcsCode D023N जैसा दिखना चाहिए।CLIENT_ID_CONFLICTयह clientId पहले से किसी अन्य सदस्य के QSO का है: नया UUID बनाएँ।
अन्य स्कीमा उल्लंघन (फ़ील्ड अनुपस्थित, enum में अज्ञात मान, बहुत लंबा टेक्स्ट…) वैलिडेटर का संदेश अंग्रेज़ी में लौटाते हैं, उदा. Invalid input: expected string, received undefined, साथ में permanent: true भी।
सीमाएँ
- प्रति IP पता प्रति मिनट 300 अनुरोध, उससे अधिक पर
429(Retry-Afterहेडर बताता है कि कितनी देर रुकना है)। अपने QSO को एक-एक करके भेजने के बजाय बैच में समूहित करें। - प्रति
POST /logs/batchअधिकतम 200 QSO। GET /logsके प्रति पृष्ठ 1 से 500 QSO (डिफ़ॉल्ट 200)।- प्रति सदस्य अधिकतम 10 सक्रिय कुंजियाँ।
ब्राउज़र से कॉल करना (CORS)
/api/v1 किसी भी origin से अनुरोध स्वीकार करता है (CORS), बिना कुकी या क्रेडेंशियल के। इसलिए कोई वेब पृष्ठ उसे सीधे कॉल कर सकता है — लेकिन केवल READ कुंजी के साथ, क्योंकि सार्वजनिक पृष्ठ का कोड सबको दिखता है।
उदाहरण
pdx_… को अपनी कुंजी से बदलें। ये उदाहरण कॉपी करने के लिए तैयार हैं; केवल टिप्पणियाँ अंग्रेज़ी में हैं।
curl
# Who am I? (checks the key)
curl -H "Authorization: Bearer pdx_…" https://pingdx.org/api/v1/me
# Everything changed since my last sync
curl -H "Authorization: Bearer pdx_…" \
"https://pingdx.org/api/v1/logs?updatedSince=2026-10-01T00:00:00Z&limit=500"
# Create or update a QSO (WRITE key)
curl -X POST -H "Authorization: Bearer pdx_…" \
-H "Content-Type: application/json" \
https://pingdx.org/api/v1/logs/batch \
-d '{"entries":[{"clientId":"0b9e6c1e-5f3a-4d2b-9c7e-1a2b3c4d5e6f",
"band":"ELEVEN_METERS","frequencyMhz":"27.555","mode":"USB",
"callsignWorked":"14KM123","qsoAt":"2026-10-05T18:42:00Z",
"rstSent":"59","rstReceived":"57"}]}'
# Delete it (no body, no Content-Type)
curl -X DELETE -H "Authorization: Bearer pdx_…" \
https://pingdx.org/api/v1/logs/0b9e6c1e-5f3a-4d2b-9c7e-1a2b3c4d5e6fJavaScript (fetch)
Node.js 18+ और Deno में काम करता है। कुंजी को सर्वर की ओर रखें (एनवायरनमेंट वेरिएबल)।
const BASE = "https://pingdx.org/api/v1";
const KEY = process.env.PINGDX_API_KEY; // pdx_… — keep it server-side
async function call(method, path, body) {
const res = await fetch(BASE + path, {
method,
headers: {
Authorization: `Bearer ${KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 204) return null;
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error?.code}`);
return data;
}
// Full download, page by page
async function pullAll(updatedSince) {
const qsos = [];
let cursor = null;
let since = null;
do {
const q = new URLSearchParams({ limit: "500" });
if (updatedSince) q.set("updatedSince", updatedSince);
if (cursor) q.set("cursor", cursor);
const page = await call("GET", `/logs?${q}`);
since ??= page.serverTime; // keep the FIRST page's serverTime
qsos.push(...page.items);
cursor = page.nextCursor;
} while (cursor);
return { qsos, nextUpdatedSince: since };
}
// Push local QSOs (create or update by clientId)
const { results } = await call("POST", "/logs/batch", {
entries: [{
clientId: crypto.randomUUID(), // store it with your QSO, reuse it forever
band: "PMR446", channel: 8, ctcssTone: "67.0", mode: "FM",
callsignWorked: "PMR-ALPHA", qsoAt: new Date().toISOString(),
}],
});
for (const r of results) if (r.id === null) console.warn(r.clientId, r.error, r.permanent);Python (requests)
import os, uuid, requests
BASE = "https://pingdx.org/api/v1"
S = requests.Session()
S.headers["Authorization"] = f"Bearer {os.environ['PINGDX_API_KEY']}" # pdx_…
def pull(updated_since=None):
"""Every QSO changed since updated_since (all of them if None)."""
qsos, cursor, next_since = [], None, None
while True:
params = {"limit": 500}
if updated_since:
params["updatedSince"] = updated_since
if cursor:
params["cursor"] = cursor
r = S.get(f"{BASE}/logs", params=params, timeout=30)
r.raise_for_status()
page = r.json()
next_since = next_since or page["serverTime"] # first page's serverTime
qsos += page["items"]
cursor = page["nextCursor"]
if not cursor:
return qsos, next_since
def push(entries):
"""Create or update up to 200 QSOs; returns the rejected ones."""
r = S.post(f"{BASE}/logs/batch", json={"entries": entries}, timeout=30)
r.raise_for_status()
return [x for x in r.json()["results"] if x["id"] is None]
rejected = push([{
"clientId": str(uuid.uuid4()), # keep it with your QSO
"band": "ELEVEN_METERS", "frequencyMhz": "27.555", "mode": "USB",
"callsignWorked": "14KM123", "qsoAt": "2026-10-05T18:42:00Z",
}])
# Deleted on PingDX? Compare clientIds with your copy
server_ids = {x["clientId"] for x in S.get(f"{BASE}/logs/ids", timeout=30).json()["items"]}कोई प्रश्न है या कोई प्रोग्राम जोड़ना चाहते हैं? हमें संपर्क पृष्ठ से लिखें।