akahu_client/client/
transactions.rs

1//! Transaction Endpoints
2//!
3//! This module contains methods for retrieving settled and pending transactions.
4
5use crate::{AccountId, Cursor, PaginatedResponse, PendingTransaction, Transaction, UserToken};
6
7use super::AkahuClient;
8use reqwest::Method;
9use std::collections::HashMap;
10
11impl AkahuClient {
12    /// Get a list of the user's settled transactions within a specified time range.
13    ///
14    /// This endpoint returns settled transactions for all accounts that the user has connected
15    /// to your application. The response is paginated - use the `cursor.next` value to fetch
16    /// subsequent pages.
17    ///
18    /// **Important Notes:**
19    /// - Time range defaults to the entire range accessible to your app if not specified
20    /// - Transactions will look different depending on your app's permissions
21    /// - All transaction timestamps are in UTC
22    /// - The start query parameter is exclusive (transactions after this timestamp)
23    /// - The end query parameter is inclusive (transactions through this timestamp)
24    /// - All Akahu timestamps use millisecond resolution (e.g. 2025-01-01T11:59:59.999Z)
25    /// - Each page contains a maximum of 100 transactions
26    /// - When querying multiple pages, use the same start/end parameters with the cursor
27    ///
28    /// # Arguments
29    ///
30    /// * `user_token` - The user's access token obtained through OAuth
31    /// * `query` - Optional query parameters to filter by date range and paginate
32    ///
33    /// # Returns
34    ///
35    /// A paginated response containing transactions and a cursor for fetching more pages.
36    ///
37    /// [<https://developers.akahu.nz/reference/get_transactions>]
38    pub async fn get_transactions(
39        &self,
40        user_token: &UserToken,
41        start: Option<chrono::DateTime<chrono::Utc>>,
42        end: Option<chrono::DateTime<chrono::Utc>>,
43        cursor: Option<Cursor>,
44    ) -> crate::error::AkahuResult<PaginatedResponse<Transaction>> {
45        const URI: &str = "transactions";
46
47        let headers = self.build_user_headers(user_token)?;
48
49        let mut query_params = HashMap::new();
50
51        if let Some(start) = start {
52            query_params.insert(
53                "start",
54                start.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
55            );
56        }
57
58        if let Some(end) = end {
59            query_params.insert(
60                "end",
61                end.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
62            );
63        }
64
65        if let Some(cursor) = cursor {
66            query_params.insert("cursor", cursor.to_string());
67        }
68
69        let url =
70            reqwest::Url::parse_with_params(&format!("{}/{}", self.base_url, URI), &query_params)?;
71
72        let req = self
73            .client
74            .request(Method::GET, url)
75            .headers(headers)
76            .build()?;
77
78        self.execute_request(req).await
79    }
80
81    /// Get a list of the user's pending transactions.
82    ///
83    /// This endpoint returns pending transactions for all accounts that the user has connected
84    /// to your application. Pending transactions are not stable - the date or description may
85    /// change due to the unreliable nature of underlying NZ bank data. They are not assigned
86    /// unique identifiers and are not enriched by Akahu.
87    ///
88    /// **Important Notes:**
89    /// - Pending transactions may change before they settle
90    /// - They do not have unique IDs
91    /// - They are not enriched with merchant/category data
92    /// - All timestamps are in UTC
93    /// - The `updated_at` field indicates when the transaction was last fetched
94    /// - This endpoint is not paginated and returns all pending transactions
95    ///
96    /// # Arguments
97    ///
98    /// * `user_token` - The user's access token obtained through OAuth
99    ///
100    /// # Returns
101    ///
102    /// A vector containing all pending transactions.
103    ///
104    /// [<https://developers.akahu.nz/reference/get_transactions-pending>]
105    pub async fn get_pending_transactions(
106        &self,
107        user_token: &UserToken,
108    ) -> crate::error::AkahuResult<Vec<PendingTransaction>> {
109        const URI: &str = "transactions/pending";
110
111        let headers = self.build_user_headers(user_token)?;
112
113        let req = self
114            .client
115            .request(Method::GET, format!("{}/{}", self.base_url, URI))
116            .headers(headers)
117            .build()?;
118
119        let response: crate::models::ListResponse<PendingTransaction> =
120            self.execute_request(req).await?;
121
122        Ok(response.items)
123    }
124
125    /// Get settled transactions for a specific account within a specified time range.
126    ///
127    /// This endpoint returns settled transactions for a specific connected account.
128    /// The response is paginated - use the `cursor.next` value to fetch subsequent pages.
129    ///
130    /// **Important Notes:**
131    /// - Time range defaults to the entire range accessible to your app if not specified
132    /// - All transaction timestamps are in UTC
133    /// - The start query parameter is exclusive (transactions after this timestamp)
134    /// - The end query parameter is inclusive (transactions through this timestamp)
135    /// - All Akahu timestamps use millisecond resolution
136    /// - Each page contains a maximum of 100 transactions
137    /// - When querying multiple pages, use the same start/end parameters with the cursor
138    ///
139    /// # Arguments
140    ///
141    /// * `user_token` - The user's access token obtained through OAuth
142    /// * `account_id` - The unique identifier for the account (prefixed with `acc_`)
143    /// * `query` - Optional query parameters to filter by date range and paginate
144    ///
145    /// # Returns
146    ///
147    /// A paginated response containing transactions and a cursor for fetching more pages.
148    ///
149    /// [<https://developers.akahu.nz/reference/get_accounts-id-transactions>]
150    pub async fn get_account_transactions(
151        &self,
152        user_token: &UserToken,
153        account_id: &AccountId,
154        start: Option<chrono::DateTime<chrono::Utc>>,
155        end: Option<chrono::DateTime<chrono::Utc>>,
156        cursor: Option<Cursor>,
157    ) -> crate::error::AkahuResult<PaginatedResponse<Transaction>> {
158        let uri = format!("accounts/{}/transactions", account_id.as_str());
159
160        let headers = self.build_user_headers(user_token)?;
161
162        let mut query_params = HashMap::new();
163
164        if let Some(start) = start {
165            query_params.insert(
166                "start",
167                start.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
168            );
169        }
170
171        if let Some(end) = end {
172            query_params.insert(
173                "end",
174                end.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
175            );
176        }
177
178        if let Some(cursor) = cursor {
179            query_params.insert("cursor", cursor.to_string());
180        }
181
182        let url =
183            reqwest::Url::parse_with_params(&format!("{}/{}", self.base_url, uri), &query_params)?;
184
185        let req = self
186            .client
187            .request(Method::GET, url)
188            .headers(headers)
189            .build()?;
190
191        self.execute_request(req).await
192    }
193
194    /// Get pending transactions for a specific account.
195    ///
196    /// This endpoint returns pending transactions for a specific connected account.
197    /// Pending transactions are not stable - the date or description may change due to
198    /// the unreliable nature of underlying NZ bank data. They are not assigned unique
199    /// identifiers and are not enriched by Akahu.
200    ///
201    /// **Important Notes:**
202    /// - Pending transactions may change before they settle
203    /// - They do not have unique IDs
204    /// - They are not enriched with merchant/category data
205    /// - All timestamps are in UTC
206    /// - The `updated_at` field indicates when the transaction was last fetched
207    /// - This endpoint is not paginated and returns all pending transactions
208    ///
209    /// # Arguments
210    ///
211    /// * `user_token` - The user's access token obtained through OAuth
212    /// * `account_id` - The unique identifier for the account (prefixed with `acc_`)
213    ///
214    /// # Returns
215    ///
216    /// A vector containing all pending transactions for the account.
217    ///
218    /// [<https://developers.akahu.nz/reference/get_accounts-id-transactions-pending>]
219    pub async fn get_account_pending_transactions(
220        &self,
221        user_token: &UserToken,
222        account_id: &AccountId,
223    ) -> crate::error::AkahuResult<Vec<PendingTransaction>> {
224        let uri = format!("accounts/{}/transactions/pending", account_id.as_str());
225
226        let headers = self.build_user_headers(user_token)?;
227
228        let req = self
229            .client
230            .request(Method::GET, format!("{}/{}", self.base_url, uri))
231            .headers(headers)
232            .build()?;
233
234        let response: crate::models::ListResponse<PendingTransaction> =
235            self.execute_request(req).await?;
236
237        Ok(response.items)
238    }
239}