Webhooks और इवेंट
जब आपके वर्कस्पेस में कुछ होता है (कोई ईमेल डिलीवर होता है, कोई प्राप्तकर्ता बाउंस करता है, कोई WhatsApp संदेश पढ़ा जाता है), तो Bird उस इवेंट टाइप की सदस्यता लेने वाले हर webhook endpoint पर एक साइन किया गया JSON इवेंट POST करता है। Bird हेडर, साइनिंग और पेलोड संरचना के लिए Standard Webhooks स्पेसिफिकेशन का पालन करता है, इसलिए अगर आप पहले से किसी अन्य Standard Webhooks प्लेटफ़ॉर्म से webhooks सत्यापित करते हैं, तो वही सत्यापन कोड यहाँ बिना बदलाव के काम करता है।
Webhook endpoints और डिलीवरी के अवलोकन के लिए Webhook क्या है? देखें।
Endpoint बनाएँ
डैशबोर्ड में Developers > Webhooks के अंतर्गत एक endpoint रजिस्टर करें, या टर्मिनल से bird CLI के साथ:
कोड उदाहरण
bird webhooks create https://example.com/webhooks/bird \
--events email.delivered,email.bounced,email.complained \
--description "Production delivery + bounce notifications"Endpoint प्रबंधन के लिए webhooks स्कोप आवश्यक है। डैशबोर्ड सेशन और CLI का लॉगिन इसे आपकी यूज़र भूमिका के माध्यम से ले जाता है, और API कीज़ भी इसे रख सकती हैं: endpoints और डिलीवरी प्रयासों की जाँच के लिए webhooks:read दें, या उन्हें प्रबंधित करने के लिए webhooks:write दें। अंतर्निहित ऑपरेशन POST /v1/webhooks से शुरू होते हैं।

Endpoint URL HTTPS होने चाहिए, अधिकतम 2,048 अक्षर, और सार्वजनिक रूप से पहुँच योग्य। प्राइवेट, लूपबैक, लिंक-लोकल, या अन्य आंतरिक पतों पर URL को endpoint बनाते या अपडेट करते समय 422 के साथ अस्वीकार कर दिया जाता है। डिलीवरी आपके नेटवर्क के बाहर Bird की डिलीवरी इन्फ्रास्ट्रक्चर से आती हैं।
events ऐरे इवेंट कैटलॉग से अधिकतम 100 टाइप सूचीबद्ध करता है। Endpoint केवल उन टाइप को प्राप्त करता है जो इसमें सूचीबद्ध हैं। भविष्य की डिलीवरी के लिए पूरी सूची बदलने के लिए PATCH /v1/webhooks/{webhook_id} का उपयोग करें। हर इवेंट प्राप्त करने के लिए, हर टाइप की सदस्यता लें: कैटलॉग के बाहर का कोई टाइप 422 के साथ अस्वीकार किया जाता है, और इसमें sms.* जैसा वाइल्डकार्ड भी शामिल है। नए टाइप उपलब्ध होने पर मौजूदा सदस्यताएँ स्वचालित रूप से विस्तारित नहीं होतीं।
Create रिस्पॉन्स में endpoint की साइनिंग secret (whsec_ प्रीफ़िक्स सहित) केवल एक बार शामिल होती है। इसे तुरंत अपने सीक्रेट मैनेजर में स्टोर करें; इसे दोबारा प्राप्त नहीं किया जा सकता, और अगर आप इसे खो दें तो इसे रोटेट करें।
कोड उदाहरण
{
"id": "whk_01ky7q639cfh99xb7ysy2x2gzj",
"url": "https://example.com/webhooks/bird",
"events": ["email.delivered", "email.bounced", "email.complained"],
"description": "Production delivery + bounce notifications",
"status": "active",
"secret": "whsec_c+dgRBsFELJ9mR4tu2cyhK0gTMMkqntv",
"created_at": "2026-07-23T14:48:29.740Z",
"updated_at": "2026-07-23T14:48:29.740Z"
}Endpoints पूर्ण CRUD सपोर्ट करते हैं: list, get, update, और delete। किसी endpoint को डिलीट करने से उसकी सभी डिलीवरी बंद हो जाती हैं, जिसमें पहले विफल डिलीवरी के फिर से प्रयास भी शामिल हैं, और इसे पूर्ववत नहीं किया जा सकता; डिलीवरी अस्थायी रूप से रोकने के लिए इसके बजाय status को paused पर सेट करें। एक वर्कस्पेस कई endpoints रजिस्टर कर सकता है, प्रत्येक का अपना URL, इवेंट फ़िल्टर और सीक्रेट होता है।
सिग्नेचर सत्यापित करें
हर डिलीवरी तीन हेडर ले कर आती है:
| हेडर | मान |
|---|---|
| webhook-id | इवेंट डिलीवरी की पहचान करता है। इसके फिर से प्रयास और रीप्ले उसी मान का पुन: उपयोग करते हैं। |
| webhook-timestamp | इस डिलीवरी प्रयास का Unix टाइमस्टैम्प (सेकंड) |
| webhook-signature | v1,<base64 HMAC-SHA256>, संभवतः कई सिग्नेचर स्पेस-डिलिमिटेड |
सिग्नेचर स्ट्रिंग {webhook-id}.{webhook-timestamp}.{raw request body} पर एक HMAC-SHA256 है, जो आपके endpoint के सीक्रेट से कीड है (whsec_ प्रीफ़िक्स हटाएँ और बाकी को base64-डिकोड करके की बाइट्स प्राप्त करें)। आपके हैंडलर को सिग्नेचर सत्यापित करना चाहिए, ऐसी डिलीवरी को अस्वीकार करना चाहिए जिनका webhook-timestamp 5 मिनट से अधिक पुराना है, और webhook-id पर डीडुप्लिकेट करना चाहिए: Bird at-least-once डिलीवर करता है, इसलिए एक ही डिलीवरी एक से अधिक बार आ सकती है।
Bird SDK के साथ, सिग्नेचर और टाइमस्टैम्प जाँच एक ही कॉल में हो जाती है; डीडुप्लिकेशन आपके हैंडलर में रहता है:
// Pass the RAW request body; set the secret via new BirdClient({ webhooks: { secret } }).
const event = bird.webhooks.unwrap(rawBody, headers);
console.log(event.type); // discriminated union: narrow on event.type# Pass the RAW request body (bytes) and the request headers.
event = client.webhooks.unwrap(request.body, request.headers)
if event.root.type == "email.delivered":
print(event.root.data.email_id)package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
bird "github.com/messagebird/bird-sdk-go"
"github.com/messagebird/bird-sdk-go/option"
)
func main() {
client, err := bird.NewClient(
option.WithAPIKey(os.Getenv("BIRD_API_KEY")),
option.WithWebhookSecret(os.Getenv("BIRD_WEBHOOK_SECRET")),
)
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/webhooks/bird", func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
event, err := client.Webhooks.Unwrap(body, r.Header)
if err != nil {
http.Error(w, "invalid signature", http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusNoContent) // ack fast, then process
payload, _ := event.AsAny()
switch p := payload.(type) {
case bird.EmailDeliveredEvent:
fmt.Println("delivered:", p.Data.EmailId, p.Data.Recipient)
case bird.EmailBouncedEvent:
fmt.Println("bounced:", p.Type)
}
})
}// Pass the raw request body because parsing changes the bytes used to compute
// the signature.
$rawBody = file_get_contents('php://input') ?: '';
try {
$event = $bird->webhooks->unwrap($rawBody, getallheaders());
// $event is the decoded payload as an array; branch on $event['type'].
echo $event['type'];
} catch (WebhookVerificationError) {
http_response_code(400); // bad signature, stale timestamp, or missing/malformed headers
}400 के साथ डिलीवरी को अस्वीकार करना, जैसा कि ऊपर के उदाहरण करते हैं, इवेंट को त्यागता नहीं है: हम इसे नीचे दी गई अनुसूची पर फिर से प्रयास करते हैं। यह जानबूझकर है, और यही आप चाहते हैं। विफल सत्यापन का सामान्य कारण एक ऐसा सीक्रेट है जो आपके हैंडलर के पास अभी नहीं है, किसी रोटेशन या खराब डिप्लॉय के दौरान, इसलिए फिर से प्रयास की विंडो सीक्रेट ठीक करने और इवेंट प्राप्त करने का आपका मौका है। 2xx केवल तभी लौटाएँ जब आप डिलीवरी को हमेशा के लिए त्यागना चाहें।
कोई भी Standard Webhooks रेफ़रेंस लाइब्रेरी भी काम करती है। अगर आप मैन्युअल रूप से सत्यापित करते हैं, तो तरीका यह है:
कोड उदाहरण
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody: string, headers: Record<string, string>, secret: string): boolean {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false; // 5-minute tolerance
const key = Buffer.from(secret.slice("whsec_".length), "base64");
const expected = createHmac("sha256", key)
.update(`${id}.${timestamp}.${rawBody}`)
.digest("base64");
// During secret rotation, the header can contain several signatures. Accept any match.
return headers["webhook-signature"].split(" ").some((part) => {
const sig = Buffer.from(part.replace(/^v1,/, ""), "base64");
return (
sig.length === Buffer.byteLength(expected, "base64") &&
timingSafeEqual(sig, Buffer.from(expected, "base64"))
);
});
}HMAC हमेशा रॉ रिक्वेस्ट बॉडी बाइट्स पर कंप्यूट करें। JSON को पार्स और री-सीरियलाइज़ करने से व्हाइटस्पेस या की ऑर्डर बदल जाता है और सिग्नेचर टूट जाता है।
डिलीवरी सिमेंटिक्स
प्रत्येक डिलीवरी Content-Type: application/json के साथ प्रति HTTP POST एक इवेंट है, कोई बैचिंग नहीं। आपके endpoint के पास जवाब देने के लिए 15 सेकंड हैं; कोई भी 2xx स्टेटस सफलता मानी जाती है, और बाकी सब कुछ (3xx रीडायरेक्ट और टाइमआउट सहित) विफलता मानी जाती है। हर विफलता उसी फिर से प्रयास अनुसूची का पालन करती है। आप जो स्टेटस लौटाते हैं वह डिलीवरी प्रयास लॉग में दिखता है, यह तय नहीं करता कि हम फिर से प्रयास करें या नहीं: ऐसा कोई स्टेटस कोड नहीं है जो डिलीवरी जल्दी रोक दे। तुरंत जवाब दें और एसिंक्रोनस रूप से प्रोसेस करें: इवेंट को क्यू करें और असली काम करने से पहले 200 लौटाएँ।
पहले प्रयास के बाद, विफल डिलीवरी इस अनुसूची पर फिर से प्रयास की जाती हैं, ±20% जिटर के साथ ताकि फिर से प्रयास सिंक्रोनाइज़ न हों:
| फिर से प्रयास | पिछले प्रयास के बाद देरी |
|---|---|
| 1 | 5 सेकंड |
| 2 | 5 मिनट |
| 3 | 30 मिनट |
| 4 | 2 घंटे |
| 5 | 5 घंटे |
| 6 | 10 घंटे |
| 7 | 10 घंटे |
यह लगभग 27.5 घंटों में कुल आठ प्रयास हैं। 429 या टाइमआउट 60 सेकंड से कम किसी भी निर्धारित विलंब को 60 सेकंड तक बढ़ा देता है, जो व्यवहार में केवल पहले फिर से प्रयास को प्रभावित करता है: जिटर के बाद, यह 48 से 72 सेकंड बाद पहुँचता है। विफल प्रतिक्रिया पर Retry-After हेडर अगली प्रतीक्षा बढ़ा सकता है। हम इस हेडर को delay-seconds या HTTP तारीख के रूप में स्वीकार करते हैं। अनुरोधित विलंब निर्धारित विलंब से अधिक होने पर उसे बदल देता है, लेकिन निर्धारित विलंब के दोगुने तक सीमित रहता है (किसी भी 60-सेकंड वृद्धि के बाद); कम विलंब अनदेखा किया जाता है, इसलिए यह हेडर कभी फिर से प्रयास को आगे नहीं ला सकता। जिटर इसके ऊपर लागू होता है। हर फिर से प्रयास वही webhook-id लेकर आता है, जिससे डिडुप्लिकेशन काम करता है। अंतिम फिर से प्रयास के बाद डिलीवरी स्थायी रूप से विफल हो जाती है; रीप्ले इसे पुनर्प्राप्त करता है।
डिलीवरी क्रमबद्ध नहीं होतीं। एक ही संदेश के लिए email.delivered email.accepted से पहले आ सकता है, विशेषकर जब फिर से प्रयास शामिल हों। इवेंट पेलोड के अंदर timestamp फ़ील्ड के अनुसार क्रमबद्ध करें, आगमन क्रम से कभी नहीं।
अपने endpoints संचालित करें
टेस्ट सेंड
POST /v1/webhooks/{webhook_id}/test आपके endpoint पर एक साइन किया गया सिंथेटिक इवेंट भेजता है और परिणाम सिंक्रोनस रूप से लौटाता है: आपके endpoint ने इसे स्वीकार किया या नहीं, उसने कौन सा HTTP स्टेटस लौटाया, और राउंड-ट्रिप विलंब। टेस्ट बॉडी केवल इवेंट type ले जाने वाला एक न्यूनतम JSON स्टब है, जो वास्तविक डिलीवरी की तरह ही साइन किया गया है; यह वास्तविक इवेंट पेलोड को प्रतिबिंबित नहीं करता। कैटलॉग से कोई भी टाइप चुनने के लिए {"event_type": "email.delivered"} पास करें, चाहे सब्सक्राइब्ड हो या नहीं, या endpoint के पहले सब्सक्राइब्ड इवेंट टाइप का उपयोग करने के लिए बॉडी छोड़ दें।
आपके endpoint के पास जवाब देने के लिए 10 सेकंड हैं। एक अगम्य endpoint रिस्पॉन्स बॉडी में status: failed उत्पन्न करता है, जबकि रिक्वेस्ट स्वयं सफल होती है। कनेक्टिविटी डीबग करने के लिए इस परिणाम का उपयोग करें। टेस्ट सेंड सीधे आपके endpoint पर जाते हैं: वे पॉज़्ड endpoint पर भी काम करते हैं और डिलीवरी प्रयास लॉग में रिकॉर्ड नहीं होते। 412 का मतलब है कि endpoint को अभी टेस्ट नहीं किया जा सकता क्योंकि इसमें वैध साइनिंग सीक्रेट या सब्सक्राइब्ड इवेंट टाइप नहीं है।
वास्तविक इवेंट फ़्लो के साथ एंड-टू-एंड परीक्षण के लिए sandbox पतों पर भेजें: sandbox सेंड सामान्य डिलीवरी पथ के माध्यम से वास्तविक webhook इवेंट उत्पन्न करते हैं, जो लाइव जाने से पहले अपने हैंडलर को परखने का सबसे अच्छा तरीका है।
विफल डिलीवरी रीप्ले करना
POST /v1/webhooks/{webhook_id}/replay विफल हुई डिलीवरी की पुनर्वितरण कतार बनाता है। जिन इवेंट को endpoint ने पहले ही सफलतापूर्वक प्राप्त कर लिया है उन्हें छोड़ दिया जाता है, इसलिए रीप्ले कभी दोहरी डिलीवरी नहीं करता; पुनर्वितरित इवेंट अपना मूल webhook-id ले कर आता है, इसलिए आपकी डीडुप्लिकेशन जाँच रीप्ले को भी कवर करती है। केवल विफल प्रयास रीप्ले किए जाते हैं: जो इवेंट आपके endpoint को कभी भेजा ही नहीं गया उसका कोई विफल प्रयास नहीं है, इसलिए रीप्ले उसे रिकवर नहीं करता।
विंडो को सीमित करने के लिए since/until टाइमस्टैम्प पास करें (डिफ़ॉल्ट: अनुरोध के समय से पिछले 24 घंटे)। दोनों सीमाएँ inclusive हैं, और दोनों इस आधार पर चयन करती हैं कि डिलीवरी कब प्रयास की गई, न कि इवेंट कब हुआ, इसलिए जो फिर से प्रयास अपने इवेंट से एक दिन बाद हुआ, वह उस घंटे के अनुसार विंडो में आता है जब उसका प्रयास किया गया। Replay डिलीवरी प्रयास लॉग पढ़ता है, जो तीन दिनों का डेटा रखता है, इसलिए यही सबसे पुराना इतिहास है जहाँ तक वह पहुँच सकता है: पहले का since विंडो को चौड़ा करता है, लेकिन उससे पुरानी किसी चीज़ को रिकवर नहीं करता। एक replay विंडो में अधिकतम सबसे पुराने 10,000 इवेंट कवर करता है।
रिक्वेस्ट 202 लौटाती है और इवेंट एसिंक्रोनस रूप से पुनर्वितरित किए जाते हैं। एक पुनर्वितरण को केवल एक प्रयास मिलता है, ऊपर दी गई फिर से प्रयास अनुसूची नहीं। प्रयास रिकॉर्ड किया जाता है और काम पूरा हो जाता है चाहे आपके endpoint ने इसे स्वीकार किया हो या नहीं, इसलिए अभी भी टूटे हुए endpoint में रीप्ले करने पर प्रति इवेंट आठ के बजाय एक रिक्वेस्ट लगती है; endpoint ठीक करें और दोबारा रीप्ले करें। वे विफलताएँ endpoint हेल्थ को नहीं छूतीं: रीप्ले endpoint को degraded पर नहीं ले जा सकता या उसे ऑटो-पॉज़ नहीं कर सकता। आपके endpoint द्वारा स्वीकार किया गया पुनर्वितरण दोनों को साफ़ करता है।
paused endpoint पर रीप्ले करें और रिक्वेस्ट अभी भी 202 लौटाती है, लेकिन कुछ भी पुनर्वितरित नहीं होता। पहले इसे पुनः सक्रिय करें, जैसा कि ऑटो-पॉज़ और पुनः सक्रिय करना में वर्णित है।
रीप्ले प्रति संगठन प्रति UTC दिन 20 तक सीमित हैं; उसके बाद रिक्वेस्ट 429 (WebhookReplayQuotaExceeded) लौटाती है। रिस्पॉन्स में काउंट या टास्क ID शामिल नहीं होती। परिणाम ट्रैक करने के लिए GET /v1/webhooks/{webhook_id}/attempts का उपयोग करें, जो हाल के डिलीवरी प्रयासों को नवीनतम से पुराने क्रम में स्टेटस कोड और विलंब के साथ सूचीबद्ध करता है। प्रत्येक HTTP रिक्वेस्ट की अपनी प्रविष्टि होती है, इसलिए एक फिर से प्रयास किया गया इवेंट प्रति प्रयास एक बार दिखता है, और पुनर्वितरण एक अतिरिक्त प्रविष्टि के रूप में दिखता है।
साइनिंग सीक्रेट रोटेट करना
POST /v1/webhooks/{webhook_id}/rotate-secret एक नया सीक्रेट जनरेट करता है और इसे एक बार लौटाता है। अगले 24 घंटों तक, Bird हर डिलीवरी को दोनों सीक्रेट से साइन करता है। webhook-signature हेडर में स्पेस-डिलिमिटेड सिग्नेचर होते हैं (v1,<old> v1,<new>), जिससे आप ओवरलैप अवधि के दौरान नया सीक्रेट डिप्लॉय कर सकते हैं। Standard Webhooks लाइब्रेरी स्वचालित रूप से सभी सिग्नेचर आज़माती हैं। 24 घंटे बाद पुराना सीक्रेट साइन करना बंद कर देता है। एक endpoint में एक साथ अधिकतम 5 वैध सीक्रेट हो सकते हैं, इसलिए ओवरलैप विंडो के अंदर बार-बार रोटेट करना WebhookTooManySecrets के साथ विफल होता है जब तक कोई पुराना सीक्रेट समाप्त नहीं हो जाता।
ऑटो-पॉज़ और पुनः सक्रिय करना
Endpoint status active, degraded, या paused होता है। हाल की डिलीवरी विफलताएँ एक endpoint को हेल्थ चेतावनी के रूप में degraded चिह्नित करती हैं; हम डिलीवर और फिर से प्रयास करना जारी रखते हैं। लगभग पाँच दिनों तक लगातार विफल होने वाला endpoint स्वचालित रूप से paused हो जाता है और सभी डिलीवरी रुक जाती है; उस अवधि में एक सफल डिलीवरी काउंटर रीसेट कर देती है। पॉज़्ड endpoint अपने आप कभी फिर से शुरू नहीं होता। इसे PATCH /v1/webhooks/{webhook_id} और {"status": "active"} के साथ (या डैशबोर्ड में Webhooks पेज से) पुनः सक्रिय करें, फिर पॉज़ होने से पहले विफल हुए प्रयासों को पुनर्वितरित करने के लिए रीप्ले करें। पहले पुनः सक्रिय करें: endpoint अभी भी पॉज़्ड होने पर अनुरोधित रीप्ले कुछ भी पुनर्वितरित नहीं करता। जब यह पॉज़्ड था तब आए इवेंट कभी भेजे नहीं गए, इसलिए रीप्ले उन्हें रिकवर नहीं करता।
इनमें से कोई भी degraded endpoint को active पर वापस लाता है:
| क्या इसे हटाता है | क्यों |
|---|---|
| एक डिलीवरी सफल होती है | Endpoint ने फिर से एक इवेंट स्वीकार किया। |
| Endpoint का url बदलना | रिकॉर्ड की गई विफलताएँ उस गंतव्य का वर्णन करती हैं जिसका आप अब उपयोग नहीं करते। |
| paused endpoint को पुनः सक्रिय करना | यह सेवा में वापस आ रहा है, इसलिए इसकी पुरानी विफलताएँ अब लागू नहीं होतीं। |
| 2xx लौटाने वाला टेस्ट सेंड | आपने दिखा दिया है कि endpoint पहुँच योग्य है। |
किसी endpoint का विवरण या उसके सब्सक्राइब्ड इवेंट टाइप संपादित करना पहुँच योग्यता के बारे में कुछ नहीं बताता, इसलिए यह degraded को बनाए रखता है, जैसा कि विफल होने वाला टेस्ट सेंड भी करता है।
जब कोई एंडपॉइंट पहली बार degraded होता है, तो हम संगठन के मालिकों को ईमेल करते हैं, हर एपिसोड में एक बार, हर विफल डिलीवरी पर नहीं। रिकवरी के बाद दोबारा गिरावट होने पर फिर से ईमेल जाता है, लेकिन 24 घंटे के कूलडाउन के अधीन: हम प्रति एंडपॉइंट हर 24 घंटे में अधिकतम एक गिरावट ईमेल भेजते हैं, ताकि active और degraded के बीच लगातार बदलने वाला एंडपॉइंट उनके इनबॉक्स में बाढ़ न लाए। एंडपॉइंट का url बदलने से कूलडाउन रीसेट हो जाता है, इसलिए नए URL पर पहली गिरावट पिछले ईमेल के 24 घंटे के भीतर भी ईमेल भेज सकती है।
इवेंट कैटलॉग
इवेंट पेलोड आपके सिस्टम के साथ सहसंबंध के लिए संक्षिप्त, प्राप्तकर्ता-स्कोप्ड तथ्य रखते हैं। इनमें पूर्ण रिसोर्स नहीं होता। अगर आपको अधिक संदर्भ चाहिए, तो रिसोर्स को उसकी ID से फ़ेच करें। इवेंट टाइप resource.action नामकरण का पालन करते हैं और प्रोडक्ट के अनुसार समूहित हैं; प्रत्येक प्रोडक्ट का इवेंट पेज प्रति-इवेंट पेलोड फ़ील्ड रखता है:
- Email इवेंट: डिलीवरी जीवनचक्र (email.accepted से email.delivered या email.bounced तक), सहभागिता (email.opened, email.clicked), अनसब्सक्राइब, और इनबाउंड ईमेल
- SMS इवेंट: sms.accepted से अंतिम स्टेटस तक संदेश जीवनचक्र
- WhatsApp webhooks: whatsapp.accepted से whatsapp.delivered तक, whatsapp.read, whatsapp.failed, whatsapp.rejected, इनबाउंड संदेश के लिए whatsapp.received, जब कोई उपयोगकर्ता आपके किसी संदेश पर प्रतिक्रिया करता है तब whatsapp.reacted, और whatsapp.group.join_request_created तथा whatsapp.group.join_request_revoked जब कोई अनुमोदन-आवश्यक ग्रुप में शामिल होने का अनुरोध करता है या अनुरोध वापस लेता है
- Verify इवेंट: सत्यापन जीवनचक्र (verify.verification.created, verify.verification.verified) और प्रत्येक सत्यापन कोड प्रयास की डिलीवरी (verify.attempt.sent, verify.attempt.delivered, verify.attempt.undelivered)
- Preference इवेंट: क्रॉस-चैनल सहमति रिकॉर्ड: preference.granted, preference.revoked, और preference.deleted
प्रत्येक डिलीवरी बॉडी type, timestamp, और एक टाइप-विशिष्ट data ऑब्जेक्ट के साथ Standard Webhooks नेस्टेड एनवेलप है। webhook-id हेडर इवेंट पहचान ले कर आता है। एनवेलप timestamp रिकॉर्ड करता है कि इवेंट कब हुआ। webhook-timestamp हेडर वर्तमान डिलीवरी प्रयास रिकॉर्ड करता है और हर फिर से प्रयास पर बदलता है।
कोड उदाहरण
{
"type": "email.delivered",
"timestamp": "2026-06-10T14:30:00Z",
"data": {
"email_id": "em_01krdgeqcxet5s7t44vh8rt9mg",
"recipient_id": "er_01krdgeqcxet5s7t44vh8rt9mg",
"workspace_id": "ws_01krdgeqcxet5s7t44vh8rt9mg",
"recipient": "user@example.com",
"recipient_role": "to",
"tags": [{ "name": "category", "value": "welcome" }],
"metadata": { "order_id": "ord_123" },
"broadcast_id": null
}
}प्रत्येक ईमेल इवेंट के data में email_id, recipient_id, workspace_id, recipient पता, और इसका एनवेलप recipient_role शामिल है। इसमें सेंड रिक्वेस्ट से tags और metadata भी शामिल हैं, या प्रदान न होने पर null। यह broadcast_id भी ले कर आता है, जो उस ब्रॉडकास्ट का नाम बताता है जिसके हिस्से के रूप में सेंड गया, या जब इसके पीछे कोई ब्रॉडकास्ट नहीं था तो null। email.unsubscribed और email.list_unsubscribed पर, null ब्रॉडकास्ट को नकारता नहीं है; ईमेल इवेंट में इसका कारण बताया गया है। इवेंट टाइप इस बेस में अपने फ़ील्ड जोड़ते हैं। प्रत्येक वेरिएंट का एक स्थिर फ़ील्ड सेट होता है: फ़ील्ड डिफ़ॉल्ट रूप से अनिवार्य होते हैं, और उनकी उपस्थिति केवल इवेंट टाइप पर निर्भर करती है।
इवेंट नाम कभी नहीं बदले जाते, और नए टाइप प्रोडक्ट शिप होने पर जोड़े जाते हैं, इसलिए अपने हैंडलर को अपरिचित टाइप अनदेखा करने के लिए लिखें।
Preference इवेंट
घोषित प्राथमिकताएँ (सहमति अनुदान और ऑप्ट-आउट जो प्रत्येक चैनल की गाइड में वर्णित हैं: email, SMS, WhatsApp) चैनलों में फैली होती हैं, इसलिए उनके इवेंट चैनल का नाम टाइप में नहीं बल्कि पेलोड में रखते हैं। preference.granted तब ट्रिगर होता है जब कोई सहमति अनुदान प्रभावी होता है, preference.revoked तब जब कोई ऑप्ट-आउट प्रभावी होता है, और preference.deleted तब जब कोई रिकॉर्ड किया गया स्टेटमेंट हटाया जाता है और उसकी key बिना किसी रिकॉर्ड की स्थिति में लौट जाती है। इवेंट का मतलब है कि key का वर्तमान रिकॉर्ड बदल गया: जो स्टेटमेंट वर्तमान रिकॉर्ड को दोहराता है वह कुछ ट्रिगर नहीं करता, और जो क्रम से बाहर होने के कारण अस्वीकृत होता है वह भी कुछ ट्रिगर नहीं करता। एन्वेलप timestamp वह समय है जब स्टेटमेंट प्रभावी हुआ, जो बैकडेटेड स्टेटमेंट के लिए वह समय है जब यह बनाया गया था, न कि जब यह Bird तक पहुँचा।
प्रत्येक पेलोड पूर्ण प्राथमिकता की ले कर आता है: channel, handle, sender_scope, और topic_id, स्कोपिंग फ़ील्ड present-with-null होते हैं जब वे इसे सीमित नहीं करते। की के साथ कथन का coverage, preference_id, लिखने द्वारा जोड़ी गई हिस्ट्री एंट्री का transition_id, और वह contact_id जिसका हैंडल कथन रिकॉर्ड होने पर मैच हुआ, या null:
कोड उदाहरण
{
"type": "preference.revoked",
"timestamp": "2026-08-25T14:52:03.192524705Z",
"data": {
"preference_id": "prf_01krdgeqcxet5s7t44vh8rt9mg",
"transition_id": "prt_01krdgeqcxet5s7t44vh8rt9mg",
"channel": "sms",
"handle": "+15550001234",
"sender_scope": null,
"topic_id": null,
"coverage": "non_transactional",
"contact_id": null
}
}अगले कदम
- Webhooks API रेफ़रेंस: पूर्ण endpoint और स्कीमा दस्तावेज़ीकरण
- Email इवेंट: प्रति-इवेंट पेलोड फ़ील्ड
- Testing & sandbox: sandbox सेंड वास्तविक webhook डिलीवरी चलाते हैं, हैंडलर परीक्षण के लिए आदर्श
संबंधित संसाधन
इस विषय के लिए डॉक्यूमेंटेशन, गाइड और उदाहरणों के साथ आगे बढ़ें। संसाधन अंग्रेज़ी में हैं।
गाइड देखेंWebhooks done right: reliable delivery eventsकॉन्सेप्ट समझेंHow do I verify a webhook signature?लर्निंग पाथ फ़ॉलो करेंOperate messaging reliably
अभ्यास करें और इम्प्लीमेंटेशन ब्रीफ़ पाएँ