एंडपॉइंट
`webhooks.list`, `list_all`, `iterate`, `get`, `create`, `update`, `delete`, `rotate_secret`, `test`, `get_delivery` और `replay_delivery`, और डिलीवरी व गतिविधि लॉग।
हर मेथड
from acme.secrets import store endpoint = client.webhooks.create({ 'url': 'https://acme.com/hooks/mail', 'eventTypes': ['email.sent', 'email.bounced'], 'description': 'Billing service',}) store(endpoint['secret']) client.webhooks.list()client.webhooks.get(endpoint['id'])client.webhooks.update(endpoint['id'], {'enabled': False})client.webhooks.test(endpoint['id'])latest = client.webhooks.list_deliveries(endpoint['id'], limit=1)['items'][0]client.webhooks.get_delivery(endpoint['id'], latest['id'])client.webhooks.replay_delivery(endpoint['id'], latest['id'])rotated = client.webhooks.rotate_secret(endpoint['id'])store(rotated['secret'])client.webhooks.delete(endpoint['id'])rotate_secret को छोड़कर create ही अकेली बार है जब secret लौटाया जाता है। कोई read उसे कभी नहीं दोहराता, इसलिए बाकी कुछ भी करने से पहले उसे संग्रहीत करें। डिफ़ॉल्ट सेट के लिए eventTypes छोड़ दें, यानी email.replied को छोड़कर हर email.* event। email.replied, domain.*, suppression.*, file.* और form.* किसी endpoint तक तभी पहुँचते हैं जब वह उनका नाम ले।
rotate_secret में कोई overlap विंडो नहीं है। पुराना secret तुरंत काम करना बंद कर देता है, इसलिए rotate करने से पहले नया तैनात करें। इसे कभी अपने आप retry नहीं किया जाता: retry दूसरी बार rotate कर देता और उस secret को रद्द कर देता जो पहली कोशिश ने लौटाया था।
आप किसकी सदस्यता ले सकते हैं
WEBHOOK_EVENTS export किया गया है ताकि आप सूची दिखा सकें। ये events **मेलबॉक्स** के हैं, इस API के नहीं: email.received उस मेल पर चलता है जो ऐप में आती है, और email.sent उस संदेश पर जिसे composer ने भेजा। सदस्यता लेना अपने API ट्रैफ़िक को देखने जैसा नहीं है।
file.uploaded तब चलता है जब कोई फ़ाइल फ़ाइलें पेज पर रखी जाती है, और file.deleted जब कोई फ़ाइल हटाई जाती है। इनका data FileEventData है: fileId, filename, mimeType, sizeBytes, direction, to, threadId, messageId, और uploadedAt या deletedAt। to वह पता है जिसकी फ़ाइल है, या पूरे वर्कस्पेस की फ़ाइल के लिए null।
फ़ाइल events डिफ़ॉल्ट सेट में नहीं हैं, इसलिए कोई endpoint इन्हें तभी पाता है जब वह eventTypes में इनका नाम ले। कुछ पतों तक सीमित endpoint सिर्फ़ उन्हीं पतों की फ़ाइलों के बारे में सुनता है, इसलिए पूरे वर्कस्पेस के लिए किया गया अपलोड, जिसमें to null है, उसे नहीं भेजा जाता।
form.submitted तब चलता है जब कोई आपके किसी फ़ॉर्म से साइन अप करता है, और form.confirmed तब जब पुष्टि की प्रतीक्षा वाला साइन-अप ऑडियंस में जुड़ता है, क्योंकि व्यक्ति ने पुष्टि लिंक खोला या आपने उसे मंज़ूरी दी। form.submitted में FormSubmittedEventData होता है: formId, formName, submissionId, email, status, answers, audienceIds, sourceUrl और submittedAt। form.confirmed में FormConfirmedEventData होता है: formId, formName, submissionId, email, audienceIds, via, जो link या approval होता है, और confirmedAt।
डबल ऑप्ट-इन के बिना वाले फ़ॉर्म पर साइन-अप status added के साथ form.submitted भेजता है और कोई form.confirmed नहीं, इसलिए उसी को वह क्षण मानें जब कोई जुड़ता है। पुष्टि से पहले फिर से साइन-अप करने वाले का submissionId वही रहता है, और form.submitted दोबारा तभी भेजा जाता है जब उसके जवाब बदले हों। फ़ॉर्म events डिफ़ॉल्ट सेट में नहीं हैं, और कुछ पतों तक सीमित endpoint इन्हें कभी नहीं पाता, क्योंकि साइन-अप पूरे वर्कस्पेस के होते हैं।
इनमें से हर data shape openemail.types में एक TypedDict है। उदाहरण के लिए, सत्यापित event को WebhookPayload[FileEventData] के रूप में annotate करें, और type checker जान लेता है कि event['data'] में क्या है।
यह साबित करना कि यह काम करता है
result = client.webhooks.test('whe_…')delivery = result['delivery'] if delivery is not None: print(delivery['status'], delivery['responseCode']) for d in client.webhooks.iterate_deliveries('whe_…'): print(d['eventType'], d['status'], d['responseCode'], d['error'])None वाले responseCode का मतलब है कि रिस्पॉन्स आया ही नहीं (DNS, TLS, कोई timeout), जो उस रिस्पॉन्स से अलग तथ्य है जिसने 0 कहा। हर पंक्ति attempt और maxAttempts लिए चलती है, इसलिए कई पंक्तियाँ एक ही event का वर्णन कर सकती हैं: उन सब पर एक जैसी eventId ही event है, और कोशिश की संख्या प्रयास है। nextAttemptAt बताता है कि किसी पंक्ति के बाद वाला अपने-आप होने वाला retry कब होना है।
इसे दोबारा भेजना
detail = client.webhooks.get_delivery('whe_…', 'whd_…')print(detail['payload'], detail['responseBody'], detail['replayRefusal']) replay = client.webhooks.replay_delivery('whe_…', 'whd_…')print(replay['delivery']['status'], replay['delivery']['responseCode'])जो delivery लगातार विफल होती रहे, उसे 8 बार तक आज़माया जाता है: तुरंत, फिर 1 मिनट, 5 मिनट, 30 मिनट, 2 घंटे, 5 घंटे, 10 घंटे और फिर 10 घंटे बाद, कुल मिलाकर लगभग साढ़े 27 घंटे। केवल वही विफलता दोहराई जाती है जिसे दोहराना सार्थक हो: कोई जवाब नहीं, 408, 425, 429 या कोई 5xx। replay सहेजे गए event को उसी id, type, createdAt और data के साथ फिर भेजता है, इसलिए जो receiver पहले से संभाली गई ids को छोड़ देता है, वह इसे वही event मानता है जिसे वह जानता है। केवल signature नया होता है।
replay_deliveryएक event अभी भेजता है और वह लौटाता है जो आपके सर्वर ने जवाब दिया। यह डिलीवर हो चुकी कोशिश पर भी काम करता है, और इसे कभी retry नहीं किया जाता। भेजने से पहले उस event के वे अपने-आप होने वाले retry रोक दिए जाते हैं जो अभी शुरू नहीं हुए: replay डिलीवर हो जाए तो वे रद्द ही रहते हैं, और विफल हो तो अपने समय पर फिर से चल पड़ते हैं।- अगर उसी पल उसी event का कोई अपने-आप होने वाला retry भेजा जा रहा हो, तो
replay_deliveryकुछ नहीं भेजता और 409retry_in_progressके साथ मना कर दिया जाता है, और जब तक उसका कोई दूसरा replay अभी भेजा जा रहा हो, 409replay_in_progressके साथ मना कर दिया जाता है, ताकि आपके receiver को एक साथ दो कॉपी कभी न मिलें, एक ही पल में भेजे गए दो replays से भी नहीं। कुछ सेकंड रुकें औरget_deliveryपढ़ें, क्योंकि वही retry या replay उसे डिलीवर कर सकता है। Replay एक बार में एक event का होता है: कोई भी call हर विफल delivery को दोबारा नहीं भेजती। - यह 409 के साथ बंद किए गए endpoint (
webhook_disabled), ऐसे event जिसे endpoint अब सुनता नहीं (event_not_subscribed) या अब कवर नहीं करता (event_out_of_scope), और बिना सहेजे event वाली कोशिश (delivery_not_replayable) को भी मना करता है।get_deliveryयही जवाब पहले सेreplayRefusalके रूप में बता देता है।
SDK replay_delivery को कभी अपने-आप retry नहीं करता, क्योंकि खोए हुए जवाब के बाद retry event को दोबारा भेज देगा।
हर इनकार OpenEmailApiError raise करता है, जिसमें status 409, is_conflict true और कारण code के रूप में होता है, जो WEBHOOK_REPLAY_ERROR_CODES के मानों में से एक है।
पैरामीटर: webhooks.create
urlstrआवश्यक- जहाँ deliveries POST की जाती हैं। केवल HTTPS, और host न `localhost` हो सकता है, न `.localhost`/`.local`/`.internal` नाम, और न loopback, private, CGNAT या link-local IP literal। यह आपके दिए पते पर सर्वर की ओर से किया गया fetch है, इसलिए वे `url` पर 422 हैं; जाँच hostname को जैसा लिखा है वैसा पढ़ती है और DNS कभी हल नहीं करती। जो संग्रहीत होता है वह आपके भेजे का URL parser वाला serialisation है, इसलिए `https://acme.com` वापस `https://acme.com/` पढ़ा जाता है।
eventTypeslist[WebhookEvent]- इस endpoint तक कौन-से events पहुँचते हैं: `WEBHOOK_EVENTS` के किसी भी नाम। `POST /webhooks` array को मौजूद events की संख्या पर सीमित करता है, इसलिए उससे एक ज़्यादा `eventTypes` पर 422 है; `PATCH` उसे सीमित नहीं करता। केवल लंबाई सीमित है, और दोहराया गया नाम हूबहू वैसा ही संग्रहीत और वापस पढ़ा जाता है जैसा आपने भेजा। छोड़ा गया या खाली, खाली सूची के रूप में संग्रहीत होता है, इसीलिए वह वापस `['*']` पढ़ा जाता है, और उसका अर्थ है `email.replied` को छोड़कर हर `email.*` event, आज चौदह, और कभी भी domain, suppression या file परिवार नहीं। बाद में जोड़ा गया कोई परिवार उस endpoint तक कभी नहीं पहुँचता जिसने उसका नाम नहीं लिया, इसलिए किसी रिलीज़ के कारण कोई integration ऐसा आकार पाना शुरू नहीं कर सकता जो उसने कभी देखा ही नहीं।
descriptionstr- endpoint के लिए एक लेबल, अधिकतम 200 वर्ण, ताकि webhooks की सूची URL के स्तंभ के बजाय नामों की तरह पढ़ी जाए। छोड़ने पर यह null के रूप में संग्रहीत और लौटाया जाता है।
रिस्पॉन्स: CreatedWebhookResource
objectLiteral['webhook']- हमेशा `'webhook'`, वही discriminator जो सादा read लौटाता है, क्योंकि secret सामान्य आकार पर एक अतिरिक्त key है, अपने आप में कोई object type नहीं। `secret` मौजूद है या नहीं, यह इस फ़ील्ड से नहीं बल्कि इससे तय होता है कि आपने कौन-सा method कॉल किया।
idstr- endpoint का पहचानकर्ता: `whe_` के बाद 24 hex वर्ण। बाकी हर webhook कॉल इसे लेता है: `get`, `update`, `delete`, `rotate_secret`, `test`, `list_deliveries`, `list_all_deliveries`, `iterate_deliveries`, `get_delivery` और `replay_delivery`।
urlstr- endpoint जैसा संग्रहीत है, HTTPS और अवरुद्ध-host जाँचें पार करने के बाद। यह पार्स किया गया URL फिर से serialise किया हुआ है, इसलिए अपनी भेजी string से नहीं, इसी मान से तुलना करें।
descriptionstr | None- जो लेबल आपने दिया, या null अगर कोई नहीं दिया। स्पष्ट null भेजने वाला `update` इसे वापस null कर देता है।
eventTypeslist[WebhookEvent] | ['*']- सदस्यता लिए गए events, या `['*']` जब endpoint ने किसी का नाम नहीं लिया। `['*']` वह तरीका है जिससे खाली संग्रहीत सूची read पर दिखाई जाती है और उसे वापस भेजा नहीं जा सकता, और वह पूरे कैटलॉग के बजाय चौदह संदेश events का प्रतीक है। `create` और `update` केवल शाब्दिक event नाम स्वीकार करते हैं।
enabledbool- क्या deliveries की कोशिश की जाती है; निष्क्रिय endpoint को events भेजते समय छोड़ दिया जाता है और उसका secret तथा उसका delivery इतिहास बना रहता है। यहाँ हमेशा true, क्योंकि `WebhookCreate` में `enabled` है ही नहीं और केवल `WebhookPatch` में है।
lastDeliveryAtstr | None- आखिरी delivery कोशिश का ISO 8601 timestamp, आखिरी सफलता का नहीं। यह विफल POST के बाद भी लगाया जाता है, इसलिए यह बताता है कि endpoint को आज़माया गया और `list_deliveries` बताता है कि क्या हुआ। पहली कोशिश तक null, इसलिए `create` पर हमेशा null।
createdAtstr- endpoint कब पंजीकृत हुआ, इसका ISO 8601 timestamp। `list` इसी फ़ील्ड के अनुसार सबसे नए endpoint पहले लौटाता है।
secretstr- वह HMAC-SHA-256 key जो हर delivery के `X-OpenEmail-Signature` पर हस्ताक्षर करती है: `whsec_` के बाद base64url में 32 यादृच्छिक बाइट, और वही जो आप `verify_webhook_signature` को देते हैं। इसे `create` और `rotate_secret` लौटाते हैं, और कुछ नहीं। कोई read इसे कभी नहीं दोहराता, इसलिए इसे अभी संग्रहीत करें; खोया हुआ secret केवल `rotate_secret` से बदला जा सकता है, जो पुराने को तुरंत रद्द कर देता है।
लॉग फ़िल्टर करना
from datetime import datetime, timedelta, timezone failed = client.webhooks.list_workspace_deliveries( status='failed', since=datetime.now(timezone.utc) - timedelta(days=1),)print(len(failed['items'])) history = client.webhooks.list_activity('whe_…')print([(change['type'], change['actor']['label'] if change['actor'] else None) for change in history['items']])list_deliveries एक एंडपॉइंट पढ़ता है और list_workspace_deliveries हर एंडपॉइंट या वे जो endpoint_ids= में हैं, और दोनों status=, since= और until= लेते हैं, जो कंसोल के डिलीवरी टैब के फ़िल्टर हैं। list_activity और list_workspace_activity ऑडिट लॉग पढ़ते हैं: किसने क्या बनाया, बदला, बंद या चालू किया, रोटेट किया, टेस्ट किया, फिर से भेजा या हटाया। हर एक के साथ एक list_all_… और एक iterate_… है, और वर्कस्पेस लॉग की हर पंक्ति में endpointId होता है।
since= और until= एक datetime या ISO 8601 string लेते हैं। naive datetime को स्थानीय समय माना जाता है और UTC में बदला जाता है, इसलिए ऊपर की तरह aware वाला पास करें।
संदर्भ
webhooks.list()पूरा रेफ़रेंसwebhooks.list_all()पूरा रेफ़रेंसwebhooks.iterate()पूरा रेफ़रेंसwebhooks.get()पूरा रेफ़रेंसwebhooks.create()पूरा रेफ़रेंसwebhooks.update()पूरा रेफ़रेंसwebhooks.delete()पूरा रेफ़रेंसwebhooks.rotate_secret()पूरा रेफ़रेंसwebhooks.test()पूरा रेफ़रेंसwebhooks.list_deliveries()पूरा रेफ़रेंसwebhooks.list_all_deliveries()पूरा रेफ़रेंसwebhooks.iterate_deliveries()पूरा रेफ़रेंसwebhooks.get_delivery()पूरा रेफ़रेंसwebhooks.replay_delivery()पूरा रेफ़रेंसwebhooks.list_workspace_deliveries()पूरा रेफ़रेंसwebhooks.list_all_workspace_deliveries()पूरा रेफ़रेंसwebhooks.iterate_workspace_deliveries()पूरा रेफ़रेंसwebhooks.list_activity()पूरा रेफ़रेंसwebhooks.list_all_activity()पूरा रेफ़रेंसwebhooks.iterate_activity()पूरा रेफ़रेंसwebhooks.list_workspace_activity()पूरा रेफ़रेंसwebhooks.list_all_workspace_activity()पूरा रेफ़रेंसwebhooks.iterate_workspace_activity()पूरा रेफ़रेंस