@model-match/api 3.47.0 → 3.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/openapi.json CHANGED
@@ -8834,6 +8834,63 @@
8834
8834
  },
8835
8835
  "type": "object"
8836
8836
  },
8837
+ "BranchLicense": {
8838
+ "properties": {
8839
+ "authorizedSince": {
8840
+ "description": "Start of the license's current authorized period (YYYY-MM-DD). Null when the license is not currently authorized.",
8841
+ "nullable": true,
8842
+ "type": "string"
8843
+ },
8844
+ "isAuthorized": {
8845
+ "nullable": true,
8846
+ "type": "boolean"
8847
+ },
8848
+ "issueDate": {
8849
+ "description": "Date the license was originally issued (YYYY-MM-DD).",
8850
+ "nullable": true,
8851
+ "type": "string"
8852
+ },
8853
+ "licenseId": {
8854
+ "nullable": true,
8855
+ "type": "string"
8856
+ },
8857
+ "licenseNumber": {
8858
+ "nullable": true,
8859
+ "type": "string"
8860
+ },
8861
+ "licenseType": {
8862
+ "nullable": true,
8863
+ "type": "string"
8864
+ },
8865
+ "regulator": {
8866
+ "description": "Issuing state regulator.",
8867
+ "nullable": true,
8868
+ "type": "string"
8869
+ },
8870
+ "status": {
8871
+ "description": "Current license status, e.g. \"Approved\", \"Voluntary Surrender\", \"Expired\".",
8872
+ "nullable": true,
8873
+ "type": "string"
8874
+ },
8875
+ "statusDate": {
8876
+ "description": "Date the license entered its current `status` (YYYY-MM-DD).",
8877
+ "nullable": true,
8878
+ "type": "string"
8879
+ }
8880
+ },
8881
+ "required": [
8882
+ "licenseId",
8883
+ "regulator",
8884
+ "licenseNumber",
8885
+ "licenseType",
8886
+ "issueDate",
8887
+ "status",
8888
+ "statusDate",
8889
+ "isAuthorized",
8890
+ "authorizedSince"
8891
+ ],
8892
+ "type": "object"
8893
+ },
8837
8894
  "BranchListRequest": {
8838
8895
  "additionalProperties": false,
8839
8896
  "properties": {
@@ -8858,6 +8915,20 @@
8858
8915
  "lenderMatchMode": {
8859
8916
  "$ref": "#/components/schemas/LenderMatchMode"
8860
8917
  },
8918
+ "licensedSince": {
8919
+ "description": "Bound the date the branch was FIRST licensed — the earliest `issueDate` across its `licenses[]` (YYYY-MM-DD, inclusive). `{gte: \"2026-07-01\"}` = branches whose every license was issued on or after July 1, 2026, i.e. new branches; an established branch that added a state recently does NOT match. Branches with no license dates on file never match. Always ANDed with the other filters. A range matching more than 5,000 branches is rejected with a 400.",
8920
+ "properties": {
8921
+ "gte": {
8922
+ "format": "date",
8923
+ "type": "string"
8924
+ },
8925
+ "lte": {
8926
+ "format": "date",
8927
+ "type": "string"
8928
+ }
8929
+ },
8930
+ "type": "object"
8931
+ },
8861
8932
  "managerName": {
8862
8933
  "description": "Branch manager name. Matches ALL the words supplied, fuzzily, against the names of the branch's licensed managers. Always ANDed with the other filters. A name matching more than 5,000 branches is rejected with a 400.",
8863
8934
  "minLength": 1,
@@ -9445,6 +9516,14 @@
9445
9516
  "nullable": true,
9446
9517
  "type": "array"
9447
9518
  },
9519
+ "licenses": {
9520
+ "description": "Every NMLS license / registration on file for the branch, authorized or not. A current snapshot (refreshed weekly), not period-scoped. Null when the branch's licenses are not on file.",
9521
+ "items": {
9522
+ "$ref": "#/components/schemas/BranchLicense"
9523
+ },
9524
+ "nullable": true,
9525
+ "type": "array"
9526
+ },
9448
9527
  "loCount": {
9449
9528
  "nullable": true,
9450
9529
  "type": "number"
@@ -15067,6 +15146,668 @@
15067
15146
  },
15068
15147
  "type": "object"
15069
15148
  },
15149
+ "CompanyRetentionSnapshot": {
15150
+ "properties": {
15151
+ "book": {
15152
+ "description": "Rows the computation read (sizing / provenance).",
15153
+ "properties": {
15154
+ "laterLoans": {
15155
+ "type": "number"
15156
+ },
15157
+ "ownLoans": {
15158
+ "type": "number"
15159
+ },
15160
+ "parcels": {
15161
+ "type": "number"
15162
+ },
15163
+ "sales": {
15164
+ "type": "number"
15165
+ }
15166
+ },
15167
+ "required": [
15168
+ "ownLoans",
15169
+ "parcels",
15170
+ "laterLoans",
15171
+ "sales"
15172
+ ],
15173
+ "type": "object"
15174
+ },
15175
+ "capturingCompanies": {
15176
+ "description": "Top 10 companies that captured lost borrowers, by volume.",
15177
+ "items": {
15178
+ "properties": {
15179
+ "count": {
15180
+ "type": "number"
15181
+ },
15182
+ "lane": {
15183
+ "enum": [
15184
+ "own_company",
15185
+ "servicer",
15186
+ "competitor"
15187
+ ],
15188
+ "type": "string"
15189
+ },
15190
+ "name": {
15191
+ "type": "string"
15192
+ },
15193
+ "nmlsId": {
15194
+ "type": "string"
15195
+ },
15196
+ "volume": {
15197
+ "type": "number"
15198
+ }
15199
+ },
15200
+ "required": [
15201
+ "nmlsId",
15202
+ "name",
15203
+ "count",
15204
+ "volume",
15205
+ "lane"
15206
+ ],
15207
+ "type": "object"
15208
+ },
15209
+ "type": "array"
15210
+ },
15211
+ "capturingOriginators": {
15212
+ "description": "Top 10 LOs that captured lost borrowers, by volume.",
15213
+ "items": {
15214
+ "properties": {
15215
+ "companyName": {
15216
+ "type": "string"
15217
+ },
15218
+ "count": {
15219
+ "type": "number"
15220
+ },
15221
+ "name": {
15222
+ "type": "string"
15223
+ },
15224
+ "nmlsId": {
15225
+ "type": "string"
15226
+ },
15227
+ "volume": {
15228
+ "type": "number"
15229
+ }
15230
+ },
15231
+ "required": [
15232
+ "nmlsId",
15233
+ "name",
15234
+ "companyName",
15235
+ "count",
15236
+ "volume"
15237
+ ],
15238
+ "type": "object"
15239
+ },
15240
+ "type": "array"
15241
+ },
15242
+ "capturingTotals": {
15243
+ "properties": {
15244
+ "companies": {
15245
+ "properties": {
15246
+ "distinct": {
15247
+ "type": "number"
15248
+ },
15249
+ "loans": {
15250
+ "type": "number"
15251
+ },
15252
+ "volume": {
15253
+ "type": "number"
15254
+ }
15255
+ },
15256
+ "required": [
15257
+ "distinct",
15258
+ "loans",
15259
+ "volume"
15260
+ ],
15261
+ "type": "object"
15262
+ },
15263
+ "originators": {
15264
+ "properties": {
15265
+ "distinct": {
15266
+ "type": "number"
15267
+ },
15268
+ "loans": {
15269
+ "type": "number"
15270
+ },
15271
+ "unattributedLoans": {
15272
+ "type": "number"
15273
+ },
15274
+ "volume": {
15275
+ "type": "number"
15276
+ }
15277
+ },
15278
+ "required": [
15279
+ "distinct",
15280
+ "loans",
15281
+ "volume",
15282
+ "unattributedLoans"
15283
+ ],
15284
+ "type": "object"
15285
+ }
15286
+ },
15287
+ "required": [
15288
+ "companies",
15289
+ "originators"
15290
+ ],
15291
+ "type": "object"
15292
+ },
15293
+ "churnTrend": {
15294
+ "items": {
15295
+ "properties": {
15296
+ "churned": {
15297
+ "type": "number"
15298
+ },
15299
+ "kept": {
15300
+ "type": "number"
15301
+ },
15302
+ "month": {
15303
+ "type": "string"
15304
+ },
15305
+ "retained": {
15306
+ "type": "number"
15307
+ },
15308
+ "secondPositions": {
15309
+ "type": "number"
15310
+ }
15311
+ },
15312
+ "required": [
15313
+ "month",
15314
+ "churned",
15315
+ "retained",
15316
+ "secondPositions",
15317
+ "kept"
15318
+ ],
15319
+ "type": "object"
15320
+ },
15321
+ "type": "array"
15322
+ },
15323
+ "companyName": {
15324
+ "nullable": true,
15325
+ "type": "string"
15326
+ },
15327
+ "companyNmlsId": {
15328
+ "type": "string"
15329
+ },
15330
+ "computedAt": {
15331
+ "description": "When the weekly batch computed this snapshot (ISO-8601).",
15332
+ "type": "string"
15333
+ },
15334
+ "lanes": {
15335
+ "description": "Where lost refinances went: the borrower's funding lender (`servicer`) or another company (`competitor`). `own_company` is always 0 at company level (those are kept).",
15336
+ "properties": {
15337
+ "competitor": {
15338
+ "properties": {
15339
+ "count": {
15340
+ "type": "number"
15341
+ },
15342
+ "volume": {
15343
+ "type": "number"
15344
+ }
15345
+ },
15346
+ "required": [
15347
+ "count",
15348
+ "volume"
15349
+ ],
15350
+ "type": "object"
15351
+ },
15352
+ "own_company": {
15353
+ "properties": {
15354
+ "count": {
15355
+ "type": "number"
15356
+ },
15357
+ "volume": {
15358
+ "type": "number"
15359
+ }
15360
+ },
15361
+ "required": [
15362
+ "count",
15363
+ "volume"
15364
+ ],
15365
+ "type": "object"
15366
+ },
15367
+ "servicer": {
15368
+ "properties": {
15369
+ "count": {
15370
+ "type": "number"
15371
+ },
15372
+ "volume": {
15373
+ "type": "number"
15374
+ }
15375
+ },
15376
+ "required": [
15377
+ "count",
15378
+ "volume"
15379
+ ],
15380
+ "type": "object"
15381
+ }
15382
+ },
15383
+ "required": [
15384
+ "own_company",
15385
+ "servicer",
15386
+ "competitor"
15387
+ ],
15388
+ "type": "object"
15389
+ },
15390
+ "leakiestOriginators": {
15391
+ "description": "The company's own LOs ranked by borrowers lost to other companies (top 10; only LOs with at least 10 refi events in the window).",
15392
+ "items": {
15393
+ "properties": {
15394
+ "churnedCount": {
15395
+ "description": "Their borrowers who refinanced at another company.",
15396
+ "type": "number"
15397
+ },
15398
+ "churnedVolume": {
15399
+ "type": "number"
15400
+ },
15401
+ "keptCount": {
15402
+ "description": "Their borrowers the company refinanced again (any LO).",
15403
+ "type": "number"
15404
+ },
15405
+ "name": {
15406
+ "type": "string"
15407
+ },
15408
+ "nmlsId": {
15409
+ "type": "string"
15410
+ },
15411
+ "refiRetentionRate": {
15412
+ "nullable": true,
15413
+ "type": "number"
15414
+ },
15415
+ "verdict": {
15416
+ "description": "On `refiRetentionRate` (kept ÷ (kept + churned) refi events): `quiet` under 10 events, `holding` ≥ 60%, `leaking` 35–60%, `bleeding` < 35% — the LO tab's thresholds.",
15417
+ "enum": [
15418
+ "holding",
15419
+ "leaking",
15420
+ "bleeding",
15421
+ "quiet"
15422
+ ],
15423
+ "type": "string"
15424
+ }
15425
+ },
15426
+ "required": [
15427
+ "nmlsId",
15428
+ "name",
15429
+ "churnedCount",
15430
+ "churnedVolume",
15431
+ "keptCount",
15432
+ "refiRetentionRate",
15433
+ "verdict"
15434
+ ],
15435
+ "type": "object"
15436
+ },
15437
+ "type": "array"
15438
+ },
15439
+ "period": {
15440
+ "properties": {
15441
+ "end": {
15442
+ "description": "Last day (UTC, inclusive).",
15443
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
15444
+ "type": "string"
15445
+ },
15446
+ "start": {
15447
+ "description": "First day (UTC).",
15448
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
15449
+ "type": "string"
15450
+ }
15451
+ },
15452
+ "required": [
15453
+ "start",
15454
+ "end"
15455
+ ],
15456
+ "type": "object"
15457
+ },
15458
+ "previous": {
15459
+ "description": "The preceding period of equal length (for deltas); null for `allTime`.",
15460
+ "nullable": true,
15461
+ "properties": {
15462
+ "period": {
15463
+ "properties": {
15464
+ "end": {
15465
+ "description": "Last day (UTC, inclusive).",
15466
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
15467
+ "type": "string"
15468
+ },
15469
+ "start": {
15470
+ "description": "First day (UTC).",
15471
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
15472
+ "type": "string"
15473
+ }
15474
+ },
15475
+ "required": [
15476
+ "start",
15477
+ "end"
15478
+ ],
15479
+ "type": "object"
15480
+ },
15481
+ "summary": {
15482
+ "properties": {
15483
+ "churnRate": {
15484
+ "type": "number"
15485
+ },
15486
+ "churnedCount": {
15487
+ "type": "number"
15488
+ },
15489
+ "daysToRefiPairsUsed": {
15490
+ "type": "number"
15491
+ },
15492
+ "keptRefiCount": {
15493
+ "description": "Same-LO refinances of the LO's own borrowers in the period",
15494
+ "type": "number"
15495
+ },
15496
+ "keptRefiVolume": {
15497
+ "type": "number"
15498
+ },
15499
+ "keptSecondCount": {
15500
+ "type": "number"
15501
+ },
15502
+ "medianDaysToRefi": {
15503
+ "nullable": true,
15504
+ "type": "number"
15505
+ },
15506
+ "propertySoldCount": {
15507
+ "type": "number"
15508
+ },
15509
+ "refiRetentionRate": {
15510
+ "description": "kept ÷ (kept + churned) refi events; null with none",
15511
+ "nullable": true,
15512
+ "type": "number"
15513
+ },
15514
+ "retainedCount": {
15515
+ "type": "number"
15516
+ },
15517
+ "secondPositionCount": {
15518
+ "type": "number"
15519
+ },
15520
+ "secondPositionVolume": {
15521
+ "type": "number"
15522
+ },
15523
+ "totalBorrowers": {
15524
+ "type": "number"
15525
+ },
15526
+ "unattributedCount": {
15527
+ "type": "number"
15528
+ },
15529
+ "volumeLost": {
15530
+ "type": "number"
15531
+ },
15532
+ "volumeRetained": {
15533
+ "type": "number"
15534
+ }
15535
+ },
15536
+ "required": [
15537
+ "totalBorrowers",
15538
+ "churnedCount",
15539
+ "retainedCount",
15540
+ "propertySoldCount",
15541
+ "unattributedCount",
15542
+ "secondPositionCount",
15543
+ "secondPositionVolume",
15544
+ "keptRefiCount",
15545
+ "keptRefiVolume",
15546
+ "keptSecondCount",
15547
+ "refiRetentionRate",
15548
+ "churnRate",
15549
+ "volumeLost",
15550
+ "volumeRetained",
15551
+ "medianDaysToRefi",
15552
+ "daysToRefiPairsUsed"
15553
+ ],
15554
+ "type": "object"
15555
+ },
15556
+ "verdict": {
15557
+ "description": "On `refiRetentionRate` (kept ÷ (kept + churned) refi events): `quiet` under 10 events, `holding` ≥ 60%, `leaking` 35–60%, `bleeding` < 35% — the LO tab's thresholds.",
15558
+ "enum": [
15559
+ "holding",
15560
+ "leaking",
15561
+ "bleeding",
15562
+ "quiet"
15563
+ ],
15564
+ "type": "string"
15565
+ }
15566
+ },
15567
+ "required": [
15568
+ "period",
15569
+ "summary",
15570
+ "verdict"
15571
+ ],
15572
+ "type": "object"
15573
+ },
15574
+ "schemaVersion": {
15575
+ "type": "integer"
15576
+ },
15577
+ "secondPositionLanes": {
15578
+ "properties": {
15579
+ "competitor": {
15580
+ "properties": {
15581
+ "count": {
15582
+ "type": "number"
15583
+ },
15584
+ "volume": {
15585
+ "type": "number"
15586
+ }
15587
+ },
15588
+ "required": [
15589
+ "count",
15590
+ "volume"
15591
+ ],
15592
+ "type": "object"
15593
+ },
15594
+ "own_company": {
15595
+ "properties": {
15596
+ "count": {
15597
+ "type": "number"
15598
+ },
15599
+ "volume": {
15600
+ "type": "number"
15601
+ }
15602
+ },
15603
+ "required": [
15604
+ "count",
15605
+ "volume"
15606
+ ],
15607
+ "type": "object"
15608
+ },
15609
+ "servicer": {
15610
+ "properties": {
15611
+ "count": {
15612
+ "type": "number"
15613
+ },
15614
+ "volume": {
15615
+ "type": "number"
15616
+ }
15617
+ },
15618
+ "required": [
15619
+ "count",
15620
+ "volume"
15621
+ ],
15622
+ "type": "object"
15623
+ }
15624
+ },
15625
+ "required": [
15626
+ "own_company",
15627
+ "servicer",
15628
+ "competitor"
15629
+ ],
15630
+ "type": "object"
15631
+ },
15632
+ "status": {
15633
+ "description": "`truncated`: a loan / sale scan hit its row cap, so counts cover the rows read. `timeout`: the book could not be read within the batch's per-company budget — every count is 0 and means 'not available', not 'none'.",
15634
+ "enum": [
15635
+ "ok",
15636
+ "timeout",
15637
+ "truncated"
15638
+ ],
15639
+ "type": "string"
15640
+ },
15641
+ "summary": {
15642
+ "description": "Same fields as the LO report. At company level a refinance by ANY LO at the company is kept; only a refinance at another company is churned.",
15643
+ "properties": {
15644
+ "churnRate": {
15645
+ "type": "number"
15646
+ },
15647
+ "churnedCount": {
15648
+ "type": "number"
15649
+ },
15650
+ "daysToRefiPairsUsed": {
15651
+ "type": "number"
15652
+ },
15653
+ "keptRefiCount": {
15654
+ "description": "Same-LO refinances of the LO's own borrowers in the period",
15655
+ "type": "number"
15656
+ },
15657
+ "keptRefiVolume": {
15658
+ "type": "number"
15659
+ },
15660
+ "keptSecondCount": {
15661
+ "type": "number"
15662
+ },
15663
+ "medianDaysToRefi": {
15664
+ "nullable": true,
15665
+ "type": "number"
15666
+ },
15667
+ "propertySoldCount": {
15668
+ "type": "number"
15669
+ },
15670
+ "refiRetentionRate": {
15671
+ "description": "kept ÷ (kept + churned) refi events; null with none",
15672
+ "nullable": true,
15673
+ "type": "number"
15674
+ },
15675
+ "retainedCount": {
15676
+ "type": "number"
15677
+ },
15678
+ "secondPositionCount": {
15679
+ "type": "number"
15680
+ },
15681
+ "secondPositionVolume": {
15682
+ "type": "number"
15683
+ },
15684
+ "totalBorrowers": {
15685
+ "type": "number"
15686
+ },
15687
+ "unattributedCount": {
15688
+ "type": "number"
15689
+ },
15690
+ "volumeLost": {
15691
+ "type": "number"
15692
+ },
15693
+ "volumeRetained": {
15694
+ "type": "number"
15695
+ }
15696
+ },
15697
+ "required": [
15698
+ "totalBorrowers",
15699
+ "churnedCount",
15700
+ "retainedCount",
15701
+ "propertySoldCount",
15702
+ "unattributedCount",
15703
+ "secondPositionCount",
15704
+ "secondPositionVolume",
15705
+ "keptRefiCount",
15706
+ "keptRefiVolume",
15707
+ "keptSecondCount",
15708
+ "refiRetentionRate",
15709
+ "churnRate",
15710
+ "volumeLost",
15711
+ "volumeRetained",
15712
+ "medianDaysToRefi",
15713
+ "daysToRefiPairsUsed"
15714
+ ],
15715
+ "type": "object"
15716
+ },
15717
+ "timing": {
15718
+ "properties": {
15719
+ "cashOutCount": {
15720
+ "type": "number"
15721
+ },
15722
+ "cashOutShare": {
15723
+ "nullable": true,
15724
+ "type": "number"
15725
+ },
15726
+ "loanTypeChangeCount": {
15727
+ "type": "number"
15728
+ },
15729
+ "medianMonths": {
15730
+ "nullable": true,
15731
+ "type": "number"
15732
+ },
15733
+ "monthsToExit": {
15734
+ "items": {
15735
+ "properties": {
15736
+ "bucket": {
15737
+ "type": "string"
15738
+ },
15739
+ "count": {
15740
+ "type": "number"
15741
+ }
15742
+ },
15743
+ "required": [
15744
+ "bucket",
15745
+ "count"
15746
+ ],
15747
+ "type": "object"
15748
+ },
15749
+ "type": "array"
15750
+ },
15751
+ "rateDeltaMedian": {
15752
+ "nullable": true,
15753
+ "type": "number"
15754
+ },
15755
+ "rateDeltaPairs": {
15756
+ "type": "number"
15757
+ }
15758
+ },
15759
+ "required": [
15760
+ "monthsToExit",
15761
+ "medianMonths",
15762
+ "cashOutCount",
15763
+ "cashOutShare",
15764
+ "rateDeltaMedian",
15765
+ "rateDeltaPairs",
15766
+ "loanTypeChangeCount"
15767
+ ],
15768
+ "type": "object"
15769
+ },
15770
+ "verdict": {
15771
+ "description": "On `refiRetentionRate` (kept ÷ (kept + churned) refi events): `quiet` under 10 events, `holding` ≥ 60%, `leaking` 35–60%, `bleeding` < 35% — the LO tab's thresholds.",
15772
+ "enum": [
15773
+ "holding",
15774
+ "leaking",
15775
+ "bleeding",
15776
+ "quiet"
15777
+ ],
15778
+ "type": "string"
15779
+ },
15780
+ "window": {
15781
+ "enum": [
15782
+ "last12Months",
15783
+ "allTime"
15784
+ ],
15785
+ "type": "string"
15786
+ }
15787
+ },
15788
+ "required": [
15789
+ "schemaVersion",
15790
+ "companyNmlsId",
15791
+ "companyName",
15792
+ "window",
15793
+ "period",
15794
+ "computedAt",
15795
+ "status",
15796
+ "summary",
15797
+ "verdict",
15798
+ "lanes",
15799
+ "secondPositionLanes",
15800
+ "timing",
15801
+ "churnTrend",
15802
+ "capturingCompanies",
15803
+ "capturingOriginators",
15804
+ "capturingTotals",
15805
+ "leakiestOriginators",
15806
+ "previous",
15807
+ "book"
15808
+ ],
15809
+ "type": "object"
15810
+ },
15070
15811
  "CompanyRoleScope": {
15071
15812
  "description": "Which of a loan's party roles make it this company's loan. `loanCompany` (default): the company named on the loan document — one company per loan. `all`: the company appears in ANY role — loan-document company, the originating LO's employer at time of loan, the LO's organization, broker, or funding lender; a loan matching several roles counts once. `employer`: the company employed the originating LO when the loan closed. `broker`: the company brokered the loan. `lender`: the company funded the loan. `tpo`: third-party origination — the company is the loan company or lender but did NOT employ the originating LO (the `channel` dimension's `tpo` bucket as a population; `employer` is its `inHouse` counterpart). Use `all` for a broker shop's full production — its loans are often recorded under the funding lender's name, so `loanCompany` undercounts it.",
15072
15813
  "enum": [
@@ -25280,6 +26021,59 @@
25280
26021
  ],
25281
26022
  "type": "object"
25282
26023
  },
26024
+ "GetSavedFilterSharesResult": {
26025
+ "properties": {
26026
+ "data": {
26027
+ "$ref": "#/components/schemas/SavedFilterSharing"
26028
+ }
26029
+ },
26030
+ "required": [
26031
+ "data"
26032
+ ],
26033
+ "type": "object"
26034
+ },
26035
+ "GrantSavedFilterAccessRequest": {
26036
+ "additionalProperties": false,
26037
+ "properties": {
26038
+ "permission": {
26039
+ "allOf": [
26040
+ {
26041
+ "$ref": "#/components/schemas/SavedFilterGrantPermission"
26042
+ },
26043
+ {
26044
+ "description": "Defaults to `viewer`."
26045
+ }
26046
+ ]
26047
+ },
26048
+ "userId": {
26049
+ "minLength": 1,
26050
+ "type": "string"
26051
+ }
26052
+ },
26053
+ "required": [
26054
+ "userId"
26055
+ ],
26056
+ "type": "object"
26057
+ },
26058
+ "GrantSavedFilterAccessResult": {
26059
+ "properties": {
26060
+ "data": {
26061
+ "properties": {
26062
+ "granted": {
26063
+ "type": "boolean"
26064
+ }
26065
+ },
26066
+ "required": [
26067
+ "granted"
26068
+ ],
26069
+ "type": "object"
26070
+ }
26071
+ },
26072
+ "required": [
26073
+ "data"
26074
+ ],
26075
+ "type": "object"
26076
+ },
25283
26077
  "HeadcountPoint": {
25284
26078
  "properties": {
25285
26079
  "active": {
@@ -40590,6 +41384,38 @@
40590
41384
  ],
40591
41385
  "type": "object"
40592
41386
  },
41387
+ "RevokeSavedFilterAccessRequest": {
41388
+ "additionalProperties": false,
41389
+ "properties": {
41390
+ "userId": {
41391
+ "minLength": 1,
41392
+ "type": "string"
41393
+ }
41394
+ },
41395
+ "required": [
41396
+ "userId"
41397
+ ],
41398
+ "type": "object"
41399
+ },
41400
+ "RevokeSavedFilterAccessResult": {
41401
+ "properties": {
41402
+ "data": {
41403
+ "properties": {
41404
+ "revoked": {
41405
+ "type": "boolean"
41406
+ }
41407
+ },
41408
+ "required": [
41409
+ "revoked"
41410
+ ],
41411
+ "type": "object"
41412
+ }
41413
+ },
41414
+ "required": [
41415
+ "data"
41416
+ ],
41417
+ "type": "object"
41418
+ },
40593
41419
  "RosterProductionTier": {
40594
41420
  "properties": {
40595
41421
  "count": {
@@ -41290,6 +42116,18 @@
41290
42116
  },
41291
42117
  "SavedFilter": {
41292
42118
  "properties": {
42119
+ "canDelete": {
42120
+ "description": "You may delete it (owner or workspace admin).",
42121
+ "type": "boolean"
42122
+ },
42123
+ "canEdit": {
42124
+ "description": "You may update its name, icon, query and UI state (owner, editor, or workspace admin).",
42125
+ "type": "boolean"
42126
+ },
42127
+ "canManageSharing": {
42128
+ "description": "You may change its visibility and who it is shared with (owner or workspace admin).",
42129
+ "type": "boolean"
42130
+ },
41293
42131
  "createdAt": {
41294
42132
  "format": "date-time",
41295
42133
  "type": "string"
@@ -41309,6 +42147,10 @@
41309
42147
  "id": {
41310
42148
  "type": "string"
41311
42149
  },
42150
+ "isOwner": {
42151
+ "description": "True for your own filters; false for ones shared with you.",
42152
+ "type": "boolean"
42153
+ },
41312
42154
  "kind": {
41313
42155
  "description": "`filter` (default) — a saved search; `view` — a saved CRM table layout (columns / order) kept in `uiState`. Views never carry a `query` and have their own 25-per-target quota. Fixed at create.",
41314
42156
  "enum": [
@@ -41317,6 +42159,12 @@
41317
42159
  ],
41318
42160
  "type": "string"
41319
42161
  },
42162
+ "lastUsedAt": {
42163
+ "description": "When it was last run; null if never.",
42164
+ "format": "date-time",
42165
+ "nullable": true,
42166
+ "type": "string"
42167
+ },
41320
42168
  "name": {
41321
42169
  "type": "string"
41322
42170
  },
@@ -41325,6 +42173,24 @@
41325
42173
  "nullable": true,
41326
42174
  "type": "string"
41327
42175
  },
42176
+ "ownerName": {
42177
+ "description": "The owner's display name on a filter shared with you; null on your own filters (and when it cannot be resolved).",
42178
+ "nullable": true,
42179
+ "type": "string"
42180
+ },
42181
+ "ownerUserId": {
42182
+ "description": "The user who owns it.",
42183
+ "type": "string"
42184
+ },
42185
+ "permission": {
42186
+ "description": "Your role: `owner`, or the access it was shared with you at (`editor` / `viewer`; a filter visible to the whole workspace without an editor grant is `viewer`).",
42187
+ "enum": [
42188
+ "owner",
42189
+ "editor",
42190
+ "viewer"
42191
+ ],
42192
+ "type": "string"
42193
+ },
41328
42194
  "query": {
41329
42195
  "additionalProperties": {
41330
42196
  "nullable": true
@@ -41393,14 +42259,12 @@
41393
42259
  "format": "date-time",
41394
42260
  "type": "string"
41395
42261
  },
42262
+ "useCount": {
42263
+ "description": "How many times the filter has been run: fetched with `getSavedFilter`, or named in `X-MM-Saved-Filter-Id` on a successful list request (count requests do not count).",
42264
+ "type": "integer"
42265
+ },
41396
42266
  "visibility": {
41397
- "description": "Always `private` in v1.",
41398
- "enum": [
41399
- "private",
41400
- "organization",
41401
- "shared"
41402
- ],
41403
- "type": "string"
42267
+ "$ref": "#/components/schemas/SavedFilterVisibility"
41404
42268
  }
41405
42269
  },
41406
42270
  "required": [
@@ -41416,6 +42280,15 @@
41416
42280
  "fidelity",
41417
42281
  "unmapped",
41418
42282
  "visibility",
42283
+ "ownerUserId",
42284
+ "ownerName",
42285
+ "isOwner",
42286
+ "permission",
42287
+ "canEdit",
42288
+ "canDelete",
42289
+ "canManageSharing",
42290
+ "useCount",
42291
+ "lastUsedAt",
41419
42292
  "operationId",
41420
42293
  "stale",
41421
42294
  "staleIssues",
@@ -41427,7 +42300,7 @@
41427
42300
  "SavedFilterError": {
41428
42301
  "properties": {
41429
42302
  "code": {
41430
- "description": "`QUOTA_EXCEEDED` (409, 25 per target + kind).",
42303
+ "description": "`QUOTA_EXCEEDED` (409, 25 per target + kind), `FORBIDDEN` (403, your access to a shared filter does not allow this), `NOT_ORG_MEMBER` (400, the user to share with is not in your workspace).",
41431
42304
  "type": "string"
41432
42305
  },
41433
42306
  "error": {
@@ -41457,91 +42330,223 @@
41457
42330
  ],
41458
42331
  "type": "object"
41459
42332
  },
42333
+ "SavedFilterGrantPermission": {
42334
+ "description": "The whole workspace's role on an `organization` filter; null for private / shared filters.",
42335
+ "enum": [
42336
+ "editor",
42337
+ "viewer",
42338
+ null
42339
+ ],
42340
+ "nullable": true,
42341
+ "type": "string"
42342
+ },
41460
42343
  "SavedFilterIcon": {
41461
- "description": "Optional marker: a color dot, a tinted icon, or an emoji.",
41462
- "oneOf": [
41463
- {
42344
+ "description": "Optional marker: one emoji. (Color dots and named icons were retired; existing ones were converted to the nearest emoji.)",
42345
+ "nullable": true,
42346
+ "properties": {
42347
+ "emoji": {
42348
+ "maxLength": 16,
42349
+ "minLength": 1,
42350
+ "type": "string"
42351
+ },
42352
+ "type": {
42353
+ "enum": [
42354
+ "emoji"
42355
+ ],
42356
+ "type": "string"
42357
+ }
42358
+ },
42359
+ "required": [
42360
+ "type",
42361
+ "emoji"
42362
+ ],
42363
+ "type": "object"
42364
+ },
42365
+ "SavedFilterList": {
42366
+ "properties": {
42367
+ "data": {
42368
+ "items": {
42369
+ "$ref": "#/components/schemas/SavedFilter"
42370
+ },
42371
+ "type": "array"
42372
+ }
42373
+ },
42374
+ "required": [
42375
+ "data"
42376
+ ],
42377
+ "type": "object"
42378
+ },
42379
+ "SavedFilterShare": {
42380
+ "properties": {
42381
+ "createdAt": {
42382
+ "description": "Epoch milliseconds.",
42383
+ "type": "number"
42384
+ },
42385
+ "email": {
42386
+ "nullable": true,
42387
+ "type": "string"
42388
+ },
42389
+ "id": {
42390
+ "type": "string"
42391
+ },
42392
+ "image": {
42393
+ "nullable": true,
42394
+ "type": "string"
42395
+ },
42396
+ "invitedByName": {
42397
+ "nullable": true,
42398
+ "type": "string"
42399
+ },
42400
+ "name": {
42401
+ "nullable": true,
42402
+ "type": "string"
42403
+ },
42404
+ "permission": {
42405
+ "enum": [
42406
+ "owner",
42407
+ "editor",
42408
+ "viewer"
42409
+ ],
42410
+ "type": "string"
42411
+ },
42412
+ "userId": {
42413
+ "type": "string"
42414
+ }
42415
+ },
42416
+ "required": [
42417
+ "id",
42418
+ "userId",
42419
+ "name",
42420
+ "email",
42421
+ "image",
42422
+ "permission",
42423
+ "invitedByName",
42424
+ "createdAt"
42425
+ ],
42426
+ "type": "object"
42427
+ },
42428
+ "SavedFilterShareableMember": {
42429
+ "properties": {
42430
+ "email": {
42431
+ "nullable": true,
42432
+ "type": "string"
42433
+ },
42434
+ "image": {
42435
+ "nullable": true,
42436
+ "type": "string"
42437
+ },
42438
+ "name": {
42439
+ "nullable": true,
42440
+ "type": "string"
42441
+ },
42442
+ "userId": {
42443
+ "type": "string"
42444
+ }
42445
+ },
42446
+ "required": [
42447
+ "userId",
42448
+ "name",
42449
+ "email",
42450
+ "image"
42451
+ ],
42452
+ "type": "object"
42453
+ },
42454
+ "SavedFilterShareableMemberList": {
42455
+ "properties": {
42456
+ "data": {
41464
42457
  "properties": {
41465
- "color": {
41466
- "pattern": "^#[0-9a-fA-F]{6}$",
41467
- "type": "string"
41468
- },
41469
- "type": {
41470
- "enum": [
41471
- "color"
41472
- ],
41473
- "type": "string"
42458
+ "members": {
42459
+ "items": {
42460
+ "$ref": "#/components/schemas/SavedFilterShareableMember"
42461
+ },
42462
+ "type": "array"
41474
42463
  }
41475
42464
  },
41476
42465
  "required": [
41477
- "type",
41478
- "color"
42466
+ "members"
41479
42467
  ],
41480
42468
  "type": "object"
42469
+ }
42470
+ },
42471
+ "required": [
42472
+ "data"
42473
+ ],
42474
+ "type": "object"
42475
+ },
42476
+ "SavedFilterSharing": {
42477
+ "properties": {
42478
+ "canManageSharing": {
42479
+ "description": "The caller may grant / revoke and change visibility (owner or workspace admin).",
42480
+ "type": "boolean"
41481
42481
  },
41482
- {
42482
+ "orgWidePermission": {
42483
+ "allOf": [
42484
+ {
42485
+ "$ref": "#/components/schemas/SavedFilterGrantPermission"
42486
+ },
42487
+ {
42488
+ "description": "On an `organization` filter, whether every member can edit or only view. Always `viewer` otherwise."
42489
+ }
42490
+ ]
42491
+ },
42492
+ "owner": {
41483
42493
  "properties": {
41484
- "color": {
41485
- "pattern": "^#[0-9a-fA-F]{6}$",
42494
+ "email": {
42495
+ "nullable": true,
41486
42496
  "type": "string"
41487
42497
  },
41488
- "icon": {
41489
- "pattern": "^[A-Za-z][A-Za-z0-9]{0,63}$",
42498
+ "image": {
42499
+ "nullable": true,
41490
42500
  "type": "string"
41491
42501
  },
41492
- "type": {
41493
- "enum": [
41494
- "icon"
41495
- ],
41496
- "type": "string"
41497
- }
41498
- },
41499
- "required": [
41500
- "type",
41501
- "icon",
41502
- "color"
41503
- ],
41504
- "type": "object"
41505
- },
41506
- {
41507
- "properties": {
41508
- "emoji": {
41509
- "maxLength": 16,
41510
- "minLength": 1,
42502
+ "name": {
42503
+ "nullable": true,
41511
42504
  "type": "string"
41512
42505
  },
41513
- "type": {
41514
- "enum": [
41515
- "emoji"
41516
- ],
42506
+ "userId": {
41517
42507
  "type": "string"
41518
42508
  }
41519
42509
  },
41520
42510
  "required": [
41521
- "type",
41522
- "emoji"
42511
+ "userId",
42512
+ "name",
42513
+ "email",
42514
+ "image"
41523
42515
  ],
41524
42516
  "type": "object"
41525
42517
  },
41526
- {
41527
- "nullable": true
41528
- }
41529
- ]
41530
- },
41531
- "SavedFilterList": {
41532
- "properties": {
41533
- "data": {
42518
+ "ownerUserId": {
42519
+ "type": "string"
42520
+ },
42521
+ "shares": {
41534
42522
  "items": {
41535
- "$ref": "#/components/schemas/SavedFilter"
42523
+ "$ref": "#/components/schemas/SavedFilterShare"
41536
42524
  },
41537
42525
  "type": "array"
42526
+ },
42527
+ "visibility": {
42528
+ "$ref": "#/components/schemas/SavedFilterVisibility"
41538
42529
  }
41539
42530
  },
41540
42531
  "required": [
41541
- "data"
42532
+ "visibility",
42533
+ "ownerUserId",
42534
+ "owner",
42535
+ "canManageSharing",
42536
+ "orgWidePermission",
42537
+ "shares"
41542
42538
  ],
41543
42539
  "type": "object"
41544
42540
  },
42541
+ "SavedFilterVisibility": {
42542
+ "description": "Who can see the filter: `private` — only its owner; `organization` — every member of the workspace (view; edit too when `orgWidePermission` is `editor`); `shared` — only the members it was shared with (see `/saved-filters/{id}/shares`).",
42543
+ "enum": [
42544
+ "private",
42545
+ "organization",
42546
+ "shared"
42547
+ ],
42548
+ "type": "string"
42549
+ },
41545
42550
  "SearchTokenResponse": {
41546
42551
  "properties": {
41547
42552
  "expiresAt": {
@@ -42599,6 +43604,16 @@
42599
43604
  "minLength": 1,
42600
43605
  "type": "string"
42601
43606
  },
43607
+ "orgWidePermission": {
43608
+ "allOf": [
43609
+ {
43610
+ "$ref": "#/components/schemas/SavedFilterGrantPermission"
43611
+ },
43612
+ {
43613
+ "description": "Owner or workspace admin only. The whole workspace's role; setting it also sets `visibility: organization`."
43614
+ }
43615
+ ]
43616
+ },
42602
43617
  "query": {
42603
43618
  "additionalProperties": {
42604
43619
  "nullable": true
@@ -42628,6 +43643,16 @@
42628
43643
  },
42629
43644
  "maxItems": 100,
42630
43645
  "type": "array"
43646
+ },
43647
+ "visibility": {
43648
+ "allOf": [
43649
+ {
43650
+ "$ref": "#/components/schemas/SavedFilterVisibility"
43651
+ },
43652
+ {
43653
+ "description": "Owner or workspace admin only. `private` removes every share; `shared` removes the workspace-wide grant; sharing with a member (`POST /saved-filters/{id}/shares`) turns a private filter into `shared` on its own."
43654
+ }
43655
+ ]
42631
43656
  }
42632
43657
  },
42633
43658
  "type": "object"
@@ -42902,7 +43927,7 @@
42902
43927
  "info": {
42903
43928
  "description": "ModelMatch API — mortgage and real-estate market data.\n\n## Bulk delivery limits\n\nThe `POST /{entity}/bulk-delivery` endpoints export a full result set to\nS3 as NDJSON, JSON, CSV, or Parquet.\n\n- **Up to 5,000 rows per delivery: no entitlement required.** Available to\n every authenticated caller.\n- **Above 5,000 rows: requires the entity's `bulk-delivery.{entity}`\n entitlement** (e.g. `bulk-delivery.loans`). The grant's scope sets your\n row ceiling and may also restrict which rows and fields you receive.\n\nA delivery that would exceed the limit available to you is rejected with\n`403 entitlement_missing`, reporting the matched row count and the ceiling\nthat applied. To stay under the limit, pass `limit` — the job then delivers\n(and bills for) only the first `limit` rows of a broader query.\n\n**Need a higher limit?** Email support@modelmatch.com to request the\nentitlement. Limits are raised per organization and per entity.\n\nBulk delivery is billed at 1 credit per delivered row whether or not\nan entitlement is held.\n\nInstead of a download, a delivery can be sent to a push target configured\non your workspace: pass `destination: { type: \"push-target\", targetId }`.\nThe same limits and billing apply.",
42904
43929
  "title": "ModelMatch API",
42905
- "version": "3.108.0"
43930
+ "version": "3.110.0"
42906
43931
  },
42907
43932
  "openapi": "3.1.0",
42908
43933
  "paths": {
@@ -53559,6 +54584,115 @@
53559
54584
  ]
53560
54585
  }
53561
54586
  },
54587
+ "/v1/companies/{nmlsId}/retention": {
54588
+ "get": {
54589
+ "description": "How well a company keeps its borrowers when they refinance: kept (refinanced again by ANY LO at the company) vs lost to other companies, with the capturing companies and LOs, timing, the trend, a verdict, and the company's leakiest LOs. Precomputed weekly — `computedAt` says when. 404 means not computed (no loans since 2017, or not reached yet), never zero retention.",
54590
+ "operationId": "companyRetention",
54591
+ "parameters": [
54592
+ {
54593
+ "description": "Company NMLS ID",
54594
+ "in": "path",
54595
+ "name": "nmlsId",
54596
+ "required": true,
54597
+ "schema": {
54598
+ "description": "Company NMLS ID",
54599
+ "type": "string"
54600
+ }
54601
+ },
54602
+ {
54603
+ "description": "`last12Months` (the trailing 12 months to the computation date, with the 12 months before as `previous`) or `allTime` (2017-01-01 on). Default `last12Months`.",
54604
+ "in": "query",
54605
+ "name": "window",
54606
+ "required": false,
54607
+ "schema": {
54608
+ "default": "last12Months",
54609
+ "description": "`last12Months` (the trailing 12 months to the computation date, with the 12 months before as `previous`) or `allTime` (2017-01-01 on). Default `last12Months`.",
54610
+ "enum": [
54611
+ "last12Months",
54612
+ "allTime"
54613
+ ],
54614
+ "type": "string"
54615
+ }
54616
+ }
54617
+ ],
54618
+ "responses": {
54619
+ "200": {
54620
+ "content": {
54621
+ "application/json": {
54622
+ "schema": {
54623
+ "$ref": "#/components/schemas/CompanyRetentionSnapshot"
54624
+ }
54625
+ }
54626
+ },
54627
+ "description": "The stored snapshot"
54628
+ },
54629
+ "400": {
54630
+ "content": {
54631
+ "application/json": {
54632
+ "schema": {
54633
+ "$ref": "#/components/schemas/ErrorResponse"
54634
+ }
54635
+ }
54636
+ },
54637
+ "description": "Validation error"
54638
+ },
54639
+ "401": {
54640
+ "content": {
54641
+ "application/json": {
54642
+ "schema": {
54643
+ "$ref": "#/components/schemas/ErrorResponse"
54644
+ }
54645
+ }
54646
+ },
54647
+ "description": "Unauthorized"
54648
+ },
54649
+ "403": {
54650
+ "content": {
54651
+ "application/json": {
54652
+ "schema": {
54653
+ "$ref": "#/components/schemas/ErrorResponse"
54654
+ }
54655
+ }
54656
+ },
54657
+ "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
54658
+ },
54659
+ "404": {
54660
+ "content": {
54661
+ "application/json": {
54662
+ "schema": {
54663
+ "$ref": "#/components/schemas/ErrorResponse"
54664
+ }
54665
+ }
54666
+ },
54667
+ "description": "Not found"
54668
+ },
54669
+ "413": {
54670
+ "content": {
54671
+ "application/json": {
54672
+ "schema": {
54673
+ "$ref": "#/components/schemas/PayloadTooLarge"
54674
+ }
54675
+ }
54676
+ },
54677
+ "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
54678
+ },
54679
+ "503": {
54680
+ "content": {
54681
+ "application/json": {
54682
+ "schema": {
54683
+ "$ref": "#/components/schemas/SearchUnavailable"
54684
+ }
54685
+ }
54686
+ },
54687
+ "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
54688
+ }
54689
+ },
54690
+ "summary": "Company borrower retention (weekly snapshot)",
54691
+ "tags": [
54692
+ "Companies"
54693
+ ]
54694
+ }
54695
+ },
53562
54696
  "/v1/companies/{nmlsId}/sponsored-individuals": {
53563
54697
  "post": {
53564
54698
  "operationId": "companySponsoredIndividuals",
@@ -78388,21 +79522,527 @@
78388
79522
  "content": {
78389
79523
  "application/json": {
78390
79524
  "schema": {
78391
- "$ref": "#/components/schemas/ErrorResponse"
79525
+ "$ref": "#/components/schemas/ErrorResponse"
79526
+ }
79527
+ }
79528
+ },
79529
+ "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
79530
+ },
79531
+ "404": {
79532
+ "content": {
79533
+ "application/json": {
79534
+ "schema": {
79535
+ "$ref": "#/components/schemas/ErrorResponse"
79536
+ }
79537
+ }
79538
+ },
79539
+ "description": "Not found"
79540
+ },
79541
+ "413": {
79542
+ "content": {
79543
+ "application/json": {
79544
+ "schema": {
79545
+ "$ref": "#/components/schemas/PayloadTooLarge"
79546
+ }
79547
+ }
79548
+ },
79549
+ "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
79550
+ },
79551
+ "503": {
79552
+ "content": {
79553
+ "application/json": {
79554
+ "schema": {
79555
+ "$ref": "#/components/schemas/SearchUnavailable"
79556
+ }
79557
+ }
79558
+ },
79559
+ "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
79560
+ }
79561
+ },
79562
+ "summary": "Count sales matching filters",
79563
+ "tags": [
79564
+ "Sales"
79565
+ ],
79566
+ "x-mm-records-via": "listSales"
79567
+ }
79568
+ },
79569
+ "/v1/sales/{id}": {
79570
+ "get": {
79571
+ "operationId": "getSale",
79572
+ "parameters": [
79573
+ {
79574
+ "description": "Sale document ID",
79575
+ "in": "path",
79576
+ "name": "id",
79577
+ "required": true,
79578
+ "schema": {
79579
+ "description": "Sale document ID",
79580
+ "type": "string"
79581
+ }
79582
+ }
79583
+ ],
79584
+ "responses": {
79585
+ "200": {
79586
+ "content": {
79587
+ "application/json": {
79588
+ "schema": {
79589
+ "$ref": "#/components/schemas/SaleDetailResponse"
79590
+ }
79591
+ }
79592
+ },
79593
+ "description": "Sale detail"
79594
+ },
79595
+ "404": {
79596
+ "content": {
79597
+ "application/json": {
79598
+ "schema": {
79599
+ "$ref": "#/components/schemas/ErrorResponse"
79600
+ }
79601
+ }
79602
+ },
79603
+ "description": "Sale not found"
79604
+ },
79605
+ "413": {
79606
+ "content": {
79607
+ "application/json": {
79608
+ "schema": {
79609
+ "$ref": "#/components/schemas/PayloadTooLarge"
79610
+ }
79611
+ }
79612
+ },
79613
+ "description": "Response payload too large"
79614
+ }
79615
+ },
79616
+ "summary": "Get sale by ID",
79617
+ "tags": [
79618
+ "Sales"
79619
+ ]
79620
+ }
79621
+ },
79622
+ "/v1/sales/{id}/related": {
79623
+ "get": {
79624
+ "description": "Return the ids of records of another type that are linked to this record. Links resolve by identifier, strongest identifier first, and equally-trusted identifiers are combined — a company's linked loans cover every role it holds on a loan, not just the first one found. The response reports which strength was used: `primary` is the canonical identifier for that pair, `secondary` is a real but weaker alternate used only when the record carries nothing better. This is a lightweight index: it returns ids and a count, not full records. For filtering, sorting, pagination and full detail, use the named endpoint for the pair (for example the originator loans endpoint) and fetch records by id.",
79625
+ "operationId": "saleRelated",
79626
+ "parameters": [
79627
+ {
79628
+ "description": "Sale id",
79629
+ "in": "path",
79630
+ "name": "id",
79631
+ "required": true,
79632
+ "schema": {
79633
+ "description": "Sale id",
79634
+ "type": "string"
79635
+ }
79636
+ },
79637
+ {
79638
+ "description": "Type of record to link to",
79639
+ "in": "query",
79640
+ "name": "to",
79641
+ "required": true,
79642
+ "schema": {
79643
+ "description": "Type of record to link to",
79644
+ "enum": [
79645
+ "agents",
79646
+ "loans",
79647
+ "properties"
79648
+ ],
79649
+ "type": "string"
79650
+ }
79651
+ },
79652
+ {
79653
+ "description": "Maximum ids to return (default 25, max 200)",
79654
+ "in": "query",
79655
+ "name": "limit",
79656
+ "required": false,
79657
+ "schema": {
79658
+ "description": "Maximum ids to return (default 25, max 200)",
79659
+ "maximum": 200,
79660
+ "minimum": 1,
79661
+ "type": "integer"
79662
+ }
79663
+ }
79664
+ ],
79665
+ "responses": {
79666
+ "200": {
79667
+ "content": {
79668
+ "application/json": {
79669
+ "schema": {
79670
+ "$ref": "#/components/schemas/RelatedResponse"
79671
+ }
79672
+ }
79673
+ },
79674
+ "description": "Linked record ids"
79675
+ },
79676
+ "400": {
79677
+ "content": {
79678
+ "application/json": {
79679
+ "schema": {
79680
+ "$ref": "#/components/schemas/ErrorResponse"
79681
+ }
79682
+ }
79683
+ },
79684
+ "description": "Validation error"
79685
+ },
79686
+ "401": {
79687
+ "content": {
79688
+ "application/json": {
79689
+ "schema": {
79690
+ "$ref": "#/components/schemas/ErrorResponse"
79691
+ }
79692
+ }
79693
+ },
79694
+ "description": "Unauthorized"
79695
+ },
79696
+ "403": {
79697
+ "content": {
79698
+ "application/json": {
79699
+ "schema": {
79700
+ "$ref": "#/components/schemas/ErrorResponse"
79701
+ }
79702
+ }
79703
+ },
79704
+ "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
79705
+ },
79706
+ "404": {
79707
+ "content": {
79708
+ "application/json": {
79709
+ "schema": {
79710
+ "$ref": "#/components/schemas/ErrorResponse"
79711
+ }
79712
+ }
79713
+ },
79714
+ "description": "Record not found"
79715
+ },
79716
+ "413": {
79717
+ "content": {
79718
+ "application/json": {
79719
+ "schema": {
79720
+ "$ref": "#/components/schemas/PayloadTooLarge"
79721
+ }
79722
+ }
79723
+ },
79724
+ "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
79725
+ },
79726
+ "503": {
79727
+ "content": {
79728
+ "application/json": {
79729
+ "schema": {
79730
+ "$ref": "#/components/schemas/SearchUnavailable"
79731
+ }
79732
+ }
79733
+ },
79734
+ "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
79735
+ }
79736
+ },
79737
+ "summary": "Records linked to this one",
79738
+ "tags": [
79739
+ "Related"
79740
+ ]
79741
+ }
79742
+ },
79743
+ "/v1/saved-filters": {
79744
+ "get": {
79745
+ "description": "The caller's saved filters (and saved CRM views) in the active organization plus the ones shared with them, oldest first, optionally narrowed by target, kind and ownership. `isOwner` / `permission` / `canEdit` on each row say whose it is and what the caller may do.",
79746
+ "operationId": "listSavedFilters",
79747
+ "parameters": [
79748
+ {
79749
+ "description": "Which list the filter runs against. Market targets run against that entity's list operation (see `operationId`, e.g. listOriginators); `crm_people` / `crm_companies` are UI-only (filtered client-side).",
79750
+ "in": "query",
79751
+ "name": "target",
79752
+ "required": false,
79753
+ "schema": {
79754
+ "description": "Which list the filter runs against. Market targets run against that entity's list operation (see `operationId`, e.g. listOriginators); `crm_people` / `crm_companies` are UI-only (filtered client-side).",
79755
+ "enum": [
79756
+ "originators",
79757
+ "agents",
79758
+ "companies",
79759
+ "branches",
79760
+ "offices",
79761
+ "loans",
79762
+ "properties",
79763
+ "sales",
79764
+ "crm_people",
79765
+ "crm_companies"
79766
+ ],
79767
+ "type": "string"
79768
+ }
79769
+ },
79770
+ {
79771
+ "description": "`filter` (default) — a saved search; `view` — a saved CRM table layout (columns / order) kept in `uiState`. Views never carry a `query` and have their own 25-per-target quota. Fixed at create.",
79772
+ "in": "query",
79773
+ "name": "kind",
79774
+ "required": false,
79775
+ "schema": {
79776
+ "description": "`filter` (default) — a saved search; `view` — a saved CRM table layout (columns / order) kept in `uiState`. Views never carry a `query` and have their own 25-per-target quota. Fixed at create.",
79777
+ "enum": [
79778
+ "filter",
79779
+ "view"
79780
+ ],
79781
+ "type": "string"
79782
+ }
79783
+ },
79784
+ {
79785
+ "description": "`mine` — only filters you own; `shared` — only filters shared with you. Omit for both.",
79786
+ "in": "query",
79787
+ "name": "ownership",
79788
+ "required": false,
79789
+ "schema": {
79790
+ "description": "`mine` — only filters you own; `shared` — only filters shared with you. Omit for both.",
79791
+ "enum": [
79792
+ "mine",
79793
+ "shared"
79794
+ ],
79795
+ "type": "string"
79796
+ }
79797
+ }
79798
+ ],
79799
+ "responses": {
79800
+ "200": {
79801
+ "content": {
79802
+ "application/json": {
79803
+ "schema": {
79804
+ "$ref": "#/components/schemas/SavedFilterList"
79805
+ }
79806
+ }
79807
+ },
79808
+ "description": "Saved filters."
79809
+ },
79810
+ "400": {
79811
+ "content": {
79812
+ "application/json": {
79813
+ "schema": {
79814
+ "$ref": "#/components/schemas/ErrorResponse"
79815
+ }
79816
+ }
79817
+ },
79818
+ "description": "Validation error"
79819
+ },
79820
+ "401": {
79821
+ "content": {
79822
+ "application/json": {
79823
+ "schema": {
79824
+ "$ref": "#/components/schemas/ErrorResponse"
79825
+ }
79826
+ }
79827
+ },
79828
+ "description": "Unauthorized"
79829
+ },
79830
+ "403": {
79831
+ "content": {
79832
+ "application/json": {
79833
+ "schema": {
79834
+ "$ref": "#/components/schemas/ErrorResponse"
79835
+ }
79836
+ }
79837
+ },
79838
+ "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
79839
+ },
79840
+ "404": {
79841
+ "content": {
79842
+ "application/json": {
79843
+ "schema": {
79844
+ "$ref": "#/components/schemas/ErrorResponse"
79845
+ }
79846
+ }
79847
+ },
79848
+ "description": "Not found"
79849
+ },
79850
+ "413": {
79851
+ "content": {
79852
+ "application/json": {
79853
+ "schema": {
79854
+ "$ref": "#/components/schemas/PayloadTooLarge"
79855
+ }
79856
+ }
79857
+ },
79858
+ "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
79859
+ },
79860
+ "503": {
79861
+ "content": {
79862
+ "application/json": {
79863
+ "schema": {
79864
+ "$ref": "#/components/schemas/SearchUnavailable"
79865
+ }
79866
+ }
79867
+ },
79868
+ "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
79869
+ }
79870
+ },
79871
+ "summary": "List your saved filters",
79872
+ "tags": [
79873
+ "Saved Filters"
79874
+ ]
79875
+ },
79876
+ "post": {
79877
+ "description": "Save a named filter for a list target. For a market target, `query` is the target operation's request body without `pagination` (e.g. the body you would send to listOriginators) and is validated against it. New filters are private. Limit: 25 you own per target (filters shared with you do not count).",
79878
+ "operationId": "createSavedFilter",
79879
+ "requestBody": {
79880
+ "content": {
79881
+ "application/json": {
79882
+ "schema": {
79883
+ "$ref": "#/components/schemas/CreateSavedFilterRequest"
79884
+ }
79885
+ }
79886
+ }
79887
+ },
79888
+ "responses": {
79889
+ "201": {
79890
+ "content": {
79891
+ "application/json": {
79892
+ "schema": {
79893
+ "$ref": "#/components/schemas/CreateSavedFilterResult"
79894
+ }
79895
+ }
79896
+ },
79897
+ "description": "The saved filter."
79898
+ },
79899
+ "400": {
79900
+ "content": {
79901
+ "application/json": {
79902
+ "schema": {
79903
+ "$ref": "#/components/schemas/SavedFilterError"
79904
+ }
79905
+ }
79906
+ },
79907
+ "description": "Validation error — including a `query` that is not a valid request for the target's operation (`issues` lists each problem)."
79908
+ },
79909
+ "401": {
79910
+ "content": {
79911
+ "application/json": {
79912
+ "schema": {
79913
+ "$ref": "#/components/schemas/ErrorResponse"
79914
+ }
79915
+ }
79916
+ },
79917
+ "description": "Unauthorized"
79918
+ },
79919
+ "403": {
79920
+ "content": {
79921
+ "application/json": {
79922
+ "schema": {
79923
+ "$ref": "#/components/schemas/ErrorResponse"
79924
+ }
79925
+ }
79926
+ },
79927
+ "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
79928
+ },
79929
+ "404": {
79930
+ "content": {
79931
+ "application/json": {
79932
+ "schema": {
79933
+ "$ref": "#/components/schemas/ErrorResponse"
79934
+ }
79935
+ }
79936
+ },
79937
+ "description": "Not found"
79938
+ },
79939
+ "409": {
79940
+ "content": {
79941
+ "application/json": {
79942
+ "schema": {
79943
+ "$ref": "#/components/schemas/SavedFilterError"
79944
+ }
79945
+ }
79946
+ },
79947
+ "description": "`QUOTA_EXCEEDED` — 25 saved filters for this target already; update or delete one."
79948
+ },
79949
+ "413": {
79950
+ "content": {
79951
+ "application/json": {
79952
+ "schema": {
79953
+ "$ref": "#/components/schemas/PayloadTooLarge"
79954
+ }
79955
+ }
79956
+ },
79957
+ "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
79958
+ },
79959
+ "503": {
79960
+ "content": {
79961
+ "application/json": {
79962
+ "schema": {
79963
+ "$ref": "#/components/schemas/SearchUnavailable"
79964
+ }
79965
+ }
79966
+ },
79967
+ "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
79968
+ }
79969
+ },
79970
+ "summary": "Save a filter",
79971
+ "tags": [
79972
+ "Saved Filters"
79973
+ ]
79974
+ }
79975
+ },
79976
+ "/v1/saved-filters/{id}": {
79977
+ "delete": {
79978
+ "description": "Owner or workspace admin only; its shares go with it. A filter shared with you cannot be deleted by you.",
79979
+ "operationId": "deleteSavedFilter",
79980
+ "parameters": [
79981
+ {
79982
+ "description": "Saved-filter id (nanoid).",
79983
+ "in": "path",
79984
+ "name": "id",
79985
+ "required": true,
79986
+ "schema": {
79987
+ "description": "Saved-filter id (nanoid).",
79988
+ "example": "V1StGXR8_Z5jdHi6B-myT",
79989
+ "maxLength": 32,
79990
+ "minLength": 1,
79991
+ "pattern": "^[\\w-]+$",
79992
+ "type": "string"
79993
+ }
79994
+ }
79995
+ ],
79996
+ "responses": {
79997
+ "200": {
79998
+ "content": {
79999
+ "application/json": {
80000
+ "schema": {
80001
+ "$ref": "#/components/schemas/DeleteSavedFilterResult"
80002
+ }
80003
+ }
80004
+ },
80005
+ "description": "Deleted."
80006
+ },
80007
+ "400": {
80008
+ "content": {
80009
+ "application/json": {
80010
+ "schema": {
80011
+ "$ref": "#/components/schemas/ErrorResponse"
80012
+ }
80013
+ }
80014
+ },
80015
+ "description": "Validation error"
80016
+ },
80017
+ "401": {
80018
+ "content": {
80019
+ "application/json": {
80020
+ "schema": {
80021
+ "$ref": "#/components/schemas/ErrorResponse"
80022
+ }
80023
+ }
80024
+ },
80025
+ "description": "Unauthorized"
80026
+ },
80027
+ "403": {
80028
+ "content": {
80029
+ "application/json": {
80030
+ "schema": {
80031
+ "$ref": "#/components/schemas/SavedFilterError"
78392
80032
  }
78393
80033
  }
78394
80034
  },
78395
- "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
80035
+ "description": "No active organization, or (`code: FORBIDDEN`) the filter is shared with you at a level that does not allow this."
78396
80036
  },
78397
80037
  "404": {
78398
80038
  "content": {
78399
80039
  "application/json": {
78400
80040
  "schema": {
78401
- "$ref": "#/components/schemas/ErrorResponse"
80041
+ "$ref": "#/components/schemas/SavedFilterError"
78402
80042
  }
78403
80043
  }
78404
80044
  },
78405
- "description": "Not found"
80045
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
78406
80046
  },
78407
80047
  "413": {
78408
80048
  "content": {
@@ -78425,107 +80065,28 @@
78425
80065
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
78426
80066
  }
78427
80067
  },
78428
- "summary": "Count sales matching filters",
78429
- "tags": [
78430
- "Sales"
78431
- ],
78432
- "x-mm-records-via": "listSales"
78433
- }
78434
- },
78435
- "/v1/sales/{id}": {
78436
- "get": {
78437
- "operationId": "getSale",
78438
- "parameters": [
78439
- {
78440
- "description": "Sale document ID",
78441
- "in": "path",
78442
- "name": "id",
78443
- "required": true,
78444
- "schema": {
78445
- "description": "Sale document ID",
78446
- "type": "string"
78447
- }
78448
- }
78449
- ],
78450
- "responses": {
78451
- "200": {
78452
- "content": {
78453
- "application/json": {
78454
- "schema": {
78455
- "$ref": "#/components/schemas/SaleDetailResponse"
78456
- }
78457
- }
78458
- },
78459
- "description": "Sale detail"
78460
- },
78461
- "404": {
78462
- "content": {
78463
- "application/json": {
78464
- "schema": {
78465
- "$ref": "#/components/schemas/ErrorResponse"
78466
- }
78467
- }
78468
- },
78469
- "description": "Sale not found"
78470
- },
78471
- "413": {
78472
- "content": {
78473
- "application/json": {
78474
- "schema": {
78475
- "$ref": "#/components/schemas/PayloadTooLarge"
78476
- }
78477
- }
78478
- },
78479
- "description": "Response payload too large"
78480
- }
78481
- },
78482
- "summary": "Get sale by ID",
80068
+ "summary": "Delete a saved filter",
78483
80069
  "tags": [
78484
- "Sales"
80070
+ "Saved Filters"
78485
80071
  ]
78486
- }
78487
- },
78488
- "/v1/sales/{id}/related": {
80072
+ },
78489
80073
  "get": {
78490
- "description": "Return the ids of records of another type that are linked to this record. Links resolve by identifier, strongest identifier first, and equally-trusted identifiers are combined — a company's linked loans cover every role it holds on a loan, not just the first one found. The response reports which strength was used: `primary` is the canonical identifier for that pair, `secondary` is a real but weaker alternate used only when the record carries nothing better. This is a lightweight index: it returns ids and a count, not full records. For filtering, sorting, pagination and full detail, use the named endpoint for the pair (for example the originator loans endpoint) and fetch records by id.",
78491
- "operationId": "saleRelated",
80074
+ "description": "Returns the saved `query` and the `operationId` to run it with — your own filter or one shared with you. Check `fidelity` (`partial` → `unmapped` lists what the query omits; `ui_only` → nothing to run) and `stale` (the query no longer validates) before running.",
80075
+ "operationId": "getSavedFilter",
78492
80076
  "parameters": [
78493
80077
  {
78494
- "description": "Sale id",
80078
+ "description": "Saved-filter id (nanoid).",
78495
80079
  "in": "path",
78496
80080
  "name": "id",
78497
80081
  "required": true,
78498
80082
  "schema": {
78499
- "description": "Sale id",
78500
- "type": "string"
78501
- }
78502
- },
78503
- {
78504
- "description": "Type of record to link to",
78505
- "in": "query",
78506
- "name": "to",
78507
- "required": true,
78508
- "schema": {
78509
- "description": "Type of record to link to",
78510
- "enum": [
78511
- "agents",
78512
- "loans",
78513
- "properties"
78514
- ],
80083
+ "description": "Saved-filter id (nanoid).",
80084
+ "example": "V1StGXR8_Z5jdHi6B-myT",
80085
+ "maxLength": 32,
80086
+ "minLength": 1,
80087
+ "pattern": "^[\\w-]+$",
78515
80088
  "type": "string"
78516
80089
  }
78517
- },
78518
- {
78519
- "description": "Maximum ids to return (default 25, max 200)",
78520
- "in": "query",
78521
- "name": "limit",
78522
- "required": false,
78523
- "schema": {
78524
- "description": "Maximum ids to return (default 25, max 200)",
78525
- "maximum": 200,
78526
- "minimum": 1,
78527
- "type": "integer"
78528
- }
78529
80090
  }
78530
80091
  ],
78531
80092
  "responses": {
@@ -78533,11 +80094,11 @@
78533
80094
  "content": {
78534
80095
  "application/json": {
78535
80096
  "schema": {
78536
- "$ref": "#/components/schemas/RelatedResponse"
80097
+ "$ref": "#/components/schemas/GetSavedFilterResult"
78537
80098
  }
78538
80099
  }
78539
80100
  },
78540
- "description": "Linked record ids"
80101
+ "description": "The saved filter."
78541
80102
  },
78542
80103
  "400": {
78543
80104
  "content": {
@@ -78573,11 +80134,11 @@
78573
80134
  "content": {
78574
80135
  "application/json": {
78575
80136
  "schema": {
78576
- "$ref": "#/components/schemas/ErrorResponse"
80137
+ "$ref": "#/components/schemas/SavedFilterError"
78577
80138
  }
78578
80139
  }
78579
80140
  },
78580
- "description": "Record not found"
80141
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
78581
80142
  },
78582
80143
  "413": {
78583
80144
  "content": {
@@ -78600,74 +80161,59 @@
78600
80161
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
78601
80162
  }
78602
80163
  },
78603
- "summary": "Records linked to this one",
80164
+ "summary": "Get a saved filter (with the operation to run it)",
78604
80165
  "tags": [
78605
- "Related"
80166
+ "Saved Filters"
78606
80167
  ]
78607
- }
78608
- },
78609
- "/v1/saved-filters": {
78610
- "get": {
78611
- "description": "The caller's saved filters (and saved CRM views) in the active organization, oldest first, optionally narrowed by target and kind.",
78612
- "operationId": "listSavedFilters",
80168
+ },
80169
+ "patch": {
80170
+ "description": "Rename, re-icon, or replace the query / UI state (owner, `editor`, or workspace admin). The target is fixed. A new `query` is validated like on create. `visibility` / `orgWidePermission` change who can see it (owner or workspace admin only).",
80171
+ "operationId": "updateSavedFilter",
78613
80172
  "parameters": [
78614
80173
  {
78615
- "description": "Which list the filter runs against. Market targets run against that entity's list operation (see `operationId`, e.g. listOriginators); `crm_people` / `crm_companies` are UI-only (filtered client-side).",
78616
- "in": "query",
78617
- "name": "target",
78618
- "required": false,
78619
- "schema": {
78620
- "description": "Which list the filter runs against. Market targets run against that entity's list operation (see `operationId`, e.g. listOriginators); `crm_people` / `crm_companies` are UI-only (filtered client-side).",
78621
- "enum": [
78622
- "originators",
78623
- "agents",
78624
- "companies",
78625
- "branches",
78626
- "offices",
78627
- "loans",
78628
- "properties",
78629
- "sales",
78630
- "crm_people",
78631
- "crm_companies"
78632
- ],
78633
- "type": "string"
78634
- }
78635
- },
78636
- {
78637
- "description": "`filter` (default) — a saved search; `view` — a saved CRM table layout (columns / order) kept in `uiState`. Views never carry a `query` and have their own 25-per-target quota. Fixed at create.",
78638
- "in": "query",
78639
- "name": "kind",
78640
- "required": false,
80174
+ "description": "Saved-filter id (nanoid).",
80175
+ "in": "path",
80176
+ "name": "id",
80177
+ "required": true,
78641
80178
  "schema": {
78642
- "description": "`filter` (default) — a saved search; `view` — a saved CRM table layout (columns / order) kept in `uiState`. Views never carry a `query` and have their own 25-per-target quota. Fixed at create.",
78643
- "enum": [
78644
- "filter",
78645
- "view"
78646
- ],
80179
+ "description": "Saved-filter id (nanoid).",
80180
+ "example": "V1StGXR8_Z5jdHi6B-myT",
80181
+ "maxLength": 32,
80182
+ "minLength": 1,
80183
+ "pattern": "^[\\w-]+$",
78647
80184
  "type": "string"
78648
80185
  }
78649
80186
  }
78650
80187
  ],
80188
+ "requestBody": {
80189
+ "content": {
80190
+ "application/json": {
80191
+ "schema": {
80192
+ "$ref": "#/components/schemas/UpdateSavedFilterRequest"
80193
+ }
80194
+ }
80195
+ }
80196
+ },
78651
80197
  "responses": {
78652
80198
  "200": {
78653
80199
  "content": {
78654
80200
  "application/json": {
78655
80201
  "schema": {
78656
- "$ref": "#/components/schemas/SavedFilterList"
80202
+ "$ref": "#/components/schemas/UpdateSavedFilterResult"
78657
80203
  }
78658
80204
  }
78659
80205
  },
78660
- "description": "Saved filters."
80206
+ "description": "The updated filter."
78661
80207
  },
78662
80208
  "400": {
78663
80209
  "content": {
78664
80210
  "application/json": {
78665
80211
  "schema": {
78666
- "$ref": "#/components/schemas/ErrorResponse"
80212
+ "$ref": "#/components/schemas/SavedFilterError"
78667
80213
  }
78668
80214
  }
78669
80215
  },
78670
- "description": "Validation error"
80216
+ "description": "Validation error — including a `query` that is not a valid request for the target's operation (`issues` lists each problem)."
78671
80217
  },
78672
80218
  "401": {
78673
80219
  "content": {
@@ -78683,21 +80229,21 @@
78683
80229
  "content": {
78684
80230
  "application/json": {
78685
80231
  "schema": {
78686
- "$ref": "#/components/schemas/ErrorResponse"
80232
+ "$ref": "#/components/schemas/SavedFilterError"
78687
80233
  }
78688
80234
  }
78689
80235
  },
78690
- "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
80236
+ "description": "No active organization, or (`code: FORBIDDEN`) the filter is shared with you at a level that does not allow this."
78691
80237
  },
78692
80238
  "404": {
78693
80239
  "content": {
78694
80240
  "application/json": {
78695
80241
  "schema": {
78696
- "$ref": "#/components/schemas/ErrorResponse"
80242
+ "$ref": "#/components/schemas/SavedFilterError"
78697
80243
  }
78698
80244
  }
78699
80245
  },
78700
- "description": "Not found"
80246
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
78701
80247
  },
78702
80248
  "413": {
78703
80249
  "content": {
@@ -78720,43 +80266,52 @@
78720
80266
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
78721
80267
  }
78722
80268
  },
78723
- "summary": "List your saved filters",
80269
+ "summary": "Update a saved filter",
78724
80270
  "tags": [
78725
80271
  "Saved Filters"
78726
80272
  ]
78727
- },
78728
- "post": {
78729
- "description": "Save a named filter for a list target. For a market target, `query` is the target operation's request body without `pagination` (e.g. the body you would send to listOriginators) and is validated against it. Limit: 25 per target.",
78730
- "operationId": "createSavedFilter",
78731
- "requestBody": {
78732
- "content": {
78733
- "application/json": {
78734
- "schema": {
78735
- "$ref": "#/components/schemas/CreateSavedFilterRequest"
78736
- }
80273
+ }
80274
+ },
80275
+ "/v1/saved-filters/{id}/shareable-members": {
80276
+ "get": {
80277
+ "description": "Owner or workspace admin only. Every member of the workspace, the owner and existing shares included — subtract them for the picker.",
80278
+ "operationId": "listSavedFilterShareableMembers",
80279
+ "parameters": [
80280
+ {
80281
+ "description": "Saved-filter id (nanoid).",
80282
+ "in": "path",
80283
+ "name": "id",
80284
+ "required": true,
80285
+ "schema": {
80286
+ "description": "Saved-filter id (nanoid).",
80287
+ "example": "V1StGXR8_Z5jdHi6B-myT",
80288
+ "maxLength": 32,
80289
+ "minLength": 1,
80290
+ "pattern": "^[\\w-]+$",
80291
+ "type": "string"
78737
80292
  }
78738
80293
  }
78739
- },
80294
+ ],
78740
80295
  "responses": {
78741
- "201": {
80296
+ "200": {
78742
80297
  "content": {
78743
80298
  "application/json": {
78744
80299
  "schema": {
78745
- "$ref": "#/components/schemas/CreateSavedFilterResult"
80300
+ "$ref": "#/components/schemas/SavedFilterShareableMemberList"
78746
80301
  }
78747
80302
  }
78748
80303
  },
78749
- "description": "The saved filter."
80304
+ "description": "The workspace roster."
78750
80305
  },
78751
80306
  "400": {
78752
80307
  "content": {
78753
80308
  "application/json": {
78754
80309
  "schema": {
78755
- "$ref": "#/components/schemas/SavedFilterError"
80310
+ "$ref": "#/components/schemas/ErrorResponse"
78756
80311
  }
78757
80312
  }
78758
80313
  },
78759
- "description": "Validation error — including a `query` that is not a valid request for the target's operation (`issues` lists each problem)."
80314
+ "description": "Validation error"
78760
80315
  },
78761
80316
  "401": {
78762
80317
  "content": {
@@ -78772,41 +80327,41 @@
78772
80327
  "content": {
78773
80328
  "application/json": {
78774
80329
  "schema": {
78775
- "$ref": "#/components/schemas/ErrorResponse"
80330
+ "$ref": "#/components/schemas/SavedFilterError"
78776
80331
  }
78777
80332
  }
78778
80333
  },
78779
- "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
80334
+ "description": "No active organization, or (`code: FORBIDDEN`) the filter is shared with you at a level that does not allow this."
78780
80335
  },
78781
80336
  "404": {
78782
80337
  "content": {
78783
80338
  "application/json": {
78784
80339
  "schema": {
78785
- "$ref": "#/components/schemas/ErrorResponse"
80340
+ "$ref": "#/components/schemas/SavedFilterError"
78786
80341
  }
78787
80342
  }
78788
80343
  },
78789
- "description": "Not found"
80344
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
78790
80345
  },
78791
- "409": {
80346
+ "413": {
78792
80347
  "content": {
78793
80348
  "application/json": {
78794
80349
  "schema": {
78795
- "$ref": "#/components/schemas/SavedFilterError"
80350
+ "$ref": "#/components/schemas/PayloadTooLarge"
78796
80351
  }
78797
80352
  }
78798
80353
  },
78799
- "description": "`QUOTA_EXCEEDED` — 25 saved filters for this target already; update or delete one."
80354
+ "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
78800
80355
  },
78801
- "413": {
80356
+ "502": {
78802
80357
  "content": {
78803
80358
  "application/json": {
78804
80359
  "schema": {
78805
- "$ref": "#/components/schemas/PayloadTooLarge"
80360
+ "$ref": "#/components/schemas/ErrorResponse"
78806
80361
  }
78807
80362
  }
78808
80363
  },
78809
- "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
80364
+ "description": "Workspace members could not be read (auth service unavailable)."
78810
80365
  },
78811
80366
  "503": {
78812
80367
  "content": {
@@ -78819,15 +80374,16 @@
78819
80374
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
78820
80375
  }
78821
80376
  },
78822
- "summary": "Save a filter",
80377
+ "summary": "List the workspace members a saved filter can be shared with",
78823
80378
  "tags": [
78824
80379
  "Saved Filters"
78825
80380
  ]
78826
80381
  }
78827
80382
  },
78828
- "/v1/saved-filters/{id}": {
80383
+ "/v1/saved-filters/{id}/shares": {
78829
80384
  "delete": {
78830
- "operationId": "deleteSavedFilter",
80385
+ "description": "Owner or workspace admin only. Removes that member's share; a no-op (`revoked: false`) when there was none.",
80386
+ "operationId": "revokeSavedFilterAccess",
78831
80387
  "parameters": [
78832
80388
  {
78833
80389
  "description": "Saved-filter id (nanoid).",
@@ -78844,16 +80400,25 @@
78844
80400
  }
78845
80401
  }
78846
80402
  ],
80403
+ "requestBody": {
80404
+ "content": {
80405
+ "application/json": {
80406
+ "schema": {
80407
+ "$ref": "#/components/schemas/RevokeSavedFilterAccessRequest"
80408
+ }
80409
+ }
80410
+ }
80411
+ },
78847
80412
  "responses": {
78848
80413
  "200": {
78849
80414
  "content": {
78850
80415
  "application/json": {
78851
80416
  "schema": {
78852
- "$ref": "#/components/schemas/DeleteSavedFilterResult"
80417
+ "$ref": "#/components/schemas/RevokeSavedFilterAccessResult"
78853
80418
  }
78854
80419
  }
78855
80420
  },
78856
- "description": "Deleted."
80421
+ "description": "Whether a share was removed."
78857
80422
  },
78858
80423
  "400": {
78859
80424
  "content": {
@@ -78879,11 +80444,11 @@
78879
80444
  "content": {
78880
80445
  "application/json": {
78881
80446
  "schema": {
78882
- "$ref": "#/components/schemas/ErrorResponse"
80447
+ "$ref": "#/components/schemas/SavedFilterError"
78883
80448
  }
78884
80449
  }
78885
80450
  },
78886
- "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
80451
+ "description": "No active organization, or (`code: FORBIDDEN`) the filter is shared with you at a level that does not allow this."
78887
80452
  },
78888
80453
  "404": {
78889
80454
  "content": {
@@ -78893,7 +80458,7 @@
78893
80458
  }
78894
80459
  }
78895
80460
  },
78896
- "description": "No saved filter with that id belongs to the caller."
80461
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
78897
80462
  },
78898
80463
  "413": {
78899
80464
  "content": {
@@ -78916,14 +80481,14 @@
78916
80481
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
78917
80482
  }
78918
80483
  },
78919
- "summary": "Delete a saved filter",
80484
+ "summary": "Stop sharing a saved filter with a member",
78920
80485
  "tags": [
78921
80486
  "Saved Filters"
78922
80487
  ]
78923
80488
  },
78924
80489
  "get": {
78925
- "description": "Returns the saved `query` and the `operationId` to run it with. Check `fidelity` (`partial` → `unmapped` lists what the query omits; `ui_only` → nothing to run) and `stale` (the query no longer validates) before running.",
78926
- "operationId": "getSavedFilter",
80490
+ "description": "Visibility, owner, the workspace-wide role and every per-user share. Readable by the owner, an `editor`, or a workspace admin.",
80491
+ "operationId": "getSavedFilterShares",
78927
80492
  "parameters": [
78928
80493
  {
78929
80494
  "description": "Saved-filter id (nanoid).",
@@ -78945,11 +80510,11 @@
78945
80510
  "content": {
78946
80511
  "application/json": {
78947
80512
  "schema": {
78948
- "$ref": "#/components/schemas/GetSavedFilterResult"
80513
+ "$ref": "#/components/schemas/GetSavedFilterSharesResult"
78949
80514
  }
78950
80515
  }
78951
80516
  },
78952
- "description": "The saved filter."
80517
+ "description": "The filter's sharing state."
78953
80518
  },
78954
80519
  "400": {
78955
80520
  "content": {
@@ -78975,11 +80540,11 @@
78975
80540
  "content": {
78976
80541
  "application/json": {
78977
80542
  "schema": {
78978
- "$ref": "#/components/schemas/ErrorResponse"
80543
+ "$ref": "#/components/schemas/SavedFilterError"
78979
80544
  }
78980
80545
  }
78981
80546
  },
78982
- "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
80547
+ "description": "No active organization, or (`code: FORBIDDEN`) the filter is shared with you at a level that does not allow this."
78983
80548
  },
78984
80549
  "404": {
78985
80550
  "content": {
@@ -78989,7 +80554,7 @@
78989
80554
  }
78990
80555
  }
78991
80556
  },
78992
- "description": "No saved filter with that id belongs to the caller."
80557
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
78993
80558
  },
78994
80559
  "413": {
78995
80560
  "content": {
@@ -79001,6 +80566,16 @@
79001
80566
  },
79002
80567
  "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
79003
80568
  },
80569
+ "502": {
80570
+ "content": {
80571
+ "application/json": {
80572
+ "schema": {
80573
+ "$ref": "#/components/schemas/ErrorResponse"
80574
+ }
80575
+ }
80576
+ },
80577
+ "description": "Workspace members could not be read (auth service unavailable)."
80578
+ },
79004
80579
  "503": {
79005
80580
  "content": {
79006
80581
  "application/json": {
@@ -79012,14 +80587,14 @@
79012
80587
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
79013
80588
  }
79014
80589
  },
79015
- "summary": "Get a saved filter (with the operation to run it)",
80590
+ "summary": "Get who a saved filter is shared with",
79016
80591
  "tags": [
79017
80592
  "Saved Filters"
79018
80593
  ]
79019
80594
  },
79020
- "patch": {
79021
- "description": "Rename, re-icon, or replace the query / UI state. The target is fixed. A new `query` is validated like on create.",
79022
- "operationId": "updateSavedFilter",
80595
+ "post": {
80596
+ "description": "Owner or workspace admin only. Re-sharing updates the member's role. Sharing a private filter makes it `shared`. Sharing with the owner is a no-op (`granted: false`).",
80597
+ "operationId": "grantSavedFilterAccess",
79023
80598
  "parameters": [
79024
80599
  {
79025
80600
  "description": "Saved-filter id (nanoid).",
@@ -79040,7 +80615,7 @@
79040
80615
  "content": {
79041
80616
  "application/json": {
79042
80617
  "schema": {
79043
- "$ref": "#/components/schemas/UpdateSavedFilterRequest"
80618
+ "$ref": "#/components/schemas/GrantSavedFilterAccessRequest"
79044
80619
  }
79045
80620
  }
79046
80621
  }
@@ -79050,11 +80625,11 @@
79050
80625
  "content": {
79051
80626
  "application/json": {
79052
80627
  "schema": {
79053
- "$ref": "#/components/schemas/UpdateSavedFilterResult"
80628
+ "$ref": "#/components/schemas/GrantSavedFilterAccessResult"
79054
80629
  }
79055
80630
  }
79056
80631
  },
79057
- "description": "The updated filter."
80632
+ "description": "Whether a new share was created (false when an existing one was updated)."
79058
80633
  },
79059
80634
  "400": {
79060
80635
  "content": {
@@ -79064,7 +80639,7 @@
79064
80639
  }
79065
80640
  }
79066
80641
  },
79067
- "description": "Validation error — including a `query` that is not a valid request for the target's operation (`issues` lists each problem)."
80642
+ "description": "Validation error, or (`code: NOT_ORG_MEMBER`) the user is not a member of your workspace."
79068
80643
  },
79069
80644
  "401": {
79070
80645
  "content": {
@@ -79080,11 +80655,11 @@
79080
80655
  "content": {
79081
80656
  "application/json": {
79082
80657
  "schema": {
79083
- "$ref": "#/components/schemas/ErrorResponse"
80658
+ "$ref": "#/components/schemas/SavedFilterError"
79084
80659
  }
79085
80660
  }
79086
80661
  },
79087
- "description": "Forbidden (authenticated, but missing required context — e.g. no active organization)"
80662
+ "description": "No active organization, or (`code: FORBIDDEN`) the filter is shared with you at a level that does not allow this."
79088
80663
  },
79089
80664
  "404": {
79090
80665
  "content": {
@@ -79094,7 +80669,7 @@
79094
80669
  }
79095
80670
  }
79096
80671
  },
79097
- "description": "No saved filter with that id belongs to the caller."
80672
+ "description": "No saved filter with that id is visible to the caller (their own, or shared with them)."
79098
80673
  },
79099
80674
  "413": {
79100
80675
  "content": {
@@ -79106,6 +80681,16 @@
79106
80681
  },
79107
80682
  "description": "Response payload too large — detail endpoint capped to fit Lambda response limits"
79108
80683
  },
80684
+ "502": {
80685
+ "content": {
80686
+ "application/json": {
80687
+ "schema": {
80688
+ "$ref": "#/components/schemas/ErrorResponse"
80689
+ }
80690
+ }
80691
+ },
80692
+ "description": "Workspace members could not be read (auth service unavailable)."
80693
+ },
79109
80694
  "503": {
79110
80695
  "content": {
79111
80696
  "application/json": {
@@ -79117,7 +80702,7 @@
79117
80702
  "description": "Search timed out or the cluster is overloaded — retry after `Retry-After` seconds."
79118
80703
  }
79119
80704
  },
79120
- "summary": "Update a saved filter",
80705
+ "summary": "Share a saved filter with a workspace member",
79121
80706
  "tags": [
79122
80707
  "Saved Filters"
79123
80708
  ]