@lerianstudio/matcher-mcp 5.0.0-beta.3 → 5.0.0-beta.31

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.
Files changed (34) hide show
  1. package/dist/matcher/client.js +14 -0
  2. package/dist/matcher/client.js.map +1 -1
  3. package/dist/matcher/idempotency.js +94 -0
  4. package/dist/matcher/idempotency.js.map +1 -0
  5. package/dist/spec/curated-operations.js +4 -0
  6. package/dist/spec/curated-operations.js.map +1 -1
  7. package/dist/spec/openapi.yaml +244 -50
  8. package/dist/tools/exception/bulk-dispatch.js +9 -2
  9. package/dist/tools/exception/bulk-dispatch.js.map +1 -1
  10. package/dist/tools/exception/dispatch.js +10 -3
  11. package/dist/tools/exception/dispatch.js.map +1 -1
  12. package/dist/tools/exception/list.js +3 -3
  13. package/dist/tools/exception/list.js.map +1 -1
  14. package/dist/tools/exception/shared.js +5 -0
  15. package/dist/tools/exception/shared.js.map +1 -1
  16. package/dist/tools/fee-schedule/create.js +5 -1
  17. package/dist/tools/fee-schedule/create.js.map +1 -1
  18. package/dist/tools/field-map/create.js +4 -2
  19. package/dist/tools/field-map/create.js.map +1 -1
  20. package/dist/tools/generic/invoke.js +12 -0
  21. package/dist/tools/generic/invoke.js.map +1 -1
  22. package/dist/tools/ingestion/job-transactions-list.js +7 -1
  23. package/dist/tools/ingestion/job-transactions-list.js.map +1 -1
  24. package/dist/tools/ingestion/transactions-search.js +7 -2
  25. package/dist/tools/ingestion/transactions-search.js.map +1 -1
  26. package/dist/tools/ingestion/upload-begin.js +5 -2
  27. package/dist/tools/ingestion/upload-begin.js.map +1 -1
  28. package/dist/tools/source/create.js +15 -1
  29. package/dist/tools/source/create.js.map +1 -1
  30. package/dist/tools/source/get.js +17 -1
  31. package/dist/tools/source/get.js.map +1 -1
  32. package/dist/tools/source/update.js +19 -1
  33. package/dist/tools/source/update.js.map +1 -1
  34. package/package.json +1 -1
@@ -230,6 +230,33 @@ components:
230
230
  - createdAt
231
231
  - updatedAt
232
232
  type: object
233
+ AdminAssignPlanInputBody:
234
+ additionalProperties: false
235
+ properties:
236
+ plan:
237
+ description: "The plan code to assign. ONLY \"enterprise\" is accepted: self-serve plans are bought through checkout and converged from the live subscription's price, so assigning one here would be a payment-processor bypass the next processor delivery silently reverts. Any other code is refused with 409."
238
+ maxLength: 64
239
+ type: string
240
+ required:
241
+ - plan
242
+ type: object
243
+ AdminAssignPlanResult:
244
+ additionalProperties: false
245
+ properties:
246
+ billingStatus:
247
+ description: The commercial standing the workspace now holds. An enterprise contract is in good standing the moment it is signed, so this is always "active".
248
+ type: string
249
+ plan:
250
+ description: The plan the workspace now holds.
251
+ type: string
252
+ slug:
253
+ description: The workspace assigned.
254
+ type: string
255
+ required:
256
+ - slug
257
+ - plan
258
+ - billingStatus
259
+ type: object
233
260
  AdminWorkspaceBilling:
234
261
  additionalProperties: false
235
262
  properties:
@@ -321,10 +348,15 @@ components:
321
348
  additionalProperties: false
322
349
  properties:
323
350
  accountRef:
324
- description: Stored opaque vendor account reference (Pluggy itemId, Belvo link id)
351
+ description: Stored opaque vendor account reference (Pluggy itemId, Belvo link id); empty while the connection is awaiting consent
325
352
  examples:
326
353
  - a1b2c3d4-5678-90ab-cdef-1234567890ab
327
354
  type: string
355
+ awaitingConsent:
356
+ description: Whether the connection is still awaiting the end customer's vendor consent (no vendor item/link bound yet)
357
+ examples:
358
+ - false
359
+ type: boolean
328
360
  baseUrl:
329
361
  description: Stored vendor API base URL
330
362
  examples:
@@ -341,6 +373,11 @@ components:
341
373
  examples:
342
374
  - a1b2c3d4-5678-90ab-cdef-1234567890ab
343
375
  type: string
376
+ testable:
377
+ description: Whether Matcher can run a connectivity test for this connection right now (its vendor has a test path AND it is bound to a vendor item/link)
378
+ examples:
379
+ - true
380
+ type: boolean
344
381
  vendor:
345
382
  description: Aggregator vendor the connection is bound to
346
383
  enum:
@@ -355,6 +392,8 @@ components:
355
392
  - configName
356
393
  - baseUrl
357
394
  - accountRef
395
+ - testable
396
+ - awaitingConsent
358
397
  type: object
359
398
  AggregatorConnectionListResponse:
360
399
  additionalProperties: false
@@ -394,10 +433,9 @@ components:
394
433
  additionalProperties: false
395
434
  properties:
396
435
  accountRef:
397
- description: Opaque vendor account reference (Pluggy itemId, Belvo link id) the webhook pull threads onto its request
436
+ description: Opaque vendor account reference (Pluggy itemId, Belvo link id) the webhook pull threads onto its request. Omit to create a connection awaiting consent — the connect flow binds it after the end customer authorizes.
398
437
  examples:
399
438
  - a1b2c3d4-5678-90ab-cdef-1234567890ab
400
- minLength: 1
401
439
  type: string
402
440
  baseUrl:
403
441
  description: Vendor API base URL, stored as the connection host
@@ -432,7 +470,6 @@ components:
432
470
  - vendor
433
471
  - configName
434
472
  - baseUrl
435
- - accountRef
436
473
  - clientId
437
474
  - secret
438
475
  type: object
@@ -440,10 +477,15 @@ components:
440
477
  additionalProperties: false
441
478
  properties:
442
479
  accountRef:
443
- description: Stored opaque vendor account reference (Pluggy itemId, Belvo link id)
480
+ description: Stored opaque vendor account reference (Pluggy itemId, Belvo link id); empty while the connection is awaiting consent
444
481
  examples:
445
482
  - a1b2c3d4-5678-90ab-cdef-1234567890ab
446
483
  type: string
484
+ awaitingConsent:
485
+ description: Whether the connection is still awaiting the end customer's vendor consent (no vendor item/link bound yet)
486
+ examples:
487
+ - false
488
+ type: boolean
447
489
  baseUrl:
448
490
  description: Stored vendor API base URL
449
491
  examples:
@@ -468,6 +510,52 @@ components:
468
510
  - configName
469
511
  - baseUrl
470
512
  - accountRef
513
+ - awaitingConsent
514
+ type: object
515
+ AggregatorConsentTokenResponse:
516
+ additionalProperties: false
517
+ properties:
518
+ accountRef:
519
+ description: Vendor item/link id this token was scoped to (the stored binding); empty on a first consent. Pass it to the vendor widget's update mode alongside the token — do not substitute a locally cached value.
520
+ examples:
521
+ - a1b2c3d4-5678-90ab-cdef-1234567890ab
522
+ type: string
523
+ configName:
524
+ description: Config name of the connection the token was minted for
525
+ examples:
526
+ - pluggy-main
527
+ type: string
528
+ expiresAt:
529
+ description: UTC instant after which the vendor rejects this consent token
530
+ examples:
531
+ - "2026-08-23T12:30:00Z"
532
+ format: date-time
533
+ type: string
534
+ reconsent:
535
+ description: Whether the token re-authorizes the connection's existing vendor item/link (true) or will create a new one (false)
536
+ examples:
537
+ - false
538
+ type: boolean
539
+ token:
540
+ description: Short-lived, widget-ready consent token. Returned exactly once and never stored — pass it to the vendor widget and discard it.
541
+ examples:
542
+ - eyJhbGciOi...
543
+ type: string
544
+ vendor:
545
+ description: Aggregator vendor the consent token was minted against
546
+ enum:
547
+ - pluggy
548
+ - belvo
549
+ examples:
550
+ - pluggy
551
+ type: string
552
+ required:
553
+ - vendor
554
+ - configName
555
+ - token
556
+ - expiresAt
557
+ - reconsent
558
+ - accountRef
471
559
  type: object
472
560
  ApproveExtractionResponse:
473
561
  additionalProperties: false
@@ -632,6 +720,12 @@ components:
632
720
  - 0
633
721
  format: int64
634
722
  type: integer
723
+ fromSeq:
724
+ description: "Effective verification floor: the first tenant_seq eligible for inspection (1 when fromSeq was omitted). Resume a truncated run at fromSeq + verifiedCount"
725
+ examples:
726
+ - 1
727
+ format: int64
728
+ type: integer
635
729
  intact:
636
730
  description: True when every inspected record links to the previous one and matches its stored hash
637
731
  examples:
@@ -650,6 +744,7 @@ components:
650
744
  type: integer
651
745
  required:
652
746
  - intact
747
+ - fromSeq
653
748
  - verifiedCount
654
749
  - truncated
655
750
  type: object
@@ -878,6 +973,11 @@ components:
878
973
  BulkFailure:
879
974
  additionalProperties: false
880
975
  properties:
976
+ code:
977
+ description: Stable product error code for this row, when the failure has one
978
+ examples:
979
+ - MTCH-0514
980
+ type: string
881
981
  error:
882
982
  description: Human-readable reason the exception could not be processed
883
983
  examples:
@@ -1795,7 +1895,7 @@ components:
1795
1895
  properties:
1796
1896
  config:
1797
1897
  additionalProperties: {}
1798
- description: Source-specific configuration object (connection and parsing settings). Optional; defaults to an empty object when omitted.
1898
+ description: "Source-specific configuration object (connection and parsing settings). Optional; defaults to an empty object when omitted. Reserved key duplicate_key: the ordered list of mapped fields that make two rows the same row — any of external_id, amount, currency, date, description, fee_amount, fee_currency. Omit it and rows are deduplicated on external_id alone. A field this source's field map does not fill is refused, because a key over a field that is always empty makes every row a duplicate of every other. A source bound to an aggregator connection (reserved key connection_config_name) cannot carry a duplicate key of its own: the aggregator retracts a movement by naming its external id, so that id has to stay this source's row identity. A config holding both is refused in either direction — drop duplicate_key from a bound source, or disconnect the aggregator connection first. Reserved read-only key duplicate_key_changed_at: the RFC 3339 moment duplicate-key detection last changed meaning on this source, set by the server; a value sent by a client is discarded. It moves for either change that re-keys future rows — editing duplicate_key, or the field map remapping the column a declared field reads (a source keyed on description whose description column moves derives a different key for the same movement). Reserved key duplicate_policy: what happens to a row repeating the duplicate key — FLAG_AS_EXCEPTION (the default: the repeat is kept out of the import and raised as a duplicate exception on the row it repeated), KEEP_FIRST (the repeat is dropped and nothing is raised), or REJECT (the repeat is counted as an import error). Changing duplicate_key governs later imports only — rows already imported keep the key they were deduplicated under."
1799
1899
  type: object
1800
1900
  mapping:
1801
1901
  additionalProperties: {}
@@ -1965,10 +2065,10 @@ components:
1965
2065
  type: integer
1966
2066
  structure:
1967
2067
  additionalProperties: {}
1968
- description: "Type-specific structure. FLAT: {\"amount\":\"1.50\"}. PERCENTAGE: {\"rate\":\"0.029\"} where rate is a 0..1 fraction of the base amount (0.029 means 2.9%), not a percent value. TIERED: {\"tiers\":[{\"rate\":\"0.01\",\"upTo\":\"1000\"},...]} with the same 0..1 fraction semantics per tier rate. EXPRESSION: {\"expression\":\"gross - desconto + multa + juros_dia * days_late(due_date, pay_date)\"} a formula over metadata fields (+ - * /, parentheses, and the functions days_late, days_between, max, min, abs, clamp)."
2068
+ description: "Type-specific structure. FLAT: {\"amount\":\"1.50\"}. PERCENTAGE: {\"rate\":\"0.029\"} where rate is a 0..1 fraction of the base amount (0.029 means 2.9%), not a percent value. TIERED: {\"tiers\":[{\"rate\":\"0.01\",\"upTo\":\"1000\"},...]} with the same 0..1 fraction semantics per tier rate. EXPRESSION: {\"expression\":\"gross - desconto + multa + juros_dia * days_late(due_date, pay_date)\"} a formula over metadata fields (+ - * /, parentheses, and the functions days_late, days_between, max, min, abs, clamp). A formula that is only the base amount times numeric literals is a percentage rate and is bounded 0..1: gross * 0.029 is 2.9%, gross * 2.9 is refused; any other formula is unbounded."
1969
2069
  type: object
1970
2070
  structureType:
1971
- description: Shape of the fee structure. FLAT is a fixed amount; PERCENTAGE is a rate of the base; TIERED applies different rates per amount tier; EXPRESSION computes the fee from a bounded arithmetic formula over transaction metadata.
2071
+ description: Shape of the fee structure; the structure field documents the object each one takes.
1972
2072
  enum:
1973
2073
  - FLAT
1974
2074
  - PERCENTAGE
@@ -2225,7 +2325,7 @@ components:
2225
2325
  properties:
2226
2326
  config:
2227
2327
  additionalProperties: {}
2228
- description: Source-specific configuration object (connection and parsing settings). Optional; defaults to an empty object when omitted.
2328
+ description: "Source-specific configuration object (connection and parsing settings). Optional; defaults to an empty object when omitted. Reserved key duplicate_key: the ordered list of mapped fields that make two rows the same row — any of external_id, amount, currency, date, description, fee_amount, fee_currency. Omit it and rows are deduplicated on external_id alone. A field this source's field map does not fill is refused, because a key over a field that is always empty makes every row a duplicate of every other. A source bound to an aggregator connection (reserved key connection_config_name) cannot carry a duplicate key of its own: the aggregator retracts a movement by naming its external id, so that id has to stay this source's row identity. A config holding both is refused in either direction — drop duplicate_key from a bound source, or disconnect the aggregator connection first. Reserved read-only key duplicate_key_changed_at: the RFC 3339 moment duplicate-key detection last changed meaning on this source, set by the server; a value sent by a client is discarded. It moves for either change that re-keys future rows — editing duplicate_key, or the field map remapping the column a declared field reads (a source keyed on description whose description column moves derives a different key for the same movement). Reserved key duplicate_policy: what happens to a row repeating the duplicate key — FLAG_AS_EXCEPTION (the default: the repeat is kept out of the import and raised as a duplicate exception on the row it repeated), KEEP_FIRST (the repeat is dropped and nothing is raised), or REJECT (the repeat is counted as an import error). Changing duplicate_key governs later imports only — rows already imported keep the key they were deduplicated under."
2229
2329
  type: object
2230
2330
  name:
2231
2331
  description: Human-readable name of the source.
@@ -2595,11 +2695,12 @@ components:
2595
2695
  additionalProperties: false
2596
2696
  properties:
2597
2697
  category:
2598
- description: "Dispute category: BANK_FEE_ERROR (incorrect fee), UNRECOGNIZED_CHARGE, DUPLICATE_TRANSACTION, or OTHER"
2698
+ description: "Dispute category: BANK_FEE_ERROR (incorrect fee), UNRECOGNIZED_CHARGE, DUPLICATE_TRANSACTION, AMOUNT_MISMATCH, or OTHER"
2599
2699
  enum:
2600
2700
  - BANK_FEE_ERROR
2601
2701
  - UNRECOGNIZED_CHARGE
2602
2702
  - DUPLICATE_TRANSACTION
2703
+ - AMOUNT_MISMATCH
2603
2704
  - OTHER
2604
2705
  examples:
2605
2706
  - BANK_FEE_ERROR
@@ -2857,10 +2958,11 @@ components:
2857
2958
  - 550e8400-e29b-41d4-a716-446655440003
2858
2959
  type: string
2859
2960
  status:
2860
- description: "Lifecycle status: OPEN (unhandled), ASSIGNED (owned by a user), RESOLVED (closed out)"
2961
+ description: "Lifecycle status: OPEN (unhandled), ASSIGNED (owned by a user), PENDING_RESOLUTION (a resolution is in flight), RESOLVED (closed out)"
2861
2962
  enum:
2862
2963
  - OPEN
2863
2964
  - ASSIGNED
2965
+ - PENDING_RESOLUTION
2864
2966
  - RESOLVED
2865
2967
  examples:
2866
2968
  - OPEN
@@ -3356,7 +3458,7 @@ components:
3356
3458
  type: integer
3357
3459
  structure:
3358
3460
  additionalProperties: {}
3359
- description: "Type-specific structure. FLAT: {\"amount\":\"1.50\"}. PERCENTAGE: {\"rate\":\"0.029\"} where rate is a 0..1 fraction of the base amount (0.029 means 2.9%), not a percent value. TIERED: {\"tiers\":[{\"rate\":\"0.01\",\"upTo\":\"1000\"},...]} with the same 0..1 fraction semantics per tier rate. EXPRESSION: {\"expression\":\"gross - desconto + multa + juros_dia * days_late(due_date, pay_date)\"} a formula over metadata fields (+ - * /, parentheses, and the functions days_late, days_between, max, min, abs, clamp)."
3461
+ description: "Type-specific structure. FLAT: {\"amount\":\"1.50\"}. PERCENTAGE: {\"rate\":\"0.029\"} where rate is a 0..1 fraction of the base amount (0.029 means 2.9%), not a percent value. TIERED: {\"tiers\":[{\"rate\":\"0.01\",\"upTo\":\"1000\"},...]} with the same 0..1 fraction semantics per tier rate. EXPRESSION: {\"expression\":\"gross - desconto + multa + juros_dia * days_late(due_date, pay_date)\"} a formula over metadata fields (+ - * /, parentheses, and the functions days_late, days_between, max, min, abs, clamp). A formula that is only the base amount times numeric literals is a percentage rate and is bounded 0..1: gross * 0.029 is 2.9%, gross * 2.9 is refused; any other formula is unbounded."
3360
3462
  type: object
3361
3463
  structureType:
3362
3464
  description: Shape of the fee structure. FLAT is a fixed amount; PERCENTAGE is a rate of the base; TIERED applies different rates per amount tier; EXPRESSION computes the fee from a bounded arithmetic formula over transaction metadata.
@@ -3966,6 +4068,11 @@ components:
3966
4068
  - "2025-01-15T00:00:00Z"
3967
4069
  format: date-time
3968
4070
  type: string
4071
+ dedupeKey:
4072
+ description: "Read-only: the duplicate-key value this row was imported under, derived from the source's duplicate key declaration at import time. A source can change that declaration later, so this is the only place that says which identity THIS row carries. Prefixed v1 when the key spells out the fields it was derived from, v1h when those fields were hashed because the spelled-out key was too long to index."
4073
+ examples:
4074
+ - v1|external_id=9:TXN-12345
4075
+ type: string
3969
4076
  description:
3970
4077
  description: Free-text description carried from the source
3971
4078
  examples:
@@ -4014,6 +4121,7 @@ components:
4014
4121
  - sourceId
4015
4122
  - contextId
4016
4123
  - externalId
4124
+ - dedupeKey
4017
4125
  - amount
4018
4126
  - currency
4019
4127
  - date
@@ -4048,17 +4156,17 @@ components:
4048
4156
  format: date-time
4049
4157
  type: string
4050
4158
  diagnosis:
4051
- description: Safe one-line diagnosis for a FAILED job (dialect diagnosis, rate-policy message, or generic safe message); empty for partial completed-with-errors jobs — internal error detail is never surfaced here
4159
+ description: Safe one-line diagnosis of anything the parser found worth reporting about the file (dialect mismatch, degraded settlement re-join, zero-detail file), the rate-policy message for policy-FAILED jobs, or a generic safe message for other FAILED jobs. Present on COMPLETED jobs too, including ones with zero failed rows; empty when there is nothing to report — internal error detail is never surfaced here
4052
4160
  examples:
4053
4161
  - file appears semicolon-delimited but the source declares comma; declare delimiter semicolon in the source dialect
4054
4162
  type: string
4055
4163
  droppedDuplicateReason:
4056
- description: "Display-only explanation of why droppedDuplicateRows rows were dropped: names the (source, external_id) collapsing key and the field mapping to check so the count does not read as silent data loss. Empty unless droppedDuplicateRows > 0"
4164
+ description: "Display-only explanation of why droppedDuplicateRows rows were kept out of the import: names the source's duplicate key as the identity that collided, says the repeats were attached as exceptions to the rows they repeated when the job flagged any (repeats of one row share one exception, so the queue holds one item per repeated row), and names the repeats that raised nothing when fewer were flagged than dropped, so the count does not read as silent data loss and the customer is sent to the configuration that decides it. Empty unless droppedDuplicateRows > 0"
4057
4165
  examples:
4058
- - Rows repeated a (source, external_id) key already present in this source and were dropped as duplicates. If unexpected, verify the field mapped to external_id is unique per row (a coarse or truncated mapping collapses distinct rows onto one key).
4166
+ - "Rows repeated the duplicate key this source deduplicates on and were kept out of the import. This source flags duplicates, so each repeat whose original was found was attached to that original as a duplicate exception in the exceptions queue. Repeats of the same original share one exception, so the queue holds one item per repeated row, not one per repeat. The rest found no imported row to attach to (another import of this source may still have been in progress), so no exception was raised for them and they are not in the queue: re-upload those rows once every import of this source has finished. If unexpected, review the source's duplicate key and the fields it names (a coarse or truncated mapping collapses distinct rows onto one key)."
4059
4167
  type: string
4060
4168
  droppedDuplicateRows:
4061
- description: Number of rows dropped as duplicates under the keep-first policy (same external_id within the upload or already persisted)
4169
+ description: Number of rows kept out of the import as duplicates (rows repeating the source's duplicate key within the upload or already persisted); see flaggedDuplicateRows for how many were also raised as exceptions
4062
4170
  examples:
4063
4171
  - 60
4064
4172
  format: int64
@@ -4085,7 +4193,7 @@ components:
4085
4193
  - transactions_2024.csv
4086
4194
  type: string
4087
4195
  flaggedDuplicateRows:
4088
- description: Number of dropped duplicates flagged as DUPLICATE_TRANSACTION exceptions under the FLAG_AS_EXCEPTION duplicate policy (subset of droppedDuplicateRows)
4196
+ description: "Number of dropped duplicate ROWS raised as DUPLICATE_TRANSACTION exceptions on the transaction they repeated, under the FLAG_AS_EXCEPTION duplicate policy — the default (subset of droppedDuplicateRows). Not a queue-item count: repeats of the same transaction share one exception, which carries how many times it was repeated"
4089
4197
  examples:
4090
4198
  - 15
4091
4199
  format: int64
@@ -6030,7 +6138,7 @@ components:
6030
6138
  type: string
6031
6139
  config:
6032
6140
  additionalProperties: {}
6033
- description: Source-specific configuration object (connection and parsing settings).
6141
+ description: Source-specific configuration object (connection and parsing settings). duplicate_key holds the ordered list of mapped fields that make two rows the same row; absent means rows are deduplicated on external_id alone. duplicate_key_changed_at is the server-set RFC 3339 moment duplicate-key detection last changed meaning on this source — either that list changing, or the field map remapping the column a declared field reads; rows imported before it keep the key they were deduplicated under.
6034
6142
  type: object
6035
6143
  contextId:
6036
6144
  description: Identifier of the context this source belongs to.
@@ -6651,7 +6759,9 @@ components:
6651
6759
  required:
6652
6760
  - id
6653
6761
  - status
6654
- type: object
6762
+ type:
6763
+ - object
6764
+ - "null"
6655
6765
  SetupProgressMatchRulesResponse:
6656
6766
  additionalProperties: false
6657
6767
  properties:
@@ -6713,7 +6823,9 @@ components:
6713
6823
  - method
6714
6824
  - path
6715
6825
  - requiredFields
6716
- type: object
6826
+ type:
6827
+ - object
6828
+ - "null"
6717
6829
  SetupProgressReadinessResponse:
6718
6830
  additionalProperties: false
6719
6831
  properties:
@@ -7356,7 +7468,7 @@ components:
7356
7468
  type: string
7357
7469
  config:
7358
7470
  additionalProperties: {}
7359
- description: Source-specific configuration object (connection and parsing settings).
7471
+ description: Source-specific configuration object (connection and parsing settings). duplicate_key holds the ordered list of mapped fields that make two rows the same row; absent means rows are deduplicated on external_id alone. duplicate_key_changed_at is the server-set RFC 3339 moment duplicate-key detection last changed meaning on this source — either that list changing, or the field map remapping the column a declared field reads; rows imported before it keep the key they were deduplicated under.
7360
7472
  type: object
7361
7473
  contextId:
7362
7474
  description: Identifier of the context this source belongs to.
@@ -7574,16 +7686,7 @@ components:
7574
7686
  - pluggy-main
7575
7687
  minLength: 1
7576
7688
  type: string
7577
- vendor:
7578
- description: "Aggregator vendor: pluggy or belvo"
7579
- enum:
7580
- - pluggy
7581
- - belvo
7582
- examples:
7583
- - pluggy
7584
- type: string
7585
7689
  required:
7586
- - vendor
7587
7690
  - configName
7588
7691
  type: object
7589
7692
  TestAggregatorConnectionResponse:
@@ -7668,6 +7771,11 @@ components:
7668
7771
  - "2025-01-15T00:00:00Z"
7669
7772
  format: date-time
7670
7773
  type: string
7774
+ dedupeKey:
7775
+ description: "Read-only: the duplicate-key value this row was imported under, derived from the source's duplicate key declaration at import time. A source can change that declaration later, so this is the only place that says which identity THIS row carries. Prefixed v1 when the key spells out the fields it was derived from, v1h when those fields were hashed because the spelled-out key was too long to index."
7776
+ examples:
7777
+ - v1|external_id=9:TXN-12345
7778
+ type: string
7671
7779
  description:
7672
7780
  description: Free-text description carried from the source
7673
7781
  examples:
@@ -7716,6 +7824,7 @@ components:
7716
7824
  - sourceId
7717
7825
  - contextId
7718
7826
  - externalId
7827
+ - dedupeKey
7719
7828
  - amount
7720
7829
  - currency
7721
7830
  - date
@@ -7854,34 +7963,27 @@ components:
7854
7963
  additionalProperties: false
7855
7964
  properties:
7856
7965
  accountRef:
7857
- description: Opaque vendor account reference (Pluggy itemId, Belvo link id) the webhook pull threads onto its request
7966
+ description: Opaque vendor account reference (Pluggy itemId, Belvo link id). Supply it to bind (or re-bind) the connection after the vendor's consent widget returns one; omit it to leave the stored value untouched.
7858
7967
  examples:
7859
7968
  - a1b2c3d4-5678-90ab-cdef-1234567890ab
7860
- minLength: 1
7861
7969
  type: string
7862
7970
  baseUrl:
7863
- description: Vendor API base URL, stored as the connection host
7971
+ description: Vendor API base URL, stored as the connection host. Omit it to leave the stored URL untouched.
7864
7972
  examples:
7865
7973
  - https://api.pluggy.ai
7866
7974
  format: uri
7867
- minLength: 1
7868
7975
  type: string
7869
7976
  clientId:
7870
7977
  description: Aggregator API client id (optional; supply with secret to rotate, omit both to keep the stored credential; sealed; never emitted)
7871
7978
  type: string
7872
7979
  configName:
7873
- description: Unique connection config name (tenant-scoped); the mint endpoint binds a token to this name
7980
+ description: Unique connection config name (tenant-scoped); the mint endpoint binds a token to this name. Omit it to leave the stored name untouched.
7874
7981
  examples:
7875
7982
  - pluggy-main
7876
- minLength: 1
7877
7983
  type: string
7878
7984
  secret:
7879
7985
  description: Aggregator API client secret (optional; supply with clientId to rotate, omit both to keep the stored credential; sealed; never emitted)
7880
7986
  type: string
7881
- required:
7882
- - configName
7883
- - baseUrl
7884
- - accountRef
7885
7987
  type: object
7886
7988
  UpdateContextRequest:
7887
7989
  additionalProperties: false
@@ -8102,7 +8204,7 @@ components:
8102
8204
  properties:
8103
8205
  config:
8104
8206
  additionalProperties: {}
8105
- description: Source-specific configuration object (connection and parsing settings).
8207
+ description: "Source-specific configuration object (connection and parsing settings). Reserved key duplicate_key: the ordered list of mapped fields that make two rows the same row — any of external_id, amount, currency, date, description, fee_amount, fee_currency. Send it empty of that key and rows are deduplicated on external_id alone. A field this source's field map does not fill is refused, because a key over a field that is always empty makes every row a duplicate of every other. A source bound to an aggregator connection (reserved key connection_config_name) cannot carry a duplicate key of its own: the aggregator retracts a movement by naming its external id, so that id has to stay this source's row identity. A config holding both is refused in either direction — drop duplicate_key from a bound source, or disconnect the aggregator connection first. Editing duplicate_key is allowed at any time and governs later imports only: rows already imported keep the key they were deduplicated under, and a duplicate straddling the change is knowingly not detected. Reserved read-only key duplicate_key_changed_at: the RFC 3339 moment duplicate-key detection last changed meaning on this source, set by the server; a value sent by a client is discarded. It moves for either change that re-keys future rows — editing duplicate_key, or the field map remapping the column a declared field reads (a source keyed on description whose description column moves derives a different key for the same movement). Reserved key duplicate_policy: what happens to a row repeating the duplicate key — FLAG_AS_EXCEPTION (the default: the repeat is kept out of the import and raised as a duplicate exception on the row it repeated), KEEP_FIRST (the repeat is dropped and nothing is raised), or REJECT (the repeat is counted as an import error)."
8106
8208
  type: object
8107
8209
  name:
8108
8210
  description: New human-readable name of the source.
@@ -8377,7 +8479,7 @@ components:
8377
8479
  format: int64
8378
8480
  type: integer
8379
8481
  monthlyLineAllowance:
8380
- description: Billable lines the plan includes per month, from the price list. Monthly on every plan regardless of billing interval. 0 when the stored plan code is not in the catalogue.
8482
+ description: Billable lines the plan includes per month, from the price list. Monthly on every plan regardless of billing interval. 0 when the plan is unmetered (see volumeUnmetered) or the stored plan code is not in the catalogue.
8381
8483
  format: int64
8382
8484
  type: integer
8383
8485
  overageCreditBalanceCents:
@@ -8385,7 +8487,7 @@ components:
8385
8487
  format: int64
8386
8488
  type: integer
8387
8489
  overageRateCentsPerThousandLines:
8388
- description: What lines beyond the allowance cost, in integer BRL cents per THOUSAND lines (per-thousand because the entry rate is 0,4 cents a line and would truncate to zero). 0 when the stored plan code is not in the catalogue.
8490
+ description: What lines beyond the allowance cost, in integer BRL cents per THOUSAND lines (per-thousand because the entry rate is 0,4 cents a line and would truncate to zero). 0 when the plan is unmetered (see volumeUnmetered) or the stored plan code is not in the catalogue.
8389
8491
  format: int64
8390
8492
  type: integer
8391
8493
  overageUncoveredCents:
@@ -8402,7 +8504,7 @@ components:
8402
8504
  description: "Setup lifecycle of the workspace: \"provisioning\" (still being built), \"active\" (ready to use), or \"failed\" (setup will not complete on its own — we have been told)."
8403
8505
  type: string
8404
8506
  provisioningStep:
8405
- description: "The setup step that is owed: \"create_tenant\", \"associate_service\", \"migrate_tenant\", \"provision_console\", or \"\" when nothing is owed. On a failed workspace this is the step it died on."
8507
+ description: "The setup step that is owed: \"create_tenant\", \"associate_service\", \"migrate_tenant\", \"provision_console\", \"grant_admin\", or \"\" when nothing is owed. On a failed workspace this is the step it died on."
8406
8508
  type: string
8407
8509
  trialEndsAt:
8408
8510
  description: When the free trial ends (UTC). Omitted for a paid plan that never trialed.
@@ -8411,6 +8513,9 @@ components:
8411
8513
  trialExpired:
8412
8514
  description: Whether the trial is over on EITHER axis (time or volume), or the workspace is already suspended.
8413
8515
  type: boolean
8516
+ volumeUnmetered:
8517
+ description: "Whether this plan is unmetered: its volume ceiling and its overage price are contractual (enterprise) rather than from the price list. When true, monthlyLineAllowance and overageRateCentsPerThousandLines are both 0 because no figure applies — do NOT render them as terms, and do not read the zero rate as free overage."
8518
+ type: boolean
8414
8519
  required:
8415
8520
  - plan
8416
8521
  - billingStatus
@@ -8423,6 +8528,7 @@ components:
8423
8528
  - provisioningState
8424
8529
  - provisioningStep
8425
8530
  - provisioningFailed
8531
+ - volumeUnmetered
8426
8532
  - monthlyLineAllowance
8427
8533
  - overageRateCentsPerThousandLines
8428
8534
  - overageCreditBalanceCents
@@ -8459,7 +8565,16 @@ info:
8459
8565
  email: support@lerian.studio
8460
8566
  name: Lerian Studio Support
8461
8567
  url: https://discord.gg/DnhqKwkGv3
8462
- description: Reconciliation engine for the Lerian Studio ecosystem. Provides automated transaction matching between Midaz ledger and external systems.
8568
+ description: |-
8569
+ Reconciliation engine for the Lerian Studio ecosystem. Provides automated transaction matching between Midaz ledger and external systems.
8570
+
8571
+ ## Idempotency
8572
+
8573
+ POST, PUT and PATCH requests accept an optional `Idempotency-Key` header (`X-Idempotency-Key` is also honoured, and wins if both are sent). Keys are 1-128 characters of letters, digits, hyphen, underscore or colon, are scoped per tenant, caller, method and request target, and are strictly opt-in: a request sent without the header is never de-duplicated. A retry under a key whose first attempt completed replays that stored response and carries `Idempotency-Replayed: true`; a retry that arrives while the first attempt is still in flight is refused with 409.
8574
+
8575
+ A request that FAILED normally releases its key, so a caller can correct the cause and retry under the same key. The exception is a dispatch whose outcome could not be confirmed (502, code `MTCH-0514`): the exception may already have been created in the target system, so that answer HOLDS its key — every retry under it replays the same 502 and no second dispatch is sent. Deliberately attempting that dispatch again therefore requires a NEW idempotency key. A dispatch the target answered and rejected (502, code `MTCH-0513`) created nothing there and releases its key as usual.
8576
+
8577
+ Secret mints are the other, sharper exception. `POST /v1/discovery/aggregator-connections/{id}/connect-token`, `POST /v1/discovery/webhooks/tokens`, `POST /v1/exceptions/callbacks/credentials` and `POST /v1/exceptions/callbacks/credentials/{credentialId}/rotate` each return a raw credential exactly ONCE, and storing that answer would keep the secret re-readable for the life of the key — so those four routes IGNORE the idempotency header entirely. Nothing is stored, nothing is replayed, and `Idempotency-Replayed` is never sent on them. A retry under the same key MINTS AGAIN and leaves a second live credential behind, so treat a mint as non-idempotent: read the first attempt's response rather than resending it. A surplus callback credential can be revoked through its own operation; a surplus aggregator webhook token has no revoke operation today and stays live.
8463
8578
  license:
8464
8579
  name: Lerian Studio General License
8465
8580
  title: Matcher Reconciliation API
@@ -8544,6 +8659,43 @@ paths:
8544
8659
  summary: Read a workspace's invoicing identification (backoffice)
8545
8660
  tags:
8546
8661
  - Onboarding
8662
+ /v1/admin/workspaces/{slug}/plan:
8663
+ put:
8664
+ description: "Puts a workspace on the contractual enterprise plan: persists plan=enterprise and billing_status=active together, then evicts the billing edge-gate and volume-resolver caches so the contractual ceiling applies immediately. ONLY \"enterprise\" is accepted. This is not a generic set-plan operation: self-serve plans are bought through hosted checkout and converged from the live subscription's price, so assigning one by hand would be a payment-processor bypass that the next processor delivery silently reverts — any other plan code returns 409. It REFUSES a workspace whose subscription the payment processor could still bill (409): the operator cancels there first, where the proration and refund decision gets human eyes, and this route never moves processor money. That refusal covers every subscription that is not permanently over — one awaiting card authentication or one that is paused is not charging today and resumes tomorrow, and it would revert this plan the moment it does; only a cancelled or expired subscription is assignable over. If the processor cannot be asked, the request is refused as retryable (503) rather than allowed through. A suspended workspace is refused (409) because this operation moves no access posture — reactivate it first, and the write is compare-and-swapped on the status read, so a suspension landing mid-request is refused rather than reversed. There is no reverse: removing the enterprise plan is not offered. The target slug comes from the URL path (backoffice operation, workspace admin action). An unknown workspace returns 404. Errors use RFC 9457 problem+json."
8665
+ operationId: admin-assign-workspace-plan
8666
+ parameters:
8667
+ - description: Slug of the workspace to assign the plan to.
8668
+ in: path
8669
+ name: slug
8670
+ required: true
8671
+ schema:
8672
+ description: Slug of the workspace to assign the plan to.
8673
+ maxLength: 255
8674
+ type: string
8675
+ requestBody:
8676
+ content:
8677
+ application/json:
8678
+ schema:
8679
+ $ref: "#/components/schemas/AdminAssignPlanInputBody"
8680
+ required: true
8681
+ responses:
8682
+ "200":
8683
+ content:
8684
+ application/json:
8685
+ schema:
8686
+ $ref: "#/components/schemas/AdminAssignPlanResult"
8687
+ description: OK
8688
+ default:
8689
+ content:
8690
+ application/problem+json:
8691
+ schema:
8692
+ $ref: "#/components/schemas/Detail"
8693
+ description: Error
8694
+ security:
8695
+ - BearerAuth: []
8696
+ summary: Assign the enterprise plan to a workspace (backoffice)
8697
+ tags:
8698
+ - Onboarding
8547
8699
  /v1/admin/workspaces/{slug}/reactivate:
8548
8700
  put:
8549
8701
  description: "Restores a suspended workspace: persists billing_status=active, re-enables interactive console login at the IdP, reactivates the tenant at the Tenant Manager (best-effort), and evicts the billing edge-gate cache. The target slug comes from the URL path (backoffice operation, workspace admin action). Idempotent. Errors use RFC 9457 problem+json."
@@ -10079,7 +10231,7 @@ paths:
10079
10231
  tags:
10080
10232
  - Configuration
10081
10233
  post:
10082
- description: "Creates a field map for a source within a context. Mapping keys form a closed vocabulary: required keys are external_id, amount, currency, date; optional keys are description, fee_amount, fee_currency. Values name source columns and must be non-empty strings."
10234
+ description: "Creates a field map for a source within a context. A source holds at most one field map: creating a second is rejected with a 409 carrying the configuration has-field-map code, and the caller should update the existing map instead. Mapping keys form a closed vocabulary: required keys are external_id, amount, currency, date; optional keys are description, fee_amount, fee_currency. Values name source columns and must be non-empty strings."
10083
10235
  operationId: createFieldMap
10084
10236
  parameters:
10085
10237
  - description: Context ID
@@ -10159,7 +10311,7 @@ paths:
10159
10311
  - Configuration
10160
10312
  /v1/discovery/aggregator-connections:
10161
10313
  get:
10162
- description: "Returns a cursor-paginated list of the tenant's Open-Finance data-aggregator (Pluggy/Belvo) connections, ordered by config name. The list is secret-free by construction: no credential material (clientId/secret/ciphertext) is ever returned."
10314
+ description: "Returns a cursor-paginated list of the tenant's Open-Finance data-aggregator (Pluggy/Belvo) connections, ordered by config name. The list is secret-free by construction: no credential material (clientId/secret/ciphertext) is ever returned. Each row carries `testable`, derived from the stored vendor, so a client knows whether the connectivity-test action can run at all without keeping its own vendor list."
10163
10315
  operationId: listAggregatorConnections
10164
10316
  parameters:
10165
10317
  - description: Maximum number of records to return
@@ -10227,7 +10379,7 @@ paths:
10227
10379
  - Discovery
10228
10380
  /v1/discovery/aggregator-connections/test:
10229
10381
  post:
10230
- description: "Runs a live connectivity check for an existing Open-Finance data-aggregator (Pluggy/Belvo) connection using its already-sealed credential, addressed by (vendor, configName). No credential is supplied or returned: the result is the secret-free boolean health of the connection."
10382
+ description: "Runs a live connectivity check for an existing Open-Finance data-aggregator (Pluggy/Belvo) connection using its already-sealed credential, addressed by configName. The vendor is read from the stored connection, not from the request. No credential is supplied or returned: the result is the secret-free boolean health of the connection. Two refusals are deliberately distinct: a config name matching no connection is 404 MTCH-0005, while a connection whose stored vendor Matcher has no test path for yet (Belvo today) is 422 MTCH-0210 and no test runs. The list endpoint's per-connection `testable` flag tells a client which is which before it offers the action."
10231
10383
  operationId: testAggregatorConnection
10232
10384
  requestBody:
10233
10385
  content:
@@ -10343,6 +10495,36 @@ paths:
10343
10495
  summary: Update aggregator connection
10344
10496
  tags:
10345
10497
  - Discovery
10498
+ /v1/discovery/aggregator-connections/{id}/connect-token:
10499
+ post:
10500
+ description: "Mints the short-lived token the aggregator vendor's OWN consent widget (Pluggy Connect / the Belvo widget) consumes in the end customer's browser, using the connection's already-sealed credential. The token is returned exactly once: it is never persisted, never logged, and there is no endpoint that reads it back. Nothing is supplied in the request — the vendor is read off the stored connection, and the mode is derived from it: a connection already bound to a vendor item/link gets a RE-CONSENT token for that same item (`reconsent: true`, and `accountRef` echoes the exact item/link the token was scoped to), while a connection awaiting consent gets a first-consent token that mints a new one (`accountRef` empty). Pass the returned `accountRef` to the vendor widget's update mode rather than a locally cached value: the token is item-scoped, and pairing it with a stale id makes the vendor run the create flow and orphan the original item. The item/link id the widget returns is bound back through PUT /v1/discovery/aggregator-connections/{id} with `accountRef` (no credential needs re-supplying). A non-aggregator connection id returns 404; a vendor with no consent path on this deployment returns 422 MTCH-0213."
10501
+ operationId: mintAggregatorConsentToken
10502
+ parameters:
10503
+ - description: Opaque aggregator connection id
10504
+ in: path
10505
+ name: id
10506
+ required: true
10507
+ schema:
10508
+ description: Opaque aggregator connection id
10509
+ type: string
10510
+ responses:
10511
+ "201":
10512
+ content:
10513
+ application/json:
10514
+ schema:
10515
+ $ref: "#/components/schemas/AggregatorConsentTokenResponse"
10516
+ description: Created
10517
+ default:
10518
+ content:
10519
+ application/problem+json:
10520
+ schema:
10521
+ $ref: "#/components/schemas/Detail"
10522
+ description: Error
10523
+ security:
10524
+ - BearerAuth: []
10525
+ summary: Mint aggregator consent token
10526
+ tags:
10527
+ - Discovery
10346
10528
  /v1/discovery/connections:
10347
10529
  get:
10348
10530
  description: Returns all discovered Fetcher database connections.
@@ -13027,7 +13209,10 @@ paths:
13027
13209
  - Governance
13028
13210
  /v1/governance/audit-logs/verify:
13029
13211
  get:
13030
- description: "Re-verifies the calling tenant's tamper-evident audit hash chain and returns a structured verdict (intact, verified count, and the first broken tenant_seq when a break is found). The check is strictly read-only: it recomputes nothing into storage and never mutates an audit record. Use the optional maxRecords query parameter to bound how many records are inspected."
13212
+ description: |-
13213
+ Re-verifies the calling tenant's tamper-evident audit hash chain and returns a structured verdict (intact, verified count, and the first broken tenant_seq when a break is found). The check is strictly read-only: it recomputes nothing into storage and never mutates an audit record. Use the optional maxRecords query parameter to bound how many records are inspected.
13214
+
13215
+ Use the optional fromSeq query parameter to bind the verification floor: the first record inspected is the one with tenant_seq == fromSeq. A floor above 1 TRUSTS that record's stored prev_hash instead of validating it against the genesis hash, so tampering BELOW the floor is out of scope for that run and is not reported. Two uses follow from that: (1) resuming — when a verdict comes back truncated, re-run with fromSeq = fromSeq + verifiedCount to verify the remainder; (2) archived-partition tenants — once the archival worker has dropped the bottom partitions, verify from the current floor, because a run from seq 1 no longer has the records it would need. The verdict always echoes the effective fromSeq, so an empty range (verifiedCount 0 with a high fromSeq) is never mistaken for an intact chain verified from genesis.
13031
13216
  operationId: verifyAuditLogChain
13032
13217
  parameters:
13033
13218
  - description: Maximum number of records to inspect; clamped to the server bound. Omit to use the default bound.
@@ -13040,6 +13225,15 @@ paths:
13040
13225
  maximum: 10000
13041
13226
  minimum: 1
13042
13227
  type: integer
13228
+ - description: "Verification floor: the first record inspected is the one with this tenant_seq. Omit to start at the chain start (seq 1)."
13229
+ explode: false
13230
+ in: query
13231
+ name: fromSeq
13232
+ schema:
13233
+ description: "Verification floor: the first record inspected is the one with this tenant_seq. Omit to start at the chain start (seq 1)."
13234
+ format: int64
13235
+ minimum: 1
13236
+ type: integer
13043
13237
  responses:
13044
13238
  "200":
13045
13239
  content:
@@ -16369,7 +16563,7 @@ paths:
16369
16563
  - Onboarding
16370
16564
  /v1/workspace/credit-purchase:
16371
16565
  post:
16372
- description: "Opens a ONE-OFF hosted payment session that buys prepaid overage credit for the AUTHENTICATED tenant's own workspace, and returns the URL to redirect the browser to. It is never a subscription. The workspace is resolved from the JWT tenant-slug claim: this endpoint never accepts a tenant identifier in the body, path, query or headers. Any workspace may buy — trialing, lapsed, monthly or annual — because the customer who has run out of allowance is the one being told to buy. Payment is by CARD on every plan, including annual: the instrument that funds overage credit is deliberately not the subscription's instrument, and the card is saved for future CREDIT purchases only. An amount outside the price list's minimum and maximum is refused before the processor is called. The credit balance moves ONLY when the processor confirms the payment through the verified webhook — never on the return page and never in this response. Errors use the RFC 9457 application/problem+json contract."
16566
+ description: "Opens a ONE-OFF hosted payment session that buys prepaid overage credit for the AUTHENTICATED tenant's own workspace, and returns the URL to redirect the browser to. It is never a subscription. The workspace is resolved from the JWT tenant-slug claim: this endpoint never accepts a tenant identifier in the body, path, query or headers. Any workspace on a self-serve plan may buy — trialing, lapsed, monthly or annual — because the customer who has run out of allowance is the one being told to buy. A workspace on a CONTRACTUAL plan is refused with 409: its volume is not metered, so prepaid overage credit buys it nothing. Payment is by CARD on every plan, including annual: the instrument that funds overage credit is deliberately not the subscription's instrument, and the card is saved for future CREDIT purchases only. An amount outside the price list's minimum and maximum is refused before the processor is called. The credit balance moves ONLY when the processor confirms the payment through the verified webhook — never on the return page and never in this response. Errors use the RFC 9457 application/problem+json contract."
16373
16567
  operationId: workspace-credit-purchase
16374
16568
  requestBody:
16375
16569
  content: