@ktmcp-cli/nordigen 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT.md +153 -434
- package/LICENSE +1 -1
- package/README.md +141 -171
- package/bin/nordigen.js +2 -79
- package/package.json +21 -21
- package/src/api.js +229 -0
- package/src/config.js +59 -0
- package/src/index.js +633 -0
- package/.env.example +0 -11
- package/.eslintrc.json +0 -17
- package/CHANGELOG.md +0 -69
- package/CONTRIBUTING.md +0 -198
- package/EXAMPLES.md +0 -561
- package/INDEX.md +0 -193
- package/OPENCLAW.md +0 -468
- package/PROJECT.md +0 -366
- package/QUICKREF.md +0 -231
- package/SETUP.md +0 -259
- package/SUMMARY.md +0 -419
- package/banner.png +0 -0
- package/banner.svg +0 -25
- package/logo.png +0 -0
- package/scripts/quickstart.sh +0 -110
- package/src/commands/accounts.js +0 -205
- package/src/commands/agreements.js +0 -241
- package/src/commands/auth.js +0 -86
- package/src/commands/config.js +0 -173
- package/src/commands/institutions.js +0 -181
- package/src/commands/payments.js +0 -228
- package/src/commands/requisitions.js +0 -239
- package/src/lib/api.js +0 -491
- package/src/lib/auth.js +0 -113
- package/src/lib/config.js +0 -145
- package/src/lib/output.js +0 -255
- package/src/lib/welcome.js +0 -47
- package/test/api.test.js +0 -88
package/AGENT.md
CHANGED
|
@@ -1,480 +1,199 @@
|
|
|
1
|
-
# Nordigen CLI
|
|
1
|
+
# AGENT.md — Nordigen CLI for AI Agents
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This document explains how to use the Nordigen CLI as an AI agent.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
The
|
|
7
|
+
The `nordigencom` CLI provides access to the Nordigen Account Information Services API. Use it to access bank account data, transactions, balances, and manage open banking connections on behalf of users.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
2. Create and manage end user agreements
|
|
11
|
-
3. Initiate bank account connections
|
|
12
|
-
4. Retrieve account balances and details
|
|
13
|
-
5. Fetch and analyze transaction history
|
|
14
|
-
6. Process payment information
|
|
9
|
+
## Prerequisites
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
The CLI must be authenticated before use. Check status with:
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```javascript
|
|
21
|
-
// Agent discovers banks in a specific country
|
|
22
|
-
async function findInstitutions(country, query = null) {
|
|
23
|
-
if (query) {
|
|
24
|
-
// Search for specific institution
|
|
25
|
-
const result = await exec(`nordigen institutions search "${query}" --country ${country} --json`);
|
|
26
|
-
return JSON.parse(result.stdout);
|
|
27
|
-
} else {
|
|
28
|
-
// List all institutions
|
|
29
|
-
const result = await exec(`nordigen institutions list --country ${country} --json`);
|
|
30
|
-
return JSON.parse(result.stdout);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Usage
|
|
35
|
-
const banks = await findInstitutions('GB', 'Barclays');
|
|
13
|
+
```bash
|
|
14
|
+
nordigencom auth status
|
|
36
15
|
```
|
|
37
16
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
async function connectBankAccount(institutionId, redirectUrl) {
|
|
43
|
-
// 1. Create end user agreement
|
|
44
|
-
const agreementCmd = `nordigen agreements create --institution-id ${institutionId} --max-days 90 --json`;
|
|
45
|
-
const agreement = JSON.parse((await exec(agreementCmd)).stdout);
|
|
46
|
-
|
|
47
|
-
// 2. Create requisition
|
|
48
|
-
const reqCmd = `nordigen requisitions create --institution-id ${institutionId} --redirect ${redirectUrl} --agreement ${agreement.id} --json`;
|
|
49
|
-
const requisition = JSON.parse((await exec(reqCmd)).stdout);
|
|
50
|
-
|
|
51
|
-
// 3. Return authentication link for user
|
|
52
|
-
return {
|
|
53
|
-
requisitionId: requisition.id,
|
|
54
|
-
authLink: requisition.link,
|
|
55
|
-
status: requisition.status
|
|
56
|
-
};
|
|
57
|
-
}
|
|
17
|
+
If not authenticated, the user must run:
|
|
18
|
+
```bash
|
|
19
|
+
nordigencom config set --secret-id <id> --secret-key <key>
|
|
20
|
+
nordigencom auth login
|
|
58
21
|
```
|
|
59
22
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// Agent retrieves and analyzes transactions
|
|
64
|
-
async function analyzeTransactions(accountId, dateFrom, dateTo) {
|
|
65
|
-
const cmd = `nordigen accounts transactions ${accountId} --from ${dateFrom} --to ${dateTo} --json`;
|
|
66
|
-
const result = await exec(cmd);
|
|
67
|
-
const data = JSON.parse(result.stdout);
|
|
68
|
-
|
|
69
|
-
const transactions = data.transactions.booked || [];
|
|
70
|
-
|
|
71
|
-
// Analyze spending patterns
|
|
72
|
-
const analysis = {
|
|
73
|
-
totalSpent: 0,
|
|
74
|
-
totalIncome: 0,
|
|
75
|
-
categories: {},
|
|
76
|
-
transactionCount: transactions.length
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
transactions.forEach(tx => {
|
|
80
|
-
const amount = parseFloat(tx.transactionAmount.amount);
|
|
81
|
-
if (amount < 0) {
|
|
82
|
-
analysis.totalSpent += Math.abs(amount);
|
|
83
|
-
} else {
|
|
84
|
-
analysis.totalIncome += amount;
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return analysis;
|
|
89
|
-
}
|
|
90
|
-
```
|
|
23
|
+
## All Commands
|
|
24
|
+
|
|
25
|
+
### Config
|
|
91
26
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Agent checks balances across multiple accounts
|
|
96
|
-
async function checkAllBalances(accountIds) {
|
|
97
|
-
const balances = await Promise.all(
|
|
98
|
-
accountIds.map(async (accountId) => {
|
|
99
|
-
try {
|
|
100
|
-
const cmd = `nordigen accounts balances ${accountId} --json`;
|
|
101
|
-
const result = await exec(cmd);
|
|
102
|
-
const data = JSON.parse(result.stdout);
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
accountId,
|
|
106
|
-
balances: data.balances,
|
|
107
|
-
success: true
|
|
108
|
-
};
|
|
109
|
-
} catch (error) {
|
|
110
|
-
return {
|
|
111
|
-
accountId,
|
|
112
|
-
error: error.message,
|
|
113
|
-
success: false
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
return balances;
|
|
120
|
-
}
|
|
27
|
+
```bash
|
|
28
|
+
nordigencom config set --secret-id <id> --secret-key <key>
|
|
29
|
+
nordigencom config show
|
|
121
30
|
```
|
|
122
31
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
async function financialHealthCheck(userId) {
|
|
129
|
-
// 1. Get all user's requisitions
|
|
130
|
-
const reqList = await exec('nordigen requisitions list --json');
|
|
131
|
-
const requisitions = JSON.parse(reqList.stdout).results;
|
|
132
|
-
|
|
133
|
-
// 2. Extract all account IDs
|
|
134
|
-
const accountIds = requisitions.flatMap(req => req.accounts);
|
|
135
|
-
|
|
136
|
-
// 3. Check balances
|
|
137
|
-
const balances = await checkAllBalances(accountIds);
|
|
138
|
-
|
|
139
|
-
// 4. Get recent transactions (last 30 days)
|
|
140
|
-
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
|
141
|
-
.toISOString().split('T')[0];
|
|
142
|
-
const today = new Date().toISOString().split('T')[0];
|
|
143
|
-
|
|
144
|
-
const transactionAnalysis = await Promise.all(
|
|
145
|
-
accountIds.map(id => analyzeTransactions(id, thirtyDaysAgo, today))
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
// 5. Generate report
|
|
149
|
-
return {
|
|
150
|
-
totalAccounts: accountIds.length,
|
|
151
|
-
totalBalance: balances.reduce((sum, b) => {
|
|
152
|
-
const balance = b.balances?.find(bal => bal.balanceType === 'expected')?.balanceAmount?.amount || 0;
|
|
153
|
-
return sum + parseFloat(balance);
|
|
154
|
-
}, 0),
|
|
155
|
-
monthlySpending: transactionAnalysis.reduce((sum, a) => sum + a.totalSpent, 0),
|
|
156
|
-
monthlyIncome: transactionAnalysis.reduce((sum, a) => sum + a.totalIncome, 0)
|
|
157
|
-
};
|
|
158
|
-
}
|
|
32
|
+
### Auth
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
nordigencom auth login # Obtain JWT token
|
|
36
|
+
nordigencom auth status # Check if authenticated
|
|
159
37
|
```
|
|
160
38
|
|
|
161
|
-
###
|
|
39
|
+
### Institutions
|
|
162
40
|
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
41
|
+
```bash
|
|
42
|
+
# List institutions
|
|
43
|
+
nordigencom institutions list
|
|
44
|
+
nordigencom institutions list --country GB
|
|
45
|
+
nordigencom institutions list --country DE
|
|
46
|
+
nordigencom institutions list --country FR
|
|
168
47
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
48
|
+
# Get single institution
|
|
49
|
+
nordigencom institutions get <institution-id>
|
|
50
|
+
```
|
|
172
51
|
|
|
173
|
-
|
|
174
|
-
if (inst.transaction_total_days >= 730) score += 3;
|
|
175
|
-
else if (inst.transaction_total_days >= 365) score += 2;
|
|
176
|
-
else if (inst.transaction_total_days >= 90) score += 1;
|
|
52
|
+
Country codes: GB, DE, FR, ES, IT, NL, BE, AT, SE, DK, NO, FI, IE, PT, PL, CZ, EE, LV, LT, LU, SI, SK, MT, CY, BG, RO, HR, GR
|
|
177
53
|
|
|
178
|
-
|
|
179
|
-
if (requirements.payments && inst.payments_enabled) score += 2;
|
|
54
|
+
### Agreements
|
|
180
55
|
|
|
181
|
-
|
|
182
|
-
|
|
56
|
+
```bash
|
|
57
|
+
# List agreements
|
|
58
|
+
nordigencom agreements list
|
|
59
|
+
nordigencom agreements list --limit 50 --offset 0
|
|
183
60
|
|
|
184
|
-
|
|
185
|
-
|
|
61
|
+
# Get single agreement
|
|
62
|
+
nordigencom agreements get <agreement-id>
|
|
186
63
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
64
|
+
# Create agreement
|
|
65
|
+
nordigencom agreements create \
|
|
66
|
+
--institution-id <institution-id> \
|
|
67
|
+
--max-historical-days 90 \
|
|
68
|
+
--access-valid-for-days 90 \
|
|
69
|
+
--access-scope balances,details,transactions
|
|
193
70
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
```javascript
|
|
197
|
-
async function categorizeTransactions(accountId, dateFrom, dateTo) {
|
|
198
|
-
const cmd = `nordigen accounts transactions ${accountId} --from ${dateFrom} --to ${dateTo} --json`;
|
|
199
|
-
const result = await exec(cmd);
|
|
200
|
-
const data = JSON.parse(result.stdout);
|
|
201
|
-
|
|
202
|
-
const transactions = data.transactions.booked || [];
|
|
203
|
-
|
|
204
|
-
// Simple rule-based categorization
|
|
205
|
-
const categories = {
|
|
206
|
-
groceries: /tesco|sainsbury|asda|morrisons|aldi|lidl/i,
|
|
207
|
-
transport: /uber|lyft|tfl|national rail|trainline/i,
|
|
208
|
-
utilities: /electricity|gas|water|internet|broadband/i,
|
|
209
|
-
entertainment: /netflix|spotify|amazon prime|cinema/i,
|
|
210
|
-
restaurants: /restaurant|cafe|pizza|burger|mcdonald/i
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const categorized = transactions.map(tx => {
|
|
214
|
-
const description = tx.remittanceInformationUnstructured || '';
|
|
215
|
-
let category = 'other';
|
|
216
|
-
|
|
217
|
-
for (const [cat, pattern] of Object.entries(categories)) {
|
|
218
|
-
if (pattern.test(description)) {
|
|
219
|
-
category = cat;
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return {
|
|
225
|
-
...tx,
|
|
226
|
-
category,
|
|
227
|
-
amount: parseFloat(tx.transactionAmount.amount)
|
|
228
|
-
};
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
// Summarize by category
|
|
232
|
-
const summary = {};
|
|
233
|
-
categorized.forEach(tx => {
|
|
234
|
-
if (!summary[tx.category]) {
|
|
235
|
-
summary[tx.category] = { count: 0, total: 0 };
|
|
236
|
-
}
|
|
237
|
-
summary[tx.category].count++;
|
|
238
|
-
summary[tx.category].total += Math.abs(tx.amount);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return { transactions: categorized, summary };
|
|
242
|
-
}
|
|
71
|
+
# Delete agreement
|
|
72
|
+
nordigencom agreements delete <agreement-id>
|
|
243
73
|
```
|
|
244
74
|
|
|
245
|
-
|
|
75
|
+
Access scopes: `balances`, `details`, `transactions`
|
|
246
76
|
|
|
247
|
-
###
|
|
77
|
+
### Requisitions
|
|
248
78
|
|
|
79
|
+
```bash
|
|
80
|
+
# List requisitions
|
|
81
|
+
nordigencom requisitions list
|
|
82
|
+
nordigencom requisitions list --limit 50 --offset 0
|
|
83
|
+
|
|
84
|
+
# Get single requisition
|
|
85
|
+
nordigencom requisitions get <requisition-id>
|
|
86
|
+
|
|
87
|
+
# Create requisition
|
|
88
|
+
nordigencom requisitions create \
|
|
89
|
+
--institution-id <institution-id> \
|
|
90
|
+
--redirect <callback-url> \
|
|
91
|
+
--reference <unique-reference> \
|
|
92
|
+
--agreement-id <agreement-id> \
|
|
93
|
+
--user-language EN
|
|
94
|
+
|
|
95
|
+
# Delete requisition
|
|
96
|
+
nordigencom requisitions delete <requisition-id>
|
|
249
97
|
```
|
|
250
|
-
User: "Connect my Barclays account"
|
|
251
98
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
3. Need to determine country (ask or infer from context)
|
|
99
|
+
User languages: EN, DE, FR, ES, IT, NL, etc.
|
|
100
|
+
|
|
101
|
+
### Accounts
|
|
256
102
|
|
|
257
|
-
|
|
258
|
-
|
|
103
|
+
```bash
|
|
104
|
+
# Get account metadata
|
|
105
|
+
nordigencom accounts get <account-id>
|
|
259
106
|
|
|
260
|
-
|
|
107
|
+
# Get account balances
|
|
108
|
+
nordigencom accounts balances <account-id>
|
|
261
109
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
2. Select appropriate institution ID
|
|
265
|
-
3. nordigen agreements create --institution-id BARCLAYS_BARCGB22 --max-days 90 --json
|
|
266
|
-
4. nordigen requisitions create --institution-id BARCLAYS_BARCGB22 --redirect https://app.example.com/callback --agreement <ID> --json
|
|
110
|
+
# Get account details
|
|
111
|
+
nordigencom accounts details <account-id>
|
|
267
112
|
|
|
268
|
-
|
|
269
|
-
|
|
113
|
+
# Get account transactions
|
|
114
|
+
nordigencom accounts transactions <account-id>
|
|
270
115
|
```
|
|
271
116
|
|
|
272
|
-
|
|
117
|
+
## JSON Output
|
|
273
118
|
|
|
274
|
-
|
|
275
|
-
User: "How much did I spend on groceries last month?"
|
|
276
|
-
|
|
277
|
-
Agent Actions:
|
|
278
|
-
1. Calculate date range (last month)
|
|
279
|
-
2. Get user's account IDs from stored requisitions
|
|
280
|
-
3. For each account:
|
|
281
|
-
- nordigen accounts transactions <ID> --from 2024-01-01 --to 2024-01-31 --json
|
|
282
|
-
4. Categorize transactions
|
|
283
|
-
5. Sum amounts in "groceries" category
|
|
284
|
-
|
|
285
|
-
Agent Response:
|
|
286
|
-
"You spent £342.67 on groceries last month across 23 transactions. The main stores were Tesco (£178.42), Sainsbury's (£121.30), and Aldi (£42.95)."
|
|
287
|
-
```
|
|
119
|
+
All list and get commands support `--json` for structured output. Always use `--json` when parsing results programmatically:
|
|
288
120
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const result = await exec(command);
|
|
295
|
-
return { success: true, data: JSON.parse(result.stdout) };
|
|
296
|
-
} catch (error) {
|
|
297
|
-
// Parse error message
|
|
298
|
-
const errorData = {
|
|
299
|
-
success: false,
|
|
300
|
-
command: command,
|
|
301
|
-
exitCode: error.code
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
// Check for common errors
|
|
305
|
-
if (error.stderr.includes('Not authenticated')) {
|
|
306
|
-
errorData.type = 'AUTH_REQUIRED';
|
|
307
|
-
errorData.message = 'User needs to authenticate first';
|
|
308
|
-
errorData.action = 'Please run: nordigen auth login --secret-id <id> --secret-key <key>';
|
|
309
|
-
} else if (error.stderr.includes('Token is invalid or expired')) {
|
|
310
|
-
errorData.type = 'TOKEN_EXPIRED';
|
|
311
|
-
errorData.message = 'Authentication token expired';
|
|
312
|
-
errorData.action = 'Re-authenticating automatically...';
|
|
313
|
-
} else if (error.stderr.includes('Rate limit')) {
|
|
314
|
-
errorData.type = 'RATE_LIMIT';
|
|
315
|
-
errorData.message = 'API rate limit exceeded';
|
|
316
|
-
errorData.action = 'Waiting before retry...';
|
|
317
|
-
} else {
|
|
318
|
-
errorData.type = 'UNKNOWN';
|
|
319
|
-
errorData.message = error.stderr;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return errorData;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
121
|
+
```bash
|
|
122
|
+
nordigencom institutions list --json
|
|
123
|
+
nordigencom agreements list --json
|
|
124
|
+
nordigencom requisitions list --json
|
|
125
|
+
nordigencom accounts transactions <account-id> --json
|
|
325
126
|
```
|
|
326
127
|
|
|
327
|
-
##
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (this.state.authenticated) {
|
|
355
|
-
await this.syncRequisitions();
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
async syncRequisitions() {
|
|
360
|
-
const result = await exec('nordigen requisitions list --json');
|
|
361
|
-
const data = JSON.parse(result.stdout);
|
|
362
|
-
this.state.activeRequisitions = data.results;
|
|
363
|
-
this.state.accountIds = data.results.flatMap(r => r.accounts);
|
|
364
|
-
this.state.lastSync = new Date().toISOString();
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async handleQuery(userInput) {
|
|
368
|
-
// Parse user intent
|
|
369
|
-
const intent = this.parseIntent(userInput);
|
|
370
|
-
|
|
371
|
-
switch (intent.type) {
|
|
372
|
-
case 'GET_BALANCE':
|
|
373
|
-
return await this.getBalances();
|
|
374
|
-
case 'GET_TRANSACTIONS':
|
|
375
|
-
return await this.getTransactions(intent.params);
|
|
376
|
-
case 'CONNECT_ACCOUNT':
|
|
377
|
-
return await this.connectAccount(intent.params);
|
|
378
|
-
default:
|
|
379
|
-
return { error: 'Unknown intent' };
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
128
|
+
## Example Workflows
|
|
129
|
+
|
|
130
|
+
### Connect a new bank account
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Step 1: Find the institution
|
|
134
|
+
nordigencom institutions list --country GB --json | jq '.[] | select(.name | contains("Revolut"))'
|
|
135
|
+
|
|
136
|
+
# Step 2: Create an agreement
|
|
137
|
+
nordigencom agreements create \
|
|
138
|
+
--institution-id REVOLUT_REVOGB21 \
|
|
139
|
+
--max-historical-days 90 \
|
|
140
|
+
--access-valid-for-days 90 \
|
|
141
|
+
--json
|
|
142
|
+
|
|
143
|
+
# Step 3: Create a requisition (use agreement ID from step 2)
|
|
144
|
+
nordigencom requisitions create \
|
|
145
|
+
--institution-id REVOLUT_REVOGB21 \
|
|
146
|
+
--redirect https://myapp.com/callback \
|
|
147
|
+
--reference user-123 \
|
|
148
|
+
--agreement-id <agreement-id> \
|
|
149
|
+
--json
|
|
150
|
+
|
|
151
|
+
# Step 4: Send the "link" URL to the user for authorization
|
|
152
|
+
# After authorization, get the requisition to see account IDs
|
|
153
|
+
|
|
154
|
+
nordigencom requisitions get <requisition-id> --json
|
|
383
155
|
```
|
|
384
156
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
```javascript
|
|
395
|
-
// Mock CLI responses for testing
|
|
396
|
-
const mockCLI = {
|
|
397
|
-
'nordigen auth status': { authenticated: true },
|
|
398
|
-
'nordigen institutions list --country GB --json': [
|
|
399
|
-
{ id: 'BARCLAYS_BARCGB22', name: 'Barclays' }
|
|
400
|
-
]
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
async function testAgentFlow() {
|
|
404
|
-
// Test institution discovery
|
|
405
|
-
const banks = await findInstitutions('GB', 'Barclays');
|
|
406
|
-
assert(banks.length > 0);
|
|
407
|
-
|
|
408
|
-
// Test error handling
|
|
409
|
-
const result = await safeExecute('nordigen accounts get invalid-id --json');
|
|
410
|
-
assert(result.success === false);
|
|
411
|
-
|
|
412
|
-
// Test transaction analysis
|
|
413
|
-
const analysis = await analyzeTransactions('test-account', '2024-01-01', '2024-01-31');
|
|
414
|
-
assert(analysis.transactionCount >= 0);
|
|
415
|
-
}
|
|
157
|
+
### Retrieve account transactions
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Get all booked transactions as JSON
|
|
161
|
+
nordigencom accounts transactions <account-id> --json | jq '.transactions.booked'
|
|
162
|
+
|
|
163
|
+
# Filter transactions by amount
|
|
164
|
+
nordigencom accounts transactions <account-id> --json | jq '.transactions.booked[] | select(.transactionAmount.amount | tonumber > 100)'
|
|
416
165
|
```
|
|
417
166
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
def run_nordigen_command(command):
|
|
425
|
-
"""Execute Nordigen CLI command and return JSON output."""
|
|
426
|
-
result = subprocess.run(
|
|
427
|
-
command,
|
|
428
|
-
shell=True,
|
|
429
|
-
capture_output=True,
|
|
430
|
-
text=True
|
|
431
|
-
)
|
|
432
|
-
|
|
433
|
-
if result.returncode != 0:
|
|
434
|
-
raise Exception(f"Command failed: {result.stderr}")
|
|
435
|
-
|
|
436
|
-
return json.loads(result.stdout)
|
|
437
|
-
|
|
438
|
-
# Agent function
|
|
439
|
-
def get_account_summary(account_id):
|
|
440
|
-
"""Get comprehensive account summary."""
|
|
441
|
-
|
|
442
|
-
# Get balances
|
|
443
|
-
balances = run_nordigen_command(
|
|
444
|
-
f"nordigen accounts balances {account_id} --json"
|
|
445
|
-
)
|
|
446
|
-
|
|
447
|
-
# Get transactions (last 30 days)
|
|
448
|
-
from datetime import datetime, timedelta
|
|
449
|
-
end_date = datetime.now().strftime('%Y-%m-%d')
|
|
450
|
-
start_date = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
|
|
451
|
-
|
|
452
|
-
transactions = run_nordigen_command(
|
|
453
|
-
f"nordigen accounts transactions {account_id} --from {start_date} --to {end_date} --json"
|
|
454
|
-
)
|
|
455
|
-
|
|
456
|
-
# Format for LLM context
|
|
457
|
-
return {
|
|
458
|
-
"account_id": account_id,
|
|
459
|
-
"balances": balances["balances"],
|
|
460
|
-
"recent_transactions": len(transactions["transactions"]["booked"]),
|
|
461
|
-
"transaction_data": transactions
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
# Use in prompt
|
|
465
|
-
account_summary = get_account_summary("abc-123")
|
|
466
|
-
prompt = f"""
|
|
467
|
-
Analyze this bank account and provide insights:
|
|
468
|
-
|
|
469
|
-
{json.dumps(account_summary, indent=2)}
|
|
470
|
-
|
|
471
|
-
Please provide:
|
|
472
|
-
1. Current financial position
|
|
473
|
-
2. Spending patterns
|
|
474
|
-
3. Recommendations
|
|
475
|
-
"""
|
|
167
|
+
### Monitor account balances
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Get current balance
|
|
171
|
+
nordigencom accounts balances <account-id> --json | jq '.balances[] | select(.balanceType == "interimAvailable")'
|
|
476
172
|
```
|
|
477
173
|
|
|
478
|
-
##
|
|
174
|
+
## Requisition Flow
|
|
175
|
+
|
|
176
|
+
The typical flow for connecting a bank account:
|
|
177
|
+
|
|
178
|
+
1. **Create Agreement** — Define what data you need and for how long
|
|
179
|
+
2. **Create Requisition** — Generate an authorization link
|
|
180
|
+
3. **User Authorizes** — User clicks the link and authenticates with their bank
|
|
181
|
+
4. **Retrieve Accounts** — After authorization, get account IDs from the requisition
|
|
182
|
+
5. **Access Data** — Use account IDs to fetch balances, details, and transactions
|
|
183
|
+
|
|
184
|
+
## Error Handling
|
|
185
|
+
|
|
186
|
+
The CLI exits with code 1 on error and prints an error message to stderr. Common errors:
|
|
187
|
+
|
|
188
|
+
- `Authentication failed` — Run `nordigencom auth login`
|
|
189
|
+
- `Resource not found` — Check the ID is correct
|
|
190
|
+
- `Rate limit exceeded` — Wait before retrying
|
|
191
|
+
|
|
192
|
+
## Tips for Agents
|
|
479
193
|
|
|
480
|
-
|
|
194
|
+
1. Always use `--json` when you need to extract specific fields
|
|
195
|
+
2. When creating requisitions, always provide a unique reference (e.g., user ID)
|
|
196
|
+
3. Store agreement IDs and requisition IDs for later use
|
|
197
|
+
4. The authorization link expires after a period, so create new requisitions as needed
|
|
198
|
+
5. JWT tokens are automatically refreshed — no need to re-authenticate unless credentials expire
|
|
199
|
+
6. Use country codes to filter institutions for better UX
|