1use crate::BlocktankError;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
5#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
6pub enum BitcoinNetworkEnum {
7 #[serde(rename = "mainnet")]
8 Mainnet,
9 #[serde(rename = "testnet")]
10 Testnet,
11 #[serde(rename = "signet")]
12 Signet,
13 #[serde(rename = "regtest")]
14 Regtest,
15}
16
17#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
18pub enum BtBolt11InvoiceState {
19 #[serde(rename = "pending")]
21 Pending,
22 #[serde(rename = "holding")]
24 Holding,
25 #[serde(rename = "paid")]
27 Paid,
28 #[serde(rename = "canceled")]
30 Canceled,
31}
32
33#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
34pub enum BtChannelOrderErrorType {
35 #[serde(rename = "WRONG_ORDER_STATE")]
37 WrongOrderState,
38 #[serde(rename = "PEER_NOT_REACHABLE")]
40 PeerNotReachable,
41 #[serde(rename = "CHANNEL_REJECTED_BY_DESTINATION")]
43 ChannelRejectedByDestination,
44 #[serde(rename = "CHANNEL_REJECTED_BY_LSP")]
46 ChannelRejectedByLsp,
47 #[serde(rename = "BLOCKTANK_NOT_READY")]
49 BlocktankNotReady,
50}
51
52#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
53pub enum BtOpenChannelState {
54 #[serde(rename = "opening")]
56 Opening,
57 #[serde(rename = "open")]
59 Open,
60 #[serde(rename = "closed")]
62 Closed,
63}
64
65#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
67pub enum BtOrderState {
68 #[serde(rename = "created")]
69 Created,
70 #[serde(rename = "expired")]
72 Expired,
73 #[serde(rename = "open")]
74 Open,
75 #[serde(rename = "closed")]
76 Closed,
77}
78
79#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
80pub enum BtOrderState2 {
81 #[serde(rename = "created")]
83 Created,
84 #[serde(rename = "expired")]
86 Expired,
87 #[serde(rename = "executed")]
89 Executed,
90 #[serde(rename = "paid")]
92 Paid,
93}
94
95#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
97pub enum BtPaymentState {
98 #[serde(rename = "created")]
100 Created,
101 #[serde(rename = "partiallyPaid")]
103 PartiallyPaid,
104 #[serde(rename = "paid")]
106 Paid,
107 #[serde(rename = "refunded")]
109 Refunded,
110 #[serde(rename = "refundAvailable")]
112 RefundAvailable,
113}
114
115#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
116pub enum BtPaymentState2 {
117 #[serde(rename = "created")]
119 Created,
120 #[serde(rename = "paid")]
122 Paid,
123 #[serde(rename = "refunded")]
125 Refunded,
126 #[serde(rename = "refundAvailable")]
128 RefundAvailable,
129 #[serde(rename = "canceled")]
131 Canceled,
132}
133
134#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
135pub enum CJitStateEnum {
136 #[serde(rename = "created")]
138 Created,
139 #[serde(rename = "completed")]
141 Completed,
142 #[serde(rename = "expired")]
144 Expired,
145 #[serde(rename = "failed")]
147 Failed,
148}
149
150#[derive(Debug, Serialize, Deserialize, Clone)]
151#[serde(rename_all = "camelCase")]
152pub struct IBt0ConfMinTxFeeWindow {
153 #[serde(rename = "satPerVByte")]
155 pub sat_per_vbyte: f64,
156 pub validity_ends_at: String,
158}
159
160#[derive(Debug, Serialize, Deserialize, Clone)]
161#[serde(rename_all = "camelCase")]
162pub struct IBtBolt11Invoice {
163 pub request: String,
164 pub state: BtBolt11InvoiceState,
165 pub expires_at: String,
166 pub updated_at: String,
167}
168
169#[derive(Debug, Serialize, Deserialize, Clone)]
170#[serde(rename_all = "camelCase")]
171pub struct FundingTx {
172 pub id: String,
173 pub vout: u64,
174}
175
176#[derive(Debug, Serialize, Deserialize, Clone)]
177#[serde(rename_all = "camelCase")]
178pub struct IBtChannel {
179 pub state: BtOpenChannelState,
180 pub lsp_node_pubkey: String,
181 pub client_node_pubkey: String,
182 pub announce_channel: bool,
183 pub funding_tx: FundingTx,
184 pub closing_tx_id: Option<String>,
186 pub close: Option<IBtChannelClose>,
188 pub short_channel_id: Option<String>,
190}
191
192#[derive(Debug, Serialize, Deserialize, Clone)]
193#[serde(rename_all = "camelCase")]
194pub struct IBtChannelClose {
195 pub tx_id: String,
197 #[serde(rename = "type")]
199 pub close_type: String, pub initiator: String, pub registered_at: String,
204}
205
206#[derive(Debug, Serialize, Deserialize, Clone)]
207#[serde(rename_all = "camelCase")]
208pub struct IBtEstimateFeeResponse {
209 pub fee_sat: u64,
210 #[serde(rename = "min0ConfTxFee")]
211 pub min_0_conf_tx_fee: IBt0ConfMinTxFeeWindow,
212}
213
214#[derive(Debug, Serialize, Deserialize, Clone)]
215#[serde(rename_all = "camelCase")]
216pub struct IBtEstimateFeeResponse2 {
217 pub fee_sat: u64,
219 pub network_fee_sat: u64,
221 pub service_fee_sat: u64,
223 #[serde(rename = "min0ConfTxFee")]
224 pub min_0_conf_tx_fee: IBt0ConfMinTxFeeWindow,
225}
226
227#[derive(Debug, Serialize, Deserialize, Clone)]
228#[serde(rename_all = "camelCase")]
229pub struct IBtInfoOptions {
230 pub min_channel_size_sat: u64,
232 pub max_channel_size_sat: u64,
234 pub min_expiry_weeks: u32,
236 pub max_expiry_weeks: u32,
238 pub min_payment_confirmations: u32,
240 pub min_high_risk_payment_confirmations: u32,
242 pub max_0_conf_client_balance_sat: u64,
244 pub max_client_balance_sat: u64,
246}
247
248#[derive(Debug, Serialize, Deserialize, Clone)]
249pub struct IBtInfoVersions {
250 pub http: String,
252 pub btc: String,
254 pub ln2: String,
256}
257
258#[derive(Debug, Serialize, Deserialize, Clone)]
259pub struct FeeRates {
260 pub fast: u32,
262 pub mid: u32,
264 pub slow: u32,
266}
267
268#[derive(Debug, Serialize, Deserialize, Clone)]
269#[serde(rename_all = "camelCase")]
270pub struct IBtInfoOnchain {
271 pub network: BitcoinNetworkEnum,
272 pub fee_rates: FeeRates,
273}
274
275#[derive(Debug, Serialize, Deserialize, Clone)]
276pub struct IBtInfo {
277 pub version: u32,
279 pub nodes: Vec<ILspNode>,
281 pub options: IBtInfoOptions,
282 pub versions: IBtInfoVersions,
284 pub onchain: IBtInfoOnchain,
285}
286
287#[derive(Debug, Serialize, Deserialize, Clone)]
288#[serde(rename_all = "camelCase")]
289pub struct IBtOnchainTransaction {
290 pub amount_sat: u64,
291 pub tx_id: String,
292 pub vout: u32,
293 pub block_height: Option<u32>,
294 pub block_confirmation_count: u32,
295 #[serde(rename = "feeRateSatPerVbyte")]
296 pub fee_rate_sat_per_vbyte: f64,
297 pub confirmed: bool,
298 #[serde(rename = "suspicious0ConfReason")]
299 pub suspicious_0_conf_reason: String,
300}
301
302#[derive(Debug, Serialize, Deserialize, Clone)]
303#[serde(rename_all = "camelCase")]
304pub struct IBtOnchainTransactions {
305 pub address: String,
306 pub confirmed_sat: u64,
307 pub required_confirmations: u32,
308 pub transactions: Vec<IBtOnchainTransaction>,
309}
310
311#[derive(Debug, Serialize, Deserialize, Clone)]
312#[serde(rename_all = "camelCase")]
313pub struct IBtOrder {
314 pub id: String,
315 pub state: BtOrderState,
317 pub state2: Option<BtOrderState2>,
319 pub fee_sat: u64,
321 pub network_fee_sat: u64,
324 pub service_fee_sat: u64,
326 pub lsp_balance_sat: u64,
327 pub client_balance_sat: u64,
329 #[serde(rename = "zeroConf")]
331 pub zero_conf: bool,
332 pub zero_reserve: bool,
334 pub client_node_id: Option<String>,
336 pub channel_expiry_weeks: u32,
338 pub channel_expires_at: String,
340 pub order_expires_at: String,
342 pub channel: Option<IBtChannel>,
344 pub lsp_node: Option<ILspNode>,
346 pub lnurl: Option<String>,
348 pub payment: Option<IBtPayment>,
350 pub coupon_code: Option<String>,
352 pub source: Option<String>,
354 pub discount: Option<IDiscount>,
356 pub updated_at: String,
357 pub created_at: String,
358}
359
360#[derive(Debug, Serialize, Deserialize, Clone)]
361#[serde(rename_all = "camelCase")]
362pub struct IBtPayment {
363 pub state: BtPaymentState,
365 pub state2: Option<BtPaymentState2>,
366 pub paid_sat: u64,
367 pub bolt11_invoice: Option<IBtBolt11Invoice>,
368 pub onchain: Option<IBtOnchainTransactions>,
369 pub is_manually_paid: Option<bool>,
371 pub manual_refunds: Option<Vec<IManualRefund>>,
373}
374
375#[derive(Debug, Serialize, Deserialize, Clone)]
376#[serde(rename_all = "camelCase")]
377pub struct ICJitEntry {
378 pub id: String,
380 pub state: CJitStateEnum,
382 pub fee_sat: u64,
384 pub network_fee_sat: u64,
387 pub service_fee_sat: u64,
389 pub channel_size_sat: u64,
391 pub channel_expiry_weeks: u32,
393 pub channel_open_error: Option<String>,
395 pub node_id: String,
397 pub invoice: IBtBolt11Invoice,
399 pub channel: Option<IBtChannel>,
401 pub lsp_node: ILspNode,
403 pub coupon_code: String,
405 pub source: Option<String>,
407 pub discount: Option<IDiscount>,
409 pub expires_at: String,
411 pub updated_at: String,
412 pub created_at: String,
413}
414
415#[derive(Debug, Serialize, Deserialize, Clone)]
416#[serde(rename_all = "camelCase")]
417pub struct IDiscount {
418 pub code: String,
420 pub absolute_sat: u64,
422 pub relative: f64,
424 pub overall_sat: u64,
426}
427
428#[derive(Debug, Serialize, Deserialize, Clone)]
429#[serde(rename_all = "camelCase")]
430pub struct ILspNode {
431 pub alias: String,
432 pub pubkey: String,
433 pub connection_strings: Vec<String>,
434 pub readonly: Option<bool>,
435}
436
437#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
438pub enum ManualRefundStateEnum {
439 #[serde(rename = "CREATED")]
440 Created,
441 #[serde(rename = "APPROVED")]
442 Approved,
443 #[serde(rename = "REJECTED")]
444 Rejected,
445 #[serde(rename = "SENT")]
446 Sent,
447}
448
449#[derive(Debug, Serialize, Deserialize, Clone)]
450#[serde(rename_all = "camelCase")]
451pub struct IManualRefund {
452 pub amount_sat: u64,
453 pub target: String,
454 pub state: ManualRefundStateEnum,
455 pub created_by_name: String,
456 pub voted_by_name: Option<String>,
457 pub reason: Option<String>,
458 #[serde(rename = "targetType")]
459 pub target_type: String, }
461
462#[derive(Debug, Serialize, Deserialize, Clone)]
463#[serde(rename_all = "camelCase")]
464pub struct CreateOrderOptions {
465 pub client_balance_sat: u64,
468
469 pub lsp_node_id: Option<String>,
472
473 pub coupon_code: String,
475
476 pub source: Option<String>,
478
479 pub discount_code: Option<String>,
481
482 pub zero_conf: bool,
484
485 pub zero_conf_payment: Option<bool>,
487
488 pub zero_reserve: bool,
490
491 pub client_node_id: Option<String>,
497
498 pub timestamp: Option<String>,
500
501 pub signature: Option<String>,
503
504 pub refund_onchain_address: Option<String>,
506
507 pub announce_channel: bool,
509}
510
511impl Default for CreateOrderOptions {
513 fn default() -> Self {
514 Self {
515 client_balance_sat: 0,
516 lsp_node_id: None,
517 coupon_code: String::new(),
518 source: None,
519 discount_code: None,
520 zero_conf: false,
521 zero_conf_payment: None,
522 zero_reserve: false,
523 client_node_id: None,
524 timestamp: None,
525 signature: None,
526 refund_onchain_address: None,
527 announce_channel: false,
528 }
529 }
530}
531
532#[derive(Debug, Serialize, Deserialize, Clone)]
533#[serde(rename_all = "camelCase")]
534pub struct CreateCjitOptions {
535 pub source: Option<String>,
537
538 pub discount_code: Option<String>,
540}
541
542impl Default for CreateCjitOptions {
544 fn default() -> Self {
545 Self {
546 source: None,
547 discount_code: None,
548 }
549 }
550}
551
552impl std::str::FromStr for BtOrderState2 {
553 type Err = BlocktankError;
554
555 fn from_str(s: &str) -> Result<Self, Self::Err> {
556 match s {
557 "Created" => Ok(BtOrderState2::Created),
558 "Expired" => Ok(BtOrderState2::Expired),
559 "Executed" => Ok(BtOrderState2::Executed),
560 "Paid" => Ok(BtOrderState2::Paid),
561 _ => Err(BlocktankError::DataError {
562 error_details: format!("Invalid BtOrderState2 value: {}", s),
563 }),
564 }
565 }
566}
567
568impl std::str::FromStr for BtOrderState {
569 type Err = BlocktankError;
570
571 fn from_str(s: &str) -> Result<Self, Self::Err> {
572 match s {
573 "Created" => Ok(BtOrderState::Created),
574 "Expired" => Ok(BtOrderState::Expired),
575 "Open" => Ok(BtOrderState::Open),
576 "Closed" => Ok(BtOrderState::Closed),
577 _ => Err(BlocktankError::DataError {
578 error_details: format!("Invalid BtOrderState value: {}", s),
579 }),
580 }
581 }
582}
583
584impl std::str::FromStr for CJitStateEnum {
585 type Err = BlocktankError;
586
587 fn from_str(s: &str) -> Result<Self, Self::Err> {
588 match s {
589 "Created" => Ok(CJitStateEnum::Created),
590 "Completed" => Ok(CJitStateEnum::Completed),
591 "Expired" => Ok(CJitStateEnum::Expired),
592 "Failed" => Ok(CJitStateEnum::Failed),
593 _ => Err(BlocktankError::DataError {
594 error_details: format!("Invalid CJitStateEnum value: {}", s),
595 }),
596 }
597 }
598}
599
600#[derive(Debug, Deserialize)]
601pub struct ApiValidationError {
602 #[serde(rename = "type")]
603 error_type: String,
604 pub(crate) errors: ApiErrorDetails,
605}
606
607#[derive(Debug, Deserialize)]
608pub struct ApiErrorDetails {
609 pub(crate) issues: Vec<ApiErrorIssue>,
610 name: String,
611}
612
613#[derive(Debug, Deserialize)]
614pub struct ApiErrorIssue {
615 code: String,
616 pub(crate) message: String,
617 path: Vec<String>,
618}
619
620#[derive(Debug, Serialize, Deserialize, Clone)]
621#[serde(rename_all = "camelCase")]
622pub struct IGiftCode {
623 pub id: String,
624 pub code: String,
625 #[serde(skip_serializing_if = "Option::is_none")]
626 pub scope: Option<String>,
627 #[serde(skip_serializing_if = "Option::is_none")]
628 pub expires_at: Option<String>,
629 #[serde(skip_serializing_if = "Option::is_none")]
630 pub gift_sat: Option<u64>,
631 #[serde(skip_serializing_if = "Option::is_none")]
632 pub max_count: Option<u32>,
633 #[serde(skip_serializing_if = "Option::is_none")]
634 pub updated_at: Option<String>,
635 #[serde(skip_serializing_if = "Option::is_none")]
636 pub created_at: Option<String>,
637}
638
639#[derive(Debug, Serialize, Deserialize, Clone)]
640#[serde(rename_all = "camelCase")]
641pub struct IGiftBtcAddress {
642 pub id: String,
643 pub address: String,
644 #[serde(default)]
645 pub transactions: Vec<serde_json::Value>,
646 #[serde(default)]
647 pub all_transactions: Vec<serde_json::Value>,
648 #[serde(skip_serializing_if = "Option::is_none")]
649 pub is_blacklisted: Option<bool>,
650 #[serde(skip_serializing_if = "Option::is_none")]
651 pub watch_until: Option<String>,
652 #[serde(skip_serializing_if = "Option::is_none")]
653 pub watch_for_block_confirmations: Option<u32>,
654 #[serde(skip_serializing_if = "Option::is_none")]
655 pub updated_at: Option<String>,
656 #[serde(skip_serializing_if = "Option::is_none")]
657 pub created_at: Option<String>,
658}
659
660#[derive(Debug, Serialize, Deserialize, Clone)]
661#[serde(rename_all = "camelCase")]
662pub struct IGiftBolt11Invoice {
663 pub id: String,
664 pub request: String,
665 pub state: String,
666 #[serde(skip_serializing_if = "Option::is_none")]
667 pub is_hodl_invoice: Option<bool>,
668 #[serde(skip_serializing_if = "Option::is_none")]
669 pub payment_hash: Option<String>,
670 #[serde(skip_serializing_if = "Option::is_none")]
671 pub amount_sat: Option<u64>,
672 #[serde(skip_serializing_if = "Option::is_none")]
673 pub amount_msat: Option<String>,
674 #[serde(skip_serializing_if = "Option::is_none")]
675 pub internal_node_pubkey: Option<String>,
676 #[serde(skip_serializing_if = "Option::is_none")]
677 pub updated_at: Option<String>,
678 #[serde(skip_serializing_if = "Option::is_none")]
679 pub created_at: Option<String>,
680 #[serde(skip_serializing_if = "Option::is_none")]
681 pub expires_at: Option<String>,
682}
683
684#[derive(Debug, Serialize, Deserialize, Clone)]
685#[serde(rename_all = "camelCase")]
686pub struct IGiftPayment {
687 pub id: String,
688 pub state: String,
689 #[serde(skip_serializing_if = "Option::is_none")]
690 pub old_state: Option<String>,
691 #[serde(skip_serializing_if = "Option::is_none")]
692 pub onchain_state: Option<String>,
693 #[serde(skip_serializing_if = "Option::is_none")]
694 pub ln_state: Option<String>,
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub paid_onchain_sat: Option<u64>,
697 #[serde(skip_serializing_if = "Option::is_none")]
698 pub paid_ln_sat: Option<u64>,
699 #[serde(skip_serializing_if = "Option::is_none")]
700 pub paid_sat: Option<u64>,
701 #[serde(skip_serializing_if = "Option::is_none")]
702 pub is_overpaid: Option<bool>,
703 #[serde(skip_serializing_if = "Option::is_none")]
704 pub is_refunded: Option<bool>,
705 #[serde(skip_serializing_if = "Option::is_none")]
706 pub overpaid_amount_sat: Option<u64>,
707 #[serde(skip_serializing_if = "Option::is_none")]
708 pub required_onchain_confirmations: Option<u32>,
709 #[serde(skip_serializing_if = "Option::is_none")]
710 pub settlement_state: Option<String>,
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub expected_amount_sat: Option<u64>,
713 #[serde(skip_serializing_if = "Option::is_none")]
714 pub is_manually_paid: Option<bool>,
715 #[serde(skip_serializing_if = "Option::is_none")]
716 pub btc_address: Option<IGiftBtcAddress>,
717 #[serde(skip_serializing_if = "Option::is_none")]
718 pub btc_address_id: Option<String>,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 pub bolt11_invoice: Option<IGiftBolt11Invoice>,
721 #[serde(skip_serializing_if = "Option::is_none")]
722 pub bolt11_invoice_id: Option<String>,
723 #[serde(default)]
724 pub manual_refunds: Vec<serde_json::Value>,
725}
726
727#[derive(Debug, Serialize, Deserialize, Clone)]
728#[serde(rename_all = "camelCase")]
729pub struct IGiftLspNode {
730 pub alias: String,
731 pub pubkey: String,
732 pub connection_strings: Vec<String>,
733}
734
735#[derive(Debug, Serialize, Deserialize, Clone)]
736#[serde(rename_all = "camelCase")]
737pub struct IGiftOrder {
738 pub id: String,
739 pub state: String,
740 #[serde(skip_serializing_if = "Option::is_none")]
741 pub old_state: Option<String>,
742 #[serde(skip_serializing_if = "Option::is_none")]
743 pub is_channel_expired: Option<bool>,
744 #[serde(skip_serializing_if = "Option::is_none")]
745 pub is_order_expired: Option<bool>,
746 #[serde(skip_serializing_if = "Option::is_none")]
747 pub lsp_balance_sat: Option<u64>,
748 #[serde(skip_serializing_if = "Option::is_none")]
749 pub client_balance_sat: Option<u64>,
750 #[serde(skip_serializing_if = "Option::is_none")]
751 pub channel_expiry_weeks: Option<u32>,
752 #[serde(skip_serializing_if = "Option::is_none")]
753 pub zero_conf: Option<bool>,
754 #[serde(skip_serializing_if = "Option::is_none")]
755 pub zero_reserve: Option<bool>,
756 #[serde(skip_serializing_if = "Option::is_none")]
757 pub announced: Option<bool>,
758 #[serde(skip_serializing_if = "Option::is_none")]
759 pub client_node_id: Option<String>,
760 #[serde(skip_serializing_if = "Option::is_none")]
761 #[serde(rename = "channelExiresAt")]
762 pub channel_expires_at: Option<String>,
763 #[serde(skip_serializing_if = "Option::is_none")]
764 pub order_expires_at: Option<String>,
765 #[serde(skip_serializing_if = "Option::is_none")]
766 pub fee_sat: Option<u64>,
767 #[serde(skip_serializing_if = "Option::is_none")]
768 pub network_fee_sat: Option<u64>,
769 #[serde(skip_serializing_if = "Option::is_none")]
770 pub service_fee_sat: Option<u64>,
771 #[serde(skip_serializing_if = "Option::is_none")]
772 pub payment: Option<IGiftPayment>,
773 #[serde(skip_serializing_if = "Option::is_none")]
774 pub lsp_node: Option<IGiftLspNode>,
775 #[serde(skip_serializing_if = "Option::is_none")]
776 pub updated_at: Option<String>,
777 #[serde(skip_serializing_if = "Option::is_none")]
778 pub created_at: Option<String>,
779 #[serde(skip_serializing_if = "Option::is_none")]
780 pub node_id_verified: Option<bool>,
781}
782
783#[derive(Debug, Serialize, Deserialize, Clone)]
784#[serde(rename_all = "camelCase")]
785pub struct IGift {
786 pub id: String,
787 pub node_id: String,
788 #[serde(skip_serializing_if = "Option::is_none")]
789 pub order_id: Option<String>,
790 #[serde(skip_serializing_if = "Option::is_none")]
791 pub order: Option<IGiftOrder>,
792 #[serde(skip_serializing_if = "Option::is_none")]
793 pub bolt11_payment_id: Option<String>,
794 #[serde(skip_serializing_if = "Option::is_none")]
795 pub bolt11_payment: Option<IGiftPayment>,
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub applied_gift_code_id: Option<String>,
798 #[serde(skip_serializing_if = "Option::is_none")]
799 pub applied_gift_code: Option<IGiftCode>,
800 #[serde(skip_serializing_if = "Option::is_none")]
801 pub updated_at: Option<String>,
802 #[serde(skip_serializing_if = "Option::is_none")]
803 pub created_at: Option<String>,
804}