paystack/endpoints/
customers.rs

1//! Customers
2//! =========
3//! Thse Customers API allows you to create and maange customers on your integration
4
5use super::PAYSTACK_BASE_URL;
6use crate::{
7    CreateCustomerRequest, CustomerResponseData, HttpClient, PaystackAPIError, PaystackResult,
8    Response, RiskAction, UpdateCustomerRequest, ValidateCustomerRequest,
9};
10use serde_json::json;
11use std::{marker::PhantomData, sync::Arc};
12
13/// A struct to hold all the functions of the customers API endpoint
14#[derive(Debug, Clone)]
15pub struct CustomersEndpoints<T: HttpClient + Default> {
16    /// Paystack API key
17    key: String,
18    /// Base URL for the customer route
19    base_url: String,
20    /// Http client for the route
21    http: Arc<T>,
22}
23
24impl<T: HttpClient + Default> CustomersEndpoints<T> {
25    /// Creates a new CustomersEndpoints instance
26    ///
27    /// # Arguments
28    /// * `key` - The Paystack API key
29    /// * `http` - The HTTP client implementation to use for API requests
30    ///
31    /// # Returns
32    /// A new CustomersEndpoints instance
33    pub fn new(key: Arc<String>, http: Arc<T>) -> CustomersEndpoints<T> {
34        let base_url = format!("{PAYSTACK_BASE_URL}/customer");
35        CustomersEndpoints {
36            key: key.to_string(),
37            base_url,
38            http,
39        }
40    }
41
42    /// Create customer on your integration
43    ///
44    /// # Arguments
45    /// * `create_customer_request` - Contains the information about the customer to be created.
46    ///   It should be built with `CreateCustomerRequestBuilder`.
47    ///
48    /// # Returns
49    /// A Result containing the customer response data or an error
50    pub async fn create_customer(
51        &self,
52        create_customer_request: CreateCustomerRequest,
53    ) -> PaystackResult<CustomerResponseData> {
54        let url = &self.base_url;
55        let body = serde_json::to_value(create_customer_request)
56            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
57
58        let response = self
59            .http
60            .post(url, &self.key, &body)
61            .await
62            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
63
64        let parsed_response: Response<CustomerResponseData> = serde_json::from_str(&response)
65            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
66
67        Ok(parsed_response)
68    }
69
70    /// Lists customers available on your integration
71    ///
72    /// # Arguments
73    /// * `per_page` - Optional number of records to retrieve per page. Default is 50
74    /// * `page` - Optional page number to retrieve. Default is 1
75    ///
76    /// # Returns
77    /// A Result containing a vector of customer response data or an error
78    pub async fn list_customers(
79        &self,
80        per_page: Option<u8>,
81        page: Option<u8>,
82    ) -> PaystackResult<Vec<CustomerResponseData>> {
83        let url = &self.base_url;
84
85        let per_page = per_page.unwrap_or(50).to_string();
86        let page = page.unwrap_or(1).to_string();
87        let query = vec![("perPage", per_page.as_str()), ("page", page.as_str())];
88
89        let response = self
90            .http
91            .get(url, &self.key, Some(&query))
92            .await
93            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
94
95        let parsed_response: Response<Vec<CustomerResponseData>> = serde_json::from_str(&response)
96            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
97
98        Ok(parsed_response)
99    }
100
101    /// Gets details of a customer on your integration
102    ///
103    /// # Arguments
104    /// * `email_or_code` - Email or customer code for the customer to fetch
105    ///
106    /// # Returns
107    /// A Result containing the customer response data or an error
108    pub async fn fetch_customer(
109        &self,
110        email_or_code: String,
111    ) -> PaystackResult<CustomerResponseData> {
112        let url = format!("{}/{}", self.base_url, email_or_code);
113
114        let response = self
115            .http
116            .get(&url, &self.key, None)
117            .await
118            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
119
120        let parsed_response: Response<CustomerResponseData> = serde_json::from_str(&response)
121            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
122
123        Ok(parsed_response)
124    }
125
126    /// Updates a customer's details on your integration
127    ///
128    /// # Arguments
129    /// * `customer_code` - The customer's code
130    /// * `update_customer_request` - The data to update the customer with.
131    ///   Should be created with the UpdateCustomerRequestBuilder struct
132    ///
133    /// # Returns
134    /// A Result containing the updated customer response data or an error
135    pub async fn update_customer(
136        &self,
137        customer_code: String,
138        update_customer_request: UpdateCustomerRequest,
139    ) -> PaystackResult<CustomerResponseData> {
140        let url = format!("{}/{}", self.base_url, customer_code);
141        let body = serde_json::to_value(update_customer_request)
142            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
143
144        let response = self
145            .http
146            .put(&url, &self.key, &body)
147            .await
148            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
149
150        let parsed_response: Response<CustomerResponseData> = serde_json::from_str(&response)
151            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
152
153        Ok(parsed_response)
154    }
155
156    /// Validates a customer's identity
157    ///
158    /// # Arguments
159    /// * `customer_code` - Email or customer code of customer to be identified
160    /// * `customer_validation_request` - The data to validate the customer with.
161    ///   Should be created with the ValidateCustomerRequestBuilder struct
162    ///
163    /// # Returns
164    /// A Result containing the validation response or an error
165    pub async fn validate_customer(
166        &self,
167        customer_code: String,
168        customer_validation_request: ValidateCustomerRequest,
169    ) -> PaystackResult<PhantomData<String>> {
170        let url = format!("{}/{}/identification", self.base_url, customer_code);
171        let body = serde_json::to_value(customer_validation_request)
172            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
173
174        let response = self
175            .http
176            .post(&url, &self.key, &body)
177            .await
178            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
179
180        let parsed_response: Response<PhantomData<String>> = serde_json::from_str(&response)
181            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
182
183        Ok(parsed_response)
184    }
185
186    /// Whitelists or blacklists a customer on your integration
187    ///
188    /// # Arguments
189    /// * `customer_code` - Customer's code or email address
190    /// * `risk_action` - The risk action to apply to the customer
191    ///
192    /// # Returns
193    /// A Result containing the updated customer response data or an error
194    pub async fn whitelist_or_blacklist_customer(
195        &self,
196        customer_code: String,
197        risk_action: RiskAction,
198    ) -> PaystackResult<CustomerResponseData> {
199        let url = format!("{}/set_risk_action", self.base_url);
200        let body = json!({
201            "customer": customer_code,
202            "risk_action": risk_action
203        });
204
205        let response = self
206            .http
207            .post(&url, &self.key, &body)
208            .await
209            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
210
211        let parsed_response: Response<CustomerResponseData> = serde_json::from_str(&response)
212            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
213
214        Ok(parsed_response)
215    }
216
217    /// Deactivates an authorization when the card needs to be forgotten
218    ///
219    /// # Arguments
220    /// * `authorization_code` - Authorization code to be deactivated
221    ///
222    /// # Returns
223    /// A Result containing the deactivation response or an error
224    pub async fn deactivate_authorization(
225        &self,
226        authorization_code: String,
227    ) -> PaystackResult<PhantomData<String>> {
228        let url = format!("{}/authorization/deactivate", self.base_url);
229        let body = json!({
230            "authorization_code": authorization_code
231        });
232
233        let response = self
234            .http
235            .post(&url, &self.key, &body)
236            .await
237            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
238
239        let parsed_response: Response<PhantomData<String>> = serde_json::from_str(&response)
240            .map_err(|e| PaystackAPIError::Customer(e.to_string()))?;
241
242        Ok(parsed_response)
243    }
244}