paddle_rust_sdk/
lib.rs

1//! # Paddle API Client
2//!
3//! This is a Rust client for the Paddle API, which allows you to interact with Paddle's services.
4
5use std::fmt::Display;
6
7use entities::{CustomerAuthenticationToken, TransactionInvoice};
8use reqwest::{header::CONTENT_TYPE, IntoUrl, Method, StatusCode, Url};
9use serde::{de::DeserializeOwned, Serialize};
10
11pub mod entities;
12pub mod enums;
13pub mod error;
14pub mod ids;
15
16pub mod addresses;
17pub mod businesses;
18pub mod customers;
19pub mod discounts;
20pub mod payment_methods;
21pub mod prices;
22pub mod products;
23pub mod subscriptions;
24pub mod transactions;
25
26pub mod response;
27
28use enums::{CountryCodeSupported, CurrencyCode, DiscountType, Disposition, TaxCategory};
29use ids::{
30    AddressID, BusinessID, CustomerID, DiscountID, PaymentMethodID, PriceID, ProductID,
31    TransactionID,
32};
33
34use response::{ErrorResponse, Response, SuccessResponse};
35
36use error::{Error, PaddleError};
37
38type Result<T> = std::result::Result<SuccessResponse<T>, Error>;
39
40/// Paddle API client
41///
42/// This struct is used to create a new Paddle client instance.
43#[derive(Clone, Debug)]
44pub struct Paddle {
45    base_url: Url,
46    api_key: String,
47}
48
49impl Paddle {
50    pub const PRODUCTION: &'static str = "https://api.paddle.com";
51    pub const SANDBOX: &'static str = "https://sandbox-api.paddle.com";
52
53    /// Creates a new Paddle client instance.
54    ///
55    /// Example:
56    /// ```
57    /// use paddle_rust_sdk::Paddle;
58    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
59    /// ```
60    #[allow(clippy::result_large_err)]
61    pub fn new(
62        api_key: impl Into<String>,
63        base_url: impl IntoUrl,
64    ) -> std::result::Result<Self, Error> {
65        Ok(Self {
66            base_url: base_url.into_url()?,
67            api_key: api_key.into(),
68        })
69    }
70
71    /// Returns a request builder for fetching products. Use the after method to page through results.
72    ///
73    /// By default, Paddle returns products that are active. Use the status method to return products that are archived.
74    /// Use the include method to include related price entities in the response.
75    ///
76    /// # Example:
77    /// ```
78    /// use paddle_rust_sdk::Paddle;
79    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
80    /// let products = client.products_list().send().await.unwrap();
81    /// ```
82    pub fn products_list(&self) -> products::ProductsList {
83        products::ProductsList::new(self)
84    }
85
86    /// Returns a request builder for creating a new product.
87    ///
88    /// # Example:
89    /// ```
90    /// use paddle_rust_sdk::Paddle;
91    /// use paddle_rust_sdk::enums::TaxCategory;
92    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
93    /// let product = client.products_create("My Product", TaxCategory::Standard).send().await.unwrap();
94    /// ```
95    pub fn product_create(
96        &self,
97        name: impl Into<String>,
98        tax_category: TaxCategory,
99    ) -> products::ProductCreate {
100        products::ProductCreate::new(self, name, tax_category)
101    }
102
103    /// Returns a request builder for fetching a specific product.
104    ///
105    /// # Example:
106    /// ```
107    /// use paddle_rust_sdk::Paddle;
108    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
109    /// let product = client.product_get("pro_01jqx9rd...").send().await.unwrap();
110    /// ```
111    pub fn product_get(&self, product_id: impl Into<ProductID>) -> products::ProductGet {
112        products::ProductGet::new(self, product_id)
113    }
114
115    /// Returns a request builder for updating a specific product.
116    ///
117    /// # Example:
118    /// ```
119    /// use paddle_rust_sdk::Paddle;
120    /// use paddle_rust_sdk::enums::TaxCategory;
121    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
122    /// let product = client.product_update("pro_01jqx9rd...").name("My New Name").send().await.unwrap();
123    /// ```
124    pub fn product_update(&self, product_id: impl Into<ProductID>) -> products::ProductUpdate {
125        products::ProductUpdate::new(self, product_id)
126    }
127
128    /// Returns a request builder listing prices
129    ///
130    /// # Example:
131    /// ```
132    /// use paddle_rust_sdk::Paddle;
133    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
134    /// let prices = client.prices_list().send().await.unwrap();
135    /// ```
136    pub fn prices_list(&self) -> prices::PricesList {
137        prices::PricesList::new(self)
138    }
139
140    /// Returns a request builder for creating a new price.
141    ///
142    /// * `product_id` - Paddle ID for the product that this price is for.
143    /// * `description` - Internal description for this price, not shown to customers. Typically notes for your team.
144    /// * `amount` - Amount of the price in the smallest unit of the currency (e.g. 1000 cents for 10 USD).
145    /// * `currency` - Currency code for the price. Use the [CurrencyCode] enum to specify the currency.
146    ///
147    /// # Example:
148    /// ```
149    /// use paddle_rust_sdk::Paddle;
150    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
151    /// let price = client.price_create("pro_01jqx9rd...", "Low price", 19.99, CurrencyCode::USD).send().await.unwrap();
152    /// ```
153    pub fn price_create(
154        &self,
155        product_id: impl Into<ProductID>,
156        description: impl Into<String>,
157        amount: u64,
158        currency: CurrencyCode,
159    ) -> prices::PricesCreate {
160        prices::PricesCreate::new(self, product_id, description, amount, currency)
161    }
162
163    /// Returns a request builder for fetching a specific price by id.
164    ///
165    /// # Example:
166    /// ```
167    /// use paddle_rust_sdk::Paddle;
168    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
169    /// let price = client.price_get("price_01jqx9rd...").send().await.unwrap();
170    /// ```
171    pub fn price_get(&self, price_id: impl Into<PriceID>) -> prices::PriceGet {
172        prices::PriceGet::new(self, price_id)
173    }
174
175    /// Returns a request builder for updating a specific price.
176    ///
177    /// # Example:
178    /// ```
179    /// use paddle_rust_sdk::Paddle;
180    /// use paddle_rust_sdk::enums::TaxCategory;
181    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
182    /// let price = client.price_update("pri_01jqxv...").name("Updated Name").send().await.unwrap();
183    /// ```
184    pub fn price_update(&self, price_id: impl Into<PriceID>) -> prices::PriceUpdate {
185        prices::PriceUpdate::new(self, price_id)
186    }
187
188    /// Returns a request builder for fetching discounts.
189    ///
190    /// # Example:
191    /// ```
192    /// use paddle_rust_sdk::Paddle;
193    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
194    /// let discounts = client.discounts_list().send().await.unwrap();
195    /// ```
196    pub fn discounts_list(&self) -> discounts::DiscountsList {
197        discounts::DiscountsList::new(self)
198    }
199
200    /// Returns a request builder for creating discounts.
201    ///
202    /// # Example:
203    /// ```
204    /// use paddle_rust_sdk::Paddle;
205    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
206    /// let discount = client.discount_create("15", "Winter Holidays", DiscountType::Percentage).send().await.unwrap();
207    /// ```
208    pub fn discount_create(
209        &self,
210        amount: impl Into<String>,
211        description: impl Into<String>,
212        discount_type: DiscountType,
213    ) -> discounts::DiscountCreate {
214        discounts::DiscountCreate::new(self, amount, description, discount_type)
215    }
216
217    /// Returns a request builder for fetching a specific discount by id.
218    ///
219    /// # Example:
220    /// ```
221    /// use paddle_rust_sdk::Paddle;
222    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
223    /// let discount = client.discount_get("dsc_01jqzpbmnq...").send().await.unwrap();
224    /// ```
225    pub fn discount_get(&self, discount_id: impl Into<DiscountID>) -> discounts::DiscountGet {
226        discounts::DiscountGet::new(self, discount_id)
227    }
228
229    /// Returns a request builder for creating discounts.
230    ///
231    /// # Example:
232    /// ```
233    /// use paddle_rust_sdk::Paddle;
234    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
235    /// let discount = client.discount_update("dsc_01jqzpbmnq...").amount("18").send().await.unwrap();
236    /// ```
237    pub fn discount_update(&self, discount_id: impl Into<DiscountID>) -> discounts::DiscountUpdate {
238        discounts::DiscountUpdate::new(self, discount_id)
239    }
240
241    /// Returns a request builder for fetching customers. Use the after method to page through results.
242    ///
243    /// By default, Paddle returns customers that are `active`. Use the status query parameter to return customers that are archived.
244    ///
245    /// # Example:
246    /// ```
247    /// use paddle_rust_sdk::Paddle;
248    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
249    /// let customers = client.customers_list().send().await.unwrap();
250    /// ```
251    pub fn customers_list(&self) -> customers::CustomersList {
252        customers::CustomersList::new(self)
253    }
254
255    /// Returns a request builder for creating a new customer.
256    ///
257    /// # Example:
258    /// ```
259    /// use paddle_rust_sdk::Paddle;
260    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
261    /// let customers = client.customer_create("test@example.com").send().await.unwrap();
262    /// ```
263    pub fn customer_create(&self, email: impl Into<String>) -> customers::CustomerCreate {
264        customers::CustomerCreate::new(self, email.into())
265    }
266
267    /// Returns a request builder for fetching a specific customer by id.
268    ///
269    /// # Example:
270    /// ```
271    /// use paddle_rust_sdk::Paddle;
272    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
273    /// let discount = client.customer_get("ctm_01jqztc78e1xfdgwhcgjzdrvgd").send().await.unwrap();
274    /// ```
275    pub fn customer_get(&self, customer_id: impl Into<CustomerID>) -> customers::CustomerGet {
276        customers::CustomerGet::new(self, customer_id)
277    }
278
279    /// Returns a request builder for updating customer data.
280    ///
281    /// # Example:
282    /// ```
283    /// use paddle_rust_sdk::Paddle;
284    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
285    /// let discount = client.customer_update("ctm_01jqztc78e1xfdgwhcgjzdrvgd").email("new_email@example.com").send().await.unwrap();
286    /// ```
287    pub fn customer_update(&self, customer_id: impl Into<CustomerID>) -> customers::CustomerUpdate {
288        customers::CustomerUpdate::new(self, customer_id)
289    }
290
291    /// Returns a request builder for fetching a list of credit balances for each currency for a customer.
292    ///
293    /// Each balance has three totals:
294    ///
295    /// * `available` - total available to use.
296    /// * `reserved` - total temporarily reserved for billed transactions.
297    /// * `used` - total amount of credit used.
298    ///
299    /// Credit is added to the available total initially. When used, it moves to the used total.
300    ///
301    /// The reserved total is used when a credit balance is applied to a transaction that's marked as billed, like when working with an issued invoice. It's not available for other transactions at this point, but isn't considered used until the transaction is completed. If a billed transaction is canceled, any reserved credit moves back to available.
302    ///
303    /// Credit balances are created automatically by Paddle when you take an action that results in Paddle creating a credit for a customer, like making prorated changes to a subscription. An empty data array is returned where a customer has no credit balances.
304    ///
305    /// The response is not paginated.
306    ///
307    /// # Example:
308    /// ```
309    /// use paddle_rust_sdk::Paddle;
310    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
311    /// let discount = client.customer_credit_balances("ctm_01jqztc78e1xfdgwhcgjzdrvgd").send().await.unwrap();
312    /// ```
313    pub fn customer_credit_balances(
314        &self,
315        customer_id: impl Into<CustomerID>,
316    ) -> customers::CustomerCreditBalances {
317        customers::CustomerCreditBalances::new(self, customer_id)
318    }
319
320    /// Generates an authentication token for a customer.
321    ///
322    /// You can pass a generated authentication token to Paddle.js when opening a checkout to let customers work with saved payment methods.
323    ///
324    /// Authentication tokens are temporary and shouldn't be cached. They're valid until the expires_at date returned in the response.
325    pub async fn generate_auth_token(
326        &self,
327        customer_id: impl Display,
328    ) -> Result<CustomerAuthenticationToken> {
329        let client = reqwest::Client::new();
330
331        let url = format!("{}customers/{}/auth-token", self.base_url, customer_id);
332
333        let res: Response<_> = client
334            .post(url)
335            .bearer_auth(self.api_key.clone())
336            .send()
337            .await?
338            .json()
339            .await?;
340
341        match res {
342            Response::Success(success) => Ok(success),
343            Response::Error(error) => Err(Error::Paddle(error)),
344        }
345    }
346
347    /// Returns a request builder for fetching customers addresses.
348    ///
349    /// By default, Paddle returns addresses that are `active`. Use the status query parameter to return addresses that are archived.
350    ///
351    /// # Example:
352    /// ```
353    /// use paddle_rust_sdk::Paddle;
354    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
355    /// let customers = client.addresses_list("ctm_01jqztc78e1xfdgwhcgjzdrvgd").send().await.unwrap();
356    /// ```
357    pub fn addresses_list(&self, customer_id: impl Into<CustomerID>) -> addresses::AddressesList {
358        addresses::AddressesList::new(self, customer_id)
359    }
360
361    /// Returns a request builder for creating a new customer address.
362    ///
363    /// # Example:
364    /// ```
365    /// use paddle_rust_sdk::Paddle;
366    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
367    /// let customers = client.address_create("ctm_01jqztc78e1xfdgwhcgjzdrvgd", CountryCodeSupported::US).send().await.unwrap();
368    /// ```
369    pub fn address_create(
370        &self,
371        customer_id: impl Into<CustomerID>,
372        country_code: CountryCodeSupported,
373    ) -> addresses::AddressCreate {
374        addresses::AddressCreate::new(self, customer_id, country_code)
375    }
376
377    /// Returns a request builder for getting an address for a customer using its ID and related customer ID.
378    ///
379    /// # Example:
380    /// ```
381    /// use paddle_rust_sdk::Paddle;
382    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
383    /// let customers = client.address_get("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "add_01hv8gwdfkw5z6d1yy6pa3xyrz").send().await.unwrap();
384    /// ```
385    pub fn address_get(
386        &self,
387        customer_id: impl Into<CustomerID>,
388        address_id: impl Into<AddressID>,
389    ) -> addresses::AddressGet {
390        addresses::AddressGet::new(self, customer_id, address_id)
391    }
392
393    /// Returns a request builder for updating an address for a customer using its ID and related customer ID.
394    ///
395    /// # Example:
396    /// ```
397    /// use paddle_rust_sdk::Paddle;
398    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
399    /// let customers = client.address_update("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "add_01hv8gwdfkw5z6d1yy6pa3xyrz").first_line("Test").send().await.unwrap();
400    /// ```
401    pub fn address_update(
402        &self,
403        customer_id: impl Into<CustomerID>,
404        address_id: impl Into<AddressID>,
405    ) -> addresses::AddressUpdate {
406        addresses::AddressUpdate::new(self, customer_id, address_id)
407    }
408
409    /// Returns a request builder for fetching customers businesses.
410    ///
411    /// By default, Paddle returns addresses that are `active`. Use the status query parameter to return businesses that are archived.
412    ///
413    /// # Example:
414    /// ```
415    /// use paddle_rust_sdk::Paddle;
416    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
417    /// let customers = client.businesses_list("ctm_01jqztc78e1xfdgwhcgjzdrvgd").send().await.unwrap();
418    /// ```
419    pub fn businesses_list(
420        &self,
421        customer_id: impl Into<CustomerID>,
422    ) -> businesses::BusinessesList {
423        businesses::BusinessesList::new(self, customer_id)
424    }
425
426    /// Returns a request builder for creating a new customer business.
427    ///
428    /// # Example:
429    /// ```
430    /// use paddle_rust_sdk::Paddle;
431    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
432    /// let customers = client.business_create("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "Company Inc.").send().await.unwrap();
433    /// ```
434    pub fn business_create(
435        &self,
436        customer_id: impl Into<CustomerID>,
437        name: impl Into<String>,
438    ) -> businesses::BusinessCreate {
439        businesses::BusinessCreate::new(self, customer_id, name)
440    }
441
442    /// Returns a request builder for getting a business for a customer using its ID and related customer ID.
443    ///
444    /// # Example:
445    /// ```
446    /// use paddle_rust_sdk::Paddle;
447    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
448    /// let customers = client.business_get("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "biz_01jr85bypq4d3w139m53zw2559").send().await.unwrap();
449    /// ```
450    pub fn business_get(
451        &self,
452        customer_id: impl Into<CustomerID>,
453        business_id: impl Into<BusinessID>,
454    ) -> businesses::BusinessGet {
455        businesses::BusinessGet::new(self, customer_id, business_id)
456    }
457
458    /// Returns a request builder for updating a business for a customer using its ID and related customer ID.
459    ///
460    /// # Example:
461    /// ```
462    /// use paddle_rust_sdk::Paddle;
463    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
464    /// let customers = client.business_update("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "biz_01jr85bypq4d3w139m53zw2559").first_line("Test").send().await.unwrap();
465    /// ```
466    pub fn business_update(
467        &self,
468        customer_id: impl Into<CustomerID>,
469        business_id: impl Into<BusinessID>,
470    ) -> businesses::BusinessUpdate {
471        businesses::BusinessUpdate::new(self, customer_id, business_id)
472    }
473
474    /// Returns a request builder for querying customer saved payment methods.
475    ///
476    /// # Example:
477    /// ```
478    /// use paddle_rust_sdk::Paddle;
479    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
480    /// let customers = client.payment_methods_list("ctm_01jqztc78e1xfdgwhcgjzdrvgd").send().await.unwrap();
481    /// ```
482    pub fn payment_methods_list(
483        &self,
484        customer_id: impl Into<CustomerID>,
485    ) -> payment_methods::PaymentMethodsList {
486        payment_methods::PaymentMethodsList::new(self, customer_id)
487    }
488
489    /// Returns a request builder for getting a saved payment for a customer using its ID and related customer ID.
490    ///
491    /// # Example:
492    /// ```
493    /// use paddle_rust_sdk::Paddle;
494    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
495    /// let customers = client.payment_method_get("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "paymtd_01j2jff1m3es31sdkejpaym164").send().await.unwrap();
496    /// ```
497    pub fn payment_method_get(
498        &self,
499        customer_id: impl Into<CustomerID>,
500        payment_method_id: impl Into<PaymentMethodID>,
501    ) -> payment_methods::PaymentMethodGet {
502        payment_methods::PaymentMethodGet::new(self, customer_id, payment_method_id)
503    }
504
505    /// Deletes a customer payment method using its ID.
506    ///
507    /// When you delete a customer payment method, it's permanently removed from that customer.
508    ///
509    /// There's no way to recover a deleted payment method.
510    ///
511    /// # Example:
512    /// ```
513    /// use paddle_rust_sdk::Paddle;
514    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
515    /// client.payment_method_delete("ctm_01jqztc78e1xfdgwhcgjzdrvgd", "paymtd_01j2jff1m3es31sdkejpaym164").await.unwrap();
516    /// ```
517    pub async fn payment_method_delete(
518        &self,
519        customer_id: impl Into<CustomerID>,
520        payment_method_id: impl Into<PaymentMethodID>,
521    ) -> std::result::Result<bool, Error> {
522        let client = reqwest::Client::new();
523
524        let url = format!(
525            "{}customers/{}/payment-methods/{}",
526            self.base_url,
527            customer_id.into().as_ref(),
528            payment_method_id.into().as_ref()
529        );
530
531        let response = client
532            .delete(url)
533            .bearer_auth(self.api_key.clone())
534            .send()
535            .await?;
536
537        Ok(response.status() == StatusCode::NO_CONTENT)
538    }
539
540    /// Creates a customer portal session for a customer.
541    ///
542    /// You can use this to generate authenticated links for a customer so that they're automatically signed in to the portal. Typically used when linking to the customer portal from your app where customers are already authenticated.
543    ///
544    /// You can include an array of subscription_ids to generate authenticated portal links that let customers make changes to their subscriptions. You can use these links as part of subscription management workflows rather than building your own billing screens.
545    ///
546    /// Customer portal sessions are temporary and shouldn't be cached.
547    ///
548    /// The customer portal is fully hosted by Paddle. For security and the best customer experience, don't embed the customer portal in an iframe.
549    ///
550    /// # Example:
551    /// ```
552    /// use paddle_rust_sdk::Paddle;
553    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
554    /// let session = client.create_portal_session("ctm_01jqztc78e1xfdgwhcgjzdrvgd").send().await.unwrap();
555    /// dbg!(session.data.urls.general.overview);
556    /// dbg!(session.data.urls.subscriptions);
557    /// ```
558    pub fn create_portal_session(
559        &self,
560        customer_id: impl Into<CustomerID>,
561    ) -> customers::PortalSessionCreate {
562        customers::PortalSessionCreate::new(self, customer_id)
563    }
564
565    /// Returns a request builder for querying transactions.
566    ///
567    /// Use the include method on the builder to include related entities in the response.
568    ///
569    /// # Example:
570    /// ```
571    /// use paddle_rust_sdk::Paddle;
572    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
573    /// let transactions = client.transactions_list().send().await.unwrap();
574    /// ```
575    pub fn transactions_list(&self) -> transactions::TransactionsList {
576        transactions::TransactionsList::new(self)
577    }
578
579    /// Returns a request builder for creating a transaction.
580    ///
581    /// See [Create Transaction](https://developer.paddle.com/api-reference/transactions/create-transaction) for more information.
582    ///
583    /// # Example:
584    /// ```
585    /// use paddle_rust_sdk::Paddle;
586    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
587    ///
588    /// let res = client.transaction_create()
589    ///     .append_catalog_item("pri_01jqxvdyjkp961jzv4me7ezg4d", 1)
590    ///     .send()
591    ///     .await
592    ///     .unwrap();
593    ///
594    /// dbg!(res.data);
595    /// ```
596    pub fn transaction_create(&self) -> transactions::TransactionCreate {
597        transactions::TransactionCreate::new(self)
598    }
599
600    /// Returns a request builder for fetching a transaction using its ID.
601    ///
602    /// # Example:
603    /// ```
604    /// use paddle_rust_sdk::Paddle;
605    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
606    /// let res = client.transaction_get("txn_01hv8wptq8987qeep44cyrewp9").send().await.unwrap();
607    /// dbg!(res.data);
608    /// ```
609    pub fn transaction_get(
610        &self,
611        transaction_id: impl Into<TransactionID>,
612    ) -> transactions::TransactionGet {
613        transactions::TransactionGet::new(self, transaction_id)
614    }
615
616    /// Returns a request builder for updating a transaction.
617    ///
618    /// # Example:
619    /// ```
620    /// use paddle_rust_sdk::{enums::TransactionStatus, Paddle};
621    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
622    /// client.transaction_update("txn_01hv8wptq8987qeep44cyrewp9").status(TransactionStatus::Billed).send().await.unwrap();
623    /// ```
624    pub fn transaction_update(
625        &self,
626        transaction_id: impl Into<TransactionID>,
627    ) -> transactions::TransactionUpdate {
628        transactions::TransactionUpdate::new(self, transaction_id)
629    }
630
631    /// Returns a link to an invoice PDF for a transaction.
632    ///
633    /// Invoice PDFs are available for both automatically and manually-collected transactions:
634    ///   - The PDF for manually-collected transactions includes payment terms, purchase order number, and notes for your customer. It's a demand for payment from your customer. It's available for transactions that are `billed` or `completed`.
635    ///   - The PDF for automatically-collected transactions lets your customer know that payment was taken successfully. Customers may require this for for tax-reporting purposes. It's available for transactions that are `completed`.
636    ///
637    /// Invoice PDFs aren't available for zero-value transactions.
638    ///
639    /// The link returned is not a permanent link. It expires after an hour.
640    ///
641    /// # Example:
642    /// ```
643    /// use paddle_rust_sdk::{enums::Disposition, Paddle};
644    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
645    /// let res = client.transaction_invoice("txn_01hv8wptq8987qeep44cyrewp9", Disposition::Inline).await.unwrap();
646    /// dbg!(res.data.url)
647    /// ```
648    pub async fn transaction_invoice(
649        &self,
650        transaction_id: impl Into<TransactionID>,
651        disposition: Disposition,
652    ) -> Result<TransactionInvoice> {
653        let transaction_id = transaction_id.into();
654
655        let url = format!("/transactions/{}/invoice", transaction_id.as_ref());
656        let params = ("disposition", disposition);
657
658        self.send(params, Method::GET, &url).await
659    }
660
661    /// Returns a request builder for generating a transaction preview without creating a transaction entity. Typically used for creating more advanced, dynamic pricing pages where users can build their own plans.
662    ///
663    /// You can provide location information when previewing a transaction. You must provide this if you want Paddle to calculate tax or automatically localize prices. You can provide one of:
664    ///   - `customer_ip_address`: Paddle fetches location using the IP address to calculate totals.
665    ///   - `address`: Paddle uses the country and ZIP code (where supplied) to calculate totals.
666    ///   - `customer_id`, `address_id`, `business_id`: Paddle uses existing customer data to calculate totals. Typically used for logged-in customers.
667    ///
668    /// When supplying items, you can exclude items from the total calculation using the `include_in_totals` boolean.
669    ///
670    /// By default, recurring items with trials are considered to have a zero charge when previewing. Set `ignore_trials` to true to ignore trial periods against prices for transaction preview calculations.
671    ///
672    /// If successful, your response includes the data you sent with a details object that includes totals for the supplied prices.
673    ///
674    /// Transaction previews don't create transactions, so no `id` is returned.
675    pub fn transaction_preview(&self) -> transactions::TransactionPreview {
676        transactions::TransactionPreview::new(self)
677    }
678
679    /// Returns a request builder to revise customer information for a billed or completed transaction.
680    ///
681    /// Revise a transaction to rectify incorrect customer, address, or business information on invoice documents generated by Paddle.
682    ///
683    /// You can revise transaction details that don't impact the tax rates on a transaction. This includes:
684    ///   - Customer name
685    ///   - Business name and tax or VAT number (`tax_identifier`)
686    ///   - Address details, apart from the country
687    ///
688    /// You can't remove a valid tax or VAT number, only replace it with another valid one. If a valid tax or VAT number is added, Paddle automatically creates an adjustment to refund any tax where applicable.
689    ///
690    /// Transactions can only be revised once.
691    ///
692    /// If successful, your response includes a copy of the transaction entity. Get a transaction using the `include` parameter with the `customer`, `address`, and `business` values to see the revised customer information.
693    ///
694    /// Only the customer information for this transaction is updated. The related customer, address, and business entities aren't updated.
695    pub fn transaction_revise(
696        &self,
697        transaction_id: impl Into<TransactionID>,
698    ) -> transactions::TransactionRevise {
699        transactions::TransactionRevise::new(self, transaction_id)
700    }
701
702    /// Returns a request builder for querying subscriptions.
703    ///
704    /// # Example:
705    /// ```
706    /// use paddle_rust_sdk::Paddle;
707    /// let client = Paddle::new("your_api_key", Paddle::SANDBOX).unwrap();
708    /// let subscriptions = client.subscriptions_list().send().await.unwrap();
709    /// ```
710    pub fn subscriptions_list(&self) -> subscriptions::SubscriptionsList {
711        subscriptions::SubscriptionsList::new(self)
712    }
713
714    async fn send<T: DeserializeOwned>(
715        &self,
716        req: impl Serialize,
717        method: Method,
718        path: &str,
719    ) -> Result<T> {
720        let mut url = self.base_url.join(path)?;
721        let client = reqwest::Client::new();
722
723        if method == reqwest::Method::GET {
724            dbg!(&serde_qs::to_string(&req)?);
725            url.set_query(Some(&serde_qs::to_string(&req)?));
726        }
727
728        let mut builder = client
729            .request(method.clone(), url)
730            .bearer_auth(self.api_key.clone())
731            .header(CONTENT_TYPE, "application/json; charset=utf-8");
732
733        builder = match method {
734            reqwest::Method::POST | reqwest::Method::PUT | reqwest::Method::PATCH => {
735                builder.json(&req)
736            }
737            _ => builder,
738        };
739
740        // let text = builder.send().await?.text().await?;
741        // println!("{}", text);
742        // todo!();
743
744        let res: Response<_> = builder.send().await?.json().await?;
745
746        match res {
747            Response::Success(success) => Ok(success),
748            Response::Error(error) => Err(Error::Paddle(error)),
749        }
750    }
751}
752
753fn comma_separated<S, T>(
754    values: &Option<Vec<T>>,
755    serializer: S,
756) -> std::result::Result<S::Ok, S::Error>
757where
758    S: serde::Serializer,
759    T: AsRef<str>,
760{
761    match values {
762        Some(values) => {
763            let values = values
764                .iter()
765                .map(|v| v.as_ref())
766                .collect::<Vec<_>>()
767                .join(",");
768
769            serializer.serialize_str(&values)
770        }
771        None => serializer.serialize_none(),
772    }
773}
774
775fn comma_separated_enum<S, T>(
776    values: &Option<Vec<T>>,
777    serializer: S,
778) -> std::result::Result<S::Ok, S::Error>
779where
780    S: serde::Serializer,
781    T: Serialize,
782{
783    match values {
784        Some(values) => {
785            let mut serialized = vec![];
786
787            for val in values {
788                let serde_value = serde_json::to_value(val).map_err(serde::ser::Error::custom)?;
789                let serialized_value = serde_value
790                    .as_str()
791                    .ok_or(serde::ser::Error::custom("Failed to serialize enum"))?
792                    .to_string();
793
794                serialized.push(serialized_value);
795            }
796
797            serializer.serialize_str(serialized.join(",").as_str())
798        }
799        None => serializer.serialize_none(),
800    }
801}