rain_sdk/models/
applications.rs

1//! Models for application endpoints
2
3use crate::models::common::*;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7// ============================================================================
8// Company Application Models
9// ============================================================================
10
11/// Request to create a company application
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(rename_all = "camelCase")]
14pub struct CreateCompanyApplicationRequest {
15    pub initial_user: InitialUser,
16    pub name: String,
17    pub address: Address,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub chain_id: Option<String>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub contract_address: Option<String>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub source_key: Option<String>,
24    pub entity: EntityInfo,
25    pub representatives: Vec<Representative>,
26    pub ultimate_beneficial_owners: Vec<UltimateBeneficialOwner>,
27}
28
29/// Initial user information
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct InitialUser {
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub id: Option<Uuid>,
35    pub first_name: String,
36    pub last_name: String,
37    pub birth_date: String,
38    pub national_id: String,
39    pub country_of_issue: String,
40    pub email: String,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub phone_country_code: Option<String>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub phone_number: Option<String>,
45    pub address: Address,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub role: Option<String>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub wallet_address: Option<String>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub solana_address: Option<String>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub tron_address: Option<String>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub stellar_address: Option<String>,
56    pub ip_address: String,
57    pub is_terms_of_service_accepted: bool,
58}
59
60/// Entity information
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(rename_all = "camelCase")]
63pub struct EntityInfo {
64    pub name: String,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub r#type: Option<String>,
67    pub description: String,
68    pub industry: String,
69    pub registration_number: String,
70    pub tax_id: String,
71    pub website: String,
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub expected_spend: Option<String>,
74}
75
76/// Entity update information (all fields optional for updates)
77#[derive(Debug, Clone, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct EntityUpdateInfo {
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub r#type: Option<String>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub description: Option<String>,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub industry: Option<String>,
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub registration_number: Option<String>,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub tax_id: Option<String>,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub website: Option<String>,
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub expected_spend: Option<String>,
94}
95
96/// Representative information
97#[derive(Debug, Clone, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct Representative {
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub id: Option<Uuid>,
102    pub first_name: String,
103    pub last_name: String,
104    pub birth_date: String,
105    pub national_id: String,
106    pub country_of_issue: String,
107    pub email: String,
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub phone_country_code: Option<String>,
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub phone_number: Option<String>,
112    pub address: Address,
113}
114
115/// Ultimate beneficial owner information
116#[derive(Debug, Clone, Serialize, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct UltimateBeneficialOwner {
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub id: Option<Uuid>,
121    pub first_name: String,
122    pub last_name: String,
123    pub birth_date: String,
124    pub national_id: String,
125    pub country_of_issue: String,
126    pub email: String,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub phone_country_code: Option<String>,
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub phone_number: Option<String>,
131    pub address: Address,
132}
133
134/// Response for company application
135#[derive(Debug, Clone, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct CompanyApplicationResponse {
138    pub id: Uuid,
139    pub name: String,
140    pub address: Address,
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub ultimate_beneficial_owners: Option<Vec<UltimateBeneficialOwnerResponse>>,
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub application_status: Option<ApplicationStatus>,
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub application_external_verification_link: Option<ApplicationLink>,
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub application_completion_link: Option<ApplicationLink>,
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub application_reason: Option<String>,
151}
152
153/// Ultimate beneficial owner response
154#[derive(Debug, Clone, Serialize, Deserialize)]
155#[serde(rename_all = "camelCase")]
156pub struct UltimateBeneficialOwnerResponse {
157    pub id: Uuid,
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub first_name: Option<String>,
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub last_name: Option<String>,
162    #[serde(skip_serializing_if = "Option::is_none")]
163    pub email: Option<String>,
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub application_status: Option<ApplicationStatus>,
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub application_external_verification_link: Option<ApplicationLink>,
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub application_completion_link: Option<ApplicationLink>,
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub application_reason: Option<String>,
172}
173
174/// Request to update a company application
175#[derive(Debug, Clone, Serialize, Deserialize)]
176#[serde(rename_all = "camelCase")]
177pub struct UpdateCompanyApplicationRequest {
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub name: Option<String>,
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub address: Option<Address>,
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub entity: Option<EntityUpdateInfo>,
184}
185
186/// Request to update an ultimate beneficial owner
187#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(rename_all = "camelCase")]
189pub struct UpdateUltimateBeneficialOwnerRequest {
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub first_name: Option<String>,
192    #[serde(skip_serializing_if = "Option::is_none")]
193    pub last_name: Option<String>,
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub birth_date: Option<String>,
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub national_id: Option<String>,
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub country_of_issue: Option<String>,
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub email: Option<String>,
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub address: Option<Address>,
204}
205
206// ============================================================================
207// User Application Models
208// ============================================================================
209
210/// Request to create a user application
211///
212/// This request supports three verification methods (oneOf in OpenAPI spec):
213/// 1. **Using Sumsub Share Token**: Provide only `sumsub_share_token`
214/// 2. **Using Persona Share Token**: Provide only `persona_share_token`
215/// 3. **Using API**: Provide full person data (all `IssuingApplicationPerson` fields)
216///
217/// Exactly one verification method must be provided. The API will validate this at runtime.
218///
219/// # Verification Methods
220///
221/// ## Sumsub Share Token
222/// ```rust
223/// use rain_sdk::models::applications::CreateUserApplicationRequest;
224///
225/// CreateUserApplicationRequest {
226///     sumsub_share_token: Some("your-sumsub-token".to_string()),
227///     persona_share_token: None,
228///     id: None,
229///     first_name: None,
230///     last_name: None,
231///     birth_date: None,
232///     national_id: None,
233///     country_of_issue: None,
234///     email: None,
235///     phone_country_code: None,
236///     phone_number: None,
237///     address: None,
238///     ip_address: "127.0.0.1".to_string(),
239///     occupation: "Engineer".to_string(),
240///     annual_salary: "100000".to_string(),
241///     account_purpose: "Business".to_string(),
242///     expected_monthly_volume: "5000".to_string(),
243///     is_terms_of_service_accepted: true,
244///     wallet_address: None,
245///     solana_address: None,
246///     tron_address: None,
247///     stellar_address: None,
248///     chain_id: None,
249///     contract_address: None,
250///     source_key: None,
251///     has_existing_documents: None,
252/// };
253/// ```
254///
255/// ## Persona Share Token
256/// ```rust
257/// use rain_sdk::models::applications::CreateUserApplicationRequest;
258///
259/// CreateUserApplicationRequest {
260///     sumsub_share_token: None,
261///     persona_share_token: Some("your-persona-token".to_string()),
262///     id: None,
263///     first_name: None,
264///     last_name: None,
265///     birth_date: None,
266///     national_id: None,
267///     country_of_issue: None,
268///     email: None,
269///     phone_country_code: None,
270///     phone_number: None,
271///     address: None,
272///     ip_address: "127.0.0.1".to_string(),
273///     occupation: "Engineer".to_string(),
274///     annual_salary: "100000".to_string(),
275///     account_purpose: "Business".to_string(),
276///     expected_monthly_volume: "5000".to_string(),
277///     is_terms_of_service_accepted: true,
278///     wallet_address: None,
279///     solana_address: None,
280///     tron_address: None,
281///     stellar_address: None,
282///     chain_id: None,
283///     contract_address: None,
284///     source_key: None,
285///     has_existing_documents: None,
286/// };
287/// ```
288///
289/// ## Full API (IssuingApplicationPerson)
290/// ```rust
291/// use rain_sdk::models::applications::CreateUserApplicationRequest;
292/// use rain_sdk::models::common::Address;
293///
294/// CreateUserApplicationRequest {
295///     sumsub_share_token: None,
296///     persona_share_token: None,
297///     id: None,
298///     first_name: Some("John".to_string()),
299///     last_name: Some("Doe".to_string()),
300///     birth_date: Some("2000-01-01".to_string()),
301///     national_id: Some("123456789".to_string()),
302///     country_of_issue: Some("US".to_string()),
303///     email: Some("john@example.com".to_string()),
304///     phone_country_code: Some("1".to_string()),
305///     phone_number: Some("5555555555".to_string()),
306///     address: Some(Address {
307///         line1: "123 Main St".to_string(),
308///         line2: None,
309///         city: "New York".to_string(),
310///         region: "NY".to_string(),
311///         postal_code: "10001".to_string(),
312///         country_code: "US".to_string(),
313///         country: None,
314///     }),
315///     ip_address: "127.0.0.1".to_string(),
316///     occupation: "Engineer".to_string(),
317///     annual_salary: "100000".to_string(),
318///     account_purpose: "Business".to_string(),
319///     expected_monthly_volume: "5000".to_string(),
320///     is_terms_of_service_accepted: true,
321///     wallet_address: None,
322///     solana_address: None,
323///     tron_address: None,
324///     stellar_address: None,
325///     chain_id: None,
326///     contract_address: None,
327///     source_key: None,
328///     has_existing_documents: None,
329/// };
330/// ```
331#[derive(Debug, Clone, Serialize, Deserialize)]
332#[serde(rename_all = "camelCase")]
333pub struct CreateUserApplicationRequest {
334    // Verification method - exactly one must be provided
335    // Option 1: Using Sumsub Share Token
336    #[serde(skip_serializing_if = "Option::is_none")]
337    pub sumsub_share_token: Option<String>,
338    // Option 2: Using Persona Share Token
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub persona_share_token: Option<String>,
341
342    // Option 3: Using API - Full IssuingApplicationPerson fields
343    /// The initiated application's Rain ID, if an application was previously initiated for this user
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub id: Option<Uuid>,
346    /// The person's first name (max 50 characters)
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub first_name: Option<String>,
349    /// The person's last name (max 50 characters)
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub last_name: Option<String>,
352    /// The person's birth date (ISO date format: YYYY-MM-DD)
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub birth_date: Option<String>,
355    /// The person's national id, 9-digit SSN if country of issue is US
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub national_id: Option<String>,
358    /// The person's country of issue of their national id (2-letter country code)
359    #[serde(skip_serializing_if = "Option::is_none")]
360    pub country_of_issue: Option<String>,
361    /// The person's email address
362    #[serde(skip_serializing_if = "Option::is_none")]
363    pub email: Option<String>,
364    /// The user's phone country code (1-3 digits)
365    #[serde(skip_serializing_if = "Option::is_none")]
366    pub phone_country_code: Option<String>,
367    /// The user's phone number (1-15 digits)
368    #[serde(skip_serializing_if = "Option::is_none")]
369    pub phone_number: Option<String>,
370    /// The person's address
371    #[serde(skip_serializing_if = "Option::is_none")]
372    pub address: Option<crate::models::common::Address>,
373
374    // Required fields (always present)
375    /// This user's IP address
376    pub ip_address: String,
377    /// The user's occupation
378    pub occupation: String,
379    /// The user's annual salary
380    pub annual_salary: String,
381    /// The purpose of the user's account
382    pub account_purpose: String,
383    /// The amount of money the user expects to spend each month
384    pub expected_monthly_volume: String,
385    /// Whether the user has accepted the terms of service
386    pub is_terms_of_service_accepted: bool,
387
388    // Optional fields
389    /// This user's EVM address; either walletAddress or solanaAddress or tronAddress or stellarAddress is required if using a Rain-managed solution, but not required otherwise
390    #[serde(skip_serializing_if = "Option::is_none")]
391    pub wallet_address: Option<String>,
392    /// This user's Solana address; either walletAddress or solanaAddress or tronAddress or stellarAddress is required if using a Rain-managed solution, but not required otherwise
393    #[serde(skip_serializing_if = "Option::is_none")]
394    pub solana_address: Option<String>,
395    /// This user's Tron address; either walletAddress or solanaAddress or tronAddress or stellarAddress is required if using a Rain-managed solution, but not required otherwise
396    #[serde(skip_serializing_if = "Option::is_none")]
397    pub tron_address: Option<String>,
398    /// This user's Stellar address; either walletAddress or solanaAddress or tronAddress or stellarAddress is required if using a Rain-managed solution, but not required otherwise
399    #[serde(skip_serializing_if = "Option::is_none")]
400    pub stellar_address: Option<String>,
401    /// If using external collateral contracts, the chain id of the user's external collateral contract; not required if using Rain's collateral contracts
402    #[serde(skip_serializing_if = "Option::is_none")]
403    pub chain_id: Option<String>,
404    /// If using external collateral contracts, the address of the user's external collateral contract; not required if using Rain's collateral contracts
405    #[serde(skip_serializing_if = "Option::is_none")]
406    pub contract_address: Option<String>,
407    /// Unique identifier for where this user is coming from
408    #[serde(skip_serializing_if = "Option::is_none")]
409    pub source_key: Option<String>,
410    /// Whether or not to use existing documents for additional verification
411    #[serde(skip_serializing_if = "Option::is_none")]
412    pub has_existing_documents: Option<bool>,
413}
414
415/// Request to initiate a user application
416#[derive(Debug, Clone, Serialize, Deserialize)]
417#[serde(rename_all = "camelCase")]
418pub struct InitiateUserApplicationRequest {
419    #[serde(skip_serializing_if = "Option::is_none")]
420    pub first_name: Option<String>,
421    #[serde(skip_serializing_if = "Option::is_none")]
422    pub last_name: Option<String>,
423    #[serde(skip_serializing_if = "Option::is_none")]
424    pub email: Option<String>,
425    #[serde(skip_serializing_if = "Option::is_none")]
426    pub wallet_address: Option<String>,
427}
428
429/// Response for user application
430#[derive(Debug, Clone, Serialize, Deserialize)]
431#[serde(rename_all = "camelCase")]
432pub struct UserApplicationResponse {
433    pub id: Uuid,
434    #[serde(skip_serializing_if = "Option::is_none")]
435    pub company_id: Option<Uuid>,
436    #[serde(skip_serializing_if = "Option::is_none")]
437    pub first_name: Option<String>,
438    #[serde(skip_serializing_if = "Option::is_none")]
439    pub last_name: Option<String>,
440    #[serde(skip_serializing_if = "Option::is_none")]
441    pub email: Option<String>,
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub is_active: Option<bool>,
444    #[serde(skip_serializing_if = "Option::is_none")]
445    pub is_terms_of_service_accepted: Option<bool>,
446    #[serde(skip_serializing_if = "Option::is_none")]
447    pub address: Option<Address>,
448    #[serde(skip_serializing_if = "Option::is_none")]
449    pub phone_country_code: Option<String>,
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub phone_number: Option<String>,
452    #[serde(skip_serializing_if = "Option::is_none")]
453    pub wallet_address: Option<String>,
454    #[serde(skip_serializing_if = "Option::is_none")]
455    pub solana_address: Option<String>,
456    #[serde(skip_serializing_if = "Option::is_none")]
457    pub application_status: Option<ApplicationStatus>,
458    #[serde(skip_serializing_if = "Option::is_none")]
459    pub application_external_verification_link: Option<ApplicationLink>,
460    #[serde(skip_serializing_if = "Option::is_none")]
461    pub application_completion_link: Option<ApplicationLink>,
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub application_reason: Option<String>,
464}
465
466/// Request to update a user application
467#[derive(Debug, Clone, Serialize, Deserialize)]
468#[serde(rename_all = "camelCase")]
469pub struct UpdateUserApplicationRequest {
470    #[serde(skip_serializing_if = "Option::is_none")]
471    pub first_name: Option<String>,
472    #[serde(skip_serializing_if = "Option::is_none")]
473    pub last_name: Option<String>,
474    #[serde(skip_serializing_if = "Option::is_none")]
475    pub birth_date: Option<String>,
476    #[serde(skip_serializing_if = "Option::is_none")]
477    pub national_id: Option<String>,
478    #[serde(skip_serializing_if = "Option::is_none")]
479    pub country_of_issue: Option<String>,
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub address: Option<Address>,
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub ip_address: Option<String>,
484    #[serde(skip_serializing_if = "Option::is_none")]
485    pub occupation: Option<String>,
486    #[serde(skip_serializing_if = "Option::is_none")]
487    pub annual_salary: Option<String>,
488    #[serde(skip_serializing_if = "Option::is_none")]
489    pub account_purpose: Option<String>,
490    #[serde(skip_serializing_if = "Option::is_none")]
491    pub expected_monthly_volume: Option<String>,
492    #[serde(skip_serializing_if = "Option::is_none")]
493    pub is_terms_of_service_accepted: Option<bool>,
494    #[serde(skip_serializing_if = "Option::is_none")]
495    pub has_existing_documents: Option<bool>,
496}
497
498// ============================================================================
499// Document Upload Models
500// ============================================================================
501
502/// Parameters for document upload
503#[derive(Debug, Clone)]
504pub struct DocumentUploadParams {
505    pub document_type: String,
506    pub side: String,
507    pub country: Option<String>,
508    pub country_code: Option<String>,
509    pub name: Option<String>, // Only for company documents
510    pub file_path: String,
511}