@firela/api-types 0.0.0-canary.2b7765ff → 0.0.0-canary.2d71872c

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.
@@ -17,6 +17,8 @@ import type {
17
17
  AccountControllerCloseResponse,
18
18
  AccountControllerReopenData,
19
19
  AccountControllerReopenResponse,
20
+ AccountControllerAddOpeningBalanceData,
21
+ AccountControllerAddOpeningBalanceResponse,
20
22
  AccountStandardsControllerGetTemplatesData,
21
23
  AccountStandardsControllerGetTemplatesResponse,
22
24
  AccountStandardsControllerGetTemplateMetadataData,
@@ -97,6 +99,18 @@ import type {
97
99
  CommodityControllerGetOrCreateResponse,
98
100
  CommodityControllerBulkCreateData,
99
101
  CommodityControllerBulkCreateResponse,
102
+ PriceControllerCreateData,
103
+ PriceControllerCreateResponse,
104
+ PriceControllerFindAllData,
105
+ PriceControllerFindAllResponse,
106
+ PriceControllerFindOneData,
107
+ PriceControllerFindOneResponse,
108
+ PriceControllerUpdateData,
109
+ PriceControllerUpdateResponse,
110
+ PriceControllerDeleteData,
111
+ PriceControllerDeleteResponse,
112
+ PriceControllerBulkCreateData,
113
+ PriceControllerBulkCreateResponse,
100
114
  RecurringRuleControllerCreateData,
101
115
  RecurringRuleControllerCreateResponse,
102
116
  RecurringRuleControllerFindAllData,
@@ -171,6 +185,28 @@ import type {
171
185
  PropertyControllerUpdateResponse,
172
186
  PropertyControllerDeleteData,
173
187
  PropertyControllerDeleteResponse,
188
+ EventControllerCreateData,
189
+ EventControllerCreateResponse,
190
+ EventControllerFindAllData,
191
+ EventControllerFindAllResponse,
192
+ EventControllerFindOneData,
193
+ EventControllerFindOneResponse,
194
+ EventControllerUpdateData,
195
+ EventControllerUpdateResponse,
196
+ EventControllerDeleteData,
197
+ EventControllerDeleteResponse,
198
+ EventControllerGetSliceData,
199
+ EventControllerGetSliceResponse,
200
+ OnboardingControllerBootstrapData,
201
+ OnboardingControllerBootstrapResponse,
202
+ ReconciliationControllerComputeData,
203
+ ReconciliationControllerComputeResponse,
204
+ ReconciliationControllerAssertData,
205
+ ReconciliationControllerAssertResponse,
206
+ ReconciliationControllerPadData,
207
+ ReconciliationControllerPadResponse,
208
+ ReconciliationControllerHistoryData,
209
+ ReconciliationControllerHistoryResponse,
174
210
  ExportControllerExportBeancountResponse,
175
211
  FileImportControllerImportFileData,
176
212
  FileImportControllerImportFileResponse,
@@ -184,22 +220,20 @@ import type {
184
220
  ImporterConfigControllerUpdateConfigResponse,
185
221
  ImporterConfigControllerResetConfigData,
186
222
  ImporterConfigControllerResetConfigResponse,
187
- PlatformControllerFindAllResponse,
188
- PlatformControllerCreateData,
189
- PlatformControllerCreateResponse,
190
- PlatformControllerGetPlatformListResponse,
191
- PlatformControllerMatchPlatformsData,
192
- PlatformControllerMatchPlatformsResponse,
193
- PlatformControllerUpdateData,
194
- PlatformControllerUpdateResponse,
195
- PlatformControllerDeleteData,
196
- PlatformControllerDeleteResponse,
197
223
  ProviderSyncControllerSyncData,
198
224
  ProviderSyncControllerSyncResponse,
199
225
  ProviderSyncControllerGetSupportedProvidersData,
200
226
  ProviderSyncControllerGetSupportedProvidersResponse,
201
227
  ProviderSyncControllerIsProviderSupportedData,
202
228
  ProviderSyncControllerIsProviderSupportedResponse,
229
+ ExternalAccountLinkControllerCreateData,
230
+ ExternalAccountLinkControllerCreateResponse,
231
+ ExternalAccountLinkControllerFindAllData,
232
+ ExternalAccountLinkControllerFindAllResponse,
233
+ ExternalAccountLinkControllerFindOneData,
234
+ ExternalAccountLinkControllerFindOneResponse,
235
+ ExternalAccountLinkControllerRemoveData,
236
+ ExternalAccountLinkControllerRemoveResponse,
203
237
  TelemetryControllerReportTelemetryData,
204
238
  TelemetryControllerReportTelemetryResponse,
205
239
  TelemetryControllerReportCoverageMissData,
@@ -212,28 +246,30 @@ import type {
212
246
  NlpControllerClearSessionResponse,
213
247
  NlpControllerGetSessionData,
214
248
  NlpControllerGetSessionResponse,
249
+ PlatformControllerFindAllResponse,
250
+ PlatformControllerCreateData,
251
+ PlatformControllerCreateResponse,
252
+ PlatformControllerGetPlatformListResponse,
253
+ PlatformControllerMatchPlatformsData,
254
+ PlatformControllerMatchPlatformsResponse,
255
+ PlatformControllerUpdateData,
256
+ PlatformControllerUpdateResponse,
257
+ PlatformControllerDeleteData,
258
+ PlatformControllerDeleteResponse,
215
259
  DashboardControllerGetNetWorthData,
216
260
  DashboardControllerGetNetWorthResponse,
217
261
  DashboardControllerGetAccountsData,
218
262
  DashboardControllerGetAccountsResponse,
219
263
  DashboardControllerGetCashFlowData,
220
264
  DashboardControllerGetCashFlowResponse,
265
+ DashboardControllerGetExpensesData,
266
+ DashboardControllerGetExpensesResponse,
221
267
  HoldingPnlControllerGetHoldingPnlData,
222
268
  HoldingPnlControllerGetHoldingPnlResponse,
223
- PriceControllerCreateData,
224
- PriceControllerCreateResponse,
225
- PriceControllerFindAllData,
226
- PriceControllerFindAllResponse,
227
- PriceControllerFindOneData,
228
- PriceControllerFindOneResponse,
229
- PriceControllerUpdateData,
230
- PriceControllerUpdateResponse,
231
- PriceControllerDeleteData,
232
- PriceControllerDeleteResponse,
233
- PriceControllerBulkCreateData,
234
- PriceControllerBulkCreateResponse,
235
269
  ReportingControllerGetPortfolioTrendsData,
236
270
  ReportingControllerGetPortfolioTrendsResponse,
271
+ ReportingControllerGetCashFlowTrendsData,
272
+ ReportingControllerGetCashFlowTrendsResponse,
237
273
  ReportingControllerGenerateSnapshotData,
238
274
  ReportingControllerGenerateSnapshotResponse,
239
275
  ReportingControllerBackfillSnapshotsData,
@@ -290,7 +326,7 @@ export class BeanAccountsService {
290
326
  * @param data.type Filter by account type
291
327
  * @param data.status Filter by status
292
328
  * @param data.isCustom Filter by custom (user-created) accounts only
293
- * @param data.search Search term for path or i18nKey
329
+ * @param data.search Search term for account path
294
330
  * @param data.limit Maximum number of results
295
331
  * @param data.offset Number of results to skip
296
332
  * @returns AccountListResponseDto Accounts retrieved successfully
@@ -452,6 +488,35 @@ export class BeanAccountsService {
452
488
  }
453
489
  });
454
490
  }
491
+
492
+ /**
493
+ * Post an opening-balance transaction
494
+ * Posts a double-entry opening-balance transaction against Equity:Opening-Balances for an existing Assets/Liabilities account. At most one active opening balance per account.
495
+ * @param data The data for the request.
496
+ * @param data.id Account UUID
497
+ * @param data.region Region code for tenant context
498
+ * @param data.requestBody
499
+ * @returns OpeningBalanceResultDto Opening-balance transaction created
500
+ * @throws ApiError
501
+ */
502
+ public static accountControllerAddOpeningBalance(
503
+ data: AccountControllerAddOpeningBalanceData
504
+ ): CancelablePromise<AccountControllerAddOpeningBalanceResponse> {
505
+ return __request(OpenAPI, {
506
+ method: 'POST',
507
+ url: '/api/v1/{region}/bean/accounts/{id}/opening-balance',
508
+ path: {
509
+ id: data.id,
510
+ region: data.region
511
+ },
512
+ body: data.requestBody,
513
+ mediaType: 'application/json',
514
+ errors: {
515
+ 404: 'Account not found',
516
+ 409: 'An opening balance already exists for this account'
517
+ }
518
+ });
519
+ }
455
520
  }
456
521
 
457
522
  export class BeanAccountStandardsService {
@@ -483,7 +548,7 @@ export class BeanAccountStandardsService {
483
548
 
484
549
  /**
485
550
  * Get template metadata for an account path
486
- * Returns extendable status and root type for a template path.
551
+ * Returns root type for a template path.
487
552
  * @param data The data for the request.
488
553
  * @param data.region Region code for tenant context
489
554
  * @param data.path Account path to check
@@ -569,6 +634,7 @@ export class BeanTransactionsService {
569
634
  * @param data.status Filter by transaction status
570
635
  * @param data.search Search in narration and payee fields (max 200 chars)
571
636
  * @param data.accountId Filter by account ID (transactions with postings to this account)
637
+ * @param data.category Filter by ADR-0075 functional category (Group segment); matches any posting to an Expenses/Income account whose derived Group segment equals this value
572
638
  * @returns TransactionListResponseDto Transaction list
573
639
  * @throws ApiError
574
640
  */
@@ -588,7 +654,8 @@ export class BeanTransactionsService {
588
654
  dateTo: data.dateTo,
589
655
  status: data.status,
590
656
  search: data.search,
591
- accountId: data.accountId
657
+ accountId: data.accountId,
658
+ category: data.category
592
659
  },
593
660
  errors: {
594
661
  400: 'Validation failed',
@@ -776,7 +843,7 @@ export class BeanBalancesService {
776
843
  * Query account balance
777
844
  * Calculate account balance at a specific date for a single currency
778
845
  * @param data The data for the request.
779
- * @param data.account Account name (e.g., "Assets:Bank:Checking")
846
+ * @param data.account Account name (e.g., "Assets:Checking")
780
847
  * @param data.region Region code for tenant context
781
848
  * @param data.date Date to calculate balance at (ISO 8601 format)
782
849
  * @param data.currency Currency to query (e.g., "USD", "CNY")
@@ -1497,6 +1564,173 @@ export class BeanCommoditiesService {
1497
1564
  }
1498
1565
  }
1499
1566
 
1567
+ export class BeanPricesService {
1568
+ /**
1569
+ * Create a new price
1570
+ * Creates a new price entry for the authenticated user
1571
+ * @param data The data for the request.
1572
+ * @param data.region Region code for tenant context
1573
+ * @param data.requestBody
1574
+ * @returns PriceResponseDto Price created successfully
1575
+ * @throws ApiError
1576
+ */
1577
+ public static priceControllerCreate(
1578
+ data: PriceControllerCreateData
1579
+ ): CancelablePromise<PriceControllerCreateResponse> {
1580
+ return __request(OpenAPI, {
1581
+ method: 'POST',
1582
+ url: '/api/v1/{region}/bean/prices',
1583
+ path: {
1584
+ region: data.region
1585
+ },
1586
+ body: data.requestBody,
1587
+ mediaType: 'application/json',
1588
+ errors: {
1589
+ 404: 'Currency or quoteCurrency commodity not found',
1590
+ 409: 'Price already exists for this currency pair and date'
1591
+ }
1592
+ });
1593
+ }
1594
+
1595
+ /**
1596
+ * List user prices
1597
+ * Returns all price entries for the authenticated user with optional filtering
1598
+ * @param data The data for the request.
1599
+ * @param data.region Region code for tenant context
1600
+ * @param data.currency Filter by currency (e.g., BTC, AAPL, USD)
1601
+ * @param data.quoteCurrency Filter by quote currency (pricing currency, e.g., USD, CNY)
1602
+ * @param data.dateFrom Filter prices from this date (ISO 8601 format)
1603
+ * @param data.dateTo Filter prices to this date (ISO 8601 format)
1604
+ * @param data.search Search term for currency or quoteCurrency (case-insensitive partial match)
1605
+ * @param data.page Page number for pagination (default: 1)
1606
+ * @param data.limit Number of items per page (default: 20, max: 100)
1607
+ * @returns PriceListResponseDto Prices retrieved successfully
1608
+ * @throws ApiError
1609
+ */
1610
+ public static priceControllerFindAll(
1611
+ data: PriceControllerFindAllData
1612
+ ): CancelablePromise<PriceControllerFindAllResponse> {
1613
+ return __request(OpenAPI, {
1614
+ method: 'GET',
1615
+ url: '/api/v1/{region}/bean/prices',
1616
+ path: {
1617
+ region: data.region
1618
+ },
1619
+ query: {
1620
+ currency: data.currency,
1621
+ quoteCurrency: data.quoteCurrency,
1622
+ dateFrom: data.dateFrom,
1623
+ dateTo: data.dateTo,
1624
+ search: data.search,
1625
+ page: data.page,
1626
+ limit: data.limit
1627
+ }
1628
+ });
1629
+ }
1630
+
1631
+ /**
1632
+ * Get price by ID
1633
+ * Returns a single price entry by its ID
1634
+ * @param data The data for the request.
1635
+ * @param data.id Price ID
1636
+ * @param data.region Region code for tenant context
1637
+ * @returns PriceResponseDto Price retrieved successfully
1638
+ * @throws ApiError
1639
+ */
1640
+ public static priceControllerFindOne(
1641
+ data: PriceControllerFindOneData
1642
+ ): CancelablePromise<PriceControllerFindOneResponse> {
1643
+ return __request(OpenAPI, {
1644
+ method: 'GET',
1645
+ url: '/api/v1/{region}/bean/prices/{id}',
1646
+ path: {
1647
+ id: data.id,
1648
+ region: data.region
1649
+ },
1650
+ errors: {
1651
+ 404: 'Price not found'
1652
+ }
1653
+ });
1654
+ }
1655
+
1656
+ /**
1657
+ * Update a price
1658
+ * Updates an existing price entry
1659
+ * @param data The data for the request.
1660
+ * @param data.id Price ID
1661
+ * @param data.region Region code for tenant context
1662
+ * @param data.requestBody
1663
+ * @returns PriceResponseDto Price updated successfully
1664
+ * @throws ApiError
1665
+ */
1666
+ public static priceControllerUpdate(
1667
+ data: PriceControllerUpdateData
1668
+ ): CancelablePromise<PriceControllerUpdateResponse> {
1669
+ return __request(OpenAPI, {
1670
+ method: 'PUT',
1671
+ url: '/api/v1/{region}/bean/prices/{id}',
1672
+ path: {
1673
+ id: data.id,
1674
+ region: data.region
1675
+ },
1676
+ body: data.requestBody,
1677
+ mediaType: 'application/json',
1678
+ errors: {
1679
+ 404: 'Price not found',
1680
+ 409: 'Updated price conflicts with existing price'
1681
+ }
1682
+ });
1683
+ }
1684
+
1685
+ /**
1686
+ * Delete a price
1687
+ * Deletes a price entry (hard delete)
1688
+ * @param data The data for the request.
1689
+ * @param data.id Price ID
1690
+ * @param data.region Region code for tenant context
1691
+ * @returns void Price deleted successfully
1692
+ * @throws ApiError
1693
+ */
1694
+ public static priceControllerDelete(
1695
+ data: PriceControllerDeleteData
1696
+ ): CancelablePromise<PriceControllerDeleteResponse> {
1697
+ return __request(OpenAPI, {
1698
+ method: 'DELETE',
1699
+ url: '/api/v1/{region}/bean/prices/{id}',
1700
+ path: {
1701
+ id: data.id,
1702
+ region: data.region
1703
+ },
1704
+ errors: {
1705
+ 404: 'Price not found'
1706
+ }
1707
+ });
1708
+ }
1709
+
1710
+ /**
1711
+ * Bulk create prices
1712
+ * Creates multiple price entries at once (skips duplicates)
1713
+ * @param data The data for the request.
1714
+ * @param data.region Region code for tenant context
1715
+ * @param data.requestBody
1716
+ * @returns PriceResponseDto Prices created successfully
1717
+ * @throws ApiError
1718
+ */
1719
+ public static priceControllerBulkCreate(
1720
+ data: PriceControllerBulkCreateData
1721
+ ): CancelablePromise<PriceControllerBulkCreateResponse> {
1722
+ return __request(OpenAPI, {
1723
+ method: 'POST',
1724
+ url: '/api/v1/{region}/bean/prices/bulk',
1725
+ path: {
1726
+ region: data.region
1727
+ },
1728
+ body: data.requestBody,
1729
+ mediaType: 'application/json'
1730
+ });
1731
+ }
1732
+ }
1733
+
1500
1734
  export class RecurringRulesService {
1501
1735
  /**
1502
1736
  * Create a new recurring rule
@@ -2460,27 +2694,335 @@ export class PropertiesService {
2460
2694
  }
2461
2695
  }
2462
2696
 
2463
- export class BeanExportService {
2697
+ export class LifeEventsService {
2464
2698
  /**
2465
- * Export Beancount ledger as ZIP
2466
- * Export all user Beancount data as a ZIP file containing ledger.beancount and yearly files in community format.
2467
- * @returns unknown
2699
+ * Create a new life event
2700
+ * Creates a new life event entry for the authenticated user. Returns ETag header carrying the row updatedAt.
2701
+ * @param data The data for the request.
2702
+ * @param data.region Region code for tenant context (decorative for life events)
2703
+ * @param data.requestBody
2704
+ * @returns EventResponseDto Life event created successfully
2468
2705
  * @throws ApiError
2469
2706
  */
2470
- public static exportControllerExportBeancount(): CancelablePromise<ExportControllerExportBeancountResponse> {
2707
+ public static eventControllerCreate(
2708
+ data: EventControllerCreateData
2709
+ ): CancelablePromise<EventControllerCreateResponse> {
2471
2710
  return __request(OpenAPI, {
2472
- method: 'GET',
2473
- url: '/api/v1/{region}/bean/export/beancount'
2711
+ method: 'POST',
2712
+ url: '/api/v1/{region}/bean/events',
2713
+ path: {
2714
+ region: data.region
2715
+ },
2716
+ body: data.requestBody,
2717
+ mediaType: 'application/json',
2718
+ errors: {
2719
+ 409: 'Life event already exists for this (userId, type, date) combination'
2720
+ }
2474
2721
  });
2475
2722
  }
2476
- }
2477
2723
 
2478
- export class BeanImportService {
2479
2724
  /**
2480
- * Import a bill file
2481
- * Upload and process a bill file (CSV, PDF, OFX, etc.). The system automatically identifies the file type, extracts transactions, validates them, and stores only validated transactions to the database. Maximum file size: 50MB. Only 1 import per user at a time (concurrent imports rejected with 429).
2725
+ * List user life events
2726
+ * Returns life events for the authenticated user with optional filtering by type, description search, and date range.
2482
2727
  * @param data The data for the request.
2483
- * @param data.region Region code for tenant context
2728
+ * @param data.region Region code for tenant context (decorative for life events)
2729
+ * @param data.type Filter by life event type (exact match)
2730
+ * @param data.q Search term for description (case-insensitive partial match)
2731
+ * @param data.from Filter life events from this date (ISO 8601 format)
2732
+ * @param data.to Filter life events to this date (ISO 8601 format)
2733
+ * @param data.page Page number for pagination (default: 1)
2734
+ * @param data.limit Number of items per page (default: 20, max: 100)
2735
+ * @returns EventListResponseDto Life events retrieved successfully
2736
+ * @throws ApiError
2737
+ */
2738
+ public static eventControllerFindAll(
2739
+ data: EventControllerFindAllData
2740
+ ): CancelablePromise<EventControllerFindAllResponse> {
2741
+ return __request(OpenAPI, {
2742
+ method: 'GET',
2743
+ url: '/api/v1/{region}/bean/events',
2744
+ path: {
2745
+ region: data.region
2746
+ },
2747
+ query: {
2748
+ type: data.type,
2749
+ q: data.q,
2750
+ from: data.from,
2751
+ to: data.to,
2752
+ page: data.page,
2753
+ limit: data.limit
2754
+ }
2755
+ });
2756
+ }
2757
+
2758
+ /**
2759
+ * Get life event by ID
2760
+ * Returns a single life event by its ID. Returns ETag header.
2761
+ * @param data The data for the request.
2762
+ * @param data.id Life event ID
2763
+ * @param data.region Region code for tenant context (decorative for life events)
2764
+ * @returns EventResponseDto Life event retrieved successfully
2765
+ * @throws ApiError
2766
+ */
2767
+ public static eventControllerFindOne(
2768
+ data: EventControllerFindOneData
2769
+ ): CancelablePromise<EventControllerFindOneResponse> {
2770
+ return __request(OpenAPI, {
2771
+ method: 'GET',
2772
+ url: '/api/v1/{region}/bean/events/{id}',
2773
+ path: {
2774
+ id: data.id,
2775
+ region: data.region
2776
+ },
2777
+ errors: {
2778
+ 404: 'Life event not found'
2779
+ }
2780
+ });
2781
+ }
2782
+
2783
+ /**
2784
+ * Update a life event
2785
+ * Updates an existing life event. If If-Match header is provided, performs optimistic concurrency check; mismatched updatedAt returns 412.
2786
+ * @param data The data for the request.
2787
+ * @param data.id Life event ID
2788
+ * @param data.region Region code for tenant context (decorative for life events)
2789
+ * @param data.requestBody
2790
+ * @returns EventResponseDto Life event updated successfully
2791
+ * @throws ApiError
2792
+ */
2793
+ public static eventControllerUpdate(
2794
+ data: EventControllerUpdateData
2795
+ ): CancelablePromise<EventControllerUpdateResponse> {
2796
+ return __request(OpenAPI, {
2797
+ method: 'PUT',
2798
+ url: '/api/v1/{region}/bean/events/{id}',
2799
+ path: {
2800
+ id: data.id,
2801
+ region: data.region
2802
+ },
2803
+ body: data.requestBody,
2804
+ mediaType: 'application/json',
2805
+ errors: {
2806
+ 400: 'If-Match header is not a valid ISO 8601 date',
2807
+ 404: 'Life event not found',
2808
+ 409: 'Updated event conflicts with an existing (userId, type, date) combination',
2809
+ 412: 'If-Match precondition failed (updatedAt mismatch)'
2810
+ }
2811
+ });
2812
+ }
2813
+
2814
+ /**
2815
+ * Delete a life event
2816
+ * Deletes a life event entry (hard delete). Returns 204.
2817
+ * @param data The data for the request.
2818
+ * @param data.id Life event ID
2819
+ * @param data.region Region code for tenant context (decorative for life events)
2820
+ * @returns void Life event deleted successfully
2821
+ * @throws ApiError
2822
+ */
2823
+ public static eventControllerDelete(
2824
+ data: EventControllerDeleteData
2825
+ ): CancelablePromise<EventControllerDeleteResponse> {
2826
+ return __request(OpenAPI, {
2827
+ method: 'DELETE',
2828
+ url: '/api/v1/{region}/bean/events/{id}',
2829
+ path: {
2830
+ id: data.id,
2831
+ region: data.region
2832
+ },
2833
+ errors: {
2834
+ 404: 'Life event not found'
2835
+ }
2836
+ });
2837
+ }
2838
+
2839
+ /**
2840
+ * Slice time-series by a life event (Phase 79)
2841
+ * Returns aggregated time-series for postings matching accountPattern within the half-open date range of the given life event.
2842
+ * @param data The data for the request.
2843
+ * @param data.id Life event ID
2844
+ * @param data.accountPattern
2845
+ * @param data.granularity
2846
+ * @param data.region Region code for tenant context (decorative for life events)
2847
+ * @returns unknown Time-series sliced by the life event range
2848
+ * @throws ApiError
2849
+ */
2850
+ public static eventControllerGetSlice(
2851
+ data: EventControllerGetSliceData
2852
+ ): CancelablePromise<EventControllerGetSliceResponse> {
2853
+ return __request(OpenAPI, {
2854
+ method: 'GET',
2855
+ url: '/api/v1/{region}/bean/events/{id}/slice',
2856
+ path: {
2857
+ id: data.id,
2858
+ region: data.region
2859
+ },
2860
+ query: {
2861
+ accountPattern: data.accountPattern,
2862
+ granularity: data.granularity
2863
+ },
2864
+ errors: {
2865
+ 400: 'accountPattern query param is empty',
2866
+ 404: 'Life event not found'
2867
+ }
2868
+ });
2869
+ }
2870
+ }
2871
+
2872
+ export class OnboardingService {
2873
+ /**
2874
+ * Bootstrap core accounts + register asset accounts with opening balances (ADR-0113)
2875
+ * @param data The data for the request.
2876
+ * @param data.region Region code for tenant context
2877
+ * @param data.requestBody
2878
+ * @returns unknown Onboarding bootstrap result.
2879
+ * @throws ApiError
2880
+ */
2881
+ public static onboardingControllerBootstrap(
2882
+ data: OnboardingControllerBootstrapData
2883
+ ): CancelablePromise<OnboardingControllerBootstrapResponse> {
2884
+ return __request(OpenAPI, {
2885
+ method: 'POST',
2886
+ url: '/api/v1/{region}/bean/onboarding',
2887
+ path: {
2888
+ region: data.region
2889
+ },
2890
+ body: data.requestBody,
2891
+ mediaType: 'application/json',
2892
+ errors: {
2893
+ 422: 'Invalid region/account path/duplicate paths.'
2894
+ }
2895
+ });
2896
+ }
2897
+ }
2898
+
2899
+ export class BalanceReconciliationService {
2900
+ /**
2901
+ * Preview reconciliation (book vs actual)
2902
+ * Computes book balance, diff, Beancount-inferred tolerance, and suggested action without persisting.
2903
+ * @param data The data for the request.
2904
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2905
+ * @param data.requestBody
2906
+ * @returns ReconciliationComputeResultDto Reconciliation preview
2907
+ * @throws ApiError
2908
+ */
2909
+ public static reconciliationControllerCompute(
2910
+ data: ReconciliationControllerComputeData
2911
+ ): CancelablePromise<ReconciliationControllerComputeResponse> {
2912
+ return __request(OpenAPI, {
2913
+ method: 'POST',
2914
+ url: '/api/v1/{region}/bean/reconciliations',
2915
+ path: {
2916
+ region: data.region
2917
+ },
2918
+ body: data.requestBody,
2919
+ mediaType: 'application/json',
2920
+ errors: {
2921
+ 404: 'Account not found'
2922
+ }
2923
+ });
2924
+ }
2925
+
2926
+ /**
2927
+ * Record a balance assertion
2928
+ * Persists the reconciliation as a BeanBalance assertion (amount = actual, diffAmount = book − actual). Re-reconciling the same day/currency upserts.
2929
+ * @param data The data for the request.
2930
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2931
+ * @param data.requestBody
2932
+ * @returns ReconciliationRecordDto Balance assertion recorded
2933
+ * @throws ApiError
2934
+ */
2935
+ public static reconciliationControllerAssert(
2936
+ data: ReconciliationControllerAssertData
2937
+ ): CancelablePromise<ReconciliationControllerAssertResponse> {
2938
+ return __request(OpenAPI, {
2939
+ method: 'POST',
2940
+ url: '/api/v1/{region}/bean/reconciliations/assert',
2941
+ path: {
2942
+ region: data.region
2943
+ },
2944
+ body: data.requestBody,
2945
+ mediaType: 'application/json',
2946
+ errors: {
2947
+ 404: 'Account not found'
2948
+ }
2949
+ });
2950
+ }
2951
+
2952
+ /**
2953
+ * Generate a pad adjusting entry
2954
+ * When book is outside tolerance, synthesizes a Beancount pad transaction (flag P) booking the diff from source_account and persists it. Source defaults to Equity:Opening-Balances.
2955
+ * @param data The data for the request.
2956
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2957
+ * @param data.requestBody
2958
+ * @returns PadResultDto Pad adjusting entry generated
2959
+ * @throws ApiError
2960
+ */
2961
+ public static reconciliationControllerPad(
2962
+ data: ReconciliationControllerPadData
2963
+ ): CancelablePromise<ReconciliationControllerPadResponse> {
2964
+ return __request(OpenAPI, {
2965
+ method: 'POST',
2966
+ url: '/api/v1/{region}/bean/reconciliations/pad',
2967
+ path: {
2968
+ region: data.region
2969
+ },
2970
+ body: data.requestBody,
2971
+ mediaType: 'application/json',
2972
+ errors: {
2973
+ 400: 'Book already within tolerance — no pad needed',
2974
+ 404: 'Account not found'
2975
+ }
2976
+ });
2977
+ }
2978
+
2979
+ /**
2980
+ * List reconciliation history for an account
2981
+ * Returns recorded balance assertions (most recent first). The latest drives the account-detail "Last <date>" badge.
2982
+ * @param data The data for the request.
2983
+ * @param data.accountId BeanAccount id
2984
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2985
+ * @returns ReconciliationRecordDto Reconciliation history
2986
+ * @throws ApiError
2987
+ */
2988
+ public static reconciliationControllerHistory(
2989
+ data: ReconciliationControllerHistoryData
2990
+ ): CancelablePromise<ReconciliationControllerHistoryResponse> {
2991
+ return __request(OpenAPI, {
2992
+ method: 'GET',
2993
+ url: '/api/v1/{region}/bean/accounts/{accountId}/reconciliations',
2994
+ path: {
2995
+ accountId: data.accountId,
2996
+ region: data.region
2997
+ },
2998
+ errors: {
2999
+ 404: 'Account not found'
3000
+ }
3001
+ });
3002
+ }
3003
+ }
3004
+
3005
+ export class BeanExportService {
3006
+ /**
3007
+ * Export Beancount ledger as ZIP
3008
+ * Export all user Beancount data as a ZIP file containing ledger.beancount and yearly files in community format.
3009
+ * @returns unknown
3010
+ * @throws ApiError
3011
+ */
3012
+ public static exportControllerExportBeancount(): CancelablePromise<ExportControllerExportBeancountResponse> {
3013
+ return __request(OpenAPI, {
3014
+ method: 'GET',
3015
+ url: '/api/v1/{region}/bean/export/beancount'
3016
+ });
3017
+ }
3018
+ }
3019
+
3020
+ export class BeanImportService {
3021
+ /**
3022
+ * Import a bill file
3023
+ * Upload and process a bill file (CSV, PDF, OFX, etc.). The system automatically identifies the file type, extracts transactions, validates them, and stores only validated transactions to the database. Maximum file size: 50MB. Only 1 import per user at a time (concurrent imports rejected with 429).
3024
+ * @param data The data for the request.
3025
+ * @param data.region Region code for tenant context
2484
3026
  * @param data.formData Bill file to import
2485
3027
  * @returns ImportResultDto File imported successfully
2486
3028
  * @throws ApiError
@@ -2638,121 +3180,6 @@ export class BeanImportService {
2638
3180
  }
2639
3181
  }
2640
3182
 
2641
- export class BeanPlatformsService {
2642
- /**
2643
- * Get all platforms with statistics
2644
- * @returns unknown List of platforms with binding and account counts
2645
- * @throws ApiError
2646
- */
2647
- public static platformControllerFindAll(): CancelablePromise<PlatformControllerFindAllResponse> {
2648
- return __request(OpenAPI, {
2649
- method: 'GET',
2650
- url: '/api/v1/bean/platforms'
2651
- });
2652
- }
2653
-
2654
- /**
2655
- * Create a new platform
2656
- * @param data The data for the request.
2657
- * @param data.requestBody
2658
- * @returns unknown Platform created successfully
2659
- * @throws ApiError
2660
- */
2661
- public static platformControllerCreate(
2662
- data: PlatformControllerCreateData
2663
- ): CancelablePromise<PlatformControllerCreateResponse> {
2664
- return __request(OpenAPI, {
2665
- method: 'POST',
2666
- url: '/api/v1/bean/platforms',
2667
- body: data.requestBody,
2668
- mediaType: 'application/json',
2669
- errors: {
2670
- 409: 'Platform already exists'
2671
- }
2672
- });
2673
- }
2674
-
2675
- /**
2676
- * Get platform list for current user
2677
- * @returns unknown List of platforms with user binding status
2678
- * @throws ApiError
2679
- */
2680
- public static platformControllerGetPlatformList(): CancelablePromise<PlatformControllerGetPlatformListResponse> {
2681
- return __request(OpenAPI, {
2682
- method: 'GET',
2683
- url: '/api/v1/bean/platforms/list'
2684
- });
2685
- }
2686
-
2687
- /**
2688
- * Match platforms by name or alias
2689
- * @param data The data for the request.
2690
- * @param data.q Search query — Chinese name, English name, or abbreviation
2691
- * @param data.region Region code for category override lookup
2692
- * @returns unknown List of matching platforms with suggested segment names
2693
- * @throws ApiError
2694
- */
2695
- public static platformControllerMatchPlatforms(
2696
- data: PlatformControllerMatchPlatformsData
2697
- ): CancelablePromise<PlatformControllerMatchPlatformsResponse> {
2698
- return __request(OpenAPI, {
2699
- method: 'GET',
2700
- url: '/api/v1/bean/platforms/match',
2701
- query: {
2702
- q: data.q,
2703
- region: data.region
2704
- }
2705
- });
2706
- }
2707
-
2708
- /**
2709
- * Update a platform
2710
- * @param data The data for the request.
2711
- * @param data.id Platform ID
2712
- * @param data.requestBody
2713
- * @returns unknown Platform updated successfully
2714
- * @throws ApiError
2715
- */
2716
- public static platformControllerUpdate(
2717
- data: PlatformControllerUpdateData
2718
- ): CancelablePromise<PlatformControllerUpdateResponse> {
2719
- return __request(OpenAPI, {
2720
- method: 'PUT',
2721
- url: '/api/v1/bean/platforms/{id}',
2722
- path: {
2723
- id: data.id
2724
- },
2725
- body: data.requestBody,
2726
- mediaType: 'application/json',
2727
- errors: {
2728
- 404: 'Platform not found'
2729
- }
2730
- });
2731
- }
2732
-
2733
- /**
2734
- * Delete a platform
2735
- * @param data The data for the request.
2736
- * @param data.id Platform ID
2737
- * @returns void Platform deleted successfully
2738
- * @throws ApiError
2739
- */
2740
- public static platformControllerDelete(
2741
- data: PlatformControllerDeleteData
2742
- ): CancelablePromise<PlatformControllerDeleteResponse> {
2743
- return __request(OpenAPI, {
2744
- method: 'DELETE',
2745
- url: '/api/v1/bean/platforms/{id}',
2746
- path: {
2747
- id: data.id
2748
- },
2749
- errors: {
2750
- 404: 'Platform not found'
2751
- }
2752
- });
2753
- }
2754
- }
2755
-
2756
3183
  export class ProviderSyncService {
2757
3184
  /**
2758
3185
  * Sync transactions from financial data provider
@@ -2853,6 +3280,101 @@ export class ProviderSyncService {
2853
3280
  }
2854
3281
  }
2855
3282
 
3283
+ export class ExternalAccountLinksService {
3284
+ /**
3285
+ * Create an external account → BeanAccount mapping (ADR-0113)
3286
+ * @param data The data for the request.
3287
+ * @param data.region Region code for tenant context
3288
+ * @param data.requestBody
3289
+ * @returns ExternalAccountLinkResponseDto Link created.
3290
+ * @throws ApiError
3291
+ */
3292
+ public static externalAccountLinkControllerCreate(
3293
+ data: ExternalAccountLinkControllerCreateData
3294
+ ): CancelablePromise<ExternalAccountLinkControllerCreateResponse> {
3295
+ return __request(OpenAPI, {
3296
+ method: 'POST',
3297
+ url: '/api/v1/{region}/bean/external-account-links',
3298
+ path: {
3299
+ region: data.region
3300
+ },
3301
+ body: data.requestBody,
3302
+ mediaType: 'application/json',
3303
+ errors: {
3304
+ 422: 'beanAccountId not owned, or an active link already exists.'
3305
+ }
3306
+ });
3307
+ }
3308
+
3309
+ /**
3310
+ * List the user's active external account links
3311
+ * @param data The data for the request.
3312
+ * @param data.provider
3313
+ * @param data.region Region code for tenant context
3314
+ * @returns ExternalAccountLinkListResponseDto Links retrieved.
3315
+ * @throws ApiError
3316
+ */
3317
+ public static externalAccountLinkControllerFindAll(
3318
+ data: ExternalAccountLinkControllerFindAllData
3319
+ ): CancelablePromise<ExternalAccountLinkControllerFindAllResponse> {
3320
+ return __request(OpenAPI, {
3321
+ method: 'GET',
3322
+ url: '/api/v1/{region}/bean/external-account-links',
3323
+ path: {
3324
+ region: data.region
3325
+ },
3326
+ query: {
3327
+ provider: data.provider
3328
+ }
3329
+ });
3330
+ }
3331
+
3332
+ /**
3333
+ * Get a single external account link
3334
+ * @param data The data for the request.
3335
+ * @param data.id
3336
+ * @param data.region Region code for tenant context
3337
+ * @returns ExternalAccountLinkResponseDto Link retrieved.
3338
+ * @throws ApiError
3339
+ */
3340
+ public static externalAccountLinkControllerFindOne(
3341
+ data: ExternalAccountLinkControllerFindOneData
3342
+ ): CancelablePromise<ExternalAccountLinkControllerFindOneResponse> {
3343
+ return __request(OpenAPI, {
3344
+ method: 'GET',
3345
+ url: '/api/v1/{region}/bean/external-account-links/{id}',
3346
+ path: {
3347
+ id: data.id,
3348
+ region: data.region
3349
+ },
3350
+ errors: {
3351
+ 422: 'Link not found or not owned by the user.'
3352
+ }
3353
+ });
3354
+ }
3355
+
3356
+ /**
3357
+ * Soft-delete (disconnect) an external account link
3358
+ * @param data The data for the request.
3359
+ * @param data.id
3360
+ * @param data.region Region code for tenant context
3361
+ * @returns void Link soft-deleted; historical transactions are unaffected.
3362
+ * @throws ApiError
3363
+ */
3364
+ public static externalAccountLinkControllerRemove(
3365
+ data: ExternalAccountLinkControllerRemoveData
3366
+ ): CancelablePromise<ExternalAccountLinkControllerRemoveResponse> {
3367
+ return __request(OpenAPI, {
3368
+ method: 'DELETE',
3369
+ url: '/api/v1/{region}/bean/external-account-links/{id}',
3370
+ path: {
3371
+ id: data.id,
3372
+ region: data.region
3373
+ }
3374
+ });
3375
+ }
3376
+ }
3377
+
2856
3378
  export class ImportTelemetryService {
2857
3379
  /**
2858
3380
  * Receive anonymous parser failure telemetry
@@ -2965,47 +3487,162 @@ export class BeanNlpService {
2965
3487
  * @returns void Session cleared successfully
2966
3488
  * @throws ApiError
2967
3489
  */
2968
- public static nlpControllerClearSession(
2969
- data: NlpControllerClearSessionData
2970
- ): CancelablePromise<NlpControllerClearSessionResponse> {
3490
+ public static nlpControllerClearSession(
3491
+ data: NlpControllerClearSessionData
3492
+ ): CancelablePromise<NlpControllerClearSessionResponse> {
3493
+ return __request(OpenAPI, {
3494
+ method: 'DELETE',
3495
+ url: '/api/v1/{region}/bean/nlp/session',
3496
+ path: {
3497
+ region: data.region
3498
+ },
3499
+ query: {
3500
+ sessionId: data.sessionId
3501
+ },
3502
+ errors: {
3503
+ 401: 'Unauthorized'
3504
+ }
3505
+ });
3506
+ }
3507
+
3508
+ /**
3509
+ * Get current session state
3510
+ * Get the current NLP dialogue session state. Useful for debugging and displaying session context in UI.
3511
+ * @param data The data for the request.
3512
+ * @param data.region Region code for tenant context
3513
+ * @param data.sessionId Specific session ID to get (defaults to user session)
3514
+ * @returns unknown Current session state (or null if no active session)
3515
+ * @throws ApiError
3516
+ */
3517
+ public static nlpControllerGetSession(
3518
+ data: NlpControllerGetSessionData
3519
+ ): CancelablePromise<NlpControllerGetSessionResponse> {
3520
+ return __request(OpenAPI, {
3521
+ method: 'GET',
3522
+ url: '/api/v1/{region}/bean/nlp/session',
3523
+ path: {
3524
+ region: data.region
3525
+ },
3526
+ query: {
3527
+ sessionId: data.sessionId
3528
+ },
3529
+ errors: {
3530
+ 401: 'Unauthorized'
3531
+ }
3532
+ });
3533
+ }
3534
+ }
3535
+
3536
+ export class BeanPlatformsService {
3537
+ /**
3538
+ * Get all platforms with statistics
3539
+ * @returns unknown List of platforms with binding and account counts
3540
+ * @throws ApiError
3541
+ */
3542
+ public static platformControllerFindAll(): CancelablePromise<PlatformControllerFindAllResponse> {
3543
+ return __request(OpenAPI, {
3544
+ method: 'GET',
3545
+ url: '/api/v1/bean/platforms'
3546
+ });
3547
+ }
3548
+
3549
+ /**
3550
+ * Create a new platform
3551
+ * @param data The data for the request.
3552
+ * @param data.requestBody
3553
+ * @returns unknown Platform created successfully
3554
+ * @throws ApiError
3555
+ */
3556
+ public static platformControllerCreate(
3557
+ data: PlatformControllerCreateData
3558
+ ): CancelablePromise<PlatformControllerCreateResponse> {
3559
+ return __request(OpenAPI, {
3560
+ method: 'POST',
3561
+ url: '/api/v1/bean/platforms',
3562
+ body: data.requestBody,
3563
+ mediaType: 'application/json',
3564
+ errors: {
3565
+ 409: 'Platform already exists'
3566
+ }
3567
+ });
3568
+ }
3569
+
3570
+ /**
3571
+ * Get platform list for current user
3572
+ * @returns PlatformListItemDto List of platforms with user binding status
3573
+ * @throws ApiError
3574
+ */
3575
+ public static platformControllerGetPlatformList(): CancelablePromise<PlatformControllerGetPlatformListResponse> {
3576
+ return __request(OpenAPI, {
3577
+ method: 'GET',
3578
+ url: '/api/v1/bean/platforms/list'
3579
+ });
3580
+ }
3581
+
3582
+ /**
3583
+ * Match platforms by name or alias
3584
+ * @param data The data for the request.
3585
+ * @param data.q Search query — Chinese name, English name, or abbreviation
3586
+ * @param data.region Region code for category override lookup
3587
+ * @returns unknown List of matching platforms with suggested segment names
3588
+ * @throws ApiError
3589
+ */
3590
+ public static platformControllerMatchPlatforms(
3591
+ data: PlatformControllerMatchPlatformsData
3592
+ ): CancelablePromise<PlatformControllerMatchPlatformsResponse> {
3593
+ return __request(OpenAPI, {
3594
+ method: 'GET',
3595
+ url: '/api/v1/bean/platforms/match',
3596
+ query: {
3597
+ q: data.q,
3598
+ region: data.region
3599
+ }
3600
+ });
3601
+ }
3602
+
3603
+ /**
3604
+ * Update a platform
3605
+ * @param data The data for the request.
3606
+ * @param data.id Platform ID
3607
+ * @param data.requestBody
3608
+ * @returns unknown Platform updated successfully
3609
+ * @throws ApiError
3610
+ */
3611
+ public static platformControllerUpdate(
3612
+ data: PlatformControllerUpdateData
3613
+ ): CancelablePromise<PlatformControllerUpdateResponse> {
2971
3614
  return __request(OpenAPI, {
2972
- method: 'DELETE',
2973
- url: '/api/v1/{region}/bean/nlp/session',
3615
+ method: 'PUT',
3616
+ url: '/api/v1/bean/platforms/{id}',
2974
3617
  path: {
2975
- region: data.region
2976
- },
2977
- query: {
2978
- sessionId: data.sessionId
3618
+ id: data.id
2979
3619
  },
3620
+ body: data.requestBody,
3621
+ mediaType: 'application/json',
2980
3622
  errors: {
2981
- 401: 'Unauthorized'
3623
+ 404: 'Platform not found'
2982
3624
  }
2983
3625
  });
2984
3626
  }
2985
3627
 
2986
3628
  /**
2987
- * Get current session state
2988
- * Get the current NLP dialogue session state. Useful for debugging and displaying session context in UI.
3629
+ * Delete a platform
2989
3630
  * @param data The data for the request.
2990
- * @param data.region Region code for tenant context
2991
- * @param data.sessionId Specific session ID to get (defaults to user session)
2992
- * @returns unknown Current session state (or null if no active session)
3631
+ * @param data.id Platform ID
3632
+ * @returns void Platform deleted successfully
2993
3633
  * @throws ApiError
2994
3634
  */
2995
- public static nlpControllerGetSession(
2996
- data: NlpControllerGetSessionData
2997
- ): CancelablePromise<NlpControllerGetSessionResponse> {
3635
+ public static platformControllerDelete(
3636
+ data: PlatformControllerDeleteData
3637
+ ): CancelablePromise<PlatformControllerDeleteResponse> {
2998
3638
  return __request(OpenAPI, {
2999
- method: 'GET',
3000
- url: '/api/v1/{region}/bean/nlp/session',
3639
+ method: 'DELETE',
3640
+ url: '/api/v1/bean/platforms/{id}',
3001
3641
  path: {
3002
- region: data.region
3003
- },
3004
- query: {
3005
- sessionId: data.sessionId
3642
+ id: data.id
3006
3643
  },
3007
3644
  errors: {
3008
- 401: 'Unauthorized'
3645
+ 404: 'Platform not found'
3009
3646
  }
3010
3647
  });
3011
3648
  }
@@ -3097,207 +3734,72 @@ export class DashboardService {
3097
3734
  }
3098
3735
  });
3099
3736
  }
3100
- }
3101
3737
 
3102
- export class InvestmentService {
3103
3738
  /**
3104
- * Get per-holding unrealized + realized P&L
3105
- * Average-cost unrealized P&L per account × commodity, plus cumulative realized P&L on sold lots (method = FIFO | average, default average).
3739
+ * Get expenses/income grouped by functional category
3740
+ * Returns amounts pre-aggregated by functional category (account-path Group segment) with server-side multi-currency conversion. flow=expense (default) aggregates ^Expenses: accounts; flow=income aggregates ^Income: accounts (issue #518)
3106
3741
  * @param data The data for the request.
3107
3742
  * @param data.region Region code for tenant context
3108
- * @param data.asOf As-of date (ISO 8601), defaults to today
3109
- * @param data.accountId Scope to a single account
3110
- * @param data.method Realized-P&L lot-matching method (default average). Does not affect the average-cost unrealized basis.
3111
- * @returns HoldingPnlResponseDto Holding P&L retrieved successfully
3743
+ * @param data.groupBy Grouping strategy
3744
+ * @param data.period Time window (1m = current calendar month)
3745
+ * @param data.flow Account root to aggregate (expense → ^Expenses:, income → ^Income:)
3746
+ * @returns ExpensesByCategoryResponseDto Expenses retrieved successfully
3112
3747
  * @throws ApiError
3113
3748
  */
3114
- public static holdingPnlControllerGetHoldingPnl(
3115
- data: HoldingPnlControllerGetHoldingPnlData
3116
- ): CancelablePromise<HoldingPnlControllerGetHoldingPnlResponse> {
3749
+ public static dashboardControllerGetExpenses(
3750
+ data: DashboardControllerGetExpensesData
3751
+ ): CancelablePromise<DashboardControllerGetExpensesResponse> {
3117
3752
  return __request(OpenAPI, {
3118
3753
  method: 'GET',
3119
- url: '/api/v1/{region}/investment/holdings/pnl',
3754
+ url: '/api/v1/{region}/dashboard/expenses',
3120
3755
  path: {
3121
3756
  region: data.region
3122
3757
  },
3123
3758
  query: {
3124
- asOf: data.asOf,
3125
- accountId: data.accountId,
3126
- method: data.method
3759
+ groupBy: data.groupBy,
3760
+ period: data.period,
3761
+ flow: data.flow
3127
3762
  },
3128
3763
  errors: {
3129
- 400: 'Invalid asOf format/value/future date, invalid accountId format, or unsupported method',
3764
+ 400: 'Invalid groupBy or period',
3130
3765
  401: 'User not authenticated'
3131
3766
  }
3132
3767
  });
3133
3768
  }
3134
3769
  }
3135
3770
 
3136
- export class BeanPricesService {
3137
- /**
3138
- * Create a new price
3139
- * Creates a new price entry for the authenticated user
3140
- * @param data The data for the request.
3141
- * @param data.region Region code for tenant context
3142
- * @param data.requestBody
3143
- * @returns PriceResponseDto Price created successfully
3144
- * @throws ApiError
3145
- */
3146
- public static priceControllerCreate(
3147
- data: PriceControllerCreateData
3148
- ): CancelablePromise<PriceControllerCreateResponse> {
3149
- return __request(OpenAPI, {
3150
- method: 'POST',
3151
- url: '/api/v1/{region}/bean/prices',
3152
- path: {
3153
- region: data.region
3154
- },
3155
- body: data.requestBody,
3156
- mediaType: 'application/json',
3157
- errors: {
3158
- 404: 'Currency or quoteCurrency commodity not found',
3159
- 409: 'Price already exists for this currency pair and date'
3160
- }
3161
- });
3162
- }
3163
-
3771
+ export class InvestmentService {
3164
3772
  /**
3165
- * List user prices
3166
- * Returns all price entries for the authenticated user with optional filtering
3773
+ * Get per-holding unrealized + realized P&L
3774
+ * Average-cost unrealized P&L per account × commodity, plus cumulative realized P&L on sold lots (method = FIFO | average, default average).
3167
3775
  * @param data The data for the request.
3168
3776
  * @param data.region Region code for tenant context
3169
- * @param data.currency Filter by currency (e.g., BTC, AAPL, USD)
3170
- * @param data.quoteCurrency Filter by quote currency (pricing currency, e.g., USD, CNY)
3171
- * @param data.dateFrom Filter prices from this date (ISO 8601 format)
3172
- * @param data.dateTo Filter prices to this date (ISO 8601 format)
3173
- * @param data.search Search term for currency or quoteCurrency (case-insensitive partial match)
3174
- * @param data.page Page number for pagination (default: 1)
3175
- * @param data.limit Number of items per page (default: 20, max: 100)
3176
- * @returns PriceListResponseDto Prices retrieved successfully
3777
+ * @param data.asOf As-of date (ISO 8601), defaults to today
3778
+ * @param data.accountId Scope to a single account
3779
+ * @param data.method Realized-P&L lot-matching method (default average). Does not affect the average-cost unrealized basis.
3780
+ * @returns HoldingPnlResponseDto Holding P&L retrieved successfully
3177
3781
  * @throws ApiError
3178
3782
  */
3179
- public static priceControllerFindAll(
3180
- data: PriceControllerFindAllData
3181
- ): CancelablePromise<PriceControllerFindAllResponse> {
3783
+ public static holdingPnlControllerGetHoldingPnl(
3784
+ data: HoldingPnlControllerGetHoldingPnlData
3785
+ ): CancelablePromise<HoldingPnlControllerGetHoldingPnlResponse> {
3182
3786
  return __request(OpenAPI, {
3183
3787
  method: 'GET',
3184
- url: '/api/v1/{region}/bean/prices',
3788
+ url: '/api/v1/{region}/investment/holdings/pnl',
3185
3789
  path: {
3186
3790
  region: data.region
3187
3791
  },
3188
3792
  query: {
3189
- currency: data.currency,
3190
- quoteCurrency: data.quoteCurrency,
3191
- dateFrom: data.dateFrom,
3192
- dateTo: data.dateTo,
3193
- search: data.search,
3194
- page: data.page,
3195
- limit: data.limit
3196
- }
3197
- });
3198
- }
3199
-
3200
- /**
3201
- * Get price by ID
3202
- * Returns a single price entry by its ID
3203
- * @param data The data for the request.
3204
- * @param data.id Price ID
3205
- * @param data.region Region code for tenant context
3206
- * @returns PriceResponseDto Price retrieved successfully
3207
- * @throws ApiError
3208
- */
3209
- public static priceControllerFindOne(
3210
- data: PriceControllerFindOneData
3211
- ): CancelablePromise<PriceControllerFindOneResponse> {
3212
- return __request(OpenAPI, {
3213
- method: 'GET',
3214
- url: '/api/v1/{region}/bean/prices/{id}',
3215
- path: {
3216
- id: data.id,
3217
- region: data.region
3218
- },
3219
- errors: {
3220
- 404: 'Price not found'
3221
- }
3222
- });
3223
- }
3224
-
3225
- /**
3226
- * Update a price
3227
- * Updates an existing price entry
3228
- * @param data The data for the request.
3229
- * @param data.id Price ID
3230
- * @param data.region Region code for tenant context
3231
- * @param data.requestBody
3232
- * @returns PriceResponseDto Price updated successfully
3233
- * @throws ApiError
3234
- */
3235
- public static priceControllerUpdate(
3236
- data: PriceControllerUpdateData
3237
- ): CancelablePromise<PriceControllerUpdateResponse> {
3238
- return __request(OpenAPI, {
3239
- method: 'PUT',
3240
- url: '/api/v1/{region}/bean/prices/{id}',
3241
- path: {
3242
- id: data.id,
3243
- region: data.region
3244
- },
3245
- body: data.requestBody,
3246
- mediaType: 'application/json',
3247
- errors: {
3248
- 404: 'Price not found',
3249
- 409: 'Updated price conflicts with existing price'
3250
- }
3251
- });
3252
- }
3253
-
3254
- /**
3255
- * Delete a price
3256
- * Deletes a price entry (hard delete)
3257
- * @param data The data for the request.
3258
- * @param data.id Price ID
3259
- * @param data.region Region code for tenant context
3260
- * @returns void Price deleted successfully
3261
- * @throws ApiError
3262
- */
3263
- public static priceControllerDelete(
3264
- data: PriceControllerDeleteData
3265
- ): CancelablePromise<PriceControllerDeleteResponse> {
3266
- return __request(OpenAPI, {
3267
- method: 'DELETE',
3268
- url: '/api/v1/{region}/bean/prices/{id}',
3269
- path: {
3270
- id: data.id,
3271
- region: data.region
3793
+ asOf: data.asOf,
3794
+ accountId: data.accountId,
3795
+ method: data.method
3272
3796
  },
3273
3797
  errors: {
3274
- 404: 'Price not found'
3798
+ 400: 'Invalid asOf format/value/future date, invalid accountId format, or unsupported method',
3799
+ 401: 'User not authenticated'
3275
3800
  }
3276
3801
  });
3277
3802
  }
3278
-
3279
- /**
3280
- * Bulk create prices
3281
- * Creates multiple price entries at once (skips duplicates)
3282
- * @param data The data for the request.
3283
- * @param data.region Region code for tenant context
3284
- * @param data.requestBody
3285
- * @returns PriceResponseDto Prices created successfully
3286
- * @throws ApiError
3287
- */
3288
- public static priceControllerBulkCreate(
3289
- data: PriceControllerBulkCreateData
3290
- ): CancelablePromise<PriceControllerBulkCreateResponse> {
3291
- return __request(OpenAPI, {
3292
- method: 'POST',
3293
- url: '/api/v1/{region}/bean/prices/bulk',
3294
- path: {
3295
- region: data.region
3296
- },
3297
- body: data.requestBody,
3298
- mediaType: 'application/json'
3299
- });
3300
- }
3301
3803
  }
3302
3804
 
3303
3805
  export class ReportingService {
@@ -3341,6 +3843,42 @@ export class ReportingService {
3341
3843
  });
3342
3844
  }
3343
3845
 
3846
+ /**
3847
+ * Get cash-flow trends
3848
+ *
3849
+ * Monthly income / expense / netSavings over a fixed N-month window
3850
+ * (current month + N−1 prior). Missing months are zero-filled (flow metric).
3851
+ *
3852
+ * **Parameters:**
3853
+ * - `period`: 1m | 3m | 6m | 1y (default 6m)
3854
+ * - `granularity`: accepted for API symmetry; v1 returns month buckets
3855
+ *
3856
+ * @param data The data for the request.
3857
+ * @param data.region Region code for tenant context
3858
+ * @param data.period Time period
3859
+ * @param data.granularity Data granularity (accepted for API symmetry; v1 returns month buckets)
3860
+ * @returns CashFlowTrendsResponseDto Cash-flow trends retrieved successfully
3861
+ * @throws ApiError
3862
+ */
3863
+ public static reportingControllerGetCashFlowTrends(
3864
+ data: ReportingControllerGetCashFlowTrendsData
3865
+ ): CancelablePromise<ReportingControllerGetCashFlowTrendsResponse> {
3866
+ return __request(OpenAPI, {
3867
+ method: 'GET',
3868
+ url: '/api/v1/{region}/reporting/cash-flow/trends',
3869
+ path: {
3870
+ region: data.region
3871
+ },
3872
+ query: {
3873
+ period: data.period,
3874
+ granularity: data.granularity
3875
+ },
3876
+ errors: {
3877
+ 401: 'User not authenticated'
3878
+ }
3879
+ });
3880
+ }
3881
+
3344
3882
  /**
3345
3883
  * Generate portfolio snapshot
3346
3884
  *