boxxkite_client/
webhooks.rs1use reqwest::Method;
12use serde::{Deserialize, Serialize};
13
14use crate::client::Client;
15use crate::error::BoxxkiteError;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
24pub enum WebhookEventType {
25 #[serde(rename = "sandbox.created")]
26 SandboxCreated,
27 #[serde(rename = "sandbox.destroyed")]
28 SandboxDestroyed,
29 #[serde(rename = "audit_log.entry")]
30 AuditLogEntry,
31}
32
33#[derive(Debug, Clone, Default, Serialize)]
35pub struct CreateWebhookOptions {
36 #[serde(skip_serializing_if = "Option::is_none")]
37 description: Option<String>,
38}
39
40impl CreateWebhookOptions {
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn description(mut self, description: impl Into<String>) -> Self {
47 self.description = Some(description.into());
48 self
49 }
50}
51
52#[derive(Debug, Clone, Deserialize)]
56pub struct Webhook {
57 pub id: String,
58 pub url: String,
59 pub event_types: Vec<String>,
60 pub description: Option<String>,
61 pub is_active: bool,
62 #[serde(default)]
63 pub payload_format: String,
64 pub created_at: String,
65 pub last_triggered_at: Option<String>,
66 pub secret: Option<String>,
70}
71
72#[derive(Debug, Clone, Deserialize)]
75pub struct WebhookDelivery {
76 pub id: String,
77 pub event_type: String,
78 pub status: String,
80 pub attempt_count: i64,
81 pub next_attempt_at: String,
82 pub last_attempt_at: Option<String>,
83 pub response_status_code: Option<i32>,
84 pub failure_reason: Option<String>,
85 pub created_at: String,
86 pub delivered_at: Option<String>,
87}
88
89#[derive(Debug, Clone, Default)]
91pub struct ListWebhookDeliveriesOptions {
92 limit: Option<u32>,
93 offset: Option<u32>,
94}
95
96impl ListWebhookDeliveriesOptions {
97 pub fn new() -> Self {
98 Self::default()
99 }
100
101 pub fn limit(mut self, limit: u32) -> Self {
103 self.limit = Some(limit);
104 self
105 }
106
107 pub fn offset(mut self, offset: u32) -> Self {
109 self.offset = Some(offset);
110 self
111 }
112}
113
114impl Client {
115 pub async fn create_webhook(
120 &self,
121 url: &str,
122 event_types: &[WebhookEventType],
123 options: CreateWebhookOptions,
124 ) -> Result<Webhook, BoxxkiteError> {
125 #[derive(Serialize)]
126 struct Body<'a> {
127 url: &'a str,
128 event_types: &'a [WebhookEventType],
129 #[serde(skip_serializing_if = "Option::is_none")]
130 description: Option<&'a str>,
131 }
132 let body = Body {
133 url,
134 event_types,
135 description: options.description.as_deref(),
136 };
137 let builder = self.request(Method::POST, "/v1/webhooks").json(&body);
138 self.send(builder).await
139 }
140
141 pub async fn list_webhooks(&self) -> Result<Vec<Webhook>, BoxxkiteError> {
144 let builder = self.request(Method::GET, "/v1/webhooks");
145 self.send_or_default(builder).await
146 }
147
148 pub async fn delete_webhook(&self, subscription_id: &str) -> Result<(), BoxxkiteError> {
151 let builder = self.request(Method::DELETE, &format!("/v1/webhooks/{subscription_id}"));
152 self.send_no_content(builder).await
153 }
154
155 pub async fn list_webhook_deliveries(
158 &self,
159 subscription_id: &str,
160 options: ListWebhookDeliveriesOptions,
161 ) -> Result<Vec<WebhookDelivery>, BoxxkiteError> {
162 let mut query = Vec::new();
163 if let Some(limit) = options.limit {
164 query.push(("limit", limit.to_string()));
165 }
166 if let Some(offset) = options.offset {
167 query.push(("offset", offset.to_string()));
168 }
169 let builder = self
170 .request(
171 Method::GET,
172 &format!("/v1/webhooks/{subscription_id}/deliveries"),
173 )
174 .query(&query);
175 self.send_or_default(builder).await
176 }
177}