@firela/api-types 0.0.0-canary.32edff08 → 0.0.0-canary.3d558482

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.
@@ -6,18 +6,12 @@ export const $CreateAccountDto = {
6
6
  path: {
7
7
  type: 'string',
8
8
  description: 'Account path (hierarchical, colon-separated)',
9
- example: 'Assets:CN:Bank:ICBC:Checking'
10
- },
11
- displayName: {
12
- type: 'string',
13
- description:
14
- 'Display name to distinguish accounts at the same path (default: "")',
15
- example: '工资卡'
9
+ example: 'Assets:CN:ICBC:Checking'
16
10
  },
17
11
  openDate: {
18
12
  format: 'date-time',
19
13
  type: 'string',
20
- description: 'Account open date',
14
+ description: 'Account open date (server defaults to today)',
21
15
  example: '2024-01-01'
22
16
  },
23
17
  currencies: {
@@ -45,26 +39,22 @@ export const $CreateAccountDto = {
45
39
  templatePath: {
46
40
  type: 'string',
47
41
  description: 'Reference to account-standards template path',
48
- example: 'Assets:CN:Bank:ICBC:Checking'
42
+ example: 'Assets:CN:Checking'
49
43
  },
50
44
  isCustom: {
51
45
  type: 'boolean',
52
46
  description: 'Whether this is a custom (user-created) account',
53
47
  default: false
54
48
  },
55
- i18nKey: {
56
- type: 'string',
57
- description: 'i18n key for display name (overrides template)',
58
- example: 'account.custom.mybank'
59
- },
60
49
  icon: {
61
50
  type: 'string',
62
51
  description: 'Icon identifier (overrides template)',
63
52
  example: 'bank-custom'
64
53
  },
65
- openMeta: {
54
+ openDirectiveMeta: {
66
55
  type: 'object',
67
- description: 'Additional metadata',
56
+ description:
57
+ 'Open directive metadata (NOT an opening-balance amount — use the opening-balance endpoint)',
68
58
  example: {
69
59
  branch: 'Downtown',
70
60
  accountNumber: '1234'
@@ -76,7 +66,7 @@ export const $CreateAccountDto = {
76
66
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
77
67
  }
78
68
  },
79
- required: ['path', 'openDate']
69
+ required: ['path']
80
70
  } as const;
81
71
 
82
72
  export const $AccountResponseDto = {
@@ -90,13 +80,7 @@ export const $AccountResponseDto = {
90
80
  path: {
91
81
  type: 'string',
92
82
  description: 'Account path (hierarchical, colon-separated)',
93
- example: 'Assets:CN:Bank:ICBC:Checking'
94
- },
95
- displayName: {
96
- type: 'string',
97
- description:
98
- 'Display name distinguishing multiple accounts at the same path',
99
- example: '工资卡'
83
+ example: 'Assets:CN:ICBC:Checking'
100
84
  },
101
85
  type: {
102
86
  type: 'string',
@@ -145,26 +129,26 @@ export const $AccountResponseDto = {
145
129
  templatePath: {
146
130
  type: 'string',
147
131
  description: 'Template path reference',
148
- example: 'Assets:CN:Bank:ICBC:Checking'
132
+ example: 'Assets:CN:Checking'
149
133
  },
150
134
  isCustom: {
151
135
  type: 'boolean',
152
136
  description: 'Whether this is a custom (user-created) account',
153
137
  example: false
154
138
  },
155
- i18nKey: {
139
+ displayName: {
156
140
  type: 'string',
157
- description: 'i18n key for display name',
158
- example: 'account.assets.cn.bank.icbc.checking'
141
+ description: 'Localized display name (ADR-0114, read-time projection)',
142
+ example: 'Checking'
159
143
  },
160
144
  icon: {
161
145
  type: 'string',
162
146
  description: 'Icon identifier',
163
147
  example: 'bank-icbc'
164
148
  },
165
- openMeta: {
149
+ openDirectiveMeta: {
166
150
  type: 'object',
167
- description: 'Account metadata',
151
+ description: 'Open directive metadata (ADR-0115 Decision 9)',
168
152
  example: {
169
153
  branch: 'Downtown'
170
154
  }
@@ -192,7 +176,6 @@ export const $AccountResponseDto = {
192
176
  required: [
193
177
  'id',
194
178
  'path',
195
- 'displayName',
196
179
  'type',
197
180
  'status',
198
181
  'openDate',
@@ -225,11 +208,6 @@ export const $AccountListResponseDto = {
225
208
  export const $UpdateAccountDto = {
226
209
  type: 'object',
227
210
  properties: {
228
- displayName: {
229
- type: 'string',
230
- description: 'Display name to distinguish accounts at the same path',
231
- example: '招行工资卡'
232
- },
233
211
  currencies: {
234
212
  description: 'Allowed currencies (null = no restriction)',
235
213
  example: ['CNY', 'USD'],
@@ -251,19 +229,15 @@ export const $UpdateAccountDto = {
251
229
  'NONE'
252
230
  ]
253
231
  },
254
- i18nKey: {
255
- type: 'string',
256
- description: 'i18n key for display name',
257
- example: 'account.custom.mybank'
258
- },
259
232
  icon: {
260
233
  type: 'string',
261
234
  description: 'Icon identifier',
262
235
  example: 'bank-custom'
263
236
  },
264
- openMeta: {
237
+ openDirectiveMeta: {
265
238
  type: 'object',
266
- description: 'Additional metadata (merged with existing)',
239
+ description:
240
+ 'Open directive metadata (merged with existing; NOT an opening-balance amount)',
267
241
  example: {
268
242
  branch: 'Uptown'
269
243
  }
@@ -310,13 +284,47 @@ export const $ReopenAccountDto = {
310
284
  }
311
285
  } as const;
312
286
 
287
+ export const $CreateOpeningBalanceDto = {
288
+ type: 'object',
289
+ properties: {
290
+ amount: {
291
+ type: 'number',
292
+ description: 'Opening balance amount (non-negative)',
293
+ example: 1000
294
+ },
295
+ currency: {
296
+ type: 'string',
297
+ description: 'Currency code',
298
+ example: 'CNY'
299
+ },
300
+ date: {
301
+ format: 'date-time',
302
+ type: 'string',
303
+ description: 'Opening-balance date (defaults to now)',
304
+ example: '2024-01-01'
305
+ }
306
+ },
307
+ required: ['amount', 'currency']
308
+ } as const;
309
+
310
+ export const $OpeningBalanceResultDto = {
311
+ type: 'object',
312
+ properties: {
313
+ transactionId: {
314
+ type: 'string',
315
+ description: 'Created opening-balance transaction id.'
316
+ }
317
+ },
318
+ required: ['transactionId']
319
+ } as const;
320
+
313
321
  export const $AccountStandardResponseDto = {
314
322
  type: 'object',
315
323
  properties: {
316
324
  path: {
317
325
  type: 'string',
318
326
  description: 'Account path (hierarchical, colon-separated)',
319
- example: 'Assets:CN:Bank:ICBC:Checking'
327
+ example: 'Assets:CN:Checking'
320
328
  },
321
329
  type: {
322
330
  type: 'string',
@@ -324,11 +332,6 @@ export const $AccountStandardResponseDto = {
324
332
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
325
333
  example: 'Assets'
326
334
  },
327
- i18nKey: {
328
- type: 'string',
329
- description: 'i18n key for localized display name',
330
- example: 'account.assets.cn.bank.icbc.checking'
331
- },
332
335
  name: {
333
336
  type: 'string',
334
337
  description: 'Short localized display name',
@@ -353,7 +356,7 @@ export const $AccountStandardResponseDto = {
353
356
  example: 'bank-icbc'
354
357
  }
355
358
  },
356
- required: ['path', 'type', 'i18nKey', 'description', 'tags', 'icon']
359
+ required: ['path', 'type', 'description', 'tags', 'icon']
357
360
  } as const;
358
361
 
359
362
  export const $AccountStandardListResponseDto = {
@@ -383,18 +386,13 @@ export const $AccountStandardListResponseDto = {
383
386
  export const $TemplateMetadataDto = {
384
387
  type: 'object',
385
388
  properties: {
386
- extendable: {
387
- type: 'boolean',
388
- description: 'Whether this path can be extended',
389
- example: true
390
- },
391
389
  rootType: {
392
390
  type: 'string',
393
391
  description: 'Root account type',
394
392
  example: 'Assets'
395
393
  }
396
394
  },
397
- required: ['extendable', 'rootType']
395
+ required: ['rootType']
398
396
  } as const;
399
397
 
400
398
  export const $TemplateMetadataResponseDto = {
@@ -466,6 +464,66 @@ export const $RegionsMetadataResponseDto = {
466
464
  required: ['regions']
467
465
  } as const;
468
466
 
467
+ export const $CostSpecDto = {
468
+ type: 'object',
469
+ properties: {
470
+ mode: {
471
+ type: 'string',
472
+ enum: ['per-unit', 'total', 'date', 'label', 'auto'],
473
+ description: 'Cost specification mode (mirrors engine CostSpec)'
474
+ },
475
+ numberPerUnit: {
476
+ type: 'string',
477
+ description: 'Per-unit cost (required when mode is "per-unit")',
478
+ example: '240'
479
+ },
480
+ totalNumber: {
481
+ type: 'string',
482
+ description: 'Total cost for all units (required when mode is "total")',
483
+ example: '12000'
484
+ },
485
+ currency: {
486
+ type: 'string',
487
+ description: 'Cost currency (required in all modes)',
488
+ example: 'USD'
489
+ },
490
+ date: {
491
+ type: 'string',
492
+ description:
493
+ 'Lot acquisition date, ISO 8601 (required when mode is "date")',
494
+ example: '2024-01-15'
495
+ },
496
+ label: {
497
+ type: 'string',
498
+ description:
499
+ 'Lot label (required when mode is "label"; optional tag in buy modes)'
500
+ },
501
+ merge: {
502
+ type: 'boolean',
503
+ description: 'Merge lots for AVERAGE booking (mode: auto)'
504
+ }
505
+ },
506
+ required: ['mode', 'currency']
507
+ } as const;
508
+
509
+ export const $AmountDto = {
510
+ type: 'object',
511
+ properties: {
512
+ number: {
513
+ type: 'string',
514
+ description:
515
+ 'Amount as decimal string (max 15 integer + 15 decimal digits)',
516
+ example: '170.50'
517
+ },
518
+ currency: {
519
+ type: 'string',
520
+ description: 'Currency/commodity code',
521
+ example: 'USD'
522
+ }
523
+ },
524
+ required: ['number', 'currency']
525
+ } as const;
526
+
469
527
  export const $CreatePostingDto = {
470
528
  type: 'object',
471
529
  properties: {
@@ -473,7 +531,7 @@ export const $CreatePostingDto = {
473
531
  type: 'string',
474
532
  description:
475
533
  'Account name in Beancount format (must start with uppercase, colon-separated)',
476
- example: 'Assets:Bank:Checking'
534
+ example: 'Assets:Checking'
477
535
  },
478
536
  units: {
479
537
  type: 'string',
@@ -495,6 +553,33 @@ export const $CreatePostingDto = {
495
553
  example: {
496
554
  'tax-lot': 'Q1-2024'
497
555
  }
556
+ },
557
+ cost: {
558
+ description:
559
+ 'Cost basis (Beancount `{...}`). Maps to engine costSpec. Required for commodity holdings so they carry a monetary weight that can balance.',
560
+ example: {
561
+ mode: 'per-unit',
562
+ numberPerUnit: '240',
563
+ currency: 'USD'
564
+ },
565
+ allOf: [
566
+ {
567
+ $ref: '#/components/schemas/CostSpecDto'
568
+ }
569
+ ]
570
+ },
571
+ price: {
572
+ description:
573
+ 'Price annotation (Beancount `@...`). Maps to engine price. Used for valuation; cost takes priority for balance weight.',
574
+ example: {
575
+ number: '170',
576
+ currency: 'USD'
577
+ },
578
+ allOf: [
579
+ {
580
+ $ref: '#/components/schemas/AmountDto'
581
+ }
582
+ ]
498
583
  }
499
584
  },
500
585
  required: ['account']
@@ -573,13 +658,39 @@ export const $CreateTransactionDto = {
573
658
  required: ['date', 'narration', 'postings']
574
659
  } as const;
575
660
 
661
+ export const $CostDetailDto = {
662
+ type: 'object',
663
+ properties: {
664
+ number: {
665
+ type: 'string',
666
+ description: 'Per-unit cost basis (mirrors engine Cost.number)',
667
+ example: '240'
668
+ },
669
+ currency: {
670
+ type: 'string',
671
+ description: 'Cost currency',
672
+ example: 'USD'
673
+ },
674
+ date: {
675
+ type: 'string',
676
+ description: 'Lot acquisition date (ISO yyyy-mm-dd)',
677
+ example: '2024-01-15'
678
+ },
679
+ label: {
680
+ type: 'string',
681
+ description: 'Lot label',
682
+ example: 'lot-2024-01'
683
+ }
684
+ }
685
+ } as const;
686
+
576
687
  export const $PostingResponseDto = {
577
688
  type: 'object',
578
689
  properties: {
579
690
  account: {
580
691
  type: 'string',
581
692
  description: 'Account name',
582
- example: 'Assets:Bank:Checking'
693
+ example: 'Assets:Checking'
583
694
  },
584
695
  units: {
585
696
  type: 'string',
@@ -591,6 +702,15 @@ export const $PostingResponseDto = {
591
702
  type: 'string',
592
703
  description: 'Currency',
593
704
  example: 'USD'
705
+ },
706
+ cost: {
707
+ description:
708
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
709
+ allOf: [
710
+ {
711
+ $ref: '#/components/schemas/CostDetailDto'
712
+ }
713
+ ]
594
714
  }
595
715
  },
596
716
  required: ['account']
@@ -841,6 +961,85 @@ export const $BatchTransactionResponseDto = {
841
961
  required: ['succeeded', 'failed']
842
962
  } as const;
843
963
 
964
+ export const $CorrectTransactionDto = {
965
+ type: 'object',
966
+ properties: {
967
+ date: {
968
+ type: 'string',
969
+ description: 'Transaction date (ISO 8601 format)',
970
+ example: '2024-11-28'
971
+ },
972
+ flag: {
973
+ type: 'string',
974
+ description: 'Transaction flag: * (cleared), ! (pending)',
975
+ enum: ['*', '!'],
976
+ example: '*'
977
+ },
978
+ payee: {
979
+ type: 'string',
980
+ description: 'Payee name',
981
+ example: 'Whole Foods Market'
982
+ },
983
+ narration: {
984
+ type: 'string',
985
+ description: 'Transaction narration/description',
986
+ example: 'Grocery shopping'
987
+ },
988
+ tags: {
989
+ description: 'Transaction tags (without # prefix)',
990
+ example: ['vacation', 'personal'],
991
+ type: 'array',
992
+ items: {
993
+ type: 'string'
994
+ }
995
+ },
996
+ links: {
997
+ description: 'Transaction links (without ^ prefix)',
998
+ example: ['invoice-123'],
999
+ type: 'array',
1000
+ items: {
1001
+ type: 'string'
1002
+ }
1003
+ },
1004
+ postings: {
1005
+ description:
1006
+ 'Transaction postings (minimum 1, typically 2 for double-entry)',
1007
+ type: 'array',
1008
+ items: {
1009
+ $ref: '#/components/schemas/CreatePostingDto'
1010
+ }
1011
+ },
1012
+ meta: {
1013
+ type: 'object',
1014
+ description: 'Transaction-level metadata',
1015
+ example: {
1016
+ invoice: '12345'
1017
+ }
1018
+ },
1019
+ idempotencyKey: {
1020
+ type: 'string',
1021
+ description:
1022
+ 'Unique key for idempotent transaction creation. If provided, duplicate requests with the same key will return the existing transaction.',
1023
+ example: 'import-2024-01-15-batch-001',
1024
+ maxLength: 128
1025
+ },
1026
+ autoCreateAccounts: {
1027
+ type: 'boolean',
1028
+ description:
1029
+ 'Auto-create accounts if not found. When true, missing accounts will be automatically created. When false (default for API), missing accounts will cause a validation error. Set to true for quick entry scenarios where you want to create accounts on-the-fly.',
1030
+ default: true,
1031
+ example: true
1032
+ },
1033
+ correctionReason: {
1034
+ type: 'string',
1035
+ description: 'Reason for correcting/superseding the original transaction',
1036
+ example: 'Wrong amount — corrected from receipt',
1037
+ maxLength: 500
1038
+ }
1039
+ },
1040
+ required: ['date', 'narration', 'postings']
1041
+ } as const;
1042
+
844
1043
  export const $PostingDetailDto = {
845
1044
  type: 'object',
846
1045
  properties: {
@@ -854,10 +1053,10 @@ export const $PostingDetailDto = {
854
1053
  description: 'Account ID',
855
1054
  example: 'clh1234567890abcdef'
856
1055
  },
857
- accountName: {
1056
+ account: {
858
1057
  type: 'string',
859
- description: 'Account name',
860
- example: 'Assets:Bank:Checking'
1058
+ description: 'Fully-qualified Beancount account path',
1059
+ example: 'Assets:Checking'
861
1060
  },
862
1061
  units: {
863
1062
  type: 'string',
@@ -885,6 +1084,15 @@ export const $PostingDetailDto = {
885
1084
  description: 'Cost date',
886
1085
  example: '2024-01-15'
887
1086
  },
1087
+ cost: {
1088
+ description:
1089
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
1090
+ allOf: [
1091
+ {
1092
+ $ref: '#/components/schemas/CostDetailDto'
1093
+ }
1094
+ ]
1095
+ },
888
1096
  priceAmount: {
889
1097
  type: 'string',
890
1098
  description: 'Price amount',
@@ -905,7 +1113,7 @@ export const $PostingDetailDto = {
905
1113
  description: 'Posting metadata'
906
1114
  }
907
1115
  },
908
- required: ['id', 'accountId', 'accountName']
1116
+ required: ['id', 'accountId', 'account']
909
1117
  } as const;
910
1118
 
911
1119
  export const $TransactionDetailDto = {
@@ -1011,6 +1219,18 @@ export const $TransactionDetailDto = {
1011
1219
  type: 'string',
1012
1220
  description: 'Correction reason (if voided or superseded)',
1013
1221
  example: 'Duplicate entry'
1222
+ },
1223
+ supersededBy: {
1224
+ type: 'string',
1225
+ description:
1226
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1227
+ example: 'clh1234567890abcdef'
1228
+ },
1229
+ originalTxn: {
1230
+ type: 'string',
1231
+ description:
1232
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1233
+ example: 'clh1234567890abcdef'
1014
1234
  }
1015
1235
  },
1016
1236
  required: [
@@ -1025,33 +1245,113 @@ export const $TransactionDetailDto = {
1025
1245
  ]
1026
1246
  } as const;
1027
1247
 
1028
- export const $TransactionListResponseDto = {
1248
+ export const $BalanceByCurrencyDto = {
1029
1249
  type: 'object',
1030
1250
  properties: {
1031
- data: {
1032
- description: 'List of transactions',
1033
- type: 'array',
1034
- items: {
1035
- $ref: '#/components/schemas/TransactionDetailDto'
1036
- }
1037
- },
1038
- total: {
1039
- type: 'number',
1040
- description: 'Total count of matching transactions',
1041
- example: 100
1042
- },
1043
- limit: {
1044
- type: 'number',
1045
- description: 'Number of items per page',
1046
- example: 20
1251
+ currency: {
1252
+ type: 'string',
1253
+ description: 'ISO 4217 currency code',
1254
+ example: 'CNY'
1047
1255
  },
1048
- offset: {
1049
- type: 'number',
1050
- description: 'Number of items skipped',
1051
- example: 0
1052
- }
1053
- },
1054
- required: ['data', 'total', 'limit', 'offset']
1256
+ balance: {
1257
+ type: 'string',
1258
+ description: 'Balance amount',
1259
+ example: '50000.00'
1260
+ }
1261
+ },
1262
+ required: ['currency', 'balance']
1263
+ } as const;
1264
+
1265
+ export const $ExchangeRateWarningDto = {
1266
+ type: 'object',
1267
+ properties: {
1268
+ type: {
1269
+ type: 'string',
1270
+ description: 'Warning type',
1271
+ example: 'MISSING_EXCHANGE_RATE'
1272
+ },
1273
+ currency: {
1274
+ type: 'string',
1275
+ description: 'Currency without exchange rate',
1276
+ example: 'EUR'
1277
+ },
1278
+ totalAmount: {
1279
+ type: 'string',
1280
+ description: 'Total amount affected',
1281
+ example: '1000.00'
1282
+ }
1283
+ },
1284
+ required: ['type', 'currency', 'totalAmount']
1285
+ } as const;
1286
+
1287
+ export const $TransactionListSummaryDto = {
1288
+ type: 'object',
1289
+ properties: {
1290
+ totalAmount: {
1291
+ type: 'string',
1292
+ description:
1293
+ 'Partial converted total in base currency (rated currencies only, raw Beancount sign). When warnings is non-empty this excludes currencies missing an FX rate; may be "0.00" if ALL non-base currencies lack a rate. Converted at the dateTo (or current) available rate.',
1294
+ example: '-6000.00'
1295
+ },
1296
+ currency: {
1297
+ type: 'string',
1298
+ description: 'Base currency (ISO 4217)',
1299
+ example: 'CNY'
1300
+ },
1301
+ balanceByCurrency: {
1302
+ description: 'Raw (unconverted) balance per currency',
1303
+ type: 'array',
1304
+ items: {
1305
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
1306
+ }
1307
+ },
1308
+ warnings: {
1309
+ description: 'Currencies missing an FX rate (omitted when empty)',
1310
+ type: 'array',
1311
+ items: {
1312
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
1313
+ }
1314
+ }
1315
+ },
1316
+ required: ['totalAmount', 'currency', 'balanceByCurrency']
1317
+ } as const;
1318
+
1319
+ export const $TransactionListResponseDto = {
1320
+ type: 'object',
1321
+ properties: {
1322
+ data: {
1323
+ description: 'List of transactions',
1324
+ type: 'array',
1325
+ items: {
1326
+ $ref: '#/components/schemas/TransactionDetailDto'
1327
+ }
1328
+ },
1329
+ total: {
1330
+ type: 'number',
1331
+ description: 'Total count of matching transactions',
1332
+ example: 100
1333
+ },
1334
+ limit: {
1335
+ type: 'number',
1336
+ description: 'Number of items per page',
1337
+ example: 20
1338
+ },
1339
+ offset: {
1340
+ type: 'number',
1341
+ description: 'Number of items skipped',
1342
+ example: 0
1343
+ },
1344
+ summary: {
1345
+ description:
1346
+ 'Amount summary for the full filtered set (#514). Present only when the request has a single account OR category viewpoint; omitted for search-only / plain-list / dual-perspective requests.',
1347
+ allOf: [
1348
+ {
1349
+ $ref: '#/components/schemas/TransactionListSummaryDto'
1350
+ }
1351
+ ]
1352
+ }
1353
+ },
1354
+ required: ['data', 'total', 'limit', 'offset']
1055
1355
  } as const;
1056
1356
 
1057
1357
  export const $TagSuggestionDto = {
@@ -1148,7 +1448,7 @@ export const $BalanceResponseDto = {
1148
1448
  account: {
1149
1449
  type: 'string',
1150
1450
  description: 'Account name',
1151
- example: 'Assets:Bank:Checking'
1451
+ example: 'Assets:Checking'
1152
1452
  },
1153
1453
  balance: {
1154
1454
  type: 'string',
@@ -1175,7 +1475,7 @@ export const $MultiCurrencyBalanceResponseDto = {
1175
1475
  account: {
1176
1476
  type: 'string',
1177
1477
  description: 'Account name',
1178
- example: 'Assets:Bank:Checking'
1478
+ example: 'Assets:Checking'
1179
1479
  },
1180
1480
  balances: {
1181
1481
  type: 'object',
@@ -1231,7 +1531,7 @@ export const $TransactionSummaryDto = {
1231
1531
  accountName: {
1232
1532
  type: 'string',
1233
1533
  description: 'Source account name (first posting)',
1234
- example: 'Assets:Bank:Checking'
1534
+ example: 'Assets:Checking'
1235
1535
  },
1236
1536
  sourceType: {
1237
1537
  type: 'string',
@@ -1633,7 +1933,8 @@ export const $ResolveResultDto = {
1633
1933
  },
1634
1934
  resolutionId: {
1635
1935
  type: 'string',
1636
- description: 'Resolution ID for undo'
1936
+ description:
1937
+ 'Resolution ID for undo. Absent when the resolver rejected the decision (review stayed PENDING).'
1637
1938
  },
1638
1939
  canUndo: {
1639
1940
  type: 'boolean',
@@ -1651,7 +1952,7 @@ export const $ResolveResultDto = {
1651
1952
  example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1652
1953
  }
1653
1954
  },
1654
- required: ['success', 'resolutionId', 'canUndo', 'undoDeadline']
1955
+ required: ['success']
1655
1956
  } as const;
1656
1957
 
1657
1958
  export const $UndoResultDto = {
@@ -2522,6 +2823,163 @@ export const $UpdateCommodityDto = {
2522
2823
  }
2523
2824
  } as const;
2524
2825
 
2826
+ export const $CreateBeanPriceDto = {
2827
+ type: 'object',
2828
+ properties: {
2829
+ currency: {
2830
+ type: 'string',
2831
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2832
+ example: 'USD'
2833
+ },
2834
+ quoteCurrency: {
2835
+ type: 'string',
2836
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
2837
+ example: 'CNY'
2838
+ },
2839
+ amount: {
2840
+ type: 'number',
2841
+ description:
2842
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2843
+ example: 175.5,
2844
+ minimum: 0
2845
+ },
2846
+ date: {
2847
+ type: 'string',
2848
+ description: 'Price date (ISO 8601 format)',
2849
+ example: '2024-11-05'
2850
+ },
2851
+ metadata: {
2852
+ type: 'object',
2853
+ description:
2854
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
2855
+ example: {
2856
+ source: 'MANUAL',
2857
+ note: 'Bank valuation report',
2858
+ confidence: 0.95
2859
+ }
2860
+ }
2861
+ },
2862
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
2863
+ } as const;
2864
+
2865
+ export const $PriceResponseDto = {
2866
+ type: 'object',
2867
+ properties: {
2868
+ id: {
2869
+ type: 'string',
2870
+ description: 'Unique identifier',
2871
+ example: 'uuid-123-456'
2872
+ },
2873
+ userId: {
2874
+ type: 'string',
2875
+ description: 'User ID (owner of the price)',
2876
+ example: 'user-123'
2877
+ },
2878
+ currency: {
2879
+ type: 'string',
2880
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2881
+ example: 'BTC'
2882
+ },
2883
+ quoteCurrency: {
2884
+ type: 'string',
2885
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2886
+ example: 'USD'
2887
+ },
2888
+ amount: {
2889
+ type: 'number',
2890
+ description:
2891
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2892
+ example: 50000
2893
+ },
2894
+ date: {
2895
+ type: 'string',
2896
+ description:
2897
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
2898
+ example: '2024-01-01',
2899
+ format: 'date'
2900
+ },
2901
+ meta: {
2902
+ type: 'object',
2903
+ description:
2904
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2905
+ example: {
2906
+ source: 'MANUAL',
2907
+ note: 'User-defined price',
2908
+ confidence: 1
2909
+ }
2910
+ },
2911
+ createdAt: {
2912
+ format: 'date-time',
2913
+ type: 'string',
2914
+ description: 'Creation timestamp',
2915
+ example: '2024-11-03T10:00:00Z'
2916
+ },
2917
+ updatedAt: {
2918
+ format: 'date-time',
2919
+ type: 'string',
2920
+ description: 'Last update timestamp',
2921
+ example: '2024-11-03T10:00:00Z'
2922
+ }
2923
+ },
2924
+ required: [
2925
+ 'id',
2926
+ 'userId',
2927
+ 'currency',
2928
+ 'quoteCurrency',
2929
+ 'amount',
2930
+ 'date',
2931
+ 'meta',
2932
+ 'createdAt',
2933
+ 'updatedAt'
2934
+ ]
2935
+ } as const;
2936
+
2937
+ export const $PriceListResponseDto = {
2938
+ type: 'object',
2939
+ properties: {
2940
+ items: {
2941
+ description: 'List of prices',
2942
+ type: 'array',
2943
+ items: {
2944
+ $ref: '#/components/schemas/PriceResponseDto'
2945
+ }
2946
+ },
2947
+ total: {
2948
+ type: 'number',
2949
+ description: 'Total number of prices',
2950
+ example: 42
2951
+ }
2952
+ },
2953
+ required: ['items', 'total']
2954
+ } as const;
2955
+
2956
+ export const $UpdateBeanPriceDto = {
2957
+ type: 'object',
2958
+ properties: {
2959
+ currency: {
2960
+ type: 'string',
2961
+ description: 'Currency being priced'
2962
+ },
2963
+ quoteCurrency: {
2964
+ type: 'string',
2965
+ description: 'Quote currency (pricing currency)'
2966
+ },
2967
+ amount: {
2968
+ type: 'number',
2969
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
2970
+ minimum: 0
2971
+ },
2972
+ date: {
2973
+ type: 'string',
2974
+ description: 'Price date (ISO 8601 format)'
2975
+ },
2976
+ metadata: {
2977
+ type: 'object',
2978
+ description: 'Metadata'
2979
+ }
2980
+ }
2981
+ } as const;
2982
+
2525
2983
  export const $CreateRecurringRuleDto = {
2526
2984
  type: 'object',
2527
2985
  properties: {
@@ -3966,6 +4424,27 @@ export const $SignupDto = {
3966
4424
  }
3967
4425
  } as const;
3968
4426
 
4427
+ export const $SignupResponseDto = {
4428
+ type: 'object',
4429
+ properties: {
4430
+ authToken: {
4431
+ type: 'string',
4432
+ description: 'JWT auth token',
4433
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4434
+ },
4435
+ accessToken: {
4436
+ type: 'string',
4437
+ description: 'Auto-generated access token'
4438
+ },
4439
+ role: {
4440
+ type: 'string',
4441
+ description: 'Assigned user role',
4442
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4443
+ }
4444
+ },
4445
+ required: ['authToken', 'accessToken', 'role']
4446
+ } as const;
4447
+
3969
4448
  export const $UpdateUserSettingDto = {
3970
4449
  type: 'object',
3971
4450
  properties: {
@@ -4089,43 +4568,711 @@ export const $UpdatePropertyDto = {
4089
4568
  required: ['value']
4090
4569
  } as const;
4091
4570
 
4092
- export const $FileImportDto = {
4571
+ export const $CurrencyBalanceDto = {
4093
4572
  type: 'object',
4094
4573
  properties: {
4095
- file: {
4574
+ currency: {
4096
4575
  type: 'string',
4097
- format: 'binary',
4098
- description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4099
- example: 'alipay.csv'
4100
- }
4101
- },
4102
- required: ['file']
4103
- } as const;
4104
-
4105
- export const $ImportErrorDto = {
4106
- type: 'object',
4107
- properties: {
4108
- index: {
4109
- type: 'number',
4110
- description: 'Index of failed transaction in the file',
4111
- example: 5
4576
+ description: 'ISO 4217 currency code',
4577
+ example: 'CNY'
4112
4578
  },
4113
- error: {
4579
+ balance: {
4114
4580
  type: 'string',
4115
- description: 'Error message',
4116
- example: 'Transaction does not balance: -100 USD != 0'
4581
+ description: 'Balance amount',
4582
+ example: '500000.00'
4117
4583
  }
4118
4584
  },
4119
- required: ['index', 'error']
4585
+ required: ['currency', 'balance']
4120
4586
  } as const;
4121
4587
 
4122
- export const $ReviewItemPreviewDto = {
4588
+ export const $TimeSeriesPointDto = {
4123
4589
  type: 'object',
4124
4590
  properties: {
4125
- index: {
4126
- type: 'number',
4127
- description: 'Index in the import batch (for tracking)',
4128
- example: 0
4591
+ date: {
4592
+ type: 'string',
4593
+ description: 'Date in YYYY-MM-DD format',
4594
+ example: '2024-06-15'
4595
+ },
4596
+ value: {
4597
+ type: 'string',
4598
+ description: 'Value at this date (in base currency)',
4599
+ example: '500000.00'
4600
+ },
4601
+ change: {
4602
+ type: 'object',
4603
+ description: 'Change from previous point',
4604
+ example: '5000.00'
4605
+ },
4606
+ assets: {
4607
+ type: 'string',
4608
+ description: 'Total assets at this date (in base currency)',
4609
+ example: '494338.00'
4610
+ },
4611
+ liabilities: {
4612
+ type: 'string',
4613
+ description: 'Total liabilities at this date (in base currency)',
4614
+ example: '310098.00'
4615
+ },
4616
+ byCurrency: {
4617
+ description: 'Multi-currency breakdown for this point',
4618
+ type: 'array',
4619
+ items: {
4620
+ $ref: '#/components/schemas/CurrencyBalanceDto'
4621
+ }
4622
+ }
4623
+ },
4624
+ required: ['date', 'value']
4625
+ } as const;
4626
+
4627
+ export const $TrendSummaryDto = {
4628
+ type: 'object',
4629
+ properties: {
4630
+ startValue: {
4631
+ type: 'string',
4632
+ description: 'Value at start of period',
4633
+ example: '450000.00'
4634
+ },
4635
+ endValue: {
4636
+ type: 'string',
4637
+ description: 'Value at end of period',
4638
+ example: '500000.00'
4639
+ },
4640
+ totalChange: {
4641
+ type: 'string',
4642
+ description: 'Total change over period',
4643
+ example: '50000.00'
4644
+ },
4645
+ totalChangePercentage: {
4646
+ type: 'string',
4647
+ description: 'Total change percentage',
4648
+ example: '+11.11%'
4649
+ }
4650
+ },
4651
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
4652
+ } as const;
4653
+
4654
+ export const $MultiCurrencyPointDto = {
4655
+ type: 'object',
4656
+ properties: {
4657
+ date: {
4658
+ type: 'string',
4659
+ description: 'Date in YYYY-MM-DD format',
4660
+ example: '2024-06-15'
4661
+ },
4662
+ byCurrency: {
4663
+ description: 'Balances by currency',
4664
+ type: 'array',
4665
+ items: {
4666
+ $ref: '#/components/schemas/CurrencyBalanceDto'
4667
+ }
4668
+ }
4669
+ },
4670
+ required: ['date', 'byCurrency']
4671
+ } as const;
4672
+
4673
+ export const $PortfolioTrendsResponseDto = {
4674
+ type: 'object',
4675
+ properties: {
4676
+ series: {
4677
+ description: 'Time series data points',
4678
+ type: 'array',
4679
+ items: {
4680
+ $ref: '#/components/schemas/TimeSeriesPointDto'
4681
+ }
4682
+ },
4683
+ summary: {
4684
+ description: 'Period summary',
4685
+ allOf: [
4686
+ {
4687
+ $ref: '#/components/schemas/TrendSummaryDto'
4688
+ }
4689
+ ]
4690
+ },
4691
+ period: {
4692
+ type: 'string',
4693
+ description: 'Period requested',
4694
+ example: '6m'
4695
+ },
4696
+ granularity: {
4697
+ type: 'string',
4698
+ description: 'Data granularity',
4699
+ example: 'month'
4700
+ },
4701
+ currency: {
4702
+ type: 'string',
4703
+ description: 'Base currency for converted values',
4704
+ example: 'CNY'
4705
+ },
4706
+ byCurrency: {
4707
+ description:
4708
+ 'Multi-currency time series (each point has currency breakdown)',
4709
+ type: 'array',
4710
+ items: {
4711
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
4712
+ }
4713
+ },
4714
+ warnings: {
4715
+ description: 'Exchange rate warnings',
4716
+ type: 'array',
4717
+ items: {
4718
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
4719
+ }
4720
+ }
4721
+ },
4722
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
4723
+ } as const;
4724
+
4725
+ export const $CashFlowPointDto = {
4726
+ type: 'object',
4727
+ properties: {
4728
+ month: {
4729
+ type: 'string',
4730
+ description: 'Month key (YYYY-MM)',
4731
+ example: '2024-03'
4732
+ },
4733
+ income: {
4734
+ type: 'string',
4735
+ description: 'Income in base currency (absolute, converted)',
4736
+ example: '10000.00'
4737
+ },
4738
+ expense: {
4739
+ type: 'string',
4740
+ description: 'Expense in base currency (absolute, converted)',
4741
+ example: '5000.00'
4742
+ },
4743
+ netSavings: {
4744
+ type: 'string',
4745
+ description: 'netSavings = income − expense (savings positive)',
4746
+ example: '5000.00'
4747
+ }
4748
+ },
4749
+ required: ['month', 'income', 'expense', 'netSavings']
4750
+ } as const;
4751
+
4752
+ export const $CashFlowTrendSummaryDto = {
4753
+ type: 'object',
4754
+ properties: {
4755
+ totalIncome: {
4756
+ type: 'string',
4757
+ description: 'Total income across the period',
4758
+ example: '60000.00'
4759
+ },
4760
+ totalExpense: {
4761
+ type: 'string',
4762
+ description: 'Total expense across the period',
4763
+ example: '30000.00'
4764
+ },
4765
+ totalNetSavings: {
4766
+ type: 'string',
4767
+ description: 'income − expense across the period',
4768
+ example: '30000.00'
4769
+ },
4770
+ averageMonthlyNetSavings: {
4771
+ type: 'string',
4772
+ description:
4773
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
4774
+ example: '5000.00'
4775
+ }
4776
+ },
4777
+ required: [
4778
+ 'totalIncome',
4779
+ 'totalExpense',
4780
+ 'totalNetSavings',
4781
+ 'averageMonthlyNetSavings'
4782
+ ]
4783
+ } as const;
4784
+
4785
+ export const $CashFlowTrendsResponseDto = {
4786
+ type: 'object',
4787
+ properties: {
4788
+ series: {
4789
+ description:
4790
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
4791
+ type: 'array',
4792
+ items: {
4793
+ $ref: '#/components/schemas/CashFlowPointDto'
4794
+ }
4795
+ },
4796
+ summary: {
4797
+ description: 'Period totals',
4798
+ allOf: [
4799
+ {
4800
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4801
+ }
4802
+ ]
4803
+ },
4804
+ period: {
4805
+ type: 'string',
4806
+ description: 'Period requested',
4807
+ example: '6m'
4808
+ },
4809
+ granularity: {
4810
+ type: 'string',
4811
+ description: 'Data granularity (v1 returns month buckets)',
4812
+ example: 'month'
4813
+ },
4814
+ currency: {
4815
+ type: 'string',
4816
+ description: 'Base currency for converted values',
4817
+ example: 'CNY'
4818
+ },
4819
+ warnings: {
4820
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
4821
+ type: 'array',
4822
+ items: {
4823
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
4824
+ }
4825
+ }
4826
+ },
4827
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
4828
+ } as const;
4829
+
4830
+ export const $GenerateSnapshotBody = {
4831
+ type: 'object',
4832
+ properties: {}
4833
+ } as const;
4834
+
4835
+ export const $GenerateSnapshotResponse = {
4836
+ type: 'object',
4837
+ properties: {}
4838
+ } as const;
4839
+
4840
+ export const $BackfillSnapshotsBody = {
4841
+ type: 'object',
4842
+ properties: {}
4843
+ } as const;
4844
+
4845
+ export const $BackfillSnapshotsResponse = {
4846
+ type: 'object',
4847
+ properties: {}
4848
+ } as const;
4849
+
4850
+ export const $CreateBeanEventDto = {
4851
+ type: 'object',
4852
+ properties: {
4853
+ date: {
4854
+ type: 'string',
4855
+ description: 'Life event date (ISO 8601)',
4856
+ example: '2024-03-15'
4857
+ },
4858
+ type: {
4859
+ type: 'string',
4860
+ description:
4861
+ 'Life event type (e.g., "employer", "location", "marital-status") — user-defined, no enum constraint at engine layer',
4862
+ example: 'employer'
4863
+ },
4864
+ description: {
4865
+ type: 'string',
4866
+ description:
4867
+ 'Life event description. Empty string is a VALID value (distinct from absence).',
4868
+ example: 'Acme Corp'
4869
+ },
4870
+ meta: {
4871
+ type: 'object',
4872
+ description:
4873
+ 'Product-side metadata (lives in BeanEvent.meta JSON, never in engine Event fields)',
4874
+ example: {
4875
+ note: 'Promotion'
4876
+ }
4877
+ }
4878
+ },
4879
+ required: ['date', 'type', 'description']
4880
+ } as const;
4881
+
4882
+ export const $EventResponseDto = {
4883
+ type: 'object',
4884
+ properties: {
4885
+ id: {
4886
+ type: 'string',
4887
+ description: 'Unique identifier',
4888
+ example: 'uuid-123-456'
4889
+ },
4890
+ userId: {
4891
+ type: 'string',
4892
+ description: 'User ID (owner of the life event)',
4893
+ example: 'user-123'
4894
+ },
4895
+ date: {
4896
+ type: 'string',
4897
+ description: 'Life event date (ISO 8601 format)',
4898
+ example: '2024-03-15',
4899
+ format: 'date'
4900
+ },
4901
+ type: {
4902
+ type: 'string',
4903
+ description:
4904
+ 'Life event type (user-defined, e.g., "employer", "location")',
4905
+ example: 'employer'
4906
+ },
4907
+ description: {
4908
+ type: 'string',
4909
+ description:
4910
+ 'Life event description. May be an empty string (a valid value distinct from absence).',
4911
+ example: 'Acme Corp'
4912
+ },
4913
+ meta: {
4914
+ type: 'object',
4915
+ description: 'Product-side metadata (free-form JSON)',
4916
+ example: {
4917
+ note: 'Promotion'
4918
+ }
4919
+ },
4920
+ createdAt: {
4921
+ format: 'date-time',
4922
+ type: 'string',
4923
+ description: 'Creation timestamp',
4924
+ example: '2024-03-15T10:00:00Z'
4925
+ },
4926
+ updatedAt: {
4927
+ format: 'date-time',
4928
+ type: 'string',
4929
+ description:
4930
+ 'Last update timestamp. Also emitted as the ETag response header for If-Match optimistic concurrency.',
4931
+ example: '2024-03-15T10:00:00Z'
4932
+ }
4933
+ },
4934
+ required: [
4935
+ 'id',
4936
+ 'userId',
4937
+ 'date',
4938
+ 'type',
4939
+ 'description',
4940
+ 'meta',
4941
+ 'createdAt',
4942
+ 'updatedAt'
4943
+ ]
4944
+ } as const;
4945
+
4946
+ export const $EventListResponseDto = {
4947
+ type: 'object',
4948
+ properties: {
4949
+ items: {
4950
+ description: 'List of life events',
4951
+ type: 'array',
4952
+ items: {
4953
+ $ref: '#/components/schemas/EventResponseDto'
4954
+ }
4955
+ },
4956
+ total: {
4957
+ type: 'number',
4958
+ description: 'Total number of life events matching the query',
4959
+ example: 42
4960
+ }
4961
+ },
4962
+ required: ['items', 'total']
4963
+ } as const;
4964
+
4965
+ export const $UpdateBeanEventDto = {
4966
+ type: 'object',
4967
+ properties: {
4968
+ date: {
4969
+ type: 'string',
4970
+ description: 'Life event date (ISO 8601)'
4971
+ },
4972
+ type: {
4973
+ type: 'string',
4974
+ description: 'Life event type (user-defined)'
4975
+ },
4976
+ description: {
4977
+ type: 'string',
4978
+ description:
4979
+ 'Life event description. Empty string is a VALID value (distinct from absence).'
4980
+ },
4981
+ meta: {
4982
+ type: 'object',
4983
+ description: 'Product-side metadata (free-form JSON)'
4984
+ }
4985
+ }
4986
+ } as const;
4987
+
4988
+ export const $OnboardingAccountDto = {
4989
+ type: 'object',
4990
+ properties: {
4991
+ path: {
4992
+ type: 'string',
4993
+ description:
4994
+ 'Account path (Assets/Liabilities only; format validated by the account service)',
4995
+ example: 'Assets:Checking'
4996
+ },
4997
+ currency: {
4998
+ type: 'string',
4999
+ description: 'ISO 4217 currency code (3 letters)',
5000
+ example: 'USD'
5001
+ },
5002
+ openingBalance: {
5003
+ type: 'string',
5004
+ description:
5005
+ 'Opening balance as a non-negative Decimal string (e.g. "1000.00")',
5006
+ example: '1000.00'
5007
+ },
5008
+ platformId: {
5009
+ type: 'string',
5010
+ description:
5011
+ 'Platform ID to bind the account to (references Platform.id); omit for unbound',
5012
+ example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
5013
+ }
5014
+ },
5015
+ required: ['path', 'currency']
5016
+ } as const;
5017
+
5018
+ export const $OnboardingDto = {
5019
+ type: 'object',
5020
+ properties: {
5021
+ accounts: {
5022
+ description: 'Asset/Liability accounts to register with opening balances',
5023
+ type: 'array',
5024
+ items: {
5025
+ $ref: '#/components/schemas/OnboardingAccountDto'
5026
+ }
5027
+ },
5028
+ skipAssetRegistration: {
5029
+ type: 'boolean',
5030
+ description:
5031
+ 'Skip asset registration; only bootstrap the core account set',
5032
+ default: false
5033
+ }
5034
+ }
5035
+ } as const;
5036
+
5037
+ export const $ActualBalanceDto = {
5038
+ type: 'object',
5039
+ properties: {
5040
+ amount: {
5041
+ type: 'string',
5042
+ description:
5043
+ 'Actual balance amount as a decimal string (preserves precision for tolerance inference).',
5044
+ example: '1234.56'
5045
+ },
5046
+ ccy: {
5047
+ type: 'string',
5048
+ description: 'Currency code (ISO 4217 or commodity ticker).',
5049
+ example: 'CNY'
5050
+ }
5051
+ },
5052
+ required: ['amount', 'ccy']
5053
+ } as const;
5054
+
5055
+ export const $ComputeReconciliationDto = {
5056
+ type: 'object',
5057
+ properties: {
5058
+ accountId: {
5059
+ type: 'string',
5060
+ description: 'BeanAccount id to reconcile.'
5061
+ },
5062
+ asOfDate: {
5063
+ type: 'string',
5064
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
5065
+ example: '2026-07-24'
5066
+ },
5067
+ actualBalance: {
5068
+ description: 'Actual balance from the external statement.',
5069
+ allOf: [
5070
+ {
5071
+ $ref: '#/components/schemas/ActualBalanceDto'
5072
+ }
5073
+ ]
5074
+ }
5075
+ },
5076
+ required: ['accountId', 'asOfDate', 'actualBalance']
5077
+ } as const;
5078
+
5079
+ export const $ReconciliationComputeResultDto = {
5080
+ type: 'object',
5081
+ properties: {
5082
+ accountId: {
5083
+ type: 'string'
5084
+ },
5085
+ asOfDate: {
5086
+ type: 'string'
5087
+ },
5088
+ bookBalance: {
5089
+ type: 'string',
5090
+ description: 'System-computed book balance (decimal string).'
5091
+ },
5092
+ actualBalance: {
5093
+ type: 'string',
5094
+ description: 'User-entered actual balance (decimal string).'
5095
+ },
5096
+ currency: {
5097
+ type: 'string'
5098
+ },
5099
+ diff: {
5100
+ type: 'string',
5101
+ description: 'Diff = book − actual (decimal string).'
5102
+ },
5103
+ tolerance: {
5104
+ type: 'string',
5105
+ description: 'Applied tolerance (decimal string).'
5106
+ },
5107
+ withinTolerance: {
5108
+ type: 'boolean',
5109
+ description: 'true when |diff| ≤ tolerance.'
5110
+ },
5111
+ suggestedAction: {
5112
+ type: 'string',
5113
+ enum: ['assert', 'pad'],
5114
+ description:
5115
+ 'Suggested next action: assert when within tolerance, pad otherwise.'
5116
+ }
5117
+ },
5118
+ required: [
5119
+ 'accountId',
5120
+ 'asOfDate',
5121
+ 'bookBalance',
5122
+ 'actualBalance',
5123
+ 'currency',
5124
+ 'diff',
5125
+ 'tolerance',
5126
+ 'withinTolerance',
5127
+ 'suggestedAction'
5128
+ ]
5129
+ } as const;
5130
+
5131
+ export const $AssertReconciliationDto = {
5132
+ type: 'object',
5133
+ properties: {
5134
+ accountId: {
5135
+ type: 'string',
5136
+ description: 'BeanAccount id to reconcile.'
5137
+ },
5138
+ asOfDate: {
5139
+ type: 'string',
5140
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
5141
+ example: '2026-07-24'
5142
+ },
5143
+ actualBalance: {
5144
+ description: 'Actual balance from the external statement.',
5145
+ allOf: [
5146
+ {
5147
+ $ref: '#/components/schemas/ActualBalanceDto'
5148
+ }
5149
+ ]
5150
+ },
5151
+ tolerance: {
5152
+ type: 'string',
5153
+ description:
5154
+ 'Optional explicit tolerance override. Omit to infer from amount precision (Beancount default).',
5155
+ example: '0.01'
5156
+ }
5157
+ },
5158
+ required: ['accountId', 'asOfDate', 'actualBalance']
5159
+ } as const;
5160
+
5161
+ export const $ReconciliationRecordDto = {
5162
+ type: 'object',
5163
+ properties: {
5164
+ id: {
5165
+ type: 'string'
5166
+ },
5167
+ accountId: {
5168
+ type: 'string'
5169
+ },
5170
+ date: {
5171
+ type: 'string'
5172
+ },
5173
+ amount: {
5174
+ type: 'string',
5175
+ description: 'Asserted (actual) amount.'
5176
+ },
5177
+ currency: {
5178
+ type: 'string'
5179
+ },
5180
+ tolerance: {
5181
+ type: 'string'
5182
+ },
5183
+ diffAmount: {
5184
+ type: 'string',
5185
+ description: 'book − actual.'
5186
+ },
5187
+ diffCurrency: {
5188
+ type: 'string'
5189
+ },
5190
+ createdAt: {
5191
+ type: 'string'
5192
+ }
5193
+ },
5194
+ required: ['id', 'accountId', 'date', 'amount', 'currency', 'createdAt']
5195
+ } as const;
5196
+
5197
+ export const $PadReconciliationDto = {
5198
+ type: 'object',
5199
+ properties: {
5200
+ accountId: {
5201
+ type: 'string',
5202
+ description: 'BeanAccount id to reconcile.'
5203
+ },
5204
+ asOfDate: {
5205
+ type: 'string',
5206
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
5207
+ example: '2026-07-24'
5208
+ },
5209
+ actualBalance: {
5210
+ description: 'Actual balance from the external statement.',
5211
+ allOf: [
5212
+ {
5213
+ $ref: '#/components/schemas/ActualBalanceDto'
5214
+ }
5215
+ ]
5216
+ },
5217
+ sourceAccount: {
5218
+ type: 'string',
5219
+ description:
5220
+ 'Pad source account. Defaults to Equity:Opening-Balances (official Beancount convention).',
5221
+ example: 'Equity:Opening-Balances',
5222
+ default: 'Equity:Opening-Balances'
5223
+ }
5224
+ },
5225
+ required: ['accountId', 'asOfDate', 'actualBalance']
5226
+ } as const;
5227
+
5228
+ export const $PadResultDto = {
5229
+ type: 'object',
5230
+ properties: {
5231
+ transactionId: {
5232
+ type: 'string',
5233
+ description: 'Created pad adjusting transaction id.'
5234
+ }
5235
+ },
5236
+ required: ['transactionId']
5237
+ } as const;
5238
+
5239
+ export const $FileImportDto = {
5240
+ type: 'object',
5241
+ properties: {
5242
+ file: {
5243
+ type: 'string',
5244
+ format: 'binary',
5245
+ description: 'Bill file to import (CSV, PDF, OFX, etc.)',
5246
+ example: 'alipay.csv'
5247
+ }
5248
+ },
5249
+ required: ['file']
5250
+ } as const;
5251
+
5252
+ export const $ImportErrorDto = {
5253
+ type: 'object',
5254
+ properties: {
5255
+ index: {
5256
+ type: 'number',
5257
+ description: 'Index of failed transaction in the file',
5258
+ example: 5
5259
+ },
5260
+ error: {
5261
+ type: 'string',
5262
+ description: 'Error message',
5263
+ example: 'Transaction does not balance: -100 USD != 0'
5264
+ }
5265
+ },
5266
+ required: ['index', 'error']
5267
+ } as const;
5268
+
5269
+ export const $ReviewItemPreviewDto = {
5270
+ type: 'object',
5271
+ properties: {
5272
+ index: {
5273
+ type: 'number',
5274
+ description: 'Index in the import batch (for tracking)',
5275
+ example: 0
4129
5276
  },
4130
5277
  date: {
4131
5278
  type: 'string',
@@ -4255,7 +5402,7 @@ export const $IdentifyResultDto = {
4255
5402
  account: {
4256
5403
  type: 'string',
4257
5404
  description: 'Default account used by this importer',
4258
- example: 'Assets:Alipay:Balance'
5405
+ example: 'Assets:CN:Alipay:Balance'
4259
5406
  },
4260
5407
  message: {
4261
5408
  type: 'string',
@@ -4272,7 +5419,7 @@ export const $MapperDefaultsDto = {
4272
5419
  sourceAccount: {
4273
5420
  type: 'string',
4274
5421
  description: 'Source account for transactions (Beancount format)',
4275
- example: 'Assets:Alipay:Balance'
5422
+ example: 'Assets:CN:Alipay:Balance'
4276
5423
  },
4277
5424
  currency: {
4278
5425
  type: 'string',
@@ -4309,7 +5456,7 @@ export const $MapperDefaultsDto = {
4309
5456
  description:
4310
5457
  'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
4311
5458
  example: {
4312
- HuaBei: 'Liabilities:Alipay:Huabei',
5459
+ HuaBei: 'Liabilities:CN:CreditLine',
4313
5460
  CreditCard: 'Liabilities:CreditCard'
4314
5461
  }
4315
5462
  }
@@ -4441,7 +5588,7 @@ export const $UpdateMapperDefaultsDto = {
4441
5588
  sourceAccount: {
4442
5589
  type: 'string',
4443
5590
  description: 'Source account for transactions (Beancount format)',
4444
- example: 'Assets:Alipay:Balance',
5591
+ example: 'Assets:CN:Alipay:Balance',
4445
5592
  pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
4446
5593
  },
4447
5594
  currency: {
@@ -4469,7 +5616,7 @@ export const $UpdateMapperDefaultsDto = {
4469
5616
  description:
4470
5617
  'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
4471
5618
  example: {
4472
- HuaBei: 'Liabilities:Alipay:Huabei',
5619
+ HuaBei: 'Liabilities:CN:CreditLine',
4473
5620
  CreditCard: 'Liabilities:CreditCard'
4474
5621
  }
4475
5622
  }
@@ -4504,119 +5651,13 @@ export const $UpdateImporterConfigDto = {
4504
5651
  }
4505
5652
  } as const;
4506
5653
 
4507
- export const $CreatePlatformDto = {
4508
- type: 'object',
4509
- properties: {
4510
- name: {
4511
- type: 'string',
4512
- description: 'Platform name',
4513
- example: 'Binance'
4514
- },
4515
- canonical: {
4516
- type: 'string',
4517
- description: 'Platform canonical identifier (lowercase, kebab-case)',
4518
- example: 'binance'
4519
- },
4520
- aliases: {
4521
- description: 'Platform aliases (multi-language names for lookup)',
4522
- example: ['Binance', 'Binance Exchange', 'BNB'],
4523
- type: 'array',
4524
- items: {
4525
- type: 'string'
4526
- }
4527
- },
4528
- url: {
4529
- type: 'string',
4530
- description: 'Platform URL',
4531
- example: 'https://www.binance.com'
4532
- },
4533
- type: {
4534
- type: 'string',
4535
- description: 'Platform type',
4536
- enum: [
4537
- 'BANK',
4538
- 'BROKERAGE',
4539
- 'CRYPTO_EXCHANGE',
4540
- 'PAYMENT',
4541
- 'INVESTMENT',
4542
- 'INSURANCE',
4543
- 'OTHER'
4544
- ],
4545
- example: 'CRYPTO_EXCHANGE'
4546
- },
4547
- logoUrl: {
4548
- type: 'string',
4549
- description: 'Platform logo URL',
4550
- example: 'https://example.com/logos/binance.png'
4551
- },
4552
- isActive: {
4553
- type: 'boolean',
4554
- description: 'Whether the platform is active',
4555
- default: true
4556
- }
4557
- },
4558
- required: ['name', 'canonical', 'aliases', 'url', 'type']
4559
- } as const;
4560
-
4561
- export const $UpdatePlatformDto = {
4562
- type: 'object',
4563
- properties: {
4564
- name: {
4565
- type: 'string',
4566
- description: 'Platform name',
4567
- example: 'Binance'
4568
- },
4569
- canonical: {
4570
- type: 'string',
4571
- description: 'Platform canonical identifier (lowercase, kebab-case)',
4572
- example: 'binance'
4573
- },
4574
- aliases: {
4575
- description: 'Platform aliases (multi-language names for lookup)',
4576
- example: ['Binance', 'Binance Exchange', 'BNB'],
4577
- type: 'array',
4578
- items: {
4579
- type: 'string'
4580
- }
4581
- },
4582
- url: {
4583
- type: 'string',
4584
- description: 'Platform URL',
4585
- example: 'https://www.binance.com'
4586
- },
4587
- type: {
4588
- type: 'string',
4589
- description: 'Platform type',
4590
- enum: [
4591
- 'BANK',
4592
- 'BROKERAGE',
4593
- 'CRYPTO_EXCHANGE',
4594
- 'PAYMENT',
4595
- 'INVESTMENT',
4596
- 'INSURANCE',
4597
- 'OTHER'
4598
- ],
4599
- example: 'CRYPTO_EXCHANGE'
4600
- },
4601
- logoUrl: {
4602
- type: 'string',
4603
- description: 'Platform logo URL',
4604
- example: 'https://example.com/logos/binance.png'
4605
- },
4606
- isActive: {
4607
- type: 'boolean',
4608
- description: 'Whether the platform is active'
4609
- }
4610
- }
4611
- } as const;
4612
-
4613
5654
  export const $ProviderSyncConfigDto = {
4614
5655
  type: 'object',
4615
5656
  properties: {
4616
5657
  sourceAccount: {
4617
5658
  type: 'string',
4618
5659
  description: 'Source account for the first posting',
4619
- example: 'Assets:Bank:Chase'
5660
+ example: 'Assets:US:Chase:Checking'
4620
5661
  },
4621
5662
  defaultCurrency: {
4622
5663
  type: 'string',
@@ -4637,6 +5678,12 @@ export const $ProviderSyncConfigDto = {
4637
5678
  type: 'boolean',
4638
5679
  description: 'Filter pending transactions',
4639
5680
  default: true
5681
+ },
5682
+ externalAccountId: {
5683
+ type: 'string',
5684
+ description:
5685
+ 'External account ID for per-batch providers (e.g. GoCardless). Overrides sourceAccount when an ExternalAccountLink mapping exists.',
5686
+ example: 'acc_gocardless_001'
4640
5687
  }
4641
5688
  },
4642
5689
  required: [
@@ -4753,7 +5800,95 @@ export const $SupportedProvidersResponseDto = {
4753
5800
  }
4754
5801
  }
4755
5802
  },
4756
- required: ['providers']
5803
+ required: ['providers']
5804
+ } as const;
5805
+
5806
+ export const $CreateExternalAccountLinkDto = {
5807
+ type: 'object',
5808
+ properties: {
5809
+ provider: {
5810
+ type: 'string',
5811
+ enum: [
5812
+ 'plaid',
5813
+ 'teller',
5814
+ 'truelayer',
5815
+ 'gocardless',
5816
+ 'simplefin',
5817
+ 'yodlee',
5818
+ 'beancount-direct',
5819
+ 'parsed-bill'
5820
+ ],
5821
+ example: 'plaid',
5822
+ description: 'Open Banking provider (whitelist)'
5823
+ },
5824
+ externalAccountId: {
5825
+ type: 'string',
5826
+ example: 'acc-plaid-001',
5827
+ description: 'External account ID from the provider'
5828
+ },
5829
+ beanAccountId: {
5830
+ type: 'string',
5831
+ example: '550e8400-e29b-41d4-a716-446655440000',
5832
+ description: 'Target BeanAccount ID (must belong to the JWT user)'
5833
+ }
5834
+ },
5835
+ required: ['provider', 'externalAccountId', 'beanAccountId']
5836
+ } as const;
5837
+
5838
+ export const $ExternalAccountLinkResponseDto = {
5839
+ type: 'object',
5840
+ properties: {
5841
+ id: {
5842
+ type: 'string'
5843
+ },
5844
+ provider: {
5845
+ type: 'string'
5846
+ },
5847
+ externalAccountId: {
5848
+ type: 'string'
5849
+ },
5850
+ beanAccountId: {
5851
+ type: 'string'
5852
+ },
5853
+ isActive: {
5854
+ type: 'boolean'
5855
+ },
5856
+ createdAt: {
5857
+ type: 'string'
5858
+ },
5859
+ updatedAt: {
5860
+ type: 'string'
5861
+ }
5862
+ },
5863
+ required: [
5864
+ 'id',
5865
+ 'provider',
5866
+ 'externalAccountId',
5867
+ 'beanAccountId',
5868
+ 'isActive',
5869
+ 'createdAt',
5870
+ 'updatedAt'
5871
+ ]
5872
+ } as const;
5873
+
5874
+ export const $ExternalAccountLinkListResponseDto = {
5875
+ type: 'object',
5876
+ properties: {
5877
+ items: {
5878
+ type: 'array',
5879
+ items: {
5880
+ $ref: '#/components/schemas/ExternalAccountLinkResponseDto'
5881
+ }
5882
+ },
5883
+ total: {
5884
+ type: 'number'
5885
+ },
5886
+ provider: {
5887
+ type: 'string',
5888
+ description: 'Filter by provider (query param)'
5889
+ }
5890
+ },
5891
+ required: ['items', 'total']
4757
5892
  } as const;
4758
5893
 
4759
5894
  export const $ParserTelemetryReportDto = {
@@ -4761,6 +5896,11 @@ export const $ParserTelemetryReportDto = {
4761
5896
  properties: {}
4762
5897
  } as const;
4763
5898
 
5899
+ export const $UncoveredFormatMissDto = {
5900
+ type: 'object',
5901
+ properties: {}
5902
+ } as const;
5903
+
4764
5904
  export const $ProcessNlpDto = {
4765
5905
  type: 'object',
4766
5906
  properties: {
@@ -5300,7 +6440,7 @@ export const $NlpSuggestedAccountDto = {
5300
6440
  account: {
5301
6441
  type: 'string',
5302
6442
  description: 'Suggested account path',
5303
- example: 'Assets:Bank:Checking'
6443
+ example: 'Assets:Checking'
5304
6444
  },
5305
6445
  confidence: {
5306
6446
  type: 'number',
@@ -5341,7 +6481,7 @@ export const $NlpDefaultAccountsDto = {
5341
6481
  asset: {
5342
6482
  type: 'string',
5343
6483
  description: 'Default asset account',
5344
- example: 'Assets:Bank:Checking'
6484
+ example: 'Assets:Checking'
5345
6485
  },
5346
6486
  expense: {
5347
6487
  type: 'string',
@@ -5563,21 +6703,252 @@ export const $NlpResponseDto = {
5563
6703
  required: ['status', 'action']
5564
6704
  } as const;
5565
6705
 
5566
- export const $BalanceByCurrencyDto = {
6706
+ export const $PlatformListItemDto = {
5567
6707
  type: 'object',
5568
6708
  properties: {
5569
- currency: {
6709
+ id: {
5570
6710
  type: 'string',
5571
- description: 'ISO 4217 currency code',
5572
- example: 'CNY'
6711
+ description: 'Global platform ID'
5573
6712
  },
5574
- balance: {
6713
+ name: {
5575
6714
  type: 'string',
5576
- description: 'Balance amount',
5577
- example: '50000.00'
6715
+ description: 'Platform name'
6716
+ },
6717
+ url: {
6718
+ type: 'string',
6719
+ description: 'Platform URL'
6720
+ },
6721
+ type: {
6722
+ type: 'string',
6723
+ description: 'Platform type',
6724
+ enum: [
6725
+ 'BANK',
6726
+ 'BROKERAGE',
6727
+ 'CRYPTO_EXCHANGE',
6728
+ 'PAYMENT',
6729
+ 'INVESTMENT',
6730
+ 'INSURANCE',
6731
+ 'OTHER'
6732
+ ]
6733
+ },
6734
+ canonical: {
6735
+ type: 'string',
6736
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
6737
+ },
6738
+ suggestedSegment: {
6739
+ type: 'string',
6740
+ description:
6741
+ 'Suggested path segment — canonical with first char uppercased (ACC_COMP_NAME_RE)'
6742
+ },
6743
+ logoUrl: {
6744
+ type: 'string',
6745
+ description: 'Logo URL',
6746
+ nullable: true
6747
+ },
6748
+ isBound: {
6749
+ type: 'boolean',
6750
+ description: 'Whether user has accounts using this platform'
5578
6751
  }
5579
6752
  },
5580
- required: ['currency', 'balance']
6753
+ required: [
6754
+ 'id',
6755
+ 'name',
6756
+ 'url',
6757
+ 'type',
6758
+ 'canonical',
6759
+ 'suggestedSegment',
6760
+ 'logoUrl',
6761
+ 'isBound'
6762
+ ]
6763
+ } as const;
6764
+
6765
+ export const $PlatformMatchResultDto = {
6766
+ type: 'object',
6767
+ properties: {
6768
+ id: {
6769
+ type: 'string',
6770
+ description: 'Global platform ID'
6771
+ },
6772
+ name: {
6773
+ type: 'string',
6774
+ description: 'Platform name (e.g., "ICBC")'
6775
+ },
6776
+ canonical: {
6777
+ type: 'string',
6778
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
6779
+ },
6780
+ type: {
6781
+ type: 'string',
6782
+ description: 'Platform type',
6783
+ enum: [
6784
+ 'BANK',
6785
+ 'BROKERAGE',
6786
+ 'CRYPTO_EXCHANGE',
6787
+ 'PAYMENT',
6788
+ 'INVESTMENT',
6789
+ 'INSURANCE',
6790
+ 'OTHER'
6791
+ ]
6792
+ },
6793
+ suggestedSegment: {
6794
+ type: 'string',
6795
+ description:
6796
+ 'Suggested path segment — canonical, already in ACCOUNT_RE format'
6797
+ },
6798
+ logoUrl: {
6799
+ type: 'string',
6800
+ description: 'Logo URL',
6801
+ nullable: true
6802
+ },
6803
+ matchType: {
6804
+ type: 'string',
6805
+ description: "How this row matched: 'exact' > 'prefix' > 'substring'",
6806
+ enum: ['exact', 'prefix', 'substring']
6807
+ }
6808
+ },
6809
+ required: [
6810
+ 'id',
6811
+ 'name',
6812
+ 'canonical',
6813
+ 'type',
6814
+ 'suggestedSegment',
6815
+ 'logoUrl',
6816
+ 'matchType'
6817
+ ]
6818
+ } as const;
6819
+
6820
+ export const $PlatformMatchResponseDto = {
6821
+ type: 'object',
6822
+ properties: {
6823
+ platforms: {
6824
+ description: 'Ranked matches, best tier first (at most 10 rows)',
6825
+ type: 'array',
6826
+ items: {
6827
+ $ref: '#/components/schemas/PlatformMatchResultDto'
6828
+ }
6829
+ },
6830
+ matchType: {
6831
+ type: 'string',
6832
+ description:
6833
+ "Overall match quality — top row's tier, or 'none' when no hits",
6834
+ enum: ['none', 'exact', 'prefix', 'substring']
6835
+ },
6836
+ total: {
6837
+ type: 'number',
6838
+ description: 'Total matches before LIMIT (truncation transparency)'
6839
+ },
6840
+ hasMore: {
6841
+ type: 'boolean',
6842
+ description: 'true when total > platforms.length (more matches exist)'
6843
+ }
6844
+ },
6845
+ required: ['platforms', 'matchType', 'total', 'hasMore']
6846
+ } as const;
6847
+
6848
+ export const $CreatePlatformDto = {
6849
+ type: 'object',
6850
+ properties: {
6851
+ name: {
6852
+ type: 'string',
6853
+ description: 'Platform name',
6854
+ example: 'Binance'
6855
+ },
6856
+ canonical: {
6857
+ type: 'string',
6858
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
6859
+ example: 'binance'
6860
+ },
6861
+ aliases: {
6862
+ description: 'Platform aliases (multi-language names for lookup)',
6863
+ example: ['Binance', 'Binance Exchange', 'BNB'],
6864
+ type: 'array',
6865
+ items: {
6866
+ type: 'string'
6867
+ }
6868
+ },
6869
+ url: {
6870
+ type: 'string',
6871
+ description: 'Platform URL',
6872
+ example: 'https://www.binance.com'
6873
+ },
6874
+ type: {
6875
+ type: 'string',
6876
+ description: 'Platform type',
6877
+ enum: [
6878
+ 'BANK',
6879
+ 'BROKERAGE',
6880
+ 'CRYPTO_EXCHANGE',
6881
+ 'PAYMENT',
6882
+ 'INVESTMENT',
6883
+ 'INSURANCE',
6884
+ 'OTHER'
6885
+ ],
6886
+ example: 'CRYPTO_EXCHANGE'
6887
+ },
6888
+ logoUrl: {
6889
+ type: 'string',
6890
+ description: 'Platform logo URL',
6891
+ example: 'https://example.com/logos/binance.png'
6892
+ },
6893
+ isActive: {
6894
+ type: 'boolean',
6895
+ description: 'Whether the platform is active',
6896
+ default: true
6897
+ }
6898
+ },
6899
+ required: ['name', 'canonical', 'aliases', 'url', 'type']
6900
+ } as const;
6901
+
6902
+ export const $UpdatePlatformDto = {
6903
+ type: 'object',
6904
+ properties: {
6905
+ name: {
6906
+ type: 'string',
6907
+ description: 'Platform name',
6908
+ example: 'Binance'
6909
+ },
6910
+ canonical: {
6911
+ type: 'string',
6912
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
6913
+ example: 'binance'
6914
+ },
6915
+ aliases: {
6916
+ description: 'Platform aliases (multi-language names for lookup)',
6917
+ example: ['Binance', 'Binance Exchange', 'BNB'],
6918
+ type: 'array',
6919
+ items: {
6920
+ type: 'string'
6921
+ }
6922
+ },
6923
+ url: {
6924
+ type: 'string',
6925
+ description: 'Platform URL',
6926
+ example: 'https://www.binance.com'
6927
+ },
6928
+ type: {
6929
+ type: 'string',
6930
+ description: 'Platform type',
6931
+ enum: [
6932
+ 'BANK',
6933
+ 'BROKERAGE',
6934
+ 'CRYPTO_EXCHANGE',
6935
+ 'PAYMENT',
6936
+ 'INVESTMENT',
6937
+ 'INSURANCE',
6938
+ 'OTHER'
6939
+ ],
6940
+ example: 'CRYPTO_EXCHANGE'
6941
+ },
6942
+ logoUrl: {
6943
+ type: 'string',
6944
+ description: 'Platform logo URL',
6945
+ example: 'https://example.com/logos/binance.png'
6946
+ },
6947
+ isActive: {
6948
+ type: 'boolean',
6949
+ description: 'Whether the platform is active'
6950
+ }
6951
+ }
5581
6952
  } as const;
5582
6953
 
5583
6954
  export const $NetWorthByCurrencyDto = {
@@ -5634,41 +7005,19 @@ export const $ConvertedNetWorthDto = {
5634
7005
  exchangeRates: {
5635
7006
  type: 'object',
5636
7007
  description: 'Exchange rates used for conversion',
5637
- example: {
5638
- USD: '7.200000',
5639
- EUR: '7.800000'
5640
- }
5641
- }
5642
- },
5643
- required: [
5644
- 'baseCurrency',
5645
- 'netWorth',
5646
- 'assets',
5647
- 'liabilities',
5648
- 'exchangeRates'
5649
- ]
5650
- } as const;
5651
-
5652
- export const $ExchangeRateWarningDto = {
5653
- type: 'object',
5654
- properties: {
5655
- type: {
5656
- type: 'string',
5657
- description: 'Warning type',
5658
- example: 'MISSING_EXCHANGE_RATE'
5659
- },
5660
- currency: {
5661
- type: 'string',
5662
- description: 'Currency without exchange rate',
5663
- example: 'EUR'
5664
- },
5665
- totalAmount: {
5666
- type: 'string',
5667
- description: 'Total amount affected',
5668
- example: '1000.00'
7008
+ example: {
7009
+ USD: '7.200000',
7010
+ EUR: '7.800000'
7011
+ }
5669
7012
  }
5670
7013
  },
5671
- required: ['type', 'currency', 'totalAmount']
7014
+ required: [
7015
+ 'baseCurrency',
7016
+ 'netWorth',
7017
+ 'assets',
7018
+ 'liabilities',
7019
+ 'exchangeRates'
7020
+ ]
5672
7021
  } as const;
5673
7022
 
5674
7023
  export const $NetWorthResponseDto = {
@@ -5756,7 +7105,7 @@ export const $AccountItemDto = {
5756
7105
  name: {
5757
7106
  type: 'string',
5758
7107
  description: 'Full account name',
5759
- example: 'Assets:Bank:CMB:Savings'
7108
+ example: 'Assets:CN:CMB:Savings'
5760
7109
  },
5761
7110
  displayName: {
5762
7111
  type: 'string',
@@ -5772,6 +7121,12 @@ export const $AccountItemDto = {
5772
7121
  type: 'string',
5773
7122
  description: 'Currency code',
5774
7123
  example: 'CNY'
7124
+ },
7125
+ convertedBalance: {
7126
+ type: 'string',
7127
+ description:
7128
+ 'FX-converted balance in base currency; omitted when not convertible',
7129
+ example: '50000.00'
5775
7130
  }
5776
7131
  },
5777
7132
  required: ['id', 'name', 'displayName', 'balance', 'currency']
@@ -5798,11 +7153,66 @@ export const $PlatformGroupDto = {
5798
7153
  },
5799
7154
  totalBalance: {
5800
7155
  type: 'string',
5801
- description: 'Total balance across all accounts in platform',
7156
+ description: 'FX-converted total balance in base currency',
7157
+ example: '100000.00'
7158
+ },
7159
+ balanceByCurrency: {
7160
+ description: 'Raw (unconverted) balances grouped by currency',
7161
+ type: 'array',
7162
+ items: {
7163
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
7164
+ }
7165
+ },
7166
+ convertedBalance: {
7167
+ type: 'string',
7168
+ description:
7169
+ 'Converted balance in base currency (omitted when no currency is convertible)',
5802
7170
  example: '100000.00'
7171
+ },
7172
+ sharePct: {
7173
+ type: 'number',
7174
+ description:
7175
+ 'Share of the grand converted total (0-100); 0 when grand total is 0',
7176
+ example: 42.5
7177
+ }
7178
+ },
7179
+ required: [
7180
+ 'platformId',
7181
+ 'platformName',
7182
+ 'accounts',
7183
+ 'totalBalance',
7184
+ 'balanceByCurrency',
7185
+ 'sharePct'
7186
+ ]
7187
+ } as const;
7188
+
7189
+ export const $AccountExchangeRateWarningDto = {
7190
+ type: 'object',
7191
+ properties: {
7192
+ type: {
7193
+ type: 'string',
7194
+ description: 'Warning type',
7195
+ example: 'MISSING_EXCHANGE_RATE'
7196
+ },
7197
+ currency: {
7198
+ type: 'string',
7199
+ description: 'Currency without exchange rate',
7200
+ example: 'USD'
7201
+ },
7202
+ accounts: {
7203
+ description: 'Affected account paths',
7204
+ type: 'array',
7205
+ items: {
7206
+ type: 'string'
7207
+ }
7208
+ },
7209
+ totalAmount: {
7210
+ type: 'string',
7211
+ description: 'Total amount in this currency',
7212
+ example: '5000.00'
5803
7213
  }
5804
7214
  },
5805
- required: ['platformId', 'platformName', 'accounts', 'totalBalance']
7215
+ required: ['type', 'currency', 'accounts', 'totalAmount']
5806
7216
  } as const;
5807
7217
 
5808
7218
  export const $AccountsSummaryDto = {
@@ -5815,9 +7225,21 @@ export const $AccountsSummaryDto = {
5815
7225
  totalPlatforms: {
5816
7226
  type: 'number',
5817
7227
  description: 'Total number of platforms'
7228
+ },
7229
+ baseCurrency: {
7230
+ type: 'string',
7231
+ description: 'Base currency for conversion',
7232
+ example: 'CNY'
7233
+ },
7234
+ warnings: {
7235
+ description: 'Per-account exchange rate warnings',
7236
+ type: 'array',
7237
+ items: {
7238
+ $ref: '#/components/schemas/AccountExchangeRateWarningDto'
7239
+ }
5818
7240
  }
5819
7241
  },
5820
- required: ['totalAccounts', 'totalPlatforms']
7242
+ required: ['totalAccounts', 'totalPlatforms', 'baseCurrency']
5821
7243
  } as const;
5822
7244
 
5823
7245
  export const $AccountsResponseDto = {
@@ -5852,7 +7274,7 @@ export const $AccountItemWithAssetClassDto = {
5852
7274
  name: {
5853
7275
  type: 'string',
5854
7276
  description: 'Full account name',
5855
- example: 'Assets:Bank:CMB:Savings'
7277
+ example: 'Assets:CN:CMB:Savings'
5856
7278
  },
5857
7279
  displayName: {
5858
7280
  type: 'string',
@@ -5869,6 +7291,12 @@ export const $AccountItemWithAssetClassDto = {
5869
7291
  description: 'Currency code',
5870
7292
  example: 'CNY'
5871
7293
  },
7294
+ convertedBalance: {
7295
+ type: 'string',
7296
+ description:
7297
+ 'FX-converted balance in base currency; omitted when not convertible',
7298
+ example: '50000.00'
7299
+ },
5872
7300
  assetClass: {
5873
7301
  type: 'string',
5874
7302
  description: 'Asset class',
@@ -5888,6 +7316,12 @@ export const $AccountItemWithAssetClassDto = {
5888
7316
  type: 'string',
5889
7317
  description: 'Risk level',
5890
7318
  example: 'LOW'
7319
+ },
7320
+ source: {
7321
+ type: 'string',
7322
+ description:
7323
+ 'ADR-0105 classification provenance (holding level always; account level only on FALLBACK)',
7324
+ enum: ['USER_META', 'FIAT_CURRENCY', 'OPENBB_MAPPING', 'FALLBACK']
5891
7325
  }
5892
7326
  },
5893
7327
  required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
@@ -5942,35 +7376,6 @@ export const $AssetClassGroupDto = {
5942
7376
  required: ['assetClass', 'accounts', 'balanceByCurrency']
5943
7377
  } as const;
5944
7378
 
5945
- export const $AccountExchangeRateWarningDto = {
5946
- type: 'object',
5947
- properties: {
5948
- type: {
5949
- type: 'string',
5950
- description: 'Warning type',
5951
- example: 'MISSING_EXCHANGE_RATE'
5952
- },
5953
- currency: {
5954
- type: 'string',
5955
- description: 'Currency without exchange rate',
5956
- example: 'USD'
5957
- },
5958
- accounts: {
5959
- description: 'Affected account paths',
5960
- type: 'array',
5961
- items: {
5962
- type: 'string'
5963
- }
5964
- },
5965
- totalAmount: {
5966
- type: 'string',
5967
- description: 'Total amount in this currency',
5968
- example: '5000.00'
5969
- }
5970
- },
5971
- required: ['type', 'currency', 'accounts', 'totalAmount']
5972
- } as const;
5973
-
5974
7379
  export const $AssetClassSummaryDto = {
5975
7380
  type: 'object',
5976
7381
  properties: {
@@ -5993,6 +7398,11 @@ export const $AssetClassSummaryDto = {
5993
7398
  items: {
5994
7399
  $ref: '#/components/schemas/AccountExchangeRateWarningDto'
5995
7400
  }
7401
+ },
7402
+ fallback: {
7403
+ type: 'object',
7404
+ description:
7405
+ 'ADR-0105 §4 fallback provenance stats (holding level only). valueRatio is the grey-area share of total converted value; count is the number of source=FALLBACK holdings.'
5996
7406
  }
5997
7407
  },
5998
7408
  required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
@@ -6015,11 +7425,107 @@ export const $AssetClassAccountsResponseDto = {
6015
7425
  $ref: '#/components/schemas/AssetClassSummaryDto'
6016
7426
  }
6017
7427
  ]
7428
+ },
7429
+ uncategorized: {
7430
+ description:
7431
+ 'ADR-0105 §6 holding-level grey-area bucket (source=FALLBACK holdings peeled out of groups). Present only for groupBy=holdingAssetClass when FALLBACK holdings exist.',
7432
+ allOf: [
7433
+ {
7434
+ $ref: '#/components/schemas/AssetClassGroupDto'
7435
+ }
7436
+ ]
6018
7437
  }
6019
7438
  },
6020
7439
  required: ['groups', 'summary']
6021
7440
  } as const;
6022
7441
 
7442
+ export const $HoldingAssetClassAccountSliceDto = {
7443
+ type: 'object',
7444
+ properties: {
7445
+ accountId: {
7446
+ type: 'string',
7447
+ description: 'Account ID'
7448
+ },
7449
+ accountPath: {
7450
+ type: 'string',
7451
+ description: 'Full account path',
7452
+ example: 'Assets:US:Fidelity:Brokerage'
7453
+ },
7454
+ accountCurrency: {
7455
+ type: 'string',
7456
+ description:
7457
+ 'Currency of the holding with the largest converted base value; undefined when no holding is convertible',
7458
+ example: 'USD'
7459
+ },
7460
+ marketValueBase: {
7461
+ type: 'string',
7462
+ description:
7463
+ "Account's market value in base currency (Σ converted holdings; grey bucket included)",
7464
+ example: '50000.00'
7465
+ },
7466
+ shareOfTotalPct: {
7467
+ type: 'number',
7468
+ description:
7469
+ 'Share of the global total (0-100). 0 when globalTotal is zero (no NaN/Infinity).',
7470
+ example: 42.5
7471
+ },
7472
+ groups: {
7473
+ description: 'Per-account asset-class breakdown',
7474
+ type: 'array',
7475
+ items: {
7476
+ $ref: '#/components/schemas/AssetClassGroupDto'
7477
+ }
7478
+ },
7479
+ uncategorized: {
7480
+ description:
7481
+ 'Per-account grey bucket (source=FALLBACK holdings, incl. broker cash)',
7482
+ allOf: [
7483
+ {
7484
+ $ref: '#/components/schemas/AssetClassGroupDto'
7485
+ }
7486
+ ]
7487
+ },
7488
+ holdings: {
7489
+ description:
7490
+ 'Every holding row for this account (account ID in each row’s `id` field)',
7491
+ type: 'array',
7492
+ items: {
7493
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
7494
+ }
7495
+ }
7496
+ },
7497
+ required: [
7498
+ 'accountId',
7499
+ 'accountPath',
7500
+ 'marketValueBase',
7501
+ 'shareOfTotalPct',
7502
+ 'groups',
7503
+ 'holdings'
7504
+ ]
7505
+ } as const;
7506
+
7507
+ export const $HoldingAssetClassCrossAccountResponseDto = {
7508
+ type: 'object',
7509
+ properties: {
7510
+ global: {
7511
+ description: 'Merged cross-account holding aggregation',
7512
+ allOf: [
7513
+ {
7514
+ $ref: '#/components/schemas/AssetClassAccountsResponseDto'
7515
+ }
7516
+ ]
7517
+ },
7518
+ byAccount: {
7519
+ description: 'Per-account slices',
7520
+ type: 'array',
7521
+ items: {
7522
+ $ref: '#/components/schemas/HoldingAssetClassAccountSliceDto'
7523
+ }
7524
+ }
7525
+ },
7526
+ required: ['global', 'byAccount']
7527
+ } as const;
7528
+
6023
7529
  export const $CashFlowByCurrencyDto = {
6024
7530
  type: 'object',
6025
7531
  properties: {
@@ -6115,202 +7621,422 @@ export const $CashFlowResponseDto = {
6115
7621
  description: 'Base currency code',
6116
7622
  example: 'CNY'
6117
7623
  },
6118
- byCurrency: {
6119
- description: 'Cash flow grouped by original currency',
6120
- allOf: [
6121
- {
6122
- $ref: '#/components/schemas/CashFlowByCurrencyDto'
6123
- }
6124
- ]
7624
+ byCurrency: {
7625
+ description: 'Cash flow grouped by original currency',
7626
+ allOf: [
7627
+ {
7628
+ $ref: '#/components/schemas/CashFlowByCurrencyDto'
7629
+ }
7630
+ ]
7631
+ },
7632
+ converted: {
7633
+ description: 'Converted values in base currency',
7634
+ allOf: [
7635
+ {
7636
+ $ref: '#/components/schemas/ConvertedCashFlowDto'
7637
+ }
7638
+ ]
7639
+ },
7640
+ warnings: {
7641
+ description: 'Exchange rate warnings',
7642
+ type: 'array',
7643
+ items: {
7644
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7645
+ }
7646
+ }
7647
+ },
7648
+ required: [
7649
+ 'period',
7650
+ 'income',
7651
+ 'expense',
7652
+ 'netSavings',
7653
+ 'savingsRate',
7654
+ 'currency'
7655
+ ]
7656
+ } as const;
7657
+
7658
+ export const $CategoryGroupDto = {
7659
+ type: 'object',
7660
+ properties: {
7661
+ category: {
7662
+ type: 'string',
7663
+ description:
7664
+ 'Functional category (account-path Group segment); regional and universal account paths merge under it',
7665
+ example: 'Food'
7666
+ },
7667
+ totalExpense: {
7668
+ type: 'string',
7669
+ description:
7670
+ 'Converted total for this category in base currency (expense amount when flow=expense, income amount when flow=income)',
7671
+ example: '1200.00'
7672
+ },
7673
+ sharePct: {
7674
+ type: 'number',
7675
+ description: 'Share of grand total (0-100); 0 when grand total is 0',
7676
+ example: 42.5
7677
+ },
7678
+ balanceByCurrency: {
7679
+ description: 'Raw (unconverted) expense per currency',
7680
+ type: 'array',
7681
+ items: {
7682
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
7683
+ }
7684
+ },
7685
+ convertedBalance: {
7686
+ type: 'string',
7687
+ description:
7688
+ 'Converted total in base currency (omitted when FX missing for all currencies in this category)',
7689
+ example: '1200.00'
7690
+ }
7691
+ },
7692
+ required: ['category', 'totalExpense', 'sharePct', 'balanceByCurrency']
7693
+ } as const;
7694
+
7695
+ export const $ExpensesByCategorySummaryDto = {
7696
+ type: 'object',
7697
+ properties: {
7698
+ totalExpense: {
7699
+ type: 'string',
7700
+ description:
7701
+ 'Total across all categories, converted (convertible categories only); expense totals when flow=expense, income totals when flow=income',
7702
+ example: '5000.00'
7703
+ },
7704
+ categoryCount: {
7705
+ type: 'number',
7706
+ description: 'Number of categories',
7707
+ example: 8
7708
+ }
7709
+ },
7710
+ required: ['totalExpense', 'categoryCount']
7711
+ } as const;
7712
+
7713
+ export const $ExpensesByCategoryResponseDto = {
7714
+ type: 'object',
7715
+ properties: {
7716
+ period: {
7717
+ type: 'string',
7718
+ description: 'Period requested',
7719
+ example: '1m'
7720
+ },
7721
+ baseCurrency: {
7722
+ type: 'string',
7723
+ description: 'Base currency for converted values',
7724
+ example: 'CNY'
7725
+ },
7726
+ groups: {
7727
+ description:
7728
+ 'Expense groups by functional category, sorted by converted total desc',
7729
+ type: 'array',
7730
+ items: {
7731
+ $ref: '#/components/schemas/CategoryGroupDto'
7732
+ }
6125
7733
  },
6126
- converted: {
6127
- description: 'Converted values in base currency',
7734
+ summary: {
7735
+ description: 'Summary statistics',
6128
7736
  allOf: [
6129
7737
  {
6130
- $ref: '#/components/schemas/ConvertedCashFlowDto'
7738
+ $ref: '#/components/schemas/ExpensesByCategorySummaryDto'
6131
7739
  }
6132
7740
  ]
6133
7741
  },
6134
7742
  warnings: {
6135
- description: 'Exchange rate warnings',
7743
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
6136
7744
  type: 'array',
6137
7745
  items: {
6138
7746
  $ref: '#/components/schemas/ExchangeRateWarningDto'
6139
7747
  }
6140
7748
  }
6141
7749
  },
6142
- required: [
6143
- 'period',
6144
- 'income',
6145
- 'expense',
6146
- 'netSavings',
6147
- 'savingsRate',
6148
- 'currency'
6149
- ]
7750
+ required: ['period', 'baseCurrency', 'groups', 'summary']
6150
7751
  } as const;
6151
7752
 
6152
- export const $CurrencyBalanceDto = {
7753
+ export const $MonetaryDto = {
6153
7754
  type: 'object',
6154
7755
  properties: {
6155
- currency: {
7756
+ amount: {
6156
7757
  type: 'string',
6157
- description: 'ISO 4217 currency code',
6158
- example: 'CNY'
7758
+ description: 'Amount (Decimal string)',
7759
+ example: '3000'
6159
7760
  },
6160
- balance: {
7761
+ currency: {
6161
7762
  type: 'string',
6162
- description: 'Balance amount',
6163
- example: '500000.00'
7763
+ description: 'ISO 4217 currency',
7764
+ example: 'USD'
7765
+ },
7766
+ baseCcyEquivalent: {
7767
+ type: 'object',
7768
+ description: 'Converted to user base currency (Decimal string)',
7769
+ example: '21600',
7770
+ nullable: true
6164
7771
  }
6165
7772
  },
6166
- required: ['currency', 'balance']
7773
+ required: ['amount', 'currency']
6167
7774
  } as const;
6168
7775
 
6169
- export const $TimeSeriesPointDto = {
7776
+ export const $CurrentPriceDto = {
6170
7777
  type: 'object',
6171
7778
  properties: {
6172
- date: {
7779
+ amount: {
6173
7780
  type: 'string',
6174
- description: 'Date in YYYY-MM-DD format',
6175
- example: '2024-06-15'
7781
+ description: 'Price amount (Decimal string)',
7782
+ example: '250'
6176
7783
  },
6177
- value: {
7784
+ currency: {
6178
7785
  type: 'string',
6179
- description: 'Value at this date (in base currency)',
6180
- example: '500000.00'
7786
+ description: 'Price currency (ISO 4217)',
7787
+ example: 'USD'
6181
7788
  },
6182
- change: {
6183
- type: 'object',
6184
- description: 'Change from previous point',
6185
- example: '5000.00'
7789
+ date: {
7790
+ type: 'string',
7791
+ description: 'Price date (ISO 8601)',
7792
+ example: '2024-06-01'
6186
7793
  },
6187
- byCurrency: {
6188
- description: 'Multi-currency breakdown for this point',
6189
- type: 'array',
6190
- items: {
6191
- $ref: '#/components/schemas/CurrencyBalanceDto'
6192
- }
7794
+ source: {
7795
+ type: 'string',
7796
+ description: 'Price source',
7797
+ example: 'USER_OVERRIDE',
7798
+ enum: ['USER_OVERRIDE', 'OPENBB_EQUITY', 'OPENBB_CURRENCY']
6193
7799
  }
6194
7800
  },
6195
- required: ['date', 'value']
7801
+ required: ['amount', 'currency', 'date', 'source']
6196
7802
  } as const;
6197
7803
 
6198
- export const $TrendSummaryDto = {
7804
+ export const $FxRateDto = {
6199
7805
  type: 'object',
6200
7806
  properties: {
6201
- startValue: {
7807
+ from: {
6202
7808
  type: 'string',
6203
- description: 'Value at start of period',
6204
- example: '450000.00'
7809
+ example: 'USD'
6205
7810
  },
6206
- endValue: {
7811
+ to: {
6207
7812
  type: 'string',
6208
- description: 'Value at end of period',
6209
- example: '500000.00'
7813
+ example: 'CNY'
6210
7814
  },
6211
- totalChange: {
7815
+ rate: {
6212
7816
  type: 'string',
6213
- description: 'Total change over period',
6214
- example: '50000.00'
7817
+ description: 'FX rate (Decimal string)',
7818
+ example: '7.2'
6215
7819
  },
6216
- totalChangePercentage: {
7820
+ date: {
6217
7821
  type: 'string',
6218
- description: 'Total change percentage',
6219
- example: '+11.11%'
7822
+ description: 'Rate date (ISO 8601)',
7823
+ example: '2024-01-15'
6220
7824
  }
6221
7825
  },
6222
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
7826
+ required: ['from', 'to', 'rate', 'date']
6223
7827
  } as const;
6224
7828
 
6225
- export const $MultiCurrencyPointDto = {
7829
+ export const $HoldingPnlRowDto = {
6226
7830
  type: 'object',
6227
7831
  properties: {
6228
- date: {
7832
+ accountId: {
6229
7833
  type: 'string',
6230
- description: 'Date in YYYY-MM-DD format',
6231
- example: '2024-06-15'
7834
+ description: 'Account UUID',
7835
+ example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
6232
7836
  },
6233
- byCurrency: {
6234
- description: 'Balances by currency',
6235
- type: 'array',
6236
- items: {
6237
- $ref: '#/components/schemas/CurrencyBalanceDto'
6238
- }
7837
+ accountPath: {
7838
+ type: 'string',
7839
+ description: 'Full account path',
7840
+ example: 'Assets:US:Broker:AAPL'
7841
+ },
7842
+ accountCcy: {
7843
+ type: 'object',
7844
+ description: 'Account settlement currency (ISO 4217), from cost currency',
7845
+ nullable: true,
7846
+ example: 'USD'
7847
+ },
7848
+ brokerType: {
7849
+ type: 'object',
7850
+ description: 'Broker type derived from Platform.type',
7851
+ nullable: true,
7852
+ example: 'broker'
7853
+ },
7854
+ symbol: {
7855
+ type: 'string',
7856
+ description: 'Commodity symbol',
7857
+ example: 'AAPL'
7858
+ },
7859
+ chartToken: {
7860
+ type: 'string',
7861
+ description: 'Chart segment token (libs/common resolver)',
7862
+ example: 'equity',
7863
+ enum: ['equity', 'fund', 'bond', 'cash', 'other']
7864
+ },
7865
+ assetClass: {
7866
+ type: 'string',
7867
+ example: 'EQUITY'
7868
+ },
7869
+ assetSubClass: {
7870
+ type: 'object',
7871
+ nullable: true,
7872
+ example: 'STOCK'
7873
+ },
7874
+ units: {
7875
+ type: 'string',
7876
+ description: 'Net held units (Decimal string)',
7877
+ example: '12'
7878
+ },
7879
+ averageCostPerUnit: {
7880
+ description:
7881
+ 'Average cost per unit; null when cost currency conflicts or no cost',
7882
+ nullable: true,
7883
+ allOf: [
7884
+ {
7885
+ $ref: '#/components/schemas/MonetaryDto'
7886
+ }
7887
+ ]
7888
+ },
7889
+ costBasis: {
7890
+ description: 'Cost basis of held units',
7891
+ nullable: true,
7892
+ allOf: [
7893
+ {
7894
+ $ref: '#/components/schemas/MonetaryDto'
7895
+ }
7896
+ ]
7897
+ },
7898
+ marketValue: {
7899
+ description: 'Market value at asOf price',
7900
+ nullable: true,
7901
+ allOf: [
7902
+ {
7903
+ $ref: '#/components/schemas/MonetaryDto'
7904
+ }
7905
+ ]
7906
+ },
7907
+ currentPrice: {
7908
+ description: 'Price used for market value',
7909
+ nullable: true,
7910
+ allOf: [
7911
+ {
7912
+ $ref: '#/components/schemas/CurrentPriceDto'
7913
+ }
7914
+ ]
7915
+ },
7916
+ unrealizedPnlBase: {
7917
+ type: 'object',
7918
+ description:
7919
+ 'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
7920
+ nullable: true,
7921
+ example: '6000'
7922
+ },
7923
+ unrealizedPnlPct: {
7924
+ type: 'object',
7925
+ description: 'Unrealized P&L % (Decimal string)',
7926
+ nullable: true,
7927
+ example: '25'
7928
+ },
7929
+ costFxRate: {
7930
+ description: 'Historical FX rate applied to cost basis',
7931
+ nullable: true,
7932
+ allOf: [
7933
+ {
7934
+ $ref: '#/components/schemas/FxRateDto'
7935
+ }
7936
+ ]
7937
+ },
7938
+ marketFxRate: {
7939
+ description: 'FX rate applied to market value',
7940
+ nullable: true,
7941
+ allOf: [
7942
+ {
7943
+ $ref: '#/components/schemas/FxRateDto'
7944
+ }
7945
+ ]
7946
+ },
7947
+ pctOfInvestedAssets: {
7948
+ type: 'object',
7949
+ description:
7950
+ 'Share of invested assets % (Decimal string); only for invested chartTokens',
7951
+ nullable: true,
7952
+ example: '40'
7953
+ },
7954
+ realizedPnl: {
7955
+ description:
7956
+ 'Cumulative realized P&L on sold lots (asOf-date cutoff); null when the method has no applicable sells, a sell lacks a price, or any required FX rate is missing (never-mix). When a sell spans multiple currencies (cross-currency sale), amount and currency reflect the base currency; baseCcyEquivalent is always the authoritative dual-FX figure',
7957
+ nullable: true,
7958
+ allOf: [
7959
+ {
7960
+ $ref: '#/components/schemas/MonetaryDto'
7961
+ }
7962
+ ]
6239
7963
  }
6240
7964
  },
6241
- required: ['date', 'byCurrency']
7965
+ required: [
7966
+ 'accountId',
7967
+ 'accountPath',
7968
+ 'symbol',
7969
+ 'chartToken',
7970
+ 'assetClass',
7971
+ 'units'
7972
+ ]
6242
7973
  } as const;
6243
7974
 
6244
- export const $PortfolioTrendsResponseDto = {
7975
+ export const $HoldingPnlWarningDto = {
6245
7976
  type: 'object',
6246
7977
  properties: {
6247
- series: {
6248
- description: 'Time series data points',
6249
- type: 'array',
6250
- items: {
6251
- $ref: '#/components/schemas/TimeSeriesPointDto'
6252
- }
6253
- },
6254
- summary: {
6255
- description: 'Period summary',
6256
- allOf: [
6257
- {
6258
- $ref: '#/components/schemas/TrendSummaryDto'
6259
- }
7978
+ type: {
7979
+ type: 'string',
7980
+ description: 'Warning type',
7981
+ example: 'MISSING_COST_FX_RATE',
7982
+ enum: [
7983
+ 'MISSING_COST_FX_RATE',
7984
+ 'MISSING_MARKET_FX_RATE',
7985
+ 'MISSING_SALE_PRICE',
7986
+ 'MISSING_REALIZED_FX_RATE',
7987
+ 'OVERSOLD_LOTS',
7988
+ 'NO_PRICE',
7989
+ 'MIXED_COST_CURRENCY'
6260
7990
  ]
6261
7991
  },
6262
- period: {
6263
- type: 'string',
6264
- description: 'Period requested',
6265
- example: '6m'
7992
+ symbol: {
7993
+ type: 'object',
7994
+ nullable: true
6266
7995
  },
6267
- granularity: {
6268
- type: 'string',
6269
- description: 'Data granularity',
6270
- example: 'month'
7996
+ accountId: {
7997
+ type: 'object',
7998
+ nullable: true
6271
7999
  },
6272
8000
  currency: {
8001
+ type: 'object',
8002
+ nullable: true
8003
+ }
8004
+ },
8005
+ required: ['type']
8006
+ } as const;
8007
+
8008
+ export const $HoldingPnlResponseDto = {
8009
+ type: 'object',
8010
+ properties: {
8011
+ asOfDate: {
8012
+ type: 'string',
8013
+ example: '2026-07-08'
8014
+ },
8015
+ baseCurrency: {
6273
8016
  type: 'string',
6274
- description: 'Base currency for converted values',
6275
8017
  example: 'CNY'
6276
8018
  },
6277
- byCurrency: {
8019
+ method: {
8020
+ type: 'string',
6278
8021
  description:
6279
- 'Multi-currency time series (each point has currency breakdown)',
8022
+ 'Realized-P&L lot-matching method (FIFO or average). Unrealized cost basis remains average regardless of this value (#473).',
8023
+ enum: ['average', 'FIFO'],
8024
+ example: 'average'
8025
+ },
8026
+ rows: {
6280
8027
  type: 'array',
6281
8028
  items: {
6282
- $ref: '#/components/schemas/MultiCurrencyPointDto'
8029
+ $ref: '#/components/schemas/HoldingPnlRowDto'
6283
8030
  }
6284
8031
  },
6285
8032
  warnings: {
6286
- description: 'Exchange rate warnings',
6287
8033
  type: 'array',
6288
8034
  items: {
6289
- $ref: '#/components/schemas/ExchangeRateWarningDto'
8035
+ $ref: '#/components/schemas/HoldingPnlWarningDto'
6290
8036
  }
6291
8037
  }
6292
8038
  },
6293
- required: ['series', 'summary', 'period', 'granularity', 'currency']
6294
- } as const;
6295
-
6296
- export const $GenerateSnapshotBody = {
6297
- type: 'object',
6298
- properties: {}
6299
- } as const;
6300
-
6301
- export const $GenerateSnapshotResponse = {
6302
- type: 'object',
6303
- properties: {}
6304
- } as const;
6305
-
6306
- export const $BackfillSnapshotsBody = {
6307
- type: 'object',
6308
- properties: {}
6309
- } as const;
6310
-
6311
- export const $BackfillSnapshotsResponse = {
6312
- type: 'object',
6313
- properties: {}
8039
+ required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6314
8040
  } as const;
6315
8041
 
6316
8042
  export const $AnonymousLoginDto = {
@@ -6323,3 +8049,15 @@ export const $AnonymousLoginDto = {
6323
8049
  },
6324
8050
  required: ['accessToken']
6325
8051
  } as const;
8052
+
8053
+ export const $AnonymousLoginResponseDto = {
8054
+ type: 'object',
8055
+ properties: {
8056
+ authToken: {
8057
+ type: 'string',
8058
+ description: 'JWT auth token',
8059
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
8060
+ }
8061
+ },
8062
+ required: ['authToken']
8063
+ } as const;