lnbits_rs/api/
payment.rs

1//! Payments
2
3use anyhow::Result;
4use chrono::{TimeZone, Utc};
5use serde::{Deserialize, Deserializer};
6
7use super::LNBitsEndpoint;
8
9/// Payment details
10#[derive(Debug, Deserialize)]
11pub struct PaymentDetails {
12    /// Payment status
13    pub status: String,
14    /// Checking id
15    pub checking_id: String,
16    /// Amount
17    pub amount: i64,
18    /// Fee
19    pub fee: i64,
20    /// Memo
21    pub memo: String,
22    /// Time
23    #[serde(deserialize_with = "deserialize_time")]
24    pub time: String,
25    /// Created at
26    #[serde(deserialize_with = "deserialize_time")]
27    pub created_at: String,
28    /// Updated at
29    #[serde(deserialize_with = "deserialize_time")]
30    pub updated_at: String,
31    /// BOLT11
32    pub bolt11: String,
33    /// Preimage
34    pub preimage: Option<String>,
35    /// Payment hash
36    pub payment_hash: String,
37    /// Expiry
38    #[serde(deserialize_with = "deserialize_time")]
39    pub expiry: String,
40    /// Extra
41    pub extra: serde_json::Value,
42    /// Wallet id
43    pub wallet_id: String,
44}
45
46/// Custom deserializer for time field that can handle both u64 and string
47/// formats
48fn deserialize_time<'de, D>(deserializer: D) -> Result<String, D::Error>
49where
50    D: Deserializer<'de>,
51{
52    #[derive(Deserialize)]
53    #[serde(untagged)]
54    enum TimeValue {
55        Unix(u64),
56        String(String),
57    }
58
59    let time_value = TimeValue::deserialize(deserializer)?;
60
61    match time_value {
62        TimeValue::Unix(timestamp) => {
63            // Convert Unix timestamp (seconds since epoch) to DateTime<Utc>
64            let datetime = Utc
65                .timestamp_opt(timestamp as i64, 0)
66                .single()
67                .ok_or_else(|| serde::de::Error::custom("Invalid timestamp"))?;
68
69            // Format the datetime as an ISO 8601 string
70            Ok(datetime.to_rfc3339())
71        }
72        TimeValue::String(s) => Ok(s),
73    }
74}
75
76/// Payment
77#[derive(Debug, Deserialize)]
78pub struct Payment {
79    /// Paid
80    pub paid: bool,
81    /// Preimage
82    pub preimage: Option<String>,
83    /// Details
84    pub details: PaymentDetails,
85}
86
87impl crate::LNBitsClient {
88    /// Check if invoice paid
89    pub async fn get_payment_info(&self, payment_hash: &str) -> Result<Payment> {
90        let body = self
91            .make_get(
92                LNBitsEndpoint::PaymentHash(payment_hash.to_string()),
93                crate::api::LNBitsRequestKey::Admin,
94            )
95            .await?;
96
97        let payment: Payment = serde_json::from_str(&body)?;
98
99        Ok(payment)
100    }
101}