1use chrono::{DateTime, Utc};
5use rust_decimal::Decimal;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9#[derive(Debug, Clone, Deserialize, Serialize)]
12pub struct Pagination {
13 pub has_more: bool,
14 pub next_cursor: Option<String>,
15}
16
17#[derive(Debug, Clone, Serialize)]
20pub struct RegisterRequest {
21 pub email: String,
22 pub password: String,
23}
24
25#[derive(Debug, Clone, Deserialize)]
26pub struct RegisterResponse {
27 pub id: Uuid,
28 pub email: String,
29 pub kyc_status: String,
30 pub created_at: DateTime<Utc>,
31}
32
33#[derive(Debug, Clone, Serialize)]
34pub struct LoginRequest {
35 pub email: String,
36 pub password: String,
37}
38
39#[derive(Debug, Clone, Deserialize)]
40pub struct LoginResponse {
41 pub user_id: Uuid,
42 pub email: String,
43 pub access_token: String,
44 pub refresh_token: String,
45}
46
47#[derive(Debug, Clone, Deserialize)]
48pub struct RefreshResponse {
49 pub refreshed: bool,
50}
51
52#[derive(Debug, Clone, Deserialize)]
53pub struct MeResponse {
54 pub id: Uuid,
55 pub email: String,
56 pub kyc_status: String,
57 pub kyc_level: i32,
58 pub max_cards: i32,
59 pub created_at: DateTime<Utc>,
60}
61
62#[derive(Debug, Clone, Serialize, Default)]
65pub struct CreateApiKeyRequest {
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub label: Option<String>,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub environment: Option<String>,
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub expires_in_days: Option<i64>,
72}
73
74#[derive(Debug, Clone, Deserialize)]
75pub struct CreateApiKeyResponse {
76 pub key_id: String,
77 pub label: String,
78 pub environment: String,
79 pub expires_at: Option<DateTime<Utc>>,
80 pub download_url: String,
81 pub download_passphrase: String,
82 pub download_expires_at: Option<DateTime<Utc>>,
83 pub instructions: String,
84}
85
86#[derive(Debug, Clone, Deserialize)]
87pub struct ApiKeyItem {
88 pub key_id: String,
89 pub label: String,
90 pub environment: String,
91 pub bundle_downloaded: bool,
92 pub expires_at: Option<DateTime<Utc>>,
93 pub revoked_at: Option<DateTime<Utc>>,
94 pub last_used_at: Option<DateTime<Utc>>,
95 pub created_at: DateTime<Utc>,
96}
97
98#[derive(Debug, Clone, Deserialize)]
99pub struct RevokeKeyResponse {
100 pub revoked_at: Option<DateTime<Utc>>,
101}
102
103#[derive(Debug, Clone, Serialize)]
106pub struct CreateCardRequest {
107 pub card_product_id: String,
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub label: Option<String>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub initial_deposit: Option<Decimal>,
112}
113
114impl CreateCardRequest {
115 pub fn builder(card_product_id: impl Into<String>) -> CreateCardRequestBuilder {
116 CreateCardRequestBuilder {
117 card_product_id: card_product_id.into(),
118 label: None,
119 initial_deposit: None,
120 }
121 }
122}
123
124pub struct CreateCardRequestBuilder {
125 card_product_id: String,
126 label: Option<String>,
127 initial_deposit: Option<Decimal>,
128}
129
130impl CreateCardRequestBuilder {
131 pub fn label(mut self, label: impl Into<String>) -> Self {
132 self.label = Some(label.into());
133 self
134 }
135
136 pub fn initial_deposit(mut self, amount: Decimal) -> Self {
137 self.initial_deposit = Some(amount);
138 self
139 }
140
141 pub fn build(self) -> CreateCardRequest {
142 CreateCardRequest {
143 card_product_id: self.card_product_id,
144 label: self.label,
145 initial_deposit: self.initial_deposit,
146 }
147 }
148}
149
150#[derive(Debug, Clone, Serialize, Default)]
151pub struct UpdateCardRequest {
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub status: Option<String>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub label: Option<String>,
156}
157
158#[derive(Debug, Clone, Deserialize)]
159pub struct CardResponse {
160 pub id: Uuid,
161 pub last_four: String,
162 pub label: String,
163 pub status: String,
164 pub network: String,
165 pub currency: String,
166 pub card_product_id: String,
167 pub card_type_id: Option<Uuid>,
168 pub created_at: DateTime<Utc>,
169}
170
171#[derive(Debug, Clone, Deserialize)]
172pub struct CardDetailResponse {
173 pub id: Uuid,
174 pub last_four: String,
175 pub label: String,
176 pub status: String,
177 pub network: String,
178 pub currency: String,
179 pub card_product_id: String,
180 pub card_type_id: Option<Uuid>,
181 pub provider_balance: Option<Decimal>,
182 pub expiry_month: i32,
183 pub expiry_year: i32,
184 pub created_at: DateTime<Utc>,
185 pub updated_at: DateTime<Utc>,
186}
187
188#[derive(Debug, Clone, Deserialize)]
189pub struct CardListResponse {
190 pub data: Vec<CardResponse>,
191 pub pagination: Pagination,
192}
193
194#[derive(Debug, Clone, Deserialize)]
195pub struct RevealCardResponse {
196 pub card_number: String,
197 pub cvv: String,
198 pub expiry: String,
199}
200
201#[derive(Debug, Clone, Deserialize)]
202pub struct UpdateCardResponse {
203 pub id: Uuid,
204 pub status: String,
205 pub label: String,
206 pub updated_at: DateTime<Utc>,
207}
208
209#[derive(Debug, Clone, Deserialize)]
210pub struct DeleteCardResponse {
211 pub status: String,
212}
213
214#[derive(Debug, Clone, Deserialize)]
217pub struct CardProduct {
218 pub id: String,
219 pub name: String,
220 pub card_network: String,
221 pub card_type: String,
222 pub currency: String,
223 pub creation_fee: String,
224 pub min_initial_deposit: String,
225 pub max_initial_deposit: String,
226 pub is_active: bool,
227}
228
229#[derive(Debug, Clone, Deserialize)]
230pub struct CardProductDetail {
231 pub id: String,
232 pub name: String,
233 pub card_network: String,
234 pub card_type: String,
235 pub currency: String,
236 pub creation_fee: String,
237 pub min_initial_deposit: String,
238 pub max_initial_deposit: String,
239 pub is_active: bool,
240 pub description: Option<String>,
241 pub daily_spend_limit: Option<String>,
242 pub monthly_spend_limit: Option<String>,
243 pub created_at: DateTime<Utc>,
244 pub updated_at: DateTime<Utc>,
245}
246
247#[derive(Debug, Clone, Deserialize)]
248pub struct CardProductListResponse {
249 pub data: Vec<CardProduct>,
250}
251
252#[derive(Debug, Clone, Deserialize)]
255pub struct ThreeDSChallengeItem {
256 pub id: Uuid,
257 pub challenge_type: String,
258 pub otp: Option<String>,
259 pub auth_url: Option<String>,
260 pub expires_at: Option<String>,
261 pub created_at: DateTime<Utc>,
262}
263
264#[derive(Debug, Clone, Deserialize)]
265pub struct ThreeDSChallengeListResponse {
266 pub data: Vec<ThreeDSChallengeItem>,
267}
268
269#[derive(Debug, Clone, Serialize)]
272pub struct CreateCardHolderRequest {
273 pub card_type_id: Uuid,
274 pub first_name: String,
275 pub last_name: String,
276 pub email: String,
277 pub country: String,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub address: Option<serde_json::Value>,
280}
281
282#[derive(Debug, Clone, Deserialize)]
283pub struct CardHolderResponse {
284 pub id: Uuid,
285 pub card_type_id: Uuid,
286 pub status: String,
287 pub first_name: String,
288 pub last_name: String,
289 pub created_at: DateTime<Utc>,
290}
291
292#[derive(Debug, Clone, Deserialize)]
293pub struct CardHolderDetailResponse {
294 pub id: Uuid,
295 pub card_type_id: Uuid,
296 pub status: String,
297 pub first_name: String,
298 pub last_name: String,
299 pub email: String,
300 pub country: String,
301 pub rejection_reason: Option<String>,
302 pub review_stage: Option<String>,
303 pub created_at: DateTime<Utc>,
304 pub updated_at: DateTime<Utc>,
305}
306
307#[derive(Debug, Clone, Deserialize)]
308pub struct CardHolderListResponse {
309 pub data: Vec<CardHolderResponse>,
310 pub pagination: Pagination,
311}
312
313#[derive(Debug, Clone, Serialize)]
316pub struct FundingRequest {
317 pub amount: Decimal,
318}
319
320#[derive(Debug, Clone, Deserialize)]
321pub struct FundingOperationResponse {
322 pub operation_id: Uuid,
323 pub amount: String,
324 pub fee: String,
325 pub status: String,
326}
327
328#[derive(Debug, Clone, Deserialize)]
329pub struct CardBalanceResponse {
330 pub provider_balance: String,
331 pub currency: String,
332}
333
334#[derive(Debug, Clone, Serialize, Default)]
337pub struct CreatePolicyRequest {
338 pub card_id: Uuid,
339 #[serde(rename = "type")]
340 pub policy_type: String,
341 #[serde(skip_serializing_if = "Option::is_none")]
342 pub amount: Option<Decimal>,
343 #[serde(skip_serializing_if = "Option::is_none")]
344 pub amount_min: Option<Decimal>,
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub amount_max: Option<Decimal>,
347 pub currency: String,
348 #[serde(skip_serializing_if = "Option::is_none")]
349 pub ttl_seconds: Option<i32>,
350 #[serde(skip_serializing_if = "Option::is_none")]
351 pub valid_from: Option<DateTime<Utc>>,
352 #[serde(skip_serializing_if = "Option::is_none")]
353 pub valid_until: Option<DateTime<Utc>>,
354 #[serde(skip_serializing_if = "Option::is_none")]
355 pub max_attempts: Option<i32>,
356 #[serde(skip_serializing_if = "Option::is_none")]
357 pub auto_close_on_success: Option<bool>,
358 #[serde(skip_serializing_if = "Option::is_none")]
359 pub geo: Option<serde_json::Value>,
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub mcc_whitelist: Option<serde_json::Value>,
362 #[serde(skip_serializing_if = "Option::is_none")]
363 pub mcc_blacklist: Option<serde_json::Value>,
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub merchant_pattern: Option<String>,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub schedule: Option<ScheduleRequest>,
368}
369
370impl CreatePolicyRequest {
371 pub fn builder(
372 card_id: Uuid,
373 policy_type: impl Into<String>,
374 currency: impl Into<String>,
375 ) -> CreatePolicyRequestBuilder {
376 CreatePolicyRequestBuilder {
377 card_id,
378 policy_type: policy_type.into(),
379 currency: currency.into(),
380 amount: None,
381 amount_min: None,
382 amount_max: None,
383 ttl_seconds: None,
384 valid_from: None,
385 valid_until: None,
386 max_attempts: None,
387 auto_close_on_success: None,
388 geo: None,
389 mcc_whitelist: None,
390 mcc_blacklist: None,
391 merchant_pattern: None,
392 schedule: None,
393 }
394 }
395}
396
397pub struct CreatePolicyRequestBuilder {
398 card_id: Uuid,
399 policy_type: String,
400 currency: String,
401 amount: Option<Decimal>,
402 amount_min: Option<Decimal>,
403 amount_max: Option<Decimal>,
404 ttl_seconds: Option<i32>,
405 valid_from: Option<DateTime<Utc>>,
406 valid_until: Option<DateTime<Utc>>,
407 max_attempts: Option<i32>,
408 auto_close_on_success: Option<bool>,
409 geo: Option<serde_json::Value>,
410 mcc_whitelist: Option<serde_json::Value>,
411 mcc_blacklist: Option<serde_json::Value>,
412 merchant_pattern: Option<String>,
413 schedule: Option<ScheduleRequest>,
414}
415
416impl CreatePolicyRequestBuilder {
417 pub fn amount(mut self, amount: Decimal) -> Self {
418 self.amount = Some(amount);
419 self
420 }
421
422 pub fn amount_min(mut self, amount: Decimal) -> Self {
423 self.amount_min = Some(amount);
424 self
425 }
426
427 pub fn amount_max(mut self, amount: Decimal) -> Self {
428 self.amount_max = Some(amount);
429 self
430 }
431
432 pub fn ttl_seconds(mut self, ttl: i32) -> Self {
433 self.ttl_seconds = Some(ttl);
434 self
435 }
436
437 pub fn valid_from(mut self, t: DateTime<Utc>) -> Self {
438 self.valid_from = Some(t);
439 self
440 }
441
442 pub fn valid_until(mut self, t: DateTime<Utc>) -> Self {
443 self.valid_until = Some(t);
444 self
445 }
446
447 pub fn max_attempts(mut self, n: i32) -> Self {
448 self.max_attempts = Some(n);
449 self
450 }
451
452 pub fn auto_close_on_success(mut self, v: bool) -> Self {
453 self.auto_close_on_success = Some(v);
454 self
455 }
456
457 pub fn geo(mut self, geo: serde_json::Value) -> Self {
458 self.geo = Some(geo);
459 self
460 }
461
462 pub fn mcc_whitelist(mut self, mcc: serde_json::Value) -> Self {
463 self.mcc_whitelist = Some(mcc);
464 self
465 }
466
467 pub fn mcc_blacklist(mut self, mcc: serde_json::Value) -> Self {
468 self.mcc_blacklist = Some(mcc);
469 self
470 }
471
472 pub fn merchant_pattern(mut self, pattern: impl Into<String>) -> Self {
473 self.merchant_pattern = Some(pattern.into());
474 self
475 }
476
477 pub fn schedule(mut self, schedule: ScheduleRequest) -> Self {
478 self.schedule = Some(schedule);
479 self
480 }
481
482 pub fn build(self) -> CreatePolicyRequest {
483 CreatePolicyRequest {
484 card_id: self.card_id,
485 policy_type: self.policy_type,
486 amount: self.amount,
487 amount_min: self.amount_min,
488 amount_max: self.amount_max,
489 currency: self.currency,
490 ttl_seconds: self.ttl_seconds,
491 valid_from: self.valid_from,
492 valid_until: self.valid_until,
493 max_attempts: self.max_attempts,
494 auto_close_on_success: self.auto_close_on_success,
495 geo: self.geo,
496 mcc_whitelist: self.mcc_whitelist,
497 mcc_blacklist: self.mcc_blacklist,
498 merchant_pattern: self.merchant_pattern,
499 schedule: self.schedule,
500 }
501 }
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct ScheduleRequest {
506 #[serde(skip_serializing_if = "Option::is_none")]
507 pub day_of_month: Option<i32>,
508 #[serde(skip_serializing_if = "Option::is_none")]
509 pub window_hours: Option<i32>,
510 #[serde(skip_serializing_if = "Option::is_none")]
511 pub timezone: Option<String>,
512}
513
514#[derive(Debug, Clone, Deserialize)]
515pub struct PolicyResponse {
516 pub id: Uuid,
517 pub card_id: Uuid,
518 #[serde(rename = "type")]
519 pub policy_type: String,
520 pub status: String,
521 pub amount: Option<Decimal>,
522 pub currency: String,
523 pub valid_from: DateTime<Utc>,
524 pub valid_until: Option<DateTime<Utc>>,
525 pub created_at: DateTime<Utc>,
526}
527
528#[derive(Debug, Clone, Deserialize)]
529pub struct PolicyDetailResponse {
530 pub id: Uuid,
531 pub card_id: Uuid,
532 #[serde(rename = "type")]
533 pub policy_type: String,
534 pub status: String,
535 pub amount: Option<Decimal>,
536 pub amount_min: Option<Decimal>,
537 pub amount_max: Option<Decimal>,
538 pub currency: String,
539 pub valid_from: DateTime<Utc>,
540 pub valid_until: Option<DateTime<Utc>>,
541 pub ttl_seconds: Option<i32>,
542 pub used_attempts: i32,
543 pub max_attempts: i32,
544 pub auto_close_on_success: bool,
545 pub geo_constraints: Option<serde_json::Value>,
546 pub mcc_whitelist: Option<serde_json::Value>,
547 pub mcc_blacklist: Option<serde_json::Value>,
548 pub created_at: DateTime<Utc>,
549}
550
551#[derive(Debug, Clone, Deserialize)]
552pub struct PolicyListResponse {
553 pub data: Vec<PolicyListItem>,
554 pub pagination: Pagination,
555}
556
557#[derive(Debug, Clone, Deserialize)]
558pub struct PolicyListItem {
559 pub id: Uuid,
560 pub card_id: Uuid,
561 #[serde(rename = "type")]
562 pub policy_type: String,
563 pub status: String,
564 pub amount: Option<Decimal>,
565 pub currency: String,
566 pub valid_from: DateTime<Utc>,
567 pub valid_until: Option<DateTime<Utc>>,
568 pub used_attempts: i32,
569 pub max_attempts: i32,
570 pub created_at: DateTime<Utc>,
571}
572
573#[derive(Debug, Clone, Deserialize)]
574pub struct DeletePolicyResponse {
575 pub status: String,
576}
577
578#[derive(Debug, Clone, Deserialize)]
581pub struct BalanceItem {
582 pub available: String,
583 pub pending: String,
584 pub currency: String,
585}
586
587#[derive(Debug, Clone, Deserialize)]
588pub struct BalancesResponse {
589 pub balances: Vec<BalanceItem>,
590}
591
592#[derive(Debug, Clone, Serialize)]
595pub struct CreateWebhookRequest {
596 pub url: String,
597 #[serde(skip_serializing_if = "Vec::is_empty")]
598 pub events: Vec<String>,
599}
600
601#[derive(Debug, Clone, Deserialize)]
602pub struct WebhookResponse {
603 pub id: Uuid,
604 pub url: String,
605 pub secret: String,
606 pub events: Option<Vec<String>>,
607 pub is_active: bool,
608 pub created_at: DateTime<Utc>,
609}
610
611#[derive(Debug, Clone, Deserialize)]
612pub struct WebhookListItem {
613 pub id: Uuid,
614 pub url: String,
615 pub events: Option<Vec<String>>,
616 pub is_active: bool,
617 pub created_at: DateTime<Utc>,
618}