Skip to main content

paddle_rust_sdk/
customers.rs

1//! Builders for making requests to the Paddle API for customers.
2//!
3//! See the [Paddle API](https://developer.paddle.com/api-reference/customers/overview) documentation for more information.
4
5use std::collections::HashMap;
6
7use reqwest::Method;
8use serde::Serialize;
9use serde_with::skip_serializing_none;
10
11use crate::entities::{CreditBalance, Customer, CustomerPortalSession};
12use crate::enums::Status;
13use crate::ids::{CustomerID, SubscriptionID};
14use crate::paginated::Paginated;
15use crate::nullable::Nullable;
16use crate::{Paddle, Result};
17
18/// Request builder for fetching customers from Paddle API.
19#[skip_serializing_none]
20#[derive(Serialize)]
21pub struct CustomersList<'a> {
22    #[serde(skip)]
23    client: &'a Paddle,
24    after: Option<CustomerID>,
25    #[serde(serialize_with = "crate::comma_separated")]
26    email: Option<Vec<String>>,
27    #[serde(serialize_with = "crate::comma_separated")]
28    id: Option<Vec<CustomerID>>,
29    order_by: Option<String>,
30    per_page: Option<usize>,
31    search: Option<String>,
32    status: Option<Status>,
33}
34
35impl<'a> CustomersList<'a> {
36    pub fn new(client: &'a Paddle) -> Self {
37        Self {
38            client,
39            after: None,
40            email: None,
41            id: None,
42            order_by: None,
43            per_page: None,
44            search: None,
45            status: None,
46        }
47    }
48
49    /// Return entities after the specified Paddle ID when working with paginated endpoints. Used in the `meta.pagination.next` URL in responses for list operations.
50    pub fn after(&mut self, customer_id: impl Into<CustomerID>) -> &mut Self {
51        self.after = Some(customer_id.into());
52        self
53    }
54
55    /// Return entities that exactly match the specified email addresses
56    pub fn emails(&mut self, emails: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
57        self.email = Some(emails.into_iter().map(|s| s.as_ref().to_string()).collect());
58        self
59    }
60
61    /// Return only the IDs specified.
62    pub fn ids(
63        &mut self,
64        customer_ids: impl IntoIterator<Item = impl Into<CustomerID>>,
65    ) -> &mut Self {
66        self.id = Some(customer_ids.into_iter().map(Into::into).collect());
67        self
68    }
69
70    /// Order returned entities by the specified field. Valid fields for ordering: id
71    pub fn order_by_asc(&mut self, field: &str) -> &mut Self {
72        self.order_by = Some(format!("{}[ASC]", field));
73        self
74    }
75
76    /// Order returned entities by the specified field. Valid fields for ordering: id
77    pub fn order_by_desc(&mut self, field: &str) -> &mut Self {
78        self.order_by = Some(format!("{}[DESC]", field));
79        self
80    }
81
82    /// Set how many entities are returned per page. Paddle returns the maximum number of results if a number greater than the maximum is requested.
83    /// Check `meta.pagination.per_page` in the response to see how many were returned.
84    ///
85    /// Default: `50`; Maximum: `200`.
86    pub fn per_page(&mut self, entities_per_page: usize) -> &mut Self {
87        self.per_page = Some(entities_per_page);
88        self
89    }
90
91    /// Return entities that match a search query. Searches `id`, `name`, and `email` fields. Use the email filter for precise matching of email addresses.
92    pub fn search(&mut self, term: impl Into<String>) -> &mut Self {
93        self.search = Some(term.into());
94        self
95    }
96
97    /// Return only prices with the specified status.
98    pub fn status(&mut self, status: Status) -> &mut Self {
99        self.status = Some(status);
100        self
101    }
102
103    /// Returns a paginator for fetching pages of entities from Paddle
104    pub fn send(&self) -> Paginated<'_, Vec<Customer>> {
105        Paginated::new(self.client, "/customers", self)
106    }
107}
108
109/// Request builder for creating customers in Paddle API.
110#[skip_serializing_none]
111#[derive(Serialize)]
112pub struct CustomerCreate<'a> {
113    #[serde(skip)]
114    client: &'a Paddle,
115    email: String,
116    name: Option<String>,
117    custom_data: Option<HashMap<String, String>>,
118    locale: Option<String>,
119}
120
121impl<'a> CustomerCreate<'a> {
122    pub fn new(client: &'a Paddle, email: String) -> Self {
123        Self {
124            client,
125            email,
126            name: None,
127            custom_data: None,
128            locale: None,
129        }
130    }
131
132    /// Full name of this customer. Required when creating transactions where `collection_mode` is `manual` (invoices).
133    pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
134        self.name = Some(name.into());
135        self
136    }
137
138    /// Your own structured key-value data.
139    pub fn custom_data(&mut self, custom_data: HashMap<String, String>) -> &mut Self {
140        self.custom_data = Some(custom_data);
141        self
142    }
143
144    /// Valid IETF BCP 47 short form locale tag. If omitted, defaults to `en`.
145    pub fn locale(&mut self, locale: impl Into<String>) -> &mut Self {
146        self.locale = Some(locale.into());
147        self
148    }
149
150    /// Send the request to Paddle and return the response.
151    pub async fn send(&self) -> Result<Customer> {
152        self.client.send(self, Method::POST, "/customers").await
153    }
154}
155
156/// Request builder for fetching a single customer from Paddle API.
157#[derive(Serialize)]
158pub struct CustomerGet<'a> {
159    #[serde(skip)]
160    client: &'a Paddle,
161    #[serde(skip)]
162    customer_id: CustomerID,
163}
164
165impl<'a> CustomerGet<'a> {
166    pub fn new(client: &'a Paddle, customer_id: impl Into<CustomerID>) -> Self {
167        Self {
168            client,
169            customer_id: customer_id.into(),
170        }
171    }
172
173    /// Send the request to Paddle and return the response.
174    pub async fn send(&self) -> Result<Customer> {
175        self.client
176            .send(
177                self,
178                Method::GET,
179                &format!("/customers/{}", self.customer_id.as_ref()),
180            )
181            .await
182    }
183}
184
185/// Request builder for updating a customer in Paddle API.
186#[derive(Serialize)]
187pub struct CustomerUpdate<'a> {
188    #[serde(skip)]
189    client: &'a Paddle,
190    #[serde(skip)]
191    customer_id: CustomerID,
192    #[serde(skip_serializing_if = "Nullable::is_unchanged")]
193    name: Nullable<String>,
194    #[serde(skip_serializing_if = "Nullable::is_unchanged")]
195    email: Nullable<String>,
196    #[serde(skip_serializing_if = "Nullable::is_unchanged")]
197    status: Nullable<Status>,
198    #[serde(skip_serializing_if = "Nullable::is_unchanged")]
199    custom_data: Nullable<HashMap<String, String>>,
200    #[serde(skip_serializing_if = "Nullable::is_unchanged")]
201    locale: Nullable<String>,
202}
203
204impl<'a> CustomerUpdate<'a> {
205    pub fn new(client: &'a Paddle, customer_id: impl Into<CustomerID>) -> Self {
206        Self {
207            client,
208            customer_id: customer_id.into(),
209            name: Nullable::Unchanged,
210            email: Nullable::Unchanged,
211            status: Nullable::Unchanged,
212            custom_data: Nullable::Unchanged,
213            locale: Nullable::Unchanged,
214        }
215    }
216
217    /// Full name of this customer. Required when creating transactions where `collection_mode` is `manual` (invoices).
218    pub fn name(&mut self, name: impl Into<Nullable<String>>) -> &mut Self {
219        self.name = name.into();
220        self
221    }
222
223    /// Email address for this customer.
224    pub fn email(&mut self, email: impl Into<Nullable<String>>) -> &mut Self {
225        self.email = email.into();
226        self
227    }
228
229    /// Whether this entity can be used in Paddle.
230    pub fn status(&mut self, status: impl Into<Nullable<Status>>) -> &mut Self {
231        self.status = status.into();
232        self
233    }
234
235    /// Your own structured key-value data.
236    pub fn custom_data(
237        &mut self,
238        custom_data: impl Into<Nullable<HashMap<String, String>>>,
239    ) -> &mut Self {
240        self.custom_data = custom_data.into();
241        self
242    }
243
244    /// Valid IETF BCP 47 short form locale tag.
245    pub fn locale(&mut self, locale: impl Into<Nullable<String>>) -> &mut Self {
246        self.locale = locale.into();
247        self
248    }
249
250    /// Send the request to Paddle and return the response.
251    pub async fn send(&self) -> Result<Customer> {
252        self.client
253            .send(
254                self,
255                Method::PATCH,
256                &format!("/customers/{}", self.customer_id.as_ref()),
257            )
258            .await
259    }
260}
261
262/// Request builder for retrieving credit balances for each currency for a customer.
263#[skip_serializing_none]
264#[derive(Serialize)]
265pub struct CustomerCreditBalances<'a> {
266    #[serde(skip)]
267    client: &'a Paddle,
268    #[serde(skip)]
269    customer_id: CustomerID,
270}
271
272impl<'a> CustomerCreditBalances<'a> {
273    pub fn new(client: &'a Paddle, customer_id: impl Into<CustomerID>) -> Self {
274        Self {
275            client,
276            customer_id: customer_id.into(),
277        }
278    }
279
280    /// Send the request to Paddle and return the response.
281    pub async fn send(&self) -> Result<Vec<CreditBalance>> {
282        self.client
283            .send(
284                self,
285                Method::GET,
286                &format!("/customers/{}/credit-balances", self.customer_id.as_ref()),
287            )
288            .await
289    }
290}
291
292/// Request builder for creating customer portal sessions
293#[skip_serializing_none]
294#[derive(Serialize)]
295pub struct PortalSessionCreate<'a> {
296    #[serde(skip)]
297    client: &'a Paddle,
298    #[serde(skip)]
299    customer_id: CustomerID,
300    subscription_ids: Option<Vec<SubscriptionID>>,
301}
302
303impl<'a> PortalSessionCreate<'a> {
304    pub fn new(client: &'a Paddle, customer_id: impl Into<CustomerID>) -> Self {
305        Self {
306            client,
307            customer_id: customer_id.into(),
308            subscription_ids: None,
309        }
310    }
311
312    /// List of subscriptions to create authenticated customer portal deep links for.
313    pub fn subscription_ids(
314        &mut self,
315        subscription_ids: impl IntoIterator<Item = impl Into<SubscriptionID>>,
316    ) -> &mut Self {
317        self.subscription_ids = Some(subscription_ids.into_iter().map(Into::into).collect());
318        self
319    }
320
321    /// Send the request to Paddle and return the response.
322    pub async fn send(&self) -> Result<CustomerPortalSession> {
323        self.client
324            .send(
325                self,
326                Method::POST,
327                &format!("/customers/{}/portal-sessions", self.customer_id.as_ref()),
328            )
329            .await
330    }
331}