API से प्रकाशन
हस्ताक्षरित API अनुरोधों से अपनी वेबसाइट या CMS पर लेख प्रकाशित करें।
Papigrows आपके HTTPS रिसीवर को हस्ताक्षरित POST अनुरोध भेजता है। आपका रिसीवर लेख सहेजकर प्रकाशित करता है और फिर उसका सार्वजनिक URL लौटाता है।
API प्रकाशन कॉन्फ़िगर करेंअपना प्रकाशन एंडपॉइंट जोड़ें
अपनी वेबसाइट पर लेख सहेजने और प्रकाशित करने वाला रिसीवर बनाएं। CMS सेटिंग में एंडपॉइंट और साझा सीक्रेट जोड़ें। जाँचें और सहेजें से खाली डेटा वाला connection.test भेजा जाता है; HTTP 200 और ok: true लौटाएं। केवल मालिक और व्यवस्थापक कनेक्शन बदल सकते हैं।
सार्वजनिक HTTPS एंडपॉइंट इस्तेमाल करें जिसमें क्वेरी पैरामीटर, फ़्रैगमेंट या एम्बेड किए गए क्रेडेंशियल न हों।
एक रैंडम सीक्रेट तैयार है। आप इसकी जगह 32 से 256 अक्षरों का अपना सीक्रेट रख सकते हैं। इसे रिसीवर में कॉपी करें और सर्वर पर सुरक्षित रखें।
{
"version": 1,
"event": "connection.test",
"id": "<event-id>",
"data": {}
}
HTTP/1.1 200 OK
Content-Type: application/json
{ "ok": true }टेस्ट करके सहेजते समय रिसीवर को पुराने और नए दोनों सीक्रेट स्वीकार करने दें। Papigrows सहेजे हुए सीक्रेट का उपयोग तब तक करता है जब तक नया कनेक्शन टेस्ट में सफल होकर सहेजा नहीं जाता। जारी डिलीवरी पूरी होने के बाद पुराना सीक्रेट हटाएँ।
अनुरोध हेडर
ये हेडर कनेक्शन परीक्षण और लेख डिलीवरी दोनों के साथ भेजे जाते हैं। हेडर नामों में छोटे-बड़े अक्षरों का अंतर नहीं होता।
| हेडर का नाम | उदाहरण मान | अर्थ |
|---|---|---|
Content-Type | application/json | JSON में अनुरोध बॉडी। |
Accept | application/json | JSON में पुष्टि अपेक्षित है। |
X-Papigrows-Event-Id | <event-id> | एनवेलप के id से मेल खाता है। |
X-Papigrows-Timestamp | <unix-seconds> | इस प्रयास का Unix समय, सेकंड में। |
X-Papigrows-Signature | v1=<hex-hmac-sha256> | v1= के बाद टाइमस्टैम्प + '.' + ठीक उसी कच्ची बॉडी का हेक्स HMAC-SHA256। |
Idempotency-Key | <event-id> | पुनः प्रयासों में वही स्थिर एनवेलप id। |
हर अनुरोध सत्यापित करें
JSON पार्स करने से पहले टाइमस्टैम्प, एक बिंदु और ठीक उसी मूल बॉडी पर v1 HMAC-SHA256 हस्ताक्षर सत्यापित करें। स्थिर समय में तुलना करें, पाँच मिनट से पुराने या भविष्य के टाइमस्टैम्प अस्वीकार करें और सीक्रेट सर्वर पर रखें। HTTPS और हस्ताक्षर डुप्लिकेट सुरक्षा का विकल्प नहीं हैं।
अनुरोध का उदाहरण
POST /your-publishing-endpoint
Content-Type: application/json
X-Papigrows-Event-Id: <event-id>
X-Papigrows-Timestamp: <unix-seconds>
X-Papigrows-Signature: v1=<hex-hmac-sha256>
Idempotency-Key: <event-id>
{
"version": 1,
"event": "article.upsert",
"id": "<event-id>",
"data": {
"id": "<permanent-article-id>",
"version": 7,
"title": "Example",
"html": "<p>...</p>",
"slug": "example",
"excerpt": "...",
"coverImageUrl": "https://example.com/cover.jpg",
"locale": "en",
"hreflangAlternates": [
{ "locale": "sv", "url": "https://example.com/sv/blog/example" }
]
}
}अनुरोध बॉडी के फ़ील्ड
ये फ़ील्ड article.upsert बताते हैं। connection.test के लिए data खाली होता है। एनवेलप का प्रोटोकॉल संस्करण लेख के सामग्री संस्करण से अलग है।
| फ़ील्ड का नाम | मान का प्रकार | कब शामिल है | अर्थ |
|---|---|---|---|
version | integer | हमेशा | प्रोटोकॉल संस्करण: मूल प्रारूप के लिए 1, या रिसीवर को स्पष्ट रूप से अपग्रेड करने के बाद 2। |
event | string | हमेशा | इवेंट प्रकार: article.upsert या connection.test। |
id | string | हमेशा | दोनों पहचान हेडर के साथ साझा स्थिर डिलीवरी ID। दोबारा लिखने से बचने के लिए इसे सहेजें। |
data | object | हमेशा | इवेंट का डेटा। connection.test के लिए खाली। |
data.id | string | हमेशा | इस एक भाषा संस्करण की स्थायी ID। इसी कुंजी से लेख बनाएं या अपडेट करें। |
data.version | integer | हमेशा | सहेजा हुआ सामग्री संशोधन, जो गैर-ऋणात्मक पूर्णांक है। पुराने संशोधन अस्वीकार करें। |
data.title | string | हमेशा | लेख का शीर्षक। |
data.html | string | हमेशा | प्रकाशित करने वाला HTML, उपलब्ध hreflang लिंक सहित। |
data.slug | string | उपलब्ध होने पर | सुझाया गया URL स्लग। बाद के संपादनों में सार्वजनिक URL स्थिर रखें। |
data.excerpt | string | उपलब्ध होने पर | लेख का अंश, उपलब्ध होने पर। |
data.coverImageUrl | string | उपलब्ध होने पर | कवर छवि का URL, उपलब्ध होने पर। |
data.locale | string | उपलब्ध होने पर | इस लेख संस्करण का भाषा कोड। |
data.hreflangAlternates | array | उपलब्ध होने पर | अन्य प्रकाशित भाषा संस्करण, उपलब्ध होने पर। |
data.hreflangAlternates[].locale | string | हर भाषा संस्करण के लिए | लिंक किए गए संस्करण का भाषा कोड। |
data.hreflangAlternates[].url | string | हर भाषा संस्करण के लिए | उस प्रकाशित संस्करण का सार्वजनिक URL। |
संस्करण 2 और संगतता
संस्करण 2 में सादा पाठ, कार्यक्षेत्र और लक्षित समूह की आईडी, सारांश, अनुभाग और टैग शामिल हैं। कनेक्शन परीक्षण में रिसीवर को संस्करण 2 की स्पष्ट पुष्टि करनी होगी। मौजूदा रिसीवर संस्करण 1 पर बने रहते हैं, जब तक आप दूसरा संस्करण चुनकर सफल परीक्षण के बाद उसे सहेज नहीं लेते।
{
"version": 2,
"event": "connection.test",
"id": "<event-id>",
"data": {}
}
HTTP/1.1 200 OK
Content-Type: application/json
{ "ok": true, "version": 2 }POST /your-publishing-endpoint
Content-Type: application/json
X-Papigrows-Event-Id: <event-id>
X-Papigrows-Timestamp: <unix-seconds>
X-Papigrows-Signature: v1=<hex-hmac-sha256>
Idempotency-Key: <event-id>
{
"version": 2,
"event": "article.upsert",
"id": "<event-id>",
"data": {
"id": "<permanent-article-id>",
"groupId": "<permanent-article-group-id>",
"workspaceId": "<owning-workspace-id>",
"primaryAudienceId": "<saved-audience-id>",
"businessAreaId": "<saved-business-area-id>",
"text": "...",
"summary": "...",
"section": "Advice",
"tags": ["Families"],
"version": 7,
"title": "Example",
"html": "<p>...</p>",
"slug": "example",
"excerpt": "...",
"coverImageUrl": "https://example.com/cover.jpg",
"locale": "en",
"hreflangAlternates": [
{ "locale": "sv", "url": "https://example.com/sv/blog/example" }
]
}
}संस्करण 2 मूल लेख फ़ील्ड बनाए रखता है और ये आवश्यक फ़ील्ड जोड़ता है। बिना सहेजे लक्ष्यीकरण वाले पुराने लेखों में लक्षित समूह की आईडी null रहती है।
| फ़ील्ड का नाम | मान का प्रकार | अर्थ |
|---|---|---|
data.groupId | UUID | भाषा रूपों का साझा स्थायी समूह। |
data.workspaceId | UUID | मालिक कार्यक्षेत्र की सहेजी गई आईडी। |
data.primaryAudienceId | UUID | null | सहेजी गई प्राथमिक लक्षित समूह आईडी; बिना लक्ष्यीकरण वाले पुराने लेख में null। |
data.businessAreaId | UUID | null | सहेजी गई व्यावसायिक क्षेत्र आईडी, या उपलब्ध न होने पर null। |
data.text | string | साफ़ किए गए लेख HTML से निकला सादा पाठ, मूल Markdown नहीं। लिंक का डेटा नहीं लिया जाता। |
data.summary | string | null | सहेजा गया लेख सारांश, या न होने पर null। |
data.section | string | null | इस प्रकाशन के लिए दर्ज अनुभाग, या null। |
data.tags | string[] | इस प्रकाशन के लिए दर्ज टैग; खाली सूची का अर्थ कोई टैग नहीं है। |
सार्वजनिक सामग्री फ़ीड
प्रकाशित लेख सार्वजनिक करने के लिए Papigrows API कनेक्शन चालू करें। स्पष्ट रूप से संस्करण 2 माँगें; संस्करण न देने पर मूल उत्तर बना रहता है। निजी कार्यक्षेत्र और अप्रकाशित लेख उपलब्ध नहीं होते।
/api/content/feed/<workspace-slug>?version=2&locale=en&limit=20हर लेख में सहेजी गई आईडी, सामग्री संस्करण, सादा पाठ और सारांश शामिल हैं। अनुभाग और टैग केवल प्रकाशन के समय दर्ज गंतव्य से आते हैं। यह रिकॉर्ड न मिलने पर टैग null होते हैं। हर कर्सर अनुरोध में version=2 और locale बनाए रखें।
सार्वजनिक फ़ीड में रूपांतरण उपलब्ध न होने पर text null होता है। 1 MiB से अधिक होने पर textUnavailable body_too_large और रूपांतरण त्रुटि पर conversion_failed होता है; अन्यथा null। HTML और पृष्ठ क्रम सुरक्षित रहते हैं।
प्रकाशन की पुष्टि करें
लेख वास्तव में सार्वजनिक होने के बाद HTTP 200 या 201, वही ID, status published और सार्वजनिक HTTPS URL लौटाएं। कतार की पुष्टि, HTTP 202 या 204, रीडायरेक्ट, ड्राफ़्ट या अमान्य उत्तर प्रकाशन नहीं माने जाते। सहेजने और प्रकाशित करने से पहले सफलता न बताएं।
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "<permanent-article-id>",
"status": "published",
"url": "https://example.com/blog/example"
}डिलीवरी और पुनः प्रयास
article.upsert, data.id को स्थायी कुंजी मानकर एक भाषा संस्करण बनाता या बदलता है। data.version और इवेंट ID को बदलाव के साथ एक ही परमाणु क्रिया में सहेजें। डुप्लिकेट पर सहेजी पुष्टि लौटाएं; पुराने संस्करण नए कंटेंट को कभी न बदलें। अधिकतम तीन प्रयास होते हैं, हर प्रयास की सीमा पाँच सेकंड है। नेटवर्क त्रुटि, HTTP 429 और HTTP 5xx पर 250 मिलीसेकंड और 1 सेकंड बाद पुनः प्रयास होता है। बॉडी और इवेंट ID वही रहते हैं; टाइमस्टैम्प और हस्ताक्षर नए होते हैं।
डिलीवरी बॉडी की सीमा 1 MiB और JSON प्रतिक्रिया की सीमा 16 KiB है। पार्स करने से पहले कच्ची अनुरोध बॉडी का आकार सीमित करें।
इस इंटीग्रेशन का दायरा
केवल लेख और Papigrows से फिर प्रकाशित किए गए संपादन। विषय या हटाने के इवेंट, पृष्ठभूमि कतार और बाहरी संपादन पढ़ना शामिल नहीं है। ईमेल के उत्तर से संपादन webhook को सुरक्षित रूप से अपडेट नहीं कर सकता; Papigrows में संपादित और प्रकाशित करें। मौजूदा योजना, गुणवत्ता और स्वचालित प्रकाशन सेटिंग लागू रहती हैं। अनिश्चित विफलता के बाद मैन्युअल पुनः प्रयास से पहले रिसीवर जाँचें; अनंत पुनः प्रयास नहीं होते।
हस्ताक्षर सत्यापन का उदाहरण
यह Node.js सहायक केवल प्रामाणिकता जाँचता है। रिसीवर को अनुरोध आकार सीमित करना, इवेंट स्कीमा जाँचना, स्थायी स्टोरेज में डुप्लिकेट और संस्करण संभालना, लेख प्रकाशित करना और नीचे दी पुष्टि लौटाना भी आवश्यक है।
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyWebhook(headers, rawBody, secret) {
const timestamp = headers.get("x-papigrows-timestamp") ?? "";
const signature = headers.get("x-papigrows-signature") ?? "";
if (!/^\d{10}$/.test(timestamp)) return false;
const age = Math.floor(Date.now() / 1000) - Number(timestamp);
if (age < 0 || age > 300) return false;
if (!/^v1=[a-f0-9]{64}$/.test(signature)) return false;
const expected = createHmac("sha256", secret)
.update(timestamp + ".").update(rawBody).digest();
const received = Buffer.from(signature.slice(3), "hex");
if (received.length !== expected.length
|| !timingSafeEqual(received, expected)) return false;
try {
const event = JSON.parse(rawBody.toString());
return typeof event.id === "string"
&& /^[a-f0-9]{64}$/.test(event.id)
&& headers.get("x-papigrows-event-id") === event.id
&& headers.get("idempotency-key") === event.id;
} catch { return false; }
}