Webhooks (प्राप्त करना)
जब आपके SupDesk प्रोजेक्ट में घटनाएँ होती हैं, तो आउटबाउंड webhooks आपके कॉन्फ़िगर किए गए एंडपॉइंट पर HTTP POST अनुरोध पहुँचाते हैं। यह पृष्ठ पेलोड प्रारूप, हस्ताक्षर तंत्र और पुनः प्रयास व्यवहार का दस्तावेज़ीकरण करता है ताकि आप विश्वसनीय webhook रिसीवर बना सकें।
पेलोड प्रारूप
हर webhook डिलीवरी एक मानक आवरण का उपयोग करती है:
{
"event": "post.created",
"timestamp": "2026-07-15T12:00:00.000Z",
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"data": { ... }
}| फ़ील्ड | प्रकार | विवरण |
|---|---|---|
event | string | वह घटना जिसने डिलीवरी ट्रिगर की |
timestamp | string | घटना कब हुई इसका ISO 8601 टाइमस्टैम्प |
project_id | string | उस प्रोजेक्ट का UUID जहाँ घटना हुई |
data | object | घटना-विशिष्ट पेलोड (नीचे देखें) |
घटनाएँ
post.created
एक नई फ़ीडबैक पोस्ट सबमिट की गई।
{
"event": "post.created",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Add dark mode",
"type": "feature",
"status": "open",
"author_type": "end_user",
"body": "It would be great to have a dark mode option.",
"created_at": "2026-07-15T12:00:00Z"
}
}post.updated
एक फ़ीडबैक पोस्ट संपादित की गई।
{
"event": "post.updated",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Add dark mode (updated)",
"type": "feature",
"status": "open",
"author_type": "end_user",
"body": "Updated description.",
"created_at": "2026-07-15T12:00:00Z"
}
}post.deleted
एक फ़ीडबैक पोस्ट हटाई गई।
{
"event": "post.deleted",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Add dark mode",
"type": "feature",
"status": "open",
"author_type": "end_user",
"body": "It would be great to have a dark mode option.",
"created_at": "2026-07-15T12:00:00Z"
}
}post.status_changed
किसी पोस्ट की स्थिति बदली गई।
{
"event": "post.status_changed",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Add dark mode",
"type": "feature",
"old_status": "open",
"new_status": "planned",
"author_type": "member",
"body": "We're planning this for Q3.",
"created_at": "2026-07-15T12:00:00Z"
}
}comment.created
किसी पोस्ट में नई टिप्पणी जोड़ी गई।
{
"event": "comment.created",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"post_id": "550e8400-e29b-41d4-a716-446655440001",
"post_title": "Add dark mode",
"author_type": "end_user",
"body": "Any update on this?",
"created_at": "2026-07-15T12:00:00Z"
}
}comment.updated
एक टिप्पणी संपादित की गई।
{
"event": "comment.updated",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"post_id": "550e8400-e29b-41d4-a716-446655440001",
"post_title": "Add dark mode",
"author_type": "end_user",
"body": "Updated comment.",
"created_at": "2026-07-15T12:00:00Z"
}
}comment.deleted
एक टिप्पणी हटाई गई।
{
"event": "comment.deleted",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"post_id": "550e8400-e29b-41d4-a716-446655440001",
"post_title": "Add dark mode",
"author_type": "end_user",
"body": "Any update on this?",
"created_at": "2026-07-15T12:00:00Z"
}
}message.created
एक नया निजी संदेश भेजा गया।
{
"event": "message.created",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"thread_id": "550e8400-e29b-41d4-a716-446655440001",
"thread_subject": "Help needed",
"sender": "end_user",
"body": "I can't find the settings page.",
"via": "web",
"created_at": "2026-07-15T12:00:00Z"
}
}message.updated
एक निजी संदेश संपादित किया गया।
{
"event": "message.updated",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"thread_id": "550e8400-e29b-41d4-a716-446655440001",
"thread_subject": "Help needed",
"sender": "end_user",
"body": "Updated message.",
"via": "web",
"created_at": "2026-07-15T12:00:00Z"
}
}message.deleted
एक निजी संदेश हटाया गया।
{
"event": "message.deleted",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"thread_id": "550e8400-e29b-41d4-a716-446655440001",
"thread_subject": "Help needed",
"sender": "end_user",
"body": "I can't find the settings page.",
"via": "web",
"created_at": "2026-07-15T12:00:00Z"
}
}beta_feedback.created
एक बीटा परीक्षक ने बीटा प्रोग्राम पर फ़ीडबैक भेजा।
{
"event": "beta_feedback.created",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"program": "Acme 2.0 Beta",
"category": "bug",
"severity": "high",
"title": "Crash on export",
"body": "The app closes when I export a large file.",
"created_at": "2026-07-15T12:00:00Z"
}
}severity null हो सकता है।
beta_feedback.deleted
एक बीटा फ़ीडबैक आइटम हटाया गया।
{
"event": "beta_feedback.deleted",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"program": "Acme 2.0 Beta",
"category": "bug",
"severity": "high",
"title": "Crash on export",
"body": "The app closes when I export a large file.",
"created_at": "2026-07-15T12:00:00Z"
}
}waitlist_signup.created
एक आगंतुक वेटलिस्ट में शामिल हुआ।
{
"event": "waitlist_signup.created",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "jamie@example.com",
"status": "waiting",
"position": 42,
"referral_count": 0,
"referral_code": "a1b2c3",
"source": "portal",
"created_at": "2026-07-15T12:00:00Z",
"invited_at": null,
"joined_at": null
}
}invited और joined प्रविष्टियों के लिए position null होता है।
waitlist_signup.invited
एक वेटलिस्ट प्रविष्टि को सूची से आमंत्रित किया गया।
{
"event": "waitlist_signup.invited",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "jamie@example.com",
"status": "invited",
"position": null,
"referral_count": 0,
"referral_code": "a1b2c3",
"source": "portal",
"created_at": "2026-07-15T12:00:00Z",
"invited_at": "2026-07-15T12:00:00Z",
"joined_at": null
}
}waitlist_signup.joined
एक आमंत्रित प्रविष्टि ने स्वीकार किया और शामिल हुई।
{
"event": "waitlist_signup.joined",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "jamie@example.com",
"status": "joined",
"position": null,
"referral_count": 0,
"referral_code": "a1b2c3",
"source": "portal",
"created_at": "2026-07-15T12:00:00Z",
"invited_at": "2026-07-15T12:00:00Z",
"joined_at": "2026-07-15T12:05:00Z"
}
}csat_survey.completed
एक CSAT संतुष्टि सर्वेक्षण रेटिंग के साथ पूरा हुआ।
{
"event": "csat_survey.completed",
"data": {
"thread_id": "550e8400-e29b-41d4-a716-446655440000",
"rating": 5,
"comment": "Support was fast and friendly.",
"created_at": "2026-07-15T12:00:00Z"
}
}rating 1 और 5 के बीच का पूर्णांक है; comment null हो सकता है।
हस्ताक्षर सत्यापन
हर डिलीवरी में एक X-SupDesk-Signature हेडर होता है:
X-SupDesk-Signature: sha256=a1b2c3d4e5f6...sha256= के बाद का मान कच्ची अनुरोध बॉडी का hex-एन्कोडेड HMAC-SHA256 है, जो आपके webhook के
साइनिंग सीक्रेट से गणना किया जाता है।
सत्यापन चरण
- कच्ची अनुरोध बॉडी पढ़ें (पहले JSON पार्स न करें)
HMAC-SHA256(signing_secret, raw_body)की गणना करें- hex डाइजेस्ट की तुलना हस्ताक्षर हेडर के मान से करें
- टाइमिंग हमलों को रोकने के लिए स्थिर-समय तुलना का उपयोग करें
Node.js उदाहरण
import { createHmac, timingSafeEqual } from "crypto";
function verifySupDeskWebhook(secret, rawBody, signatureHeader) {
const expected = createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
const received = signatureHeader.replace("sha256=", "");
return timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}
// Express example
app.post("/webhooks/supdesk", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["x-supdesk-signature"];
if (!verifySupDeskWebhook(SECRET, req.body, sig)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.body);
// Process event...
res.status(200).json({ ok: true });
});Python उदाहरण
import hmac
import hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = "your-signing-secret"
def verify_signature(secret: str, body: bytes, header: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
received = header.removeprefix("sha256=")
return hmac.compare_digest(expected, received)
@app.route("/webhooks/supdesk", methods=["POST"])
def handle_webhook():
sig = request.headers.get("X-SupDesk-Signature", "")
if not verify_signature(WEBHOOK_SECRET, request.data, sig):
return jsonify(error="Invalid signature"), 401
event = request.get_json()
# Process event...
return jsonify(ok=True), 200Ruby उदाहरण
require "openssl"
require "sinatra"
require "json"
WEBHOOK_SECRET = "your-signing-secret"
def verify_signature(secret, body, header)
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, body)
received = header.sub("sha256=", "")
Rack::Utils.secure_compare(expected, received)
end
post "/webhooks/supdesk" do
body = request.body.read
sig = request.env["HTTP_X_SUPDESK_SIGNATURE"] || ""
unless verify_signature(WEBHOOK_SECRET, body, sig)
halt 401, { error: "Invalid signature" }.to_json
end
event = JSON.parse(body)
# Process event...
status 200
{ ok: true }.to_json
endपुनः प्रयास
जब कोई webhook डिलीवरी विफल होती है, तो SupDesk एक्सपोनेंशियल बैकऑफ़ के साथ पुनः प्रयास करता है:
| प्रयास | विलंब |
|---|---|
| 1 | तत्काल |
| 2 | 1 सेकंड |
| 3 | 2 सेकंड |
जिन स्थितियों में पुनः प्रयास होता है: 5xx प्रतिक्रियाएँ, नेटवर्क त्रुटियाँ, टाइमआउट (10 सेकंड)।
पुनः प्रयास नहीं: 4xx प्रतिक्रियाएँ (क्लाइंट त्रुटियाँ कॉन्फ़िगरेशन समस्या दर्शाती हैं)।
webhooks का उत्तर देना
- प्राप्ति स्वीकार करने के लिए 2xx स्थिति कोड लौटाएँ
- टाइमआउट पुनः प्रयास से बचने के लिए 10 सेकंड के भीतर उत्तर दें
- यदि आपके लॉजिक में अधिक समय लगे तो घटना को अतुल्यकालिक रूप से संसाधित करें
- डुप्लिकेट डिलीवरी के लिए वही प्रतिक्रिया लौटाएँ (idempotency)