1use crate::v1::{Client, error, BASE_URL, standard};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Deserialize, Debug)]
8pub struct ListWebhooksResponse {
9 pub data : Vec<WebhookResource>,
11 pub links : ResponseLinks,
12}
13
14#[derive(Deserialize, Debug)]
15pub struct GetWebhookResponse {
16 pub data : WebhookResource,
18}
19
20#[derive(Deserialize, Debug)]
21pub struct CreateWebhookResponse {
22 pub data : WebhookResource,
24}
25
26#[derive(Deserialize, Debug)]
27pub struct WebhookResource {
28 pub r#type : String,
30 pub id : String,
32 pub attributes : Attributes,
33 pub relationships : Relationships,
34 pub links : WebhookResourceLinks,
35}
36
37#[derive(Deserialize, Debug)]
38#[serde(rename_all = "camelCase")]
39pub struct Attributes {
40 pub url : String,
42 pub description : Option<String>,
44 pub secret_key : Option<String>,
47 pub created_at : String,
49}
50
51#[derive(Deserialize, Debug)]
52pub struct Relationships {
53 pub logs : Logs,
54}
55
56#[derive(Deserialize, Debug)]
57pub struct Logs {
58 pub links : Option<LogsLinks>,
59}
60
61#[derive(Deserialize, Debug)]
62pub struct LogsLinks {
63 pub related : String,
65}
66
67#[derive(Deserialize, Debug)]
68pub struct WebhookResourceLinks {
69 #[serde(rename = "self")]
71 pub this : String,
72}
73
74#[derive(Deserialize, Debug)]
75pub struct ResponseLinks {
76 pub prev : Option<String>,
78 pub next : Option<String>,
80}
81
82#[derive(Deserialize, Debug)]
83pub struct PingWebhookResponse {
84 pub data : WebhookEventResource,
86}
87
88#[derive(Deserialize, Debug)]
89pub struct WebhookEventResource {
90 pub r#type : String,
92 pub id : String,
94 pub attributes : EventAttributes,
95 pub relationships : EventRelationships,
96}
97
98#[derive(Deserialize, Debug)]
99pub struct EventRelationships {
100 pub webhook : Webhook,
101 pub transaction : Option<Transaction>,
102}
103
104#[derive(Deserialize, Debug)]
105pub struct Transaction {
106 pub data : TransactionData,
107 pub links : Option<TransactionLinks>,
108}
109
110#[derive(Deserialize, Debug)]
111pub struct Webhook {
112 pub data : WebhookData,
113 pub links : Option<WebhookLinks>,
114}
115
116#[derive(Deserialize, Debug)]
117pub struct WebhookData {
118 pub r#type : String,
120 pub id : String,
122}
123
124#[derive(Deserialize, Debug)]
125pub struct WebhookLinks {
126 pub related : String,
128}
129
130#[derive(Deserialize, Debug)]
131pub struct TransactionData {
132 pub r#type : String,
134 pub id : String,
136}
137
138#[derive(Deserialize, Debug)]
139pub struct TransactionLinks {
140 pub related : String,
142}
143
144#[derive(Deserialize, Debug)]
145#[serde(rename_all = "camelCase")]
146pub struct EventAttributes {
147 pub event_type : standard::WebhookEventTypeEnum,
149 pub created_at : String,
151}
152
153
154#[derive(Deserialize, Debug)]
155pub struct ListWebhookLogsResponse {
156 pub data : Vec<WebhookDeliveryLogResource>,
158 pub links : LogsResponseLinks,
159}
160
161#[derive(Deserialize, Debug)]
162pub struct WebhookDeliveryLogResource {
163 pub r#type : String,
165 pub id : String,
167 pub attributes : DeliveryLogAttributes,
168 pub relationships : DeliveryLogRelationships,
169}
170
171#[derive(Deserialize, Debug)]
172#[serde(rename_all = "camelCase")]
173pub struct DeliveryLogRelationships {
174 pub webhook_event : WebhookEvent,
175}
176
177#[derive(Deserialize, Debug)]
178pub struct WebhookEvent {
179 pub data : WebhookEventData
180}
181
182#[derive(Deserialize, Debug)]
183pub struct WebhookEventData {
184 pub r#type : String,
186 pub id : String,
188}
189
190#[derive(Deserialize, Debug)]
191#[serde(rename_all = "camelCase")]
192pub struct DeliveryLogAttributes {
193 pub request : Request,
195 pub response : Option<Response>,
197 pub delivery_status : standard::WebhookDeliveryStatusEnum,
199 pub created_at : String,
201}
202
203#[derive(Deserialize, Debug)]
204pub struct Request {
205 pub body : String,
207}
208
209#[derive(Deserialize, Debug)]
210#[serde(rename_all = "camelCase")]
211pub struct Response {
212 pub status_code : i64,
214 pub body : String,
216}
217
218#[derive(Deserialize, Debug)]
219pub struct LogsResponseLinks {
220 pub prev : Option<String>,
222 pub next : Option<String>,
224}
225
226
227#[derive(Default)]
230pub struct ListWebhooksOptions {
231 page_size : Option<u8>,
233}
234
235impl ListWebhooksOptions {
236 pub fn page_size(&mut self, value : u8) {
238 self.page_size = Some(value);
239 }
240
241 fn add_params(&self, url : &mut reqwest::Url) {
242 let mut query = String::new();
243
244 if let Some(value) = &self.page_size {
245 if !query.is_empty() {
246 query.push('&');
247 }
248 query.push_str(&format!("page[size]={}", value));
249 }
250
251 if !query.is_empty() {
252 url.set_query(Some(&query));
253 }
254 }
255}
256
257#[derive(Default)]
258pub struct ListWebhookLogsOptions {
259 page_size : Option<u8>,
261}
262
263impl ListWebhookLogsOptions {
264 pub fn page_size(&mut self, value : u8) {
266 self.page_size = Some(value);
267 }
268
269 fn add_params(&self, url : &mut reqwest::Url) {
270 let mut query = String::new();
271
272 if let Some(value) = &self.page_size {
273 if !query.is_empty() {
274 query.push('&');
275 }
276 query.push_str(&format!("page[size]={}", value));
277 }
278
279 if !query.is_empty() {
280 url.set_query(Some(&query));
281 }
282 }
283}
284
285#[derive(Serialize)]
288pub struct CreateWebhookRequest {
289 pub data : WebhookInputResource,
291}
292
293#[derive(Serialize)]
294pub struct WebhookInputResource {
295 pub attributes : InputAttributes,
296}
297
298#[derive(Serialize)]
299pub struct InputAttributes {
300 pub url : String,
302 pub description : Option<String>,
304}
305
306impl Client {
307 pub async fn list_webhooks(&self, options : &ListWebhooksOptions) -> Result<ListWebhooksResponse, error::Error> {
309 let mut url = reqwest::Url::parse(&format!("{}/webhooks", BASE_URL)).map_err(error::Error::UrlParse)?;
310 options.add_params(&mut url);
311
312 let res = reqwest::Client::new()
313 .get(url)
314 .header("Authorization", self.auth_header())
315 .send()
316 .await
317 .map_err(error::Error::Request)?;
318
319 match res.status() {
320 reqwest::StatusCode::OK => {
321 let body = res.text().await.map_err(error::Error::BodyRead)?;
322 let webhook_response : ListWebhooksResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
323
324 Ok(webhook_response)
325 },
326 _ => {
327 let body = res.text().await.map_err(error::Error::BodyRead)?;
328 let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
329
330 Err(error::Error::Api(error))
331 }
332 }
333 }
334
335 pub async fn get_webhook(&self, id : &str) -> Result<GetWebhookResponse, error::Error> {
337 if id.is_empty() {
340 panic!("The provided webhook ID must not be empty.");
341 }
342
343 let url = reqwest::Url::parse(&format!("{}/webhooks/{}", BASE_URL, id)).map_err(error::Error::UrlParse)?;
344
345 let res = reqwest::Client::new()
346 .get(url)
347 .header("Authorization", self.auth_header())
348 .send()
349 .await
350 .map_err(error::Error::Request)?;
351
352 match res.status() {
353 reqwest::StatusCode::OK => {
354 let body = res.text().await.map_err(error::Error::BodyRead)?;
355 let webhook_response : GetWebhookResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
356
357 Ok(webhook_response)
358 },
359 _ => {
360 let body = res.text().await.map_err(error::Error::BodyRead)?;
361 let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
362
363 Err(error::Error::Api(error))
364 }
365 }
366 }
367
368 pub async fn create_webhook(&self, webhook_url : &str, description : Option<String>) -> Result<CreateWebhookResponse, error::Error> {
373 let url = reqwest::Url::parse(&format!("{}/webhooks", BASE_URL)).map_err(error::Error::UrlParse)?;
374
375 let body = CreateWebhookRequest {
376 data : WebhookInputResource {
377 attributes : InputAttributes { url : String::from(webhook_url), description }
378 }
379 };
380
381 let body = serde_json::to_string(&body).map_err(error::Error::Serialize)?;
382
383 let res = reqwest::Client::new()
384 .post(url)
385 .header("Authorization", self.auth_header())
386 .header("Content-Type", "application/json")
387 .body(body)
388 .send()
389 .await
390 .map_err(error::Error::Request)?;
391
392 match res.status() {
393 reqwest::StatusCode::CREATED => {
394 let body = res.text().await.map_err(error::Error::BodyRead)?;
395 let webhook_response : CreateWebhookResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
396
397 Ok(webhook_response)
398 },
399 _ => {
400 let body = res.text().await.map_err(error::Error::BodyRead)?;
401 let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
402
403 Err(error::Error::Api(error))
404 }
405 }
406 }
407
408 pub async fn delete_webhook(&self, id : &str) -> Result<(), error::Error> {
410 let url = reqwest::Url::parse(&format!("{}/webhooks/{}", BASE_URL, id)).map_err(error::Error::UrlParse)?;
411
412 let res = reqwest::Client::new()
413 .delete(url)
414 .header("Authorization", self.auth_header())
415 .send()
416 .await
417 .map_err(error::Error::Request)?;
418
419 match res.status() {
420 reqwest::StatusCode::NO_CONTENT => {
421 Ok(())
422 },
423 _ => {
424 let body = res.text().await.map_err(error::Error::BodyRead)?;
425 let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
426
427 Err(error::Error::Api(error))
428 }
429 }
430 }
431
432 pub async fn ping_webhook(&self, id : &str) -> Result<PingWebhookResponse, error::Error> {
434 let url = reqwest::Url::parse(&format!("{}/webhooks/{}/ping", BASE_URL, id)).map_err(error::Error::UrlParse)?;
435
436 let res = reqwest::Client::new()
437 .post(url)
438 .header("Authorization", self.auth_header())
439 .header("Content-Type", "application/json")
440 .header("Content-Length", "0")
441 .send()
442 .await
443 .map_err(error::Error::Request)?;
444
445 match res.status() {
446 reqwest::StatusCode::CREATED => {
447 let body = res.text().await.map_err(error::Error::BodyRead)?;
448 let webhook_response : PingWebhookResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
449
450 Ok(webhook_response)
451 },
452 _ => {
453 let body = res.text().await.map_err(error::Error::BodyRead)?;
454 let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
455
456 Err(error::Error::Api(error))
457 }
458 }
459 }
460
461 pub async fn list_webhook_logs(&self, id : &str, options : &ListWebhookLogsOptions) -> Result<ListWebhookLogsResponse, error::Error> {
463 let mut url = reqwest::Url::parse(&format!("{}/webhooks/{}/logs", BASE_URL, id)).map_err(error::Error::UrlParse)?;
464 options.add_params(&mut url);
465
466 let res = reqwest::Client::new()
467 .get(url)
468 .header("Authorization", self.auth_header())
469 .send()
470 .await
471 .map_err(error::Error::Request)?;
472
473 match res.status() {
474 reqwest::StatusCode::OK => {
475 let body = res.text().await.map_err(error::Error::BodyRead)?;
476 let webhook_response : ListWebhookLogsResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
477
478 Ok(webhook_response)
479 },
480 _ => {
481 let body = res.text().await.map_err(error::Error::BodyRead)?;
482 let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
483
484 Err(error::Error::Api(error))
485 }
486 }
487 }
488}
489
490implement_pagination_v1!(ListWebhooksResponse);