rain_sdk/api/
applications.rs

1//! Applications API
2//!
3//! This module provides functionality to manage company and user applications in the Rain API.
4//!
5//! # Examples
6//!
7//! This module provides functionality to manage company and user applications.
8//!
9//! See the individual function documentation for examples.
10
11use crate::client::RainClient;
12use crate::error::Result;
13use crate::models::applications::*;
14use uuid::Uuid;
15
16impl RainClient {
17    // ============================================================================
18    // Company Application Methods
19    // ============================================================================
20
21    /// Create a company application
22    ///
23    /// # Arguments
24    ///
25    /// * `request` - The company application request
26    ///
27    /// # Returns
28    ///
29    /// Returns a [`CompanyApplicationResponse`] containing the application information.
30    ///
31    /// # Examples
32    ///
33    /// ```no_run
34    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
35    /// use rain_sdk::models::applications::*;
36    /// use rain_sdk::models::common::*;
37    ///
38    /// # #[cfg(feature = "async")]
39    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
40    /// let config = Config::new(Environment::Dev);
41    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
42    /// let client = RainClient::new(config, auth)?;
43    ///
44    /// // Note: In practice, you would populate all required fields.
45    /// // This is a simplified example - see the full struct definitions for required fields.
46    /// # let request = todo!();
47    /// let application = client.create_company_application(&request).await?;
48    /// # Ok(())
49    /// # }
50    /// ```
51    #[cfg(feature = "async")]
52    pub async fn create_company_application(
53        &self,
54        request: &CreateCompanyApplicationRequest,
55    ) -> Result<CompanyApplicationResponse> {
56        let path = "/issuing/applications/company";
57        self.post(path, request).await
58    }
59
60    /// Get a company application by ID
61    ///
62    /// # Arguments
63    ///
64    /// * `company_id` - The unique identifier of the company
65    ///
66    /// # Returns
67    ///
68    /// Returns a [`CompanyApplicationResponse`] containing the application information.
69    ///
70    /// # Examples
71    ///
72    /// ```no_run
73    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
74    /// use uuid::Uuid;
75    ///
76    /// # #[cfg(feature = "async")]
77    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
78    /// let config = Config::new(Environment::Dev);
79    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
80    /// let client = RainClient::new(config, auth)?;
81    ///
82    /// let company_id = Uuid::new_v4();
83    /// let application = client.get_company_application(&company_id).await?;
84    /// # Ok(())
85    /// # }
86    /// ```
87    #[cfg(feature = "async")]
88    pub async fn get_company_application(
89        &self,
90        company_id: &Uuid,
91    ) -> Result<CompanyApplicationResponse> {
92        let path = format!("/issuing/applications/company/{company_id}");
93        self.get(&path).await
94    }
95
96    /// Update a company application
97    ///
98    /// # Arguments
99    ///
100    /// * `company_id` - The unique identifier of the company
101    /// * `request` - The update request
102    ///
103    /// # Returns
104    ///
105    /// Returns a [`CompanyApplicationResponse`] containing the updated application information.
106    ///
107    /// # Examples
108    ///
109    /// ```no_run
110    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
111    /// use rain_sdk::models::applications::UpdateCompanyApplicationRequest;
112    /// use uuid::Uuid;
113    ///
114    /// # #[cfg(feature = "async")]
115    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
116    /// let config = Config::new(Environment::Dev);
117    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
118    /// let client = RainClient::new(config, auth)?;
119    ///
120    /// let company_id = Uuid::new_v4();
121    /// let request = UpdateCompanyApplicationRequest {
122    ///     name: Some("Updated Name".to_string()),
123    ///     address: None,
124    ///     entity: None,
125    /// };
126    /// let application = client.update_company_application(&company_id, &request).await?;
127    /// # Ok(())
128    /// # }
129    /// ```
130    #[cfg(feature = "async")]
131    pub async fn update_company_application(
132        &self,
133        company_id: &Uuid,
134        request: &UpdateCompanyApplicationRequest,
135    ) -> Result<CompanyApplicationResponse> {
136        let path = format!("/issuing/applications/company/{company_id}");
137        self.patch(&path, request).await
138    }
139
140    /// Update an ultimate beneficial owner
141    ///
142    /// # Arguments
143    ///
144    /// * `company_id` - The unique identifier of the company
145    /// * `ubo_id` - The unique identifier of the ultimate beneficial owner
146    /// * `request` - The update request
147    ///
148    /// # Returns
149    ///
150    /// Returns a [`CompanyApplicationResponse`] containing the updated application information.
151    ///
152    /// # Examples
153    ///
154    /// ```no_run
155    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
156    /// use rain_sdk::models::applications::UpdateUltimateBeneficialOwnerRequest;
157    /// use uuid::Uuid;
158    ///
159    /// # #[cfg(feature = "async")]
160    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
161    /// let config = Config::new(Environment::Dev);
162    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
163    /// let client = RainClient::new(config, auth)?;
164    ///
165    /// let company_id = Uuid::new_v4();
166    /// let ubo_id = Uuid::new_v4();
167    /// let request = UpdateUltimateBeneficialOwnerRequest {
168    ///     first_name: Some("John".to_string()),
169    ///     last_name: Some("Doe".to_string()),
170    ///     birth_date: None,
171    ///     national_id: None,
172    ///     country_of_issue: None,
173    ///     email: None,
174    ///     address: None,
175    /// };
176    /// let application = client.update_ultimate_beneficial_owner(&company_id, &ubo_id, &request).await?;
177    /// # Ok(())
178    /// # }
179    /// ```
180    #[cfg(feature = "async")]
181    pub async fn update_ultimate_beneficial_owner(
182        &self,
183        company_id: &Uuid,
184        ubo_id: &Uuid,
185        request: &UpdateUltimateBeneficialOwnerRequest,
186    ) -> Result<CompanyApplicationResponse> {
187        let path = format!("/issuing/applications/company/{company_id}/ubo/{ubo_id}");
188        self.patch(&path, request).await
189    }
190
191    /// Upload a document for a company application
192    ///
193    /// # Arguments
194    ///
195    /// * `company_id` - The unique identifier of the company
196    /// * `params` - Document upload parameters
197    ///
198    /// # Returns
199    ///
200    /// Returns a success response.
201    ///
202    /// # Examples
203    ///
204    /// ```no_run
205    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
206    /// use rain_sdk::models::applications::DocumentUploadParams;
207    /// use uuid::Uuid;
208    ///
209    /// # #[cfg(feature = "async")]
210    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
211    /// let config = Config::new(Environment::Dev);
212    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
213    /// let client = RainClient::new(config, auth)?;
214    ///
215    /// let company_id = Uuid::new_v4();
216    /// let params = DocumentUploadParams {
217    ///     document_type: "directorsRegistry".to_string(),
218    ///     side: "front".to_string(),
219    ///     country: Some("US".to_string()),
220    ///     country_code: Some("US".to_string()),
221    ///     name: Some("Document Name".to_string()),
222    ///     file_path: "/path/to/file.pdf".to_string(),
223    /// };
224    /// client.upload_company_document(&company_id, &params).await?;
225    /// # Ok(())
226    /// # }
227    /// ```
228    #[cfg(feature = "async")]
229    pub async fn upload_company_document(
230        &self,
231        company_id: &Uuid,
232        params: &DocumentUploadParams,
233    ) -> Result<serde_json::Value> {
234        let path = format!("/issuing/applications/company/{company_id}/document");
235        let form = self.build_company_document_form(params)?;
236        self.put_multipart(&path, form).await
237    }
238
239    /// Upload a document for an ultimate beneficial owner
240    ///
241    /// # Arguments
242    ///
243    /// * `company_id` - The unique identifier of the company
244    /// * `ubo_id` - The unique identifier of the ultimate beneficial owner
245    /// * `params` - Document upload parameters
246    ///
247    /// # Returns
248    ///
249    /// Returns a success response.
250    ///
251    /// # Examples
252    ///
253    /// ```no_run
254    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
255    /// use rain_sdk::models::applications::DocumentUploadParams;
256    /// use uuid::Uuid;
257    ///
258    /// # #[cfg(feature = "async")]
259    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
260    /// let config = Config::new(Environment::Dev);
261    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
262    /// let client = RainClient::new(config, auth)?;
263    ///
264    /// let company_id = Uuid::new_v4();
265    /// let ubo_id = Uuid::new_v4();
266    /// let params = DocumentUploadParams {
267    ///     document_type: "idCard".to_string(),
268    ///     side: "front".to_string(),
269    ///     country: Some("US".to_string()),
270    ///     country_code: Some("US".to_string()),
271    ///     name: None,
272    ///     file_path: "/path/to/file.pdf".to_string(),
273    /// };
274    /// client.upload_ubo_document(&company_id, &ubo_id, &params).await?;
275    /// # Ok(())
276    /// # }
277    /// ```
278    #[cfg(feature = "async")]
279    pub async fn upload_ubo_document(
280        &self,
281        company_id: &Uuid,
282        ubo_id: &Uuid,
283        params: &DocumentUploadParams,
284    ) -> Result<serde_json::Value> {
285        let path = format!("/issuing/applications/company/{company_id}/ubo/{ubo_id}/document");
286        let form = self.build_user_document_form(params)?;
287        self.put_multipart(&path, form).await
288    }
289
290    // ============================================================================
291    // User Application Methods
292    // ============================================================================
293
294    /// Create a user application
295    ///
296    /// # Arguments
297    ///
298    /// * `request` - The user application request
299    ///
300    /// # Returns
301    ///
302    /// Returns a [`UserApplicationResponse`] containing the application information.
303    ///
304    /// # Examples
305    ///
306    /// ```no_run
307    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
308    /// use rain_sdk::models::applications::CreateUserApplicationRequest;
309    ///
310    /// # #[cfg(feature = "async")]
311    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
312    /// let config = Config::new(Environment::Dev);
313    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
314    /// let client = RainClient::new(config, auth)?;
315    ///
316    /// let request = CreateUserApplicationRequest {
317    ///     ip_address: "127.0.0.1".to_string(),
318    ///     occupation: "Engineer".to_string(),
319    ///     annual_salary: "100000".to_string(),
320    ///     account_purpose: "Business".to_string(),
321    ///     expected_monthly_volume: "5000".to_string(),
322    ///     is_terms_of_service_accepted: true,
323    ///     sumsub_share_token: "token".to_string(),
324    ///     wallet_address: None,
325    ///     solana_address: None,
326    ///     tron_address: None,
327    ///     stellar_address: None,
328    ///     chain_id: None,
329    ///     contract_address: None,
330    ///     source_key: None,
331    ///     has_existing_documents: None,
332    /// };
333    /// let application = client.create_user_application(&request).await?;
334    /// # Ok(())
335    /// # }
336    /// ```
337    #[cfg(feature = "async")]
338    pub async fn create_user_application(
339        &self,
340        request: &CreateUserApplicationRequest,
341    ) -> Result<UserApplicationResponse> {
342        let path = "/issuing/applications/user";
343        self.post(path, request).await
344    }
345
346    /// Initiate a user application
347    ///
348    /// # Arguments
349    ///
350    /// * `request` - The initiate user application request
351    ///
352    /// # Returns
353    ///
354    /// Returns a [`UserApplicationResponse`] containing the application information.
355    ///
356    /// # Examples
357    ///
358    /// ```no_run
359    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
360    /// use rain_sdk::models::applications::InitiateUserApplicationRequest;
361    ///
362    /// # #[cfg(feature = "async")]
363    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
364    /// let config = Config::new(Environment::Dev);
365    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
366    /// let client = RainClient::new(config, auth)?;
367    ///
368    /// let request = InitiateUserApplicationRequest {
369    ///     first_name: Some("John".to_string()),
370    ///     last_name: Some("Doe".to_string()),
371    ///     email: Some("john@example.com".to_string()),
372    ///     wallet_address: None,
373    /// };
374    /// let application = client.initiate_user_application(&request).await?;
375    /// # Ok(())
376    /// # }
377    /// ```
378    #[cfg(feature = "async")]
379    pub async fn initiate_user_application(
380        &self,
381        request: &InitiateUserApplicationRequest,
382    ) -> Result<UserApplicationResponse> {
383        let path = "/issuing/applications/user/initiate";
384        self.post(path, request).await
385    }
386
387    /// Get a user application by ID
388    ///
389    /// # Arguments
390    ///
391    /// * `user_id` - The unique identifier of the user
392    ///
393    /// # Returns
394    ///
395    /// Returns a [`UserApplicationResponse`] containing the application information.
396    ///
397    /// # Examples
398    ///
399    /// ```no_run
400    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
401    /// use uuid::Uuid;
402    ///
403    /// # #[cfg(feature = "async")]
404    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
405    /// let config = Config::new(Environment::Dev);
406    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
407    /// let client = RainClient::new(config, auth)?;
408    ///
409    /// let user_id = Uuid::new_v4();
410    /// let application = client.get_user_application(&user_id).await?;
411    /// # Ok(())
412    /// # }
413    /// ```
414    #[cfg(feature = "async")]
415    pub async fn get_user_application(&self, user_id: &Uuid) -> Result<UserApplicationResponse> {
416        let path = format!("/issuing/applications/user/{user_id}");
417        self.get(&path).await
418    }
419
420    /// Update a user application
421    ///
422    /// # Arguments
423    ///
424    /// * `user_id` - The unique identifier of the user
425    /// * `request` - The update request
426    ///
427    /// # Returns
428    ///
429    /// Returns a [`UserApplicationResponse`] containing the updated application information.
430    ///
431    /// # Examples
432    ///
433    /// ```no_run
434    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
435    /// use rain_sdk::models::applications::UpdateUserApplicationRequest;
436    /// use uuid::Uuid;
437    ///
438    /// # #[cfg(feature = "async")]
439    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
440    /// let config = Config::new(Environment::Dev);
441    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
442    /// let client = RainClient::new(config, auth)?;
443    ///
444    /// let user_id = Uuid::new_v4();
445    /// let request = UpdateUserApplicationRequest {
446    ///     first_name: Some("John".to_string()),
447    ///     last_name: None,
448    ///     birth_date: None,
449    ///     national_id: None,
450    ///     country_of_issue: None,
451    ///     address: None,
452    ///     ip_address: None,
453    ///     occupation: None,
454    ///     annual_salary: None,
455    ///     account_purpose: None,
456    ///     expected_monthly_volume: None,
457    ///     is_terms_of_service_accepted: None,
458    ///     has_existing_documents: None,
459    /// };
460    /// let application = client.update_user_application(&user_id, &request).await?;
461    /// # Ok(())
462    /// # }
463    /// ```
464    #[cfg(feature = "async")]
465    pub async fn update_user_application(
466        &self,
467        user_id: &Uuid,
468        request: &UpdateUserApplicationRequest,
469    ) -> Result<UserApplicationResponse> {
470        let path = format!("/issuing/applications/user/{user_id}");
471        self.patch(&path, request).await
472    }
473
474    /// Upload a document for a user application
475    ///
476    /// # Arguments
477    ///
478    /// * `user_id` - The unique identifier of the user
479    /// * `params` - Document upload parameters
480    ///
481    /// # Returns
482    ///
483    /// Returns a success response.
484    ///
485    /// # Examples
486    ///
487    /// ```no_run
488    /// use rain_sdk::{RainClient, Config, Environment, AuthConfig};
489    /// use rain_sdk::models::applications::DocumentUploadParams;
490    /// use uuid::Uuid;
491    ///
492    /// # #[cfg(feature = "async")]
493    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
494    /// let config = Config::new(Environment::Dev);
495    /// let auth = AuthConfig::with_api_key("your-api-key".to_string());
496    /// let client = RainClient::new(config, auth)?;
497    ///
498    /// let user_id = Uuid::new_v4();
499    /// let params = DocumentUploadParams {
500    ///     document_type: "idCard".to_string(),
501    ///     side: "front".to_string(),
502    ///     country: Some("US".to_string()),
503    ///     country_code: Some("US".to_string()),
504    ///     name: Some("ID Card".to_string()),
505    ///     file_path: "/path/to/file.pdf".to_string(),
506    /// };
507    /// client.upload_user_document(&user_id, &params).await?;
508    /// # Ok(())
509    /// # }
510    /// ```
511    #[cfg(feature = "async")]
512    pub async fn upload_user_document(
513        &self,
514        user_id: &Uuid,
515        params: &DocumentUploadParams,
516    ) -> Result<serde_json::Value> {
517        let path = format!("/issuing/applications/user/{user_id}/document");
518        let form = self.build_user_document_form(params)?;
519        self.put_multipart(&path, form).await
520    }
521
522    // ============================================================================
523    // Helper Methods
524    // ============================================================================
525
526    #[cfg(feature = "async")]
527    fn build_company_document_form(
528        &self,
529        params: &DocumentUploadParams,
530    ) -> Result<reqwest::multipart::Form> {
531        use std::fs;
532
533        let file_bytes = fs::read(&params.file_path).map_err(|e| {
534            crate::error::RainError::Other(anyhow::anyhow!("Failed to read file: {e}"))
535        })?;
536
537        let file_name = params
538            .file_path
539            .split('/')
540            .next_back()
541            .unwrap_or("document")
542            .to_string();
543
544        let part = reqwest::multipart::Part::bytes(file_bytes)
545            .file_name(file_name)
546            .mime_str("application/octet-stream")
547            .map_err(|e| {
548                crate::error::RainError::Other(anyhow::anyhow!("Invalid MIME type: {e}"))
549            })?;
550
551        let mut form = reqwest::multipart::Form::new()
552            .part("document", part)
553            .text("type", params.document_type.clone())
554            .text("side", params.side.clone());
555
556        if let Some(ref name) = params.name {
557            form = form.text("name", name.clone());
558        }
559
560        if let Some(ref country) = params.country {
561            form = form.text("country", country.clone());
562        }
563
564        if let Some(ref country_code) = params.country_code {
565            form = form.text("countryCode", country_code.clone());
566        }
567
568        Ok(form)
569    }
570
571    #[cfg(feature = "async")]
572    fn build_user_document_form(
573        &self,
574        params: &DocumentUploadParams,
575    ) -> Result<reqwest::multipart::Form> {
576        use std::fs;
577
578        let file_bytes = fs::read(&params.file_path).map_err(|e| {
579            crate::error::RainError::Other(anyhow::anyhow!("Failed to read file: {e}"))
580        })?;
581
582        let file_name = params
583            .file_path
584            .split('/')
585            .next_back()
586            .unwrap_or("document")
587            .to_string();
588
589        let part = reqwest::multipart::Part::bytes(file_bytes)
590            .file_name(file_name)
591            .mime_str("application/octet-stream")
592            .map_err(|e| {
593                crate::error::RainError::Other(anyhow::anyhow!("Invalid MIME type: {e}"))
594            })?;
595
596        let mut form = reqwest::multipart::Form::new()
597            .part("document", part)
598            .text("type", params.document_type.clone())
599            .text("side", params.side.clone());
600
601        if let Some(ref name) = params.name {
602            form = form.text("name", name.clone());
603        }
604
605        if let Some(ref country) = params.country {
606            form = form.text("country", country.clone());
607        }
608
609        if let Some(ref country_code) = params.country_code {
610            form = form.text("countryCode", country_code.clone());
611        }
612
613        Ok(form)
614    }
615
616    // ============================================================================
617    // Blocking Methods
618    // ============================================================================
619
620    /// Create a company application (blocking)
621    #[cfg(feature = "sync")]
622    pub fn create_company_application_blocking(
623        &self,
624        request: &CreateCompanyApplicationRequest,
625    ) -> Result<CompanyApplicationResponse> {
626        let path = "/issuing/applications/company";
627        self.post_blocking(path, request)
628    }
629
630    /// Get a company application by ID (blocking)
631    #[cfg(feature = "sync")]
632    pub fn get_company_application_blocking(
633        &self,
634        company_id: &Uuid,
635    ) -> Result<CompanyApplicationResponse> {
636        let path = format!("/issuing/applications/company/{company_id}");
637        self.get_blocking(&path)
638    }
639
640    /// Update a company application (blocking)
641    #[cfg(feature = "sync")]
642    pub fn update_company_application_blocking(
643        &self,
644        company_id: &Uuid,
645        request: &UpdateCompanyApplicationRequest,
646    ) -> Result<CompanyApplicationResponse> {
647        let path = format!("/issuing/applications/company/{company_id}");
648        self.patch_blocking(&path, request)
649    }
650
651    /// Update an ultimate beneficial owner (blocking)
652    #[cfg(feature = "sync")]
653    pub fn update_ultimate_beneficial_owner_blocking(
654        &self,
655        company_id: &Uuid,
656        ubo_id: &Uuid,
657        request: &UpdateUltimateBeneficialOwnerRequest,
658    ) -> Result<CompanyApplicationResponse> {
659        let path = format!("/issuing/applications/company/{company_id}/ubo/{ubo_id}");
660        self.patch_blocking(&path, request)
661    }
662
663    /// Create a user application (blocking)
664    #[cfg(feature = "sync")]
665    pub fn create_user_application_blocking(
666        &self,
667        request: &CreateUserApplicationRequest,
668    ) -> Result<UserApplicationResponse> {
669        let path = "/issuing/applications/user";
670        self.post_blocking(path, request)
671    }
672
673    /// Initiate a user application (blocking)
674    #[cfg(feature = "sync")]
675    pub fn initiate_user_application_blocking(
676        &self,
677        request: &InitiateUserApplicationRequest,
678    ) -> Result<UserApplicationResponse> {
679        let path = "/issuing/applications/user/initiate";
680        self.post_blocking(path, request)
681    }
682
683    /// Get a user application by ID (blocking)
684    #[cfg(feature = "sync")]
685    pub fn get_user_application_blocking(&self, user_id: &Uuid) -> Result<UserApplicationResponse> {
686        let path = format!("/issuing/applications/user/{user_id}");
687        self.get_blocking(&path)
688    }
689
690    /// Update a user application (blocking)
691    #[cfg(feature = "sync")]
692    pub fn update_user_application_blocking(
693        &self,
694        user_id: &Uuid,
695        request: &UpdateUserApplicationRequest,
696    ) -> Result<UserApplicationResponse> {
697        let path = format!("/issuing/applications/user/{user_id}");
698        self.patch_blocking(&path, request)
699    }
700}