پرش به مستندات
Ruby

اندپوینت‌ها

`webhooks.list`، `list_all`، `iterate`، `get`، `create`، `update`، `delete`، `rotate_secret`، `test`، `get_delivery` و `replay_delivery`، به‌همراه گزارش‌های تحویل و فعالیت.

همهٔ متدها

webhooks.rb
endpoint = client.webhooks.create(  url: "https://acme.com/hooks/mail",  eventTypes: ["email.sent", "email.bounced"],  description: "Billing service") File.write(".openemail-webhook-secret", endpoint[:secret]) client.webhooks.listclient.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.firstclient.webhooks.get_delivery(endpoint[:id], latest[:id])client.webhooks.replay_delivery(endpoint[:id], latest[:id])rotated = client.webhooks.rotate_secret(endpoint[:id])File.write(".openemail-webhook-secret", rotated[:secret])client.webhooks.delete(endpoint[:id])

create، جدا از rotate_secret، «تنها» باری است که secret برگردانده می‌شود. هیچ خواندنی آن را بازنمی‌گرداند، پس پیش از هر کار دیگری ذخیره‌اش کنید. برای مجموعهٔ پیش‌فرض، یعنی همهٔ رویدادهای email.* جز email.replied، eventTypes را ننویسید. email.replied، domain.*، suppression.*، file.* و form.* فقط وقتی به یک اندپوینت می‌رسند که آن‌ها را نام ببرد.

rotate_secret هیچ پنجرهٔ هم‌پوشانی ندارد. secret قدیمی بی‌درنگ از کار می‌افتد، پس پیش از چرخاندن، secret تازه را مستقر کنید. هرگز خودکار دوباره امتحان نمی‌شود: تلاش دوباره بار دوم می‌چرخاند و secretی را که تلاش نخست برگردانده بود باطل می‌کند.

create هم دوباره امتحان نمی‌شود، پس یک شکست شبکه ممکن است اندپوینتی ساخته‌شده با secretی که هرگز ندیده‌اید باقی بگذارد. پیش از ساختن دوباره، list را بررسی کنید. هر فضای کاری به‌طور پیش‌فرض 10 اندپوینت دارد، و اندپوینت بعدی پس از این سقف یک 422 workspace_limit_reached است.

چه چیزهایی را می‌توان اشتراک گرفت

OpenEmail::WEBHOOK_EVENTS یک Hash منجمد از نام همهٔ رویدادهاست، تا بتوانید فهرست را بدون درخواست نمایش دهید، و webhooks.list_events همان نام‌ها را با یک جمله برای هرکدام برمی‌گرداند، به‌علاوهٔ محدودیت‌هایی که اندپوینت به آن‌ها مقید است. رویدادها، رویدادهای **صندوق پستی** هستند نه این API: email.received برای ایمیلی که در برنامه می‌رسد رخ می‌دهد، و email.sent برای پیامی که کامپوزر فرستاده است. مشترک شدن با تماشای ترافیک API خودتان یکی نیست.

file.uploaded وقتی رخ می‌دهد که فایلی در صفحهٔ «فایل‌ها» گذاشته شود، و file.deleted وقتی فایلی حذف شود. data آن‌ها شامل fileId، filename، mimeType، sizeBytes، direction، to، threadId، messageId، و uploadedAt یا deletedAt است. to نشانی‌ای است که فایل به آن تعلق دارد، یا nil برای فایلی که به کل فضای کاری تعلق دارد.

رویدادهای فایل در مجموعهٔ پیش‌فرض نیستند، پس اندپوینت فقط وقتی آن‌ها را دریافت می‌کند که در eventTypes نامشان را ببرد. اندپوینتی که به برخی نشانی‌ها محدود است فقط دربارهٔ فایل‌های همان نشانی‌ها خبر می‌گیرد، پس بارگذاری برای کل فضای کاری، با to برابر nil، برای آن فرستاده نمی‌شود.

form.submitted وقتی رخ می‌دهد که کسی از راه یکی از فرم‌های شما ثبت‌نام کند، و form.confirmed وقتی یک ثبت‌نامِ در انتظار به گروه‌های مخاطب می‌پیوندد، چون شخص پیوند تأیید را باز کرده یا شما آن را تأیید کرده‌اید. data در form.submitted شامل formId، formName، submissionId، email، status، answers، audienceIds، sourceUrl و submittedAt است. data در form.confirmed شامل formId، formName، submissionId، email، audienceIds، via، که link یا approval است، و confirmedAt است.

ثبت‌نام در فرمی بدون تأیید دوگانه، form.submitted را با status برابر added می‌فرستد و form.confirmed نمی‌فرستد، پس همین را لحظهٔ پیوستن کسی بدانید. کسی که پیش از تأیید دوباره ثبت‌نام کند همان submissionId را نگه می‌دارد، و form.submitted فقط وقتی دوباره فرستاده می‌شود که پاسخ‌هایش تغییر کرده باشد. رویدادهای فرم در مجموعهٔ پیش‌فرض نیستند، و اندپوینتی که به برخی نشانی‌ها محدود است هرگز آن‌ها را دریافت نمی‌کند، چون ثبت‌نام‌ها به کل فضای کاری تعلق دارند.

اثبات اینکه کار می‌کند

webhook_test.rb
result = client.webhooks.test("whe_3f9c2a7b1e4d8f60a5c7b92d")puts result.dig(:delivery, :status), result.dig(:delivery, :responseCode) client.webhooks.iterate_deliveries("whe_3f9c2a7b1e4d8f60a5c7b92d") do |delivery|  puts "#{delivery[:eventType]} #{delivery[:status]} #{delivery[:responseCode]} #{delivery[:error]}"end

test یک رویداد ساختگیِ امضاشدهٔ email.sent را POST می‌کند و منتظر می‌ماند تا تلاش تمام شود. هر پاسخی که گیرندهٔ شما داده باشد، به‌طور عادی برمی‌گردد، پس روی delivery[:status] شاخه بزنید، نه روی اینکه فراخوانی خطا raise کرده یا نه. یک 4xx پاسخ مفیدی است: URL در دسترس است و رد شدن از هندلر خودتان آمده، اغلب از بررسی امضای آن.

responseCode برابر nil یعنی اصلاً پاسخی نیامده (DNS، TLS، پایان مهلت)، که واقعیتی متفاوت با پاسخی است که 0 گفته باشد. هر ردیف attempt و maxAttempts دارد، پس چند ردیف می‌توانند یک رویداد را توصیف کنند: eventId یکسان در میان آن‌ها همان رویداد است، و شمارهٔ تلاش همان دفعهٔ تلاش. nextAttemptAt می‌گوید تلاش دوبارهٔ خودکار پس از یک ردیف کی موعدش است.

فرستادن دوباره

webhook_replay.rb
detail = client.webhooks.get_delivery("whe_3f9c2a7b1e4d8f60a5c7b92d", "whd_8c1e4a7f2b9d3e6a0c5f1b28")p detail[:payload], detail[:responseBody], detail[:replayRefusal] replay = client.webhooks.replay_delivery("whe_3f9c2a7b1e4d8f60a5c7b92d", "whd_8c1e4a7f2b9d3e6a0c5f1b28")p replay.dig(:delivery, :status), replay.dig(:delivery, :responseCode)

تحویلی که پیوسته شکست می‌خورد تا 8 بار تلاش می‌شود: همان لحظه، سپس پس از 1 دقیقه، 5 دقیقه، 30 دقیقه، 2 ساعت، 5 ساعت، 10 ساعت و 10 ساعت دیگر، روی هم حدود 27 ساعت و نیم. فقط شکستی تکرار می‌شود که ارزش تکرار داشته باشد: بی‌پاسخی، 408، 425، 429 یا یک 5xx. بازپخش، رویداد ذخیره‌شده را با همان id، type، createdAt و data دوباره می‌فرستد، پس گیرنده‌ای که شناسه‌های پردازش‌شده را کنار می‌گذارد آن را همان رویدادی می‌داند که می‌شناسد. فقط امضا تازه است.

  • replay_delivery یک رویداد را همین حالا می‌فرستد و آنچه سرور شما پاسخ داده را برمی‌گرداند. روی تلاشی که تحویل شده هم کار می‌کند و هرگز دوباره امتحان نمی‌شود. پیش از فرستادن، تلاش‌های دوبارهٔ خودکار آن رویداد که هنوز آغاز نشده‌اند متوقف می‌شوند: وقتی بازپخش تحویل شود لغوشده می‌مانند، و وقتی شکست بخورد طبق زمان‌بندی خودشان از سر گرفته می‌شوند.
  • اگر در همان لحظه یک تلاش دوبارهٔ خودکار از همان رویداد در حال فرستاده شدن باشد، replay_delivery چیزی نمی‌فرستد و یک 409 retry_in_progress را raise می‌کند، و تا وقتی بازپخش دیگری از آن هنوز در حال فرستاده شدن است یک 409 replay_in_progress را raise می‌کند، تا گیرندهٔ شما هرگز دو نسخه را هم‌زمان نگیرد، حتی از دو بازپخش که در یک لحظه فرستاده شده‌اند. چند ثانیه صبر کنید و get_delivery را بخوانید، چون آن تلاش دوباره یا بازپخش ممکن است آن را تحویل دهد. بازپخش هر بار برای یک رویداد است: هیچ فراخوانی‌ای همهٔ تحویل‌های ناموفق را دوباره نمی‌فرستد.
  • همچنین برای اندپوینت خاموش‌شده (webhook_disabled)، رویدادی که اندپوینت دیگر به آن گوش نمی‌دهد (event_not_subscribed) یا دیگر آن را پوشش نمی‌دهد (event_out_of_scope)، و تلاشی بدون رویداد ذخیره‌شده (delivery_not_replayable) یک 409 را raise می‌کند. get_delivery این پاسخ را از پیش به‌صورت replayRefusal گزارش می‌کند.

gem هرگز خودش replay_delivery را دوباره امتحان نمی‌کند، چون تلاش دوباره پس از پاسخی گم‌شده رویداد را دوباره می‌فرستاد.

پارامترها: webhooks.create

urlStringالزامی
جایی که تحویل‌ها به آن POST می‌شوند. فقط HTTPS، و میزبان نمی‌تواند `localhost`، نامی با `.localhost`، `.local` یا `.internal`، یا یک IP صریح از نوع loopback، خصوصی، CGNAT یا link-local باشد. این درخواستی سمت سرور به نشانی‌ای است که شما می‌دهید، پس این‌ها یک 422 `invalid_webhook_url` روی `url` هستند. بررسی نام میزبان را همان‌طور که نوشته شده می‌خواند، و هر تحویل میزبان را دوباره جست‌وجو می‌کند و از فرستادن به نشانی‌ای در یکی از آن بازه‌ها خودداری می‌کند. تحویل‌ها هرگز هدایت‌ها را دنبال نمی‌کنند، پس نشانی نهایی را ثبت کنید. آنچه ذخیره می‌شود سریال‌سازیِ تجزیه‌گر URL از چیزی است که فرستاده‌اید، پس `https://acme.com` به شکل `https://acme.com/` خوانده می‌شود.
eventTypesArray<String>
کدام رویدادها به این اندپوینت می‌رسند: هر یک از مقدارهای `OpenEmail::WEBHOOK_EVENTS`. `create` اندازهٔ Array را به تعداد رویدادهای موجود محدود می‌کند، پس یکی بیشتر از آن یک 422 روی `eventTypes` است، و `update` آن را محدود نمی‌کند. فقط طول محدود می‌شود، و نام تکراری دقیقاً همان‌طور که فرستاده‌اید ذخیره و خوانده می‌شود. اگر ننویسید یا خالی باشد، به‌صورت فهرستی خالی ذخیره می‌شود، و به همین دلیل به شکل `["*"]` خوانده می‌شود، و یعنی همهٔ رویدادهای `email.*` جز `email.replied`، امروز چهارده رویداد، و هرگز خانواده‌های دامنه، توقیف، فایل یا فرم. خانواده‌ای که بعدها افزوده شود هرگز به اندپوینتی که نامش را نبرده نمی‌رسد، پس یک یکپارچه‌سازی نمی‌تواند به خاطر یک انتشار، دریافت شکلی را آغاز کند که هرگز ندیده است.
descriptionString
برچسبی برای اندپوینت، حداکثر 200 نویسه، تا فهرستی از وب‌هوک‌ها به‌صورت نام‌ها خوانده شود نه ستونی از URLها. اگر ننویسید، به‌صورت nil ذخیره و برگردانده می‌شود.
addressAllowlistArray<String>
نشانی‌های تکی که این اندپوینت دربارهٔ آن‌ها خبر می‌گیرد. رویدادی تحویل می‌شود که نشانی مربوط به آن در این فهرست باشد، یا دامنه‌اش در `domainAllowlist`. هر دو را خالی بگذارید تا اندپوینت دربارهٔ همهٔ نشانی‌هایی که فضای کاری مالک آن‌هاست خبر بگیرد. حداکثر 50، و نشانی‌ای که این فضای کاری مالکش نیست یک 422 `invalid_parameter` است.
domainAllowlistArray<String>
دامنه‌های کاملی که این اندپوینت دربارهٔ آن‌ها خبر می‌گیرد، از جمله نشانی‌هایی که بعداً به آن‌ها افزوده می‌شوند. یک دامنه رویدادهای `domain.*` خودش را هم می‌آورد. حداکثر 25.
api_keyString
اندپوینت را به‌جای کلید کلاینت با این کلید می‌سازد.

پاسخ: اندپوینت ساخته‌شده

یک Hash با کلیدهای Symbol. get، list و update همین شکل را بدون secret برمی‌گردانند.

objectString
همیشه `webhook`، همان تمایزدهنده‌ای که یک خواندن ساده برمی‌گرداند، چون secret یک کلید اضافه روی همان شکل معمولی است نه یک نوع شیء جداگانه. اینکه `secret` حاضر باشد یا نه را متدی که فراخوانده‌اید تعیین می‌کند، نه این فیلد.
idString
شناسهٔ اندپوینت: `whe_` و به دنبالش 24 نویسهٔ hex. هر فراخوانی دیگر وب‌هوک آن را می‌گیرد: `get`، `update`، `delete`، `rotate_secret`، `test`، `list_deliveries`، `list_all_deliveries`، `iterate_deliveries`، `get_delivery` و `replay_delivery`.
urlString
اندپوینت همان‌طور که ذخیره شده، پس از گذر از بررسی‌های HTTPS و میزبان‌های مسدود. همان URL تجزیه‌شده است که دوباره سریال‌سازی شده، پس با این مقدار مقایسه کنید نه با Stringی که فرستاده‌اید.
descriptionString or nil
برچسبی که به آن داده‌اید، یا nil اگر چیزی نداده باشید. `update`ی که `description: nil` بفرستد آن را پاک می‌کند.
eventTypesArray<String>
رویدادهای مشترک‌شده، یا `["*"]` وقتی اندپوینت هیچ‌کدام را نام نبرده. `["*"]` شکلی است که یک فهرست ذخیره‌شدهٔ خالی هنگام خواندن نمایش داده می‌شود و نمی‌توان آن را پس فرستاد، و نمایندهٔ چهارده رویداد پیام است نه کل فهرست رویدادها. `create` و `update` فقط نام‌های عینی رویدادها را می‌پذیرند.
enabledBoolean
اینکه آیا تحویل‌ها تلاش می‌شوند یا نه. اندپوینت غیرفعال هنگام روانه شدن رویدادها نادیده گرفته می‌شود و secret و تاریخچهٔ تحویلش را نگه می‌دارد. اینجا همیشه true است، چون فقط `update` مقدار `enabled` را می‌گیرد.
disabledAtString or nil
زمانی که سرور پس از 100 تحویل ناموفق پیاپی اندپوینت را خاموش کرد. تا وقتی روشن است nil است، و همچنین وقتی خودتان آن را خاموش کرده‌اید.
disabledReasonString or nil
اینکه چرا سرور آن را خاموش کرد. هر وقت `disabledAt` برابر nil باشد nil است.
consecutiveFailuresInteger
تحویل‌های ناموفق پیاپی. هر رویداد تحویل‌شده آن را به 0 بازمی‌گرداند، و `update` با `enabled: true` هم همین‌طور.
addressAllowlistArray<String>
نشانی‌های تکی که این اندپوینت دربارهٔ آن‌ها خبر می‌گیرد.
domainAllowlistArray<String>
دامنه‌های کاملی که این اندپوینت دربارهٔ آن‌ها خبر می‌گیرد. خالی بودن هر دو فهرست یعنی همهٔ نشانی‌هایی که فضای کاری مالک آن‌هاست.
lastDeliveryAtString or nil
مهر زمانی ISO 8601 آخرین «تلاش» تحویل، نه آخرین موفقیت. پس از یک POST ناموفق هم ثبت می‌شود، پس به شما می‌گوید اندپوینت امتحان شده و `list_deliveries` می‌گوید نتیجه چه بوده. تا نخستین تلاش nil است، و بنابراین روی `create` همیشه nil است.
createdAtString
مهر زمانی ISO 8601 زمانی که اندپوینت ثبت شده است. `list` اندپوینت‌ها را بر اساس همین فیلد از تازه‌ترین بازمی‌گرداند.
secretString
کلید HMAC-SHA-256 که `X-OpenEmail-Signature` هر تحویل را امضا می‌کند: `whsec_` و به دنبالش 43 نویسهٔ base64url، و همان چیزی که با پیشوندش به `OpenEmail.verify_webhook_signature` می‌دهید. فقط `create` و `rotate_secret` آن را برمی‌گردانند و هیچ چیز دیگری. هیچ خواندنی آن را بازنمی‌گرداند، پس همین حالا ذخیره‌اش کنید. secret گم‌شده را فقط می‌توان با `rotate_secret` جایگزین کرد، که secret قدیمی را بی‌درنگ باطل می‌کند.

فیلتر کردن گزارش‌ها

webhook_logs.rb
failed = client.webhooks.list_workspace_deliveries(status: "failed", since: Time.now - 86_400)p failed.items.map { |delivery| [delivery[:endpointId], delivery[:eventType], delivery[:responseCode]] } history = client.webhooks.list_activity("whe_3f9c2a7b1e4d8f60a5c7b92d")p history.items.map { |change| [change[:type], change.dig(:actor, :label)] }

list_deliveries یک اندپوینت را می‌خواند و list_workspace_deliveries همهٔ اندپوینت‌ها، یا آن‌هایی را که endpoint_ids: نام می‌برد، و هر دو status:، since: و until: را می‌گیرند، یعنی فیلترهای زبانهٔ «تحویل‌ها» در کنسول. list_activity و list_workspace_activity گزارش ممیزی را می‌خوانند: چه کسی چه چیزی را ساخت، تغییر داد، روشن یا خاموش کرد، چرخاند، آزمود، بازپخش کرد یا حذف کرد. هرکدام یک نسخهٔ list_all_ و یک نسخهٔ iterate_ در کنار خود دارند، و هر ردیف گزارش فضای کاری endpointId دارد. webhooks.stats عددهای پشت زبانهٔ «تحلیل» را برای بازه‌ای که انتخاب می‌کنید برمی‌گرداند.

since: و until: یک Time، یک DateTime یا یک لحظهٔ ISO 8601 به‌صورت String می‌گیرند، و Date در Ruby یعنی نیمه‌شب UTC همان روز. until یک کلیدواژهٔ Ruby است، اما مانند هر آرگومان کلیدواژه‌ای دیگر کار می‌کند: list_deliveries(id, since: start, until: finish).