lnbits_rs/api/
invoice.rs

1//! Invoice related api
2
3use anyhow::{bail, Result};
4use serde::{Deserialize, Serialize};
5
6use super::LNBitsEndpoint;
7
8/// Create invoice response
9#[derive(Debug, Deserialize)]
10pub struct CreateInvoiceResponse {
11    /// Payment hash
12    payment_hash: String,
13    /// Bolt11
14    bolt11: String,
15}
16
17impl CreateInvoiceResponse {
18    /// Payment hash
19    pub fn payment_hash(&self) -> &str {
20        &self.payment_hash
21    }
22
23    /// Get bolt11 from response
24    pub fn bolt11(&self) -> &str {
25        &self.bolt11
26    }
27}
28
29/// Pay invoice response
30#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize)]
31pub struct PayInvoiceResponse {
32    /// Payment hash
33    pub payment_hash: String,
34}
35
36/// Create invoice request
37#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
38pub struct CreateInvoiceRequest {
39    /// Amount (sat)
40    pub amount: u64,
41    /// Unit
42    pub unit: String,
43    /// Memo
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub memo: Option<String>,
46    /// Expiry is in seconds
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub expiry: Option<u64>,
49    /// Internal payment
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub internal: Option<bool>,
52    /// Incoming or outgoing payment
53    pub out: bool,
54}
55
56/// Decode invoice response
57#[derive(Debug, Clone, PartialEq, Deserialize)]
58pub struct DecodeInvoiceResponse {
59    /// Payment hash
60    pub payment_hash: String,
61    /// Amount (msat)
62    pub amount_msat: i64,
63    /// Description
64    pub description: String,
65    /// Description hash
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub description_hash: Option<String>,
68    /// Payee
69    pub payee: String,
70    /// Date
71    pub date: i64,
72    /// Expiry
73    pub expiry: f64,
74    /// Secret
75    pub secret: String,
76    /// Route hints
77    pub route_hints: Vec<String>,
78    /// Mint final cltx expiry
79    pub min_final_cltv_expiry: i64,
80}
81
82impl crate::LNBitsClient {
83    /// Create an invoice
84    pub async fn create_invoice(
85        &self,
86        params: &CreateInvoiceRequest,
87    ) -> Result<CreateInvoiceResponse> {
88        let body = self
89            .make_post(
90                LNBitsEndpoint::Payments,
91                crate::api::LNBitsRequestKey::InvoiceRead,
92                &serde_json::to_string(&params)?,
93            )
94            .await?;
95
96        match serde_json::from_str(&body) {
97            Ok(res) => Ok(res),
98            Err(_) => {
99                log::error!("Api error response on invoice creation");
100                log::error!("{}", body);
101                bail!("Could not create invoice")
102            }
103        }
104    }
105
106    /// Pay an invoice
107    pub async fn pay_invoice(
108        &self,
109        bolt11: &str,
110        _amount_sats: Option<u64>,
111    ) -> Result<PayInvoiceResponse> {
112        let body = self
113            .make_post(
114                LNBitsEndpoint::Payments,
115                crate::api::LNBitsRequestKey::Admin,
116                &serde_json::to_string(&serde_json::json!({ "out": true, "bolt11": bolt11 }))?,
117            )
118            .await?;
119
120        match serde_json::from_str(&body) {
121            Ok(res) => Ok(res),
122            Err(_) => {
123                log::error!("Api error response on paying invoice");
124                log::error!("{}", body);
125                bail!("Could not pay invoice")
126            }
127        }
128    }
129
130    /// Decode invoice
131    pub async fn decode_invoice(&self, invoice: &str) -> Result<DecodeInvoiceResponse> {
132        let body = self
133            .make_post(
134                LNBitsEndpoint::PaymentsDecode,
135                crate::api::LNBitsRequestKey::Admin,
136                &serde_json::to_string(&serde_json::json!({ "data": invoice }))?,
137            )
138            .await?;
139
140        match serde_json::from_str(&body) {
141            Ok(res) => Ok(res),
142            Err(_) => {
143                log::error!("Api error response decode invoice");
144                log::error!("{}", body);
145                bail!("Could not decode invoice")
146            }
147        }
148    }
149
150    /// Check if invoice paid
151    pub async fn is_invoice_paid(&self, payment_hash: &str) -> Result<bool> {
152        let body = self
153            .make_get(
154                LNBitsEndpoint::PaymentHash(payment_hash.to_string()),
155                crate::api::LNBitsRequestKey::Admin,
156            )
157            .await?;
158
159        let invoice_result: serde_json::Value = serde_json::from_str(&body)?;
160        Ok(invoice_result["paid"].as_bool().unwrap_or(false))
161    }
162}