alchemy_api/api/notify/
create_webhook.rs

1use super::WebhookType;
2use crate::{
3    cores::endpoint::Endpoint,
4    types::{chain::AlchemyChain, common::NftFilter},
5};
6use derive_builder::Builder;
7use ethers_core::types::Address;
8use http::Method;
9use serde::{Deserialize, Serialize};
10use serde_with::{serde_as, skip_serializing_none};
11
12/// This endpoint allows you to create a webhook.
13#[serde_as]
14#[skip_serializing_none]
15#[derive(Builder, Default, Debug, Clone, Serialize, Deserialize)]
16#[builder(setter(into, strip_option), build_fn(validate = "Self::validate"))]
17pub struct CreateWebhook {
18    /// Network of webhook.
19    #[builder(setter(skip))]
20    network: AlchemyChain,
21    /// Type of webhook.
22    #[builder(setter)]
23    webhook_type: WebhookType,
24    /// URL where requests are sent.
25    #[builder(setter)]
26    webhook_url: String,
27    /// Required for mined and dropped webhooks, optional for address activity or custom webhooks.
28    #[builder(default)]
29    app_id: Option<String>,
30    /// List of addresses you want to track. Required for address activity webhooks only.
31    #[builder(default)]
32    addresses: Vec<Address>,
33    /// List of nft filter objects to track transfer activity for.
34    #[builder(default)]
35    nft_filters: Option<Vec<NftFilter>>,
36    /// List of nft metadata filter objects to track metadata updates for.
37    #[builder(default)]
38    nft_metadata_filters: Option<Vec<NftFilter>>,
39}
40
41impl CreateWebhook {
42    /// Create a builder for the endpoint.
43    pub fn builder() -> CreateWebhookBuilder {
44        CreateWebhookBuilder::default()
45    }
46}
47
48impl CreateWebhookBuilder {
49    /// Pre-Build Validation.
50    fn validate(&self) -> Result<(), String> {
51        // Alchemy rules:
52        // * `app_id`: required for mined and dropped webhooks, optional for address activity or
53        // custom webhooks.
54        // * `addresses`: required for address activity webhooks only.
55        if let Some(whtype) = self.webhook_type {
56            match whtype {
57                WebhookType::MinedTransaction | WebhookType::DroppedTransaction
58                    if self.app_id.is_none() =>
59                {
60                    Err("app_id is required for mined and dropped webhooks".to_string())
61                }
62                WebhookType::AddressActivity
63                    if self.addresses.is_none() || self.addresses.as_ref().unwrap().is_empty() =>
64                {
65                    Err("addresses is required for address activity webhooks".to_string())
66                }
67                _ => Ok(()),
68            }
69        } else {
70            Err("webhook_type is required".to_string())
71        }
72    }
73}
74
75impl Endpoint for CreateWebhook {
76    fn method(&self) -> http::Method {
77        Method::POST
78    }
79
80    fn endpoint(&self) -> std::borrow::Cow<'static, str> {
81        "api/create-webhook".into()
82    }
83
84    fn body(&self) -> anyhow::Result<Option<(&'static str, Vec<u8>)>> {
85        let body = serde_json::to_vec(self)?;
86        Ok(Some(("application/json", body)))
87    }
88}