feat(transactions): add full pagination support with older_id and custom count parameters

This commit is contained in:
Juergen Kunz
2025-07-25 02:58:15 +00:00
parent 7cb38acf1e
commit 1190500221
4 changed files with 169 additions and 6 deletions

View File

@@ -1,5 +1,17 @@
# Changelog # Changelog
## 2025-07-25 - 4.1.0 - feat(transactions)
Enhanced transaction pagination support with full control over historical data retrieval
- Added full `IBunqPaginationOptions` support to `getTransactions()` method
- Now supports `older_id` for paginating backwards through historical transactions
- Supports custom `count` parameter (defaults to 200)
- Maintains backward compatibility - passing a number is still treated as `newer_id`
- Only includes pagination parameters that are explicitly set (not false/undefined)
- Added `example.pagination.ts` demonstrating various pagination patterns
This enhancement allows banking applications to properly fetch and paginate through historical transaction data using both `newer_id` and `older_id` parameters.
## 2025-07-25 - 4.0.0 - BREAKING CHANGE(core) ## 2025-07-25 - 4.0.0 - BREAKING CHANGE(core)
Complete stateless architecture - consumers now have full control over session persistence Complete stateless architecture - consumers now have full control over session persistence

128
example.pagination.ts Normal file
View File

@@ -0,0 +1,128 @@
import { BunqAccount, IBunqPaginationOptions } from './ts/index.js';
// Example demonstrating the enhanced pagination support in getTransactions
async function demonstratePagination() {
const bunq = new BunqAccount({
apiKey: 'your-api-key',
deviceName: 'Pagination Demo',
environment: 'PRODUCTION',
});
// Initialize and get session
const sessionData = await bunq.init();
// Get accounts
const { accounts } = await bunq.getAccounts();
const account = accounts[0];
// Example 1: Get most recent transactions (default behavior)
const recentTransactions = await account.getTransactions();
console.log(`Got ${recentTransactions.length} recent transactions`);
// Example 2: Get transactions with custom count
const smallBatch = await account.getTransactions({ count: 10 });
console.log(`Got ${smallBatch.length} transactions with custom count`);
// Example 3: Get older transactions using older_id
if (recentTransactions.length > 0) {
const oldestTransaction = recentTransactions[recentTransactions.length - 1];
const olderTransactions = await account.getTransactions({
count: 50,
older_id: oldestTransaction.id
});
console.log(`Got ${olderTransactions.length} older transactions`);
}
// Example 4: Get newer transactions using newer_id
if (recentTransactions.length > 0) {
const newestTransaction = recentTransactions[0];
const newerTransactions = await account.getTransactions({
count: 20,
newer_id: newestTransaction.id
});
console.log(`Got ${newerTransactions.length} newer transactions`);
}
// Example 5: Backward compatibility - using number as newer_id
const backwardCompatible = await account.getTransactions(12345);
console.log(`Backward compatible call returned ${backwardCompatible.length} transactions`);
// Example 6: Paginating through all historical transactions
async function getAllTransactions(account: any): Promise<any[]> {
const allTransactions: any[] = [];
let lastTransactionId: number | false = false;
let hasMore = true;
while (hasMore) {
const options: IBunqPaginationOptions = {
count: 200,
older_id: lastTransactionId
};
const batch = await account.getTransactions(options);
if (batch.length === 0) {
hasMore = false;
} else {
allTransactions.push(...batch);
lastTransactionId = batch[batch.length - 1].id;
console.log(`Fetched ${batch.length} transactions, total: ${allTransactions.length}`);
}
}
return allTransactions;
}
// Example 7: Getting transactions between two dates
async function getTransactionsBetweenDates(
account: any,
startDate: Date,
endDate: Date
): Promise<any[]> {
const transactions: any[] = [];
let olderId: number | false = false;
let keepFetching = true;
while (keepFetching) {
const batch = await account.getTransactions({
count: 200,
older_id: olderId
});
if (batch.length === 0) {
keepFetching = false;
break;
}
for (const transaction of batch) {
const transactionDate = new Date(transaction.created);
if (transactionDate >= startDate && transactionDate <= endDate) {
transactions.push(transaction);
} else if (transactionDate < startDate) {
// We've gone past our date range
keepFetching = false;
break;
}
}
olderId = batch[batch.length - 1].id;
}
return transactions;
}
// Usage
const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
const transactionsLastMonth = await getTransactionsBetweenDates(
account,
lastMonth,
new Date()
);
console.log(`Found ${transactionsLastMonth.length} transactions in the last month`);
}
// Run the demo
demonstratePagination().catch(console.error);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@apiclient.xyz/bunq", "name": "@apiclient.xyz/bunq",
"version": "4.0.1", "version": "4.1.0",
"private": false, "private": false,
"description": "A full-featured TypeScript/JavaScript client for the bunq API", "description": "A full-featured TypeScript/JavaScript client for the bunq API",
"type": "module", "type": "module",

View File

@@ -111,18 +111,41 @@ export class BunqMonetaryAccount {
/** /**
* gets all transactions on this account * gets all transactions on this account
* @param options - Pagination options or a number for backward compatibility (treated as newer_id)
*/ */
public async getTransactions(startingIdArg: number | false = false): Promise<BunqTransaction[]> { public async getTransactions(options?: IBunqPaginationOptions | number | false): Promise<BunqTransaction[]> {
const paginationOptions: IBunqPaginationOptions = { let paginationOptions: IBunqPaginationOptions = {};
count: 200,
newer_id: startingIdArg, // Backward compatibility: if a number or false is passed, treat it as newer_id
if (typeof options === 'number' || options === false) {
paginationOptions.newer_id = options;
} else if (options) {
paginationOptions = { ...options };
}
// Set default count if not specified
if (!paginationOptions.count) {
paginationOptions.count = 200;
}
// Build clean pagination object - only include properties that are not false/undefined
const cleanPaginationOptions: IBunqPaginationOptions = {
count: paginationOptions.count,
}; };
if (paginationOptions.newer_id !== undefined && paginationOptions.newer_id !== false) {
cleanPaginationOptions.newer_id = paginationOptions.newer_id;
}
if (paginationOptions.older_id !== undefined && paginationOptions.older_id !== false) {
cleanPaginationOptions.older_id = paginationOptions.older_id;
}
await this.bunqAccountRef.apiContext.ensureValidSession(); await this.bunqAccountRef.apiContext.ensureValidSession();
const response = await this.bunqAccountRef.getHttpClient().list( const response = await this.bunqAccountRef.getHttpClient().list(
`/v1/user/${this.bunqAccountRef.userId}/monetary-account/${this.id}/payment`, `/v1/user/${this.bunqAccountRef.userId}/monetary-account/${this.id}/payment`,
paginationOptions cleanPaginationOptions
); );
const transactionsArray: BunqTransaction[] = []; const transactionsArray: BunqTransaction[] = [];