akahu_client/models/account.rs
1//! Rust structs representing the Account Model Akahu uses, the documentation
2//! for the Akahu model this is derived from is
3//! [here](https://developers.akahu.nz/docs/the-account-model).
4
5use serde::{Deserialize, Serialize};
6
7use crate::{AccountId, AuthorizationId, BankAccountNumber};
8
9/// An Akahu account is something that has a balance. Some connections (like
10/// banks) have lots of accounts, while others (like KiwiSaver providers) may
11/// only have one. Different types of accounts have different attributes and
12/// abilities, which can get a bit confusing! The rest of this page should help
13/// you figure everything out, from an account's provider to whether it can make
14/// payments.
15///
16/// Keep in mind that we limit what information is available depending on your
17/// app permissions. This is done in order to protect user privacy, however it
18/// also means that some of the data here may not be visible to you.
19#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
20pub struct Account {
21 /// The `id` key is a unique identifier for the account in the Akahu system.
22 ///
23 /// It is always be prefixed by acc_ so that you can tell that it belongs to
24 /// an account.
25 ///
26 /// [<https://developers.akahu.nz/docs/the-account-model#_id>]
27 #[serde(rename = "_id")]
28 pub id: AccountId,
29
30 /// The identifier of this account's predecessor.
31 ///
32 /// This attribute is only present if the account has been migrated to an
33 /// official open banking connection from a classic Akahu connection.
34 ///
35 /// Read more about official open banking, and migrating to it
36 /// [here](https://developers.akahu.nz/docs/official-open-banking).
37 ///
38 /// [<https://developers.akahu.nz/docs/the-account-model#_migrated>]
39 #[serde(default, skip_serializing_if = "Option::is_none", rename = "_migrated")]
40 pub migrated: Option<String>,
41
42 /// Financial accounts are connected to Akahu via an authorisation with the
43 /// user's financial institution. Multiple accounts can be connected during
44 /// a single authorisation, causing them to have the same authorisation
45 /// identifier. This identifier can also be used to link a specific account
46 /// to identity data for the
47 /// [party](https://developers.akahu.nz/reference/get_parties) who completed
48 /// the authorisation.
49 ///
50 /// This identifier can also be used to revoke access to all the accounts
51 /// connected to that authorisation.
52 ///
53 /// For example, if you have 3 ANZ accounts, they will all have the same
54 /// `authorisation`. Your ANZ accounts and your friend's ANZ accounts have
55 /// different logins, so they will have a different `authorisation key`. The
56 /// `authorisation` key is in no way derived or related to your login
57 /// credentials - it's just a random ID.
58 ///
59 /// [<https://developers.akahu.nz/docs/the-account-model#_authorisation>]
60 #[serde(rename = "_authorisation")]
61 pub authorisation: AuthorizationId,
62
63 /// Deprecated: Please use `authorisation` instead.
64 ///
65 /// [<https://developers.akahu.nz/docs/the-account-model#_credentials-deprecated>]
66 #[deprecated(note = "Please use `authorisation` instead.")]
67 #[serde(
68 rename = "_credentials",
69 default,
70 skip_serializing_if = "Option::is_none"
71 )]
72 pub credentials: Option<AuthorizationId>,
73
74 /// This is the name of the account. If the connection allows customisation,
75 /// the name will be the custom name (or nickname), e.g. "Spending Account".
76 /// Otherwise Akahu falls back to the product name, e.g. "Super Saver".
77 ///
78 /// [<https://developers.akahu.nz/docs/the-account-model#name>]
79 pub name: String,
80
81 /// This attribute indicates the status of Akahu's connection to this account.
82 ///
83 /// It is possible for Akahu to lose the ability to authenticate with a
84 /// financial institution if the user revokes Akahu's access directly via
85 /// their institution, or changes their login credentials, which in some
86 /// cases can cause our long-lived access to be revoked.
87 ///
88 /// [<https://developers.akahu.nz/docs/the-account-model#status>]
89 pub status: Active,
90
91 /// If the account has a well defined account number (eg. a bank account
92 /// number, or credit card number) this will be defined here with a standard
93 /// format across connections. This field will be the value undefined for
94 /// accounts with KiwiSaver providers and investment platform accounts.
95 ///
96 /// For NZ banks, we use the common format 00-0000-0000000-00. For credit
97 /// cards, we return a redacted card number 1234-****-****-1234 or
98 /// ****-****-****-1234
99 ///
100 /// [<https://developers.akahu.nz/docs/the-account-model#formatted_account>]
101 // TODO: could hyave a strongly defined type here.
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub formatted_acount: Option<String>,
104
105 /// Akahu can refresh different parts of an account's data at different rates.
106 /// The timestamps in the refreshed object tell you when that account data was
107 /// last updated.
108 ///
109 /// When looking at a timestamp in here, you can think "Akahu's view of the
110 /// account (balance/metadata/transactions) is up to date as of $TIME".
111 ///
112 /// [<https://developers.akahu.nz/docs/the-account-model#refreshed>]
113 pub refreshed: RefreshDetails,
114
115 /// The account balance.
116 ///
117 /// [<https://developers.akahu.nz/docs/the-account-model#balance>]
118 pub balance: BalanceDetails,
119
120 /// What sort of account this is. Akahu provides specific bank account
121 /// types, and falls back to more general types for other types of
122 /// connection.
123 ///
124 /// [<https://developers.akahu.nz/docs/the-account-model#type>]
125 #[serde(rename = "type")]
126 pub kind: BankAccountKind,
127
128 /// The list of attributes indicates what abilities an account has.
129 ///
130 /// See [Attribute] for more information.
131 ///
132 /// [<https://developers.akahu.nz/docs/the-account-model#attributes>]
133 #[serde(default, skip_serializing_if = "Vec::is_empty")]
134 pub attributes: Vec<Attribute>,
135}
136
137/// This attribute indicates the status of Akahu's connection to this account.
138///
139/// It is possible for Akahu to lose the ability to authenticate with a
140/// financial institution if the user revokes Akahu's access directly via
141/// their institution, or changes their login credentials, which in some
142/// cases can cause our long-lived access to be revoked.
143///
144/// [<https://developers.akahu.nz/docs/the-account-model#status>]
145#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
146#[serde(rename_all = "UPPERCASE")]
147pub enum Active {
148 /// Akahu can authenticate with the institution to retrieve data
149 /// and/or initiate payments for this account.
150 Active,
151 /// Akahu no longer has access to this account. Your
152 /// application will still be able to access Akahu's cached copy of data for
153 /// this account, but this will no longer be updated by
154 /// [refreshes](https://developers.akahu.nz/docs/data-refreshes). Write
155 /// actions such as payments or transfers will no longer be available. Once
156 /// an account is assigned the INACTIVE status, it will stay this way until
157 /// the user re-establishes the connection. When your application observes
158 /// an account with a status of INACTIVE, the user should be directed back
159 /// to the Akahu OAuth flow or to [<https://my.akahu.nz/connections>] where
160 /// they will be prompted to re-establish the connection.
161 Inactive,
162}
163
164/// This is a less defined part of our API that lets us expose data that may be
165/// specific to certain account types or financial institutions. An investment
166/// provider, for example, may expose a breakdown of investment results.
167///
168/// Akahu standardises this metadata as much as possible. However depending on
169/// the specific integration and account, some data fields may be unavailable or
170/// poorly specified. Treat all fields in the meta object as optional.
171///
172/// [<https://developers.akahu.nz/docs/the-account-model#meta>]
173#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
174pub struct AccountMetadata {
175 /// The account holder name as exposed by the provider. In the case of bank
176 /// accounts this is the name on the bank statement.
177 #[serde(default, skip_serializing_if = "Option::is_none")]
178 pub holder: Option<String>,
179
180 /// Indicates if the account has other holders that are not listed in the
181 /// holder field. This only applies to official open banking connections
182 /// where the institution indicates a joint account, but only provides the
183 /// authorising party's name.
184 #[serde(default, skip_serializing_if = "Option::is_none")]
185 pub has_unlisted_holders: Option<bool>,
186
187 /// If the account can be paid but is not a bank account (for example a
188 /// KiwiSaver account), this field will have payment details.
189 #[serde(default, skip_serializing_if = "Option::is_none")]
190 pub payment_details: Option<PaymentDetails>,
191
192 /// Includes detailed information related to a loan account (if available
193 /// from the loan provider).
194 #[serde(default, skip_serializing_if = "Option::is_none")]
195 pub loan_details: Option<LoanDetails>,
196
197 /// An investment breakdown. Details are passed straight through from
198 /// integrations, making them very inconsistent.
199 #[serde(default, skip_serializing_if = "Option::is_none")]
200 pub breakdown: Option<serde_json::Value>,
201
202 /// An investment portfolio. Details are passed through from integrations,
203 /// so some are missing various fields. A maximum of 200 funds/instruments
204 /// are supported per investment account.
205 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub portfolio: Option<serde_json::Value>,
207}
208
209/// Details for making a payment to an account that is not a bank account.
210#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
211pub struct PaymentDetails {
212 /// The recipient's name.
213 pub account_holder: String,
214 /// The recipient's NZ bank account number.
215 pub account_number: BankAccountNumber,
216 /// Details required to be in the payment particulars.
217 #[serde(default, skip_serializing_if = "Option::is_none")]
218 pub particulars: Option<String>,
219 /// Details required to be in the payment code.
220 #[serde(default, skip_serializing_if = "Option::is_none")]
221 pub code: Option<String>,
222 /// Details required to be in the payment reference.
223 #[serde(default, skip_serializing_if = "Option::is_none")]
224 pub reference: Option<String>,
225 /// If there is a minimum amount in order to have the payment accepted, in
226 /// dollars.
227 #[serde(
228 default,
229 skip_serializing_if = "Option::is_none",
230 with = "rust_decimal::serde::arbitrary_precision_option"
231 )]
232 pub minimum_amount: Option<rust_decimal::Decimal>,
233}
234
235/// Detailed information related to a loan account.
236#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
237pub struct LoanDetails {
238 /// The purpose of the loan (E.g. HOME), if we can't determine the purpose,
239 /// this will be UNKNOWN.
240 pub purpose: String,
241 /// The type of loan (E.g. TABLE), if we can't determine the type, this will
242 /// be UNKNOWN.
243 // TODO: Could be an enum but we do not know all possible classifications.
244 #[serde(rename = "type")]
245 pub loan_type: String,
246 /// Interest rate information for the loan.
247 #[serde(default, skip_serializing_if = "Option::is_none")]
248 pub interest: Option<InterestDetails>,
249 /// Is the loan currently in an interest only period?
250 #[serde(default, skip_serializing_if = "Option::is_none")]
251 pub is_interest_only: Option<bool>,
252 /// When the interest only period expires, if available.
253 #[serde(default, skip_serializing_if = "Option::is_none")]
254 pub interest_only_expires_at: Option<chrono::DateTime<chrono::Utc>>,
255 /// The duration/term of the loan for it to be paid to completion from the
256 /// start date of the loan.
257 #[serde(default, skip_serializing_if = "Option::is_none")]
258 pub term: Option<String>,
259 /// When the loan matures, if available.
260 #[serde(default, skip_serializing_if = "Option::is_none")]
261 pub matures_at: Option<chrono::DateTime<chrono::Utc>>,
262 /// The loan initial principal amount, this was the original amount
263 /// borrowed.
264 #[serde(
265 default,
266 skip_serializing_if = "Option::is_none",
267 with = "rust_decimal::serde::arbitrary_precision_option"
268 )]
269 pub initial_principal: Option<rust_decimal::Decimal>,
270 /// Loan repayment information if available.
271 #[serde(default, skip_serializing_if = "Option::is_none")]
272 pub repayment: Option<RepaymentDetails>,
273}
274
275/// Interest rate information for a loan.
276#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
277pub struct InterestDetails {
278 /// The rate of interest.
279 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
280 pub rate: rust_decimal::Decimal,
281 /// The type of interest rate (E.g. FIXED).
282 // TODO: Could be an enum but we do not know all possible classifications.
283 #[serde(rename = "type")]
284 pub interest_type: String,
285 /// When this interest rate expires, if available.
286 pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
287}
288
289/// Loan repayment information.
290#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
291pub struct RepaymentDetails {
292 /// The frequency of the loan repayment (E.g. MONTHLY).
293 pub frequency: String,
294 /// The next repayment date, if available.
295 pub next_date: Option<chrono::DateTime<chrono::Utc>>,
296 /// The next instalment amount.
297 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
298 pub next_amount: rust_decimal::Decimal,
299}
300
301/// Akahu can refresh different parts of an account's data at different rates.
302/// The timestamps in the refreshed object tell you when that account data was
303/// last updated.
304///
305/// When looking at a timestamp in here, you can think "Akahu's view of the
306/// account (balance/metadata/transactions) is up to date as of $TIME".
307///
308/// [<https://developers.akahu.nz/docs/the-account-model#refreshed>]
309#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
310pub struct RefreshDetails {
311 /// When the balance was last updated.
312 #[serde(default, skip_serializing_if = "Option::is_none")]
313 pub balance: Option<chrono::DateTime<chrono::Utc>>,
314
315 /// When other account metadata was last updated (any account property apart
316 /// from balance).
317 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub meta: Option<chrono::DateTime<chrono::Utc>>,
319
320 /// When we last checked for and processed any new transactions.
321 ///
322 /// This flag may be missing when an account has first connected, as it
323 /// takes a few seconds for new transactions to be processed.
324 #[serde(default, skip_serializing_if = "Option::is_none")]
325 pub transactions: Option<chrono::DateTime<chrono::Utc>>,
326
327 /// When we last fetched identity data about the
328 /// [party](https://developers.akahu.nz/docs/enduring-identity-verification#party-data)
329 /// who has authenticated with the financial institution when connecting
330 /// this account.
331 ///
332 /// This data is updated by Akahu on a fixed 30 day interval, regardless of
333 /// your app's [data
334 /// refresh](https://developers.akahu.nz/docs/data-refreshes) configuration.
335 #[serde(default, skip_serializing_if = "Option::is_none")]
336 pub party: Option<chrono::DateTime<chrono::Utc>>,
337}
338
339/// The account balance.
340///
341/// [<https://developers.akahu.nz/docs/the-account-model#balance>]
342#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
343pub struct BalanceDetails {
344 /// The current account balance.
345 ///
346 /// A negative balance indicates the amount owed to the account issuer. For
347 /// example a checking account in overdraft will have a negative balance,
348 /// same as the amount owed on a credit card or the principal remaining on a
349 /// loan.
350 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
351 pub current: rust_decimal::Decimal,
352
353 /// The balance that is currently available to the account holder.
354 #[serde(
355 default,
356 skip_serializing_if = "Option::is_none",
357 with = "rust_decimal::serde::arbitrary_precision_option"
358 )]
359 pub available: Option<rust_decimal::Decimal>,
360
361 /// The credit limit for this account.
362 ///
363 /// For example a credit card limit or an overdraft limit. This value is
364 /// only present when provided directly by the connected financial
365 /// institution.
366 #[serde(
367 default,
368 skip_serializing_if = "Option::is_none",
369 with = "rust_decimal::serde::arbitrary_precision_option"
370 )]
371 pub limit: Option<rust_decimal::Decimal>,
372
373 /// A boolean indicating whether this account is in overdraft.
374 #[serde(default, skip_serializing_if = "Option::is_none")]
375 pub overdrawn: Option<bool>,
376
377 /// The [3 letter ISO 4217 currency code](https://www.xe.com/iso4217.php)
378 /// that this balance is in (e.g. NZD).
379 pub currency: iso_currency::Currency,
380}
381
382/// What sort of account this is. Akahu provides specific bank account types,
383/// and falls back to more general types for other types of connection.
384///
385/// [<https://developers.akahu.nz/docs/the-account-model#type>]
386#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
387#[serde(rename_all = "UPPERCASE")]
388pub enum BankAccountKind {
389 /// An everyday spending account.
390 Checking,
391 /// A savings account.
392 ///
393 /// NOTE: A savings account is not necessarily a regular bank account. It might
394 /// not have transactions associated, or be able to receive payments. Check
395 /// the attributes field to see what this account can do.
396 Savings,
397 /// A credit card.
398 #[serde(rename = "CREDITCARD")]
399 CreditCard,
400 /// A loan account.
401 Loan,
402 /// A KiwiSaver investment product.
403 Kiwisaver,
404 /// A general investment product.
405 Investment,
406 /// A term deposit.
407 #[serde(rename = "TERMDEPOSIT")]
408 TermDeposit,
409 /// An account holding a foreign currency.
410 Foreign,
411 /// An account with tax authorities.
412 Tax,
413 /// An account for rewards points, e.g. Fly Buys or True Rewards.
414 Rewards,
415 /// Available cash for investment or withdrawal from an investment provider.
416 Wallet,
417}
418
419/// The list of attributes indicates what abilities an account has.
420///
421/// [<https://developers.akahu.nz/docs/the-account-model#attributes>]
422#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
423#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
424pub enum Attribute {
425 /// Akahu can fetch available transactions from this account.
426 Transactions,
427 /// This account can receive transfers from accounts belonging to the same
428 /// set of credentials.
429 TransferTo,
430 /// This account can initiate transfers to accounts belonging to the same
431 /// set of credentials.
432 TransferFrom,
433 /// This account can receive payments from another bank account.
434 PaymentTo,
435 /// This account can initiate payments to another bank account.
436 PaymentFrom,
437}