akahu_client/models/
identity.rs

1//! Identity verification and party information models.
2//!
3//! Types for working with identity verification, party data, and address information.
4
5use serde::{Deserialize, Serialize};
6
7use crate::{BankAccountNumber, ConnectionId, space_separated_strings_as_vec};
8
9/// Status of an identity verification
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
11#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
12pub enum IdentityStatus {
13    /// Identity verification is still being processed
14    Processing,
15    /// Identity verification is complete
16    Complete,
17    /// Identity verification encountered an error
18    Error,
19}
20
21/// Identity item containing account holder information
22#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
23pub struct Identity {
24    /// Account holder's name
25    pub name: String,
26
27    /// New Zealand bank account number in standard format (00-0000-0000000-00)
28    pub formatted_account: BankAccountNumber,
29
30    /// Reserved metadata object
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    pub meta: Option<serde_json::Value>,
33}
34
35/// Address information from financial institution
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
37pub struct Address {
38    /// Type of address
39    #[serde(rename = "type")]
40    pub kind: AddressKind,
41
42    /// Raw address string as provided by the bank
43    pub value: String,
44
45    /// Parsed and formatted address string
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub formatted_address: Option<String>,
48
49    /// Google Places API identifier
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub place_id: Option<String>,
52
53    /// Structured address components
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub components: Option<AddressComponents>,
56}
57
58/// Type of address
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
60#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
61pub enum AddressKind {
62    /// Residential address
63    Residential,
64    /// Postal address
65    Postal,
66    /// Unknown address type
67    Unknown,
68}
69
70/// Structured address components
71#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
72pub struct AddressComponents {
73    /// Street address
74    #[serde(default, skip_serializing_if = "Option::is_none")]
75    pub street: Option<String>,
76
77    /// Suburb name
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub suburb: Option<String>,
80
81    /// City name
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub city: Option<String>,
84
85    /// Region or state
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub region: Option<String>,
88
89    /// Postal code
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub postal_code: Option<String>,
92
93    /// Country name
94    #[serde(default, skip_serializing_if = "Option::is_none")]
95    pub country: Option<String>,
96}
97
98/// Account information from identity verification
99#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
100pub struct IdentityAccount {
101    /// Account nickname or product name (e.g., "Spending", "Everyday")
102    pub name: String,
103
104    /// Account number in NZ format or masked identifier
105    pub account_number: BankAccountNumber,
106
107    /// Account holder name as displayed by the bank
108    pub holder: String,
109
110    /// Whether there are additional unlisted joint account holders
111    pub has_unlisted_holders: bool,
112
113    /// Optional address string
114    #[serde(default, skip_serializing_if = "Option::is_none")]
115    pub address: Option<String>,
116
117    /// Bank/institution name
118    pub bank: String,
119
120    /// Optional branch information
121    #[serde(default, skip_serializing_if = "Option::is_none")]
122    pub branch: Option<BranchInfo>,
123}
124
125/// Bank branch information
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
127pub struct BranchInfo {
128    /// Unique Akahu ID beginning with `bank_branch_`
129    #[serde(rename = "_id")]
130    pub id: String,
131
132    /// Descriptive name of the branch
133    pub description: String,
134
135    /// Phone number in E.164 format
136    #[serde(default, skip_serializing_if = "Option::is_none")]
137    pub phone: Option<String>,
138
139    /// Branch address
140    #[serde(default, skip_serializing_if = "Option::is_none")]
141    pub address: Option<String>,
142}
143
144/// Information about the institution connection
145#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
146pub struct IdentitySource {
147    /// Akahu Connection ID beginning with `conn_`
148    #[serde(rename = "_id")]
149    pub id: ConnectionId,
150}
151
152/// OAuth profile information
153#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
154pub struct IdentityProfile {
155    /// Profile ID beginning with `profile_`
156    #[serde(rename = "_id")]
157    pub id: String,
158}
159
160/// Request to verify a name
161#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
162pub struct VerifyNameRequest {
163    /// Family name (surname) - required
164    pub family_name: String,
165
166    /// Given name (first name) - optional
167    #[serde(default, skip_serializing_if = "Option::is_none")]
168    pub given_name: Option<String>,
169
170    /// Middle name(s) - optional
171    /// If multiple middle names, separate with spaces
172    #[serde(
173        rename = "middle_name",
174        default,
175        skip_serializing_if = "Option::is_none",
176        with = "space_separated_strings_as_vec"
177    )]
178    pub middle_names: Option<Vec<String>>,
179}
180
181/// Response from name verification
182#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
183pub struct VerifyNameResponse {
184    /// Whether the verification was successful
185    pub success: bool,
186
187    /// Verification details
188    pub item: VerifyNameItem,
189}
190
191/// Verification details
192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
193pub struct VerifyNameItem {
194    /// Array of verification sources (empty if no matches)
195    pub sources: Vec<VerificationSource>,
196
197    /// Echo of the input parameters
198    pub name: VerifyNameRequest,
199}
200
201/// A single verification source result
202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
203pub struct VerificationSource {
204    /// Type of verification source
205    #[serde(rename = "type")]
206    pub source_type: VerificationSourceType,
207
208    /// Source-specific metadata
209    pub meta: serde_json::Value,
210
211    /// Match result (only present if matched)
212    #[serde(default, skip_serializing_if = "Option::is_none")]
213    pub match_result: Option<MatchResult>,
214
215    /// Boolean flags indicating which name components matched
216    #[serde(default, skip_serializing_if = "Option::is_none")]
217    pub verification: Option<NameVerification>,
218}
219
220/// Type of verification source
221#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
222#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
223pub enum VerificationSourceType {
224    /// Bank account holder name
225    HolderName,
226    /// Party name from financial institution
227    PartyName,
228}
229
230/// Match result from verification
231#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
232#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
233pub enum MatchResult {
234    /// All supplied parameters match the verification source
235    Match,
236    /// Family name matches but other supplied parameters don't
237    PartialMatch,
238}
239
240/// Boolean flags for name component verification
241#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
242pub struct NameVerification {
243    /// Whether family name matched
244    #[serde(default, skip_serializing_if = "Option::is_none")]
245    pub family_name: Option<bool>,
246
247    /// Whether given name matched
248    #[serde(default, skip_serializing_if = "Option::is_none")]
249    pub given_name: Option<bool>,
250
251    /// Whether middle name matched
252    #[serde(default, skip_serializing_if = "Option::is_none")]
253    pub middle_name: Option<bool>,
254
255    /// Whether middle initial matched
256    #[serde(default, skip_serializing_if = "Option::is_none")]
257    pub middle_initial: Option<bool>,
258
259    /// Whether given initial matched
260    #[serde(default, skip_serializing_if = "Option::is_none")]
261    pub given_initial: Option<bool>,
262}
263
264/// Party information from enduring access
265///
266/// Contains customer profile information from financial institutions.
267/// This is returned from the GET /parties endpoint.
268#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
269pub struct Party {
270    /// Unique identifier
271    #[serde(rename = "_id")]
272    pub id: String,
273
274    /// Party name
275    pub name: String,
276
277    /// Email address
278    #[serde(default, skip_serializing_if = "Option::is_none")]
279    pub email: Option<String>,
280
281    /// Phone number
282    #[serde(default, skip_serializing_if = "Option::is_none")]
283    pub phone: Option<String>,
284
285    /// Addresses associated with this party
286    #[serde(default, skip_serializing_if = "Option::is_none")]
287    pub addresses: Option<Vec<Address>>,
288
289    /// Tax identification number
290    #[serde(default, skip_serializing_if = "Option::is_none")]
291    pub tax_number: Option<String>,
292
293    /// Additional metadata
294    #[serde(default, skip_serializing_if = "Option::is_none")]
295    pub meta: Option<serde_json::Value>,
296}