@wevion/cli 1.0.3384 → 1.0.3391

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 (2) hide show
  1. package/openapi.json +2566 -647
  2. package/package.json +1 -1
package/openapi.json CHANGED
@@ -4613,7 +4613,7 @@
4613
4613
  "tags": [
4614
4614
  "ad-creatives"
4615
4615
  ],
4616
- "description": "Fetches creative details for an ad from Meta API, including thumbnail, image, video source, and full picture. Falls back to DB-stored thumbnail if the API call fails. Shape tracks Meta Graph v25.0 and tolerates additional pass-through fields.",
4616
+ "description": "Fetches creative details for an ad from Meta API, including thumbnail, image, video source, and full picture. For video creatives it also mirrors the video node's read-only `is_ai_generated` flag as `meta_ai_recognized` (present only when Meta reports it; absent means unknown, not \"not AI\"). Falls back to DB-stored thumbnail if the API call fails. Shape tracks Meta Graph v25.0 and tolerates additional pass-through fields.",
4617
4617
  "parameters": [
4618
4618
  {
4619
4619
  "schema": {
@@ -4711,6 +4711,9 @@
4711
4711
  "video_proxy_url": {
4712
4712
  "type": "string"
4713
4713
  },
4714
+ "meta_ai_recognized": {
4715
+ "type": "boolean"
4716
+ },
4714
4717
  "call_to_action_type": {
4715
4718
  "type": "string"
4716
4719
  },
@@ -10816,7 +10819,7 @@
10816
10819
  "tags": [
10817
10820
  "ai-suggestions"
10818
10821
  ],
10819
- "description": "Approves a visible proactive suggestion and dispatches its action when it is executable.",
10822
+ "description": "Approves a visible proactive suggestion and dispatches its action when it is executable. Refused with 423 while WAVO autonomy is stopped (kill-switch down or paused) and with 403 when the caller is below the approver floor; `code` names which gate refused.",
10820
10823
  "parameters": [
10821
10824
  {
10822
10825
  "schema": {
@@ -10978,6 +10981,33 @@
10978
10981
  }
10979
10982
  }
10980
10983
  }
10984
+ },
10985
+ "423": {
10986
+ "description": "Response 423",
10987
+ "content": {
10988
+ "application/json": {
10989
+ "schema": {
10990
+ "type": "object",
10991
+ "required": [
10992
+ "error"
10993
+ ],
10994
+ "properties": {
10995
+ "statusCode": {
10996
+ "type": "integer"
10997
+ },
10998
+ "error": {
10999
+ "type": "string"
11000
+ },
11001
+ "message": {
11002
+ "type": "string"
11003
+ },
11004
+ "code": {
11005
+ "type": "string"
11006
+ }
11007
+ }
11008
+ }
11009
+ }
11010
+ }
10981
11011
  }
10982
11012
  }
10983
11013
  }
@@ -32734,6 +32764,7 @@
32734
32764
  "current_period_end",
32735
32765
  "trial_start",
32736
32766
  "trial_end",
32767
+ "trial_eligible",
32737
32768
  "cancel_at_period_end",
32738
32769
  "extra_user_slots",
32739
32770
  "is_read_only",
@@ -32809,6 +32840,9 @@
32809
32840
  }
32810
32841
  ]
32811
32842
  },
32843
+ "trial_eligible": {
32844
+ "type": "boolean"
32845
+ },
32812
32846
  "cancel_at_period_end": {
32813
32847
  "type": "boolean"
32814
32848
  },
@@ -33001,7 +33035,8 @@
33001
33035
  "allow_cross_platform",
33002
33036
  "allow_api_access",
33003
33037
  "ai_models_tier",
33004
- "has_trial"
33038
+ "has_trial",
33039
+ "trial_days"
33005
33040
  ],
33006
33041
  "properties": {
33007
33042
  "id": {
@@ -33171,6 +33206,9 @@
33171
33206
  "has_trial": {
33172
33207
  "type": "boolean"
33173
33208
  },
33209
+ "trial_days": {
33210
+ "type": "number"
33211
+ },
33174
33212
  "max_api_keys": {
33175
33213
  "anyOf": [
33176
33214
  {
@@ -33333,7 +33371,8 @@
33333
33371
  "allow_cross_platform",
33334
33372
  "allow_api_access",
33335
33373
  "ai_models_tier",
33336
- "has_trial"
33374
+ "has_trial",
33375
+ "trial_days"
33337
33376
  ],
33338
33377
  "properties": {
33339
33378
  "id": {
@@ -33503,6 +33542,9 @@
33503
33542
  "has_trial": {
33504
33543
  "type": "boolean"
33505
33544
  },
33545
+ "trial_days": {
33546
+ "type": "number"
33547
+ },
33506
33548
  "max_api_keys": {
33507
33549
  "anyOf": [
33508
33550
  {
@@ -46879,6 +46921,16 @@
46879
46921
  "additionalProperties": false,
46880
46922
  "type": "object",
46881
46923
  "properties": {
46924
+ "aiGenerated": {
46925
+ "anyOf": [
46926
+ {
46927
+ "type": "boolean"
46928
+ },
46929
+ {
46930
+ "type": "null"
46931
+ }
46932
+ ]
46933
+ },
46882
46934
  "cardDescription": {
46883
46935
  "anyOf": [
46884
46936
  {
@@ -47163,6 +47215,16 @@
47163
47215
  "additionalProperties": false,
47164
47216
  "type": "object",
47165
47217
  "properties": {
47218
+ "aiGenerated": {
47219
+ "anyOf": [
47220
+ {
47221
+ "type": "boolean"
47222
+ },
47223
+ {
47224
+ "type": "null"
47225
+ }
47226
+ ]
47227
+ },
47166
47228
  "cardDescription": {
47167
47229
  "anyOf": [
47168
47230
  {
@@ -47449,245 +47511,265 @@
47449
47511
  "additionalProperties": false,
47450
47512
  "type": "object",
47451
47513
  "properties": {
47452
- "cardDescription": {
47453
- "anyOf": [
47454
- {
47455
- "type": "string"
47456
- },
47457
- {
47458
- "type": "null"
47459
- }
47460
- ]
47461
- },
47462
- "cardHeadline": {
47463
- "anyOf": [
47464
- {
47465
- "type": "string"
47466
- },
47467
- {
47468
- "type": "null"
47469
- }
47470
- ]
47471
- },
47472
- "crops": {
47473
- "anyOf": [
47474
- {
47475
- "additionalProperties": false,
47476
- "type": "object",
47477
- "properties": {
47478
- "100x100": {
47479
- "anyOf": [
47480
- {
47481
- "minItems": 2,
47482
- "maxItems": 2,
47483
- "type": "array",
47484
- "items": {
47485
- "minItems": 2,
47486
- "maxItems": 2,
47487
- "type": "array",
47488
- "items": {
47489
- "type": "number"
47490
- }
47491
- }
47492
- },
47493
- {
47494
- "type": "null"
47495
- }
47496
- ]
47497
- },
47498
- "191x100": {
47499
- "anyOf": [
47500
- {
47501
- "minItems": 2,
47502
- "maxItems": 2,
47503
- "type": "array",
47504
- "items": {
47505
- "minItems": 2,
47506
- "maxItems": 2,
47507
- "type": "array",
47508
- "items": {
47509
- "type": "number"
47510
- }
47511
- }
47512
- },
47513
- {
47514
- "type": "null"
47515
- }
47516
- ]
47517
- },
47518
- "400x500": {
47519
- "anyOf": [
47520
- {
47521
- "minItems": 2,
47522
- "maxItems": 2,
47523
- "type": "array",
47524
- "items": {
47525
- "minItems": 2,
47526
- "maxItems": 2,
47527
- "type": "array",
47528
- "items": {
47529
- "type": "number"
47530
- }
47531
- }
47532
- },
47533
- {
47534
- "type": "null"
47535
- }
47536
- ]
47537
- }
47538
- }
47539
- },
47540
- {
47541
- "type": "null"
47542
- }
47543
- ]
47544
- },
47545
- "duration": {
47546
- "anyOf": [
47547
- {
47548
- "type": "number"
47549
- },
47550
- {
47551
- "type": "null"
47552
- }
47553
- ]
47554
- },
47555
- "fileSizeBytes": {
47556
- "anyOf": [
47557
- {
47558
- "type": "number"
47559
- },
47560
- {
47561
- "type": "null"
47562
- }
47563
- ]
47564
- },
47565
- "height": {
47566
- "anyOf": [
47567
- {
47568
- "type": "number"
47569
- },
47570
- {
47571
- "type": "null"
47572
- }
47573
- ]
47574
- },
47575
- "metaHash": {
47514
+ "aiGenerated": {
47576
47515
  "anyOf": [
47577
47516
  {
47578
- "type": "string"
47517
+ "type": "boolean"
47518
+ },
47519
+ {
47520
+ "type": "null"
47521
+ }
47522
+ ]
47523
+ },
47524
+ "cardDescription": {
47525
+ "anyOf": [
47526
+ {
47527
+ "type": "string"
47528
+ },
47529
+ {
47530
+ "type": "null"
47531
+ }
47532
+ ]
47533
+ },
47534
+ "cardHeadline": {
47535
+ "anyOf": [
47536
+ {
47537
+ "type": "string"
47538
+ },
47539
+ {
47540
+ "type": "null"
47541
+ }
47542
+ ]
47543
+ },
47544
+ "crops": {
47545
+ "anyOf": [
47546
+ {
47547
+ "additionalProperties": false,
47548
+ "type": "object",
47549
+ "properties": {
47550
+ "100x100": {
47551
+ "anyOf": [
47552
+ {
47553
+ "minItems": 2,
47554
+ "maxItems": 2,
47555
+ "type": "array",
47556
+ "items": {
47557
+ "minItems": 2,
47558
+ "maxItems": 2,
47559
+ "type": "array",
47560
+ "items": {
47561
+ "type": "number"
47562
+ }
47563
+ }
47564
+ },
47565
+ {
47566
+ "type": "null"
47567
+ }
47568
+ ]
47569
+ },
47570
+ "191x100": {
47571
+ "anyOf": [
47572
+ {
47573
+ "minItems": 2,
47574
+ "maxItems": 2,
47575
+ "type": "array",
47576
+ "items": {
47577
+ "minItems": 2,
47578
+ "maxItems": 2,
47579
+ "type": "array",
47580
+ "items": {
47581
+ "type": "number"
47582
+ }
47583
+ }
47584
+ },
47585
+ {
47586
+ "type": "null"
47587
+ }
47588
+ ]
47589
+ },
47590
+ "400x500": {
47591
+ "anyOf": [
47592
+ {
47593
+ "minItems": 2,
47594
+ "maxItems": 2,
47595
+ "type": "array",
47596
+ "items": {
47597
+ "minItems": 2,
47598
+ "maxItems": 2,
47599
+ "type": "array",
47600
+ "items": {
47601
+ "type": "number"
47602
+ }
47603
+ }
47604
+ },
47605
+ {
47606
+ "type": "null"
47607
+ }
47608
+ ]
47609
+ }
47610
+ }
47611
+ },
47612
+ {
47613
+ "type": "null"
47614
+ }
47615
+ ]
47616
+ },
47617
+ "duration": {
47618
+ "anyOf": [
47619
+ {
47620
+ "type": "number"
47621
+ },
47622
+ {
47623
+ "type": "null"
47624
+ }
47625
+ ]
47626
+ },
47627
+ "fileSizeBytes": {
47628
+ "anyOf": [
47629
+ {
47630
+ "type": "number"
47631
+ },
47632
+ {
47633
+ "type": "null"
47634
+ }
47635
+ ]
47636
+ },
47637
+ "height": {
47638
+ "anyOf": [
47639
+ {
47640
+ "type": "number"
47641
+ },
47642
+ {
47643
+ "type": "null"
47644
+ }
47645
+ ]
47646
+ },
47647
+ "metaHash": {
47648
+ "anyOf": [
47649
+ {
47650
+ "type": "string"
47651
+ },
47652
+ {
47653
+ "type": "null"
47654
+ }
47655
+ ]
47656
+ },
47657
+ "metaVideoId": {
47658
+ "anyOf": [
47659
+ {
47660
+ "type": "string"
47661
+ },
47662
+ {
47663
+ "type": "null"
47664
+ }
47665
+ ]
47666
+ },
47667
+ "snapchatMediaId": {
47668
+ "anyOf": [
47669
+ {
47670
+ "type": "string"
47671
+ },
47672
+ {
47673
+ "type": "null"
47674
+ }
47675
+ ]
47676
+ },
47677
+ "sourceUrl": {
47678
+ "anyOf": [
47679
+ {
47680
+ "type": "string"
47681
+ },
47682
+ {
47683
+ "type": "null"
47684
+ }
47685
+ ]
47686
+ },
47687
+ "thumbnailUrl": {
47688
+ "anyOf": [
47689
+ {
47690
+ "type": "string"
47691
+ },
47692
+ {
47693
+ "type": "null"
47694
+ }
47695
+ ]
47696
+ },
47697
+ "tiktokVideoId": {
47698
+ "anyOf": [
47699
+ {
47700
+ "type": "string"
47701
+ },
47702
+ {
47703
+ "type": "null"
47704
+ }
47705
+ ]
47706
+ },
47707
+ "type": {
47708
+ "anyOf": [
47709
+ {
47710
+ "anyOf": [
47711
+ {
47712
+ "type": "string",
47713
+ "enum": [
47714
+ "image"
47715
+ ]
47716
+ },
47717
+ {
47718
+ "type": "string",
47719
+ "enum": [
47720
+ "video"
47721
+ ]
47722
+ }
47723
+ ]
47724
+ },
47725
+ {
47726
+ "type": "null"
47727
+ }
47728
+ ]
47729
+ },
47730
+ "videoId": {
47731
+ "anyOf": [
47732
+ {
47733
+ "type": "string"
47734
+ },
47735
+ {
47736
+ "type": "null"
47737
+ }
47738
+ ]
47739
+ },
47740
+ "width": {
47741
+ "anyOf": [
47742
+ {
47743
+ "type": "number"
47744
+ },
47745
+ {
47746
+ "type": "null"
47747
+ }
47748
+ ]
47749
+ }
47750
+ }
47751
+ },
47752
+ {
47753
+ "type": "null"
47754
+ }
47755
+ ]
47756
+ },
47757
+ "story": {
47758
+ "anyOf": [
47759
+ {
47760
+ "additionalProperties": false,
47761
+ "type": "object",
47762
+ "properties": {
47763
+ "aiGenerated": {
47764
+ "anyOf": [
47765
+ {
47766
+ "type": "boolean"
47579
47767
  },
47580
47768
  {
47581
47769
  "type": "null"
47582
47770
  }
47583
47771
  ]
47584
47772
  },
47585
- "metaVideoId": {
47586
- "anyOf": [
47587
- {
47588
- "type": "string"
47589
- },
47590
- {
47591
- "type": "null"
47592
- }
47593
- ]
47594
- },
47595
- "snapchatMediaId": {
47596
- "anyOf": [
47597
- {
47598
- "type": "string"
47599
- },
47600
- {
47601
- "type": "null"
47602
- }
47603
- ]
47604
- },
47605
- "sourceUrl": {
47606
- "anyOf": [
47607
- {
47608
- "type": "string"
47609
- },
47610
- {
47611
- "type": "null"
47612
- }
47613
- ]
47614
- },
47615
- "thumbnailUrl": {
47616
- "anyOf": [
47617
- {
47618
- "type": "string"
47619
- },
47620
- {
47621
- "type": "null"
47622
- }
47623
- ]
47624
- },
47625
- "tiktokVideoId": {
47626
- "anyOf": [
47627
- {
47628
- "type": "string"
47629
- },
47630
- {
47631
- "type": "null"
47632
- }
47633
- ]
47634
- },
47635
- "type": {
47636
- "anyOf": [
47637
- {
47638
- "anyOf": [
47639
- {
47640
- "type": "string",
47641
- "enum": [
47642
- "image"
47643
- ]
47644
- },
47645
- {
47646
- "type": "string",
47647
- "enum": [
47648
- "video"
47649
- ]
47650
- }
47651
- ]
47652
- },
47653
- {
47654
- "type": "null"
47655
- }
47656
- ]
47657
- },
47658
- "videoId": {
47659
- "anyOf": [
47660
- {
47661
- "type": "string"
47662
- },
47663
- {
47664
- "type": "null"
47665
- }
47666
- ]
47667
- },
47668
- "width": {
47669
- "anyOf": [
47670
- {
47671
- "type": "number"
47672
- },
47673
- {
47674
- "type": "null"
47675
- }
47676
- ]
47677
- }
47678
- }
47679
- },
47680
- {
47681
- "type": "null"
47682
- }
47683
- ]
47684
- },
47685
- "story": {
47686
- "anyOf": [
47687
- {
47688
- "additionalProperties": false,
47689
- "type": "object",
47690
- "properties": {
47691
47773
  "cardDescription": {
47692
47774
  "anyOf": [
47693
47775
  {
@@ -48012,6 +48094,16 @@
48012
48094
  "additionalProperties": false,
48013
48095
  "type": "object",
48014
48096
  "properties": {
48097
+ "aiGenerated": {
48098
+ "anyOf": [
48099
+ {
48100
+ "type": "boolean"
48101
+ },
48102
+ {
48103
+ "type": "null"
48104
+ }
48105
+ ]
48106
+ },
48015
48107
  "cardDescription": {
48016
48108
  "anyOf": [
48017
48109
  {
@@ -49268,6 +49360,19 @@
49268
49360
  }
49269
49361
  ]
49270
49362
  },
49363
+ "locales": {
49364
+ "anyOf": [
49365
+ {
49366
+ "type": "array",
49367
+ "items": {
49368
+ "type": "number"
49369
+ }
49370
+ },
49371
+ {
49372
+ "type": "null"
49373
+ }
49374
+ ]
49375
+ },
49271
49376
  "locations": {
49272
49377
  "anyOf": [
49273
49378
  {
@@ -51220,6 +51325,16 @@
51220
51325
  "additionalProperties": false,
51221
51326
  "type": "object",
51222
51327
  "properties": {
51328
+ "aiGenerated": {
51329
+ "anyOf": [
51330
+ {
51331
+ "type": "boolean"
51332
+ },
51333
+ {
51334
+ "type": "null"
51335
+ }
51336
+ ]
51337
+ },
51223
51338
  "cardDescription": {
51224
51339
  "anyOf": [
51225
51340
  {
@@ -51504,6 +51619,16 @@
51504
51619
  "additionalProperties": false,
51505
51620
  "type": "object",
51506
51621
  "properties": {
51622
+ "aiGenerated": {
51623
+ "anyOf": [
51624
+ {
51625
+ "type": "boolean"
51626
+ },
51627
+ {
51628
+ "type": "null"
51629
+ }
51630
+ ]
51631
+ },
51507
51632
  "cardDescription": {
51508
51633
  "anyOf": [
51509
51634
  {
@@ -51790,6 +51915,16 @@
51790
51915
  "additionalProperties": false,
51791
51916
  "type": "object",
51792
51917
  "properties": {
51918
+ "aiGenerated": {
51919
+ "anyOf": [
51920
+ {
51921
+ "type": "boolean"
51922
+ },
51923
+ {
51924
+ "type": "null"
51925
+ }
51926
+ ]
51927
+ },
51793
51928
  "cardDescription": {
51794
51929
  "anyOf": [
51795
51930
  {
@@ -52029,6 +52164,16 @@
52029
52164
  "additionalProperties": false,
52030
52165
  "type": "object",
52031
52166
  "properties": {
52167
+ "aiGenerated": {
52168
+ "anyOf": [
52169
+ {
52170
+ "type": "boolean"
52171
+ },
52172
+ {
52173
+ "type": "null"
52174
+ }
52175
+ ]
52176
+ },
52032
52177
  "cardDescription": {
52033
52178
  "anyOf": [
52034
52179
  {
@@ -52353,6 +52498,16 @@
52353
52498
  "additionalProperties": false,
52354
52499
  "type": "object",
52355
52500
  "properties": {
52501
+ "aiGenerated": {
52502
+ "anyOf": [
52503
+ {
52504
+ "type": "boolean"
52505
+ },
52506
+ {
52507
+ "type": "null"
52508
+ }
52509
+ ]
52510
+ },
52356
52511
  "cardDescription": {
52357
52512
  "anyOf": [
52358
52513
  {
@@ -53609,6 +53764,19 @@
53609
53764
  }
53610
53765
  ]
53611
53766
  },
53767
+ "locales": {
53768
+ "anyOf": [
53769
+ {
53770
+ "type": "array",
53771
+ "items": {
53772
+ "type": "number"
53773
+ }
53774
+ },
53775
+ {
53776
+ "type": "null"
53777
+ }
53778
+ ]
53779
+ },
53612
53780
  "locations": {
53613
53781
  "anyOf": [
53614
53782
  {
@@ -55462,6 +55630,16 @@
55462
55630
  "additionalProperties": false,
55463
55631
  "type": "object",
55464
55632
  "properties": {
55633
+ "aiGenerated": {
55634
+ "anyOf": [
55635
+ {
55636
+ "type": "boolean"
55637
+ },
55638
+ {
55639
+ "type": "null"
55640
+ }
55641
+ ]
55642
+ },
55465
55643
  "cardDescription": {
55466
55644
  "anyOf": [
55467
55645
  {
@@ -55746,6 +55924,16 @@
55746
55924
  "additionalProperties": false,
55747
55925
  "type": "object",
55748
55926
  "properties": {
55927
+ "aiGenerated": {
55928
+ "anyOf": [
55929
+ {
55930
+ "type": "boolean"
55931
+ },
55932
+ {
55933
+ "type": "null"
55934
+ }
55935
+ ]
55936
+ },
55749
55937
  "cardDescription": {
55750
55938
  "anyOf": [
55751
55939
  {
@@ -56032,245 +56220,265 @@
56032
56220
  "additionalProperties": false,
56033
56221
  "type": "object",
56034
56222
  "properties": {
56035
- "cardDescription": {
56036
- "anyOf": [
56037
- {
56038
- "type": "string"
56039
- },
56040
- {
56041
- "type": "null"
56042
- }
56043
- ]
56044
- },
56045
- "cardHeadline": {
56223
+ "aiGenerated": {
56046
56224
  "anyOf": [
56047
56225
  {
56048
- "type": "string"
56226
+ "type": "boolean"
56227
+ },
56228
+ {
56229
+ "type": "null"
56230
+ }
56231
+ ]
56232
+ },
56233
+ "cardDescription": {
56234
+ "anyOf": [
56235
+ {
56236
+ "type": "string"
56237
+ },
56238
+ {
56239
+ "type": "null"
56240
+ }
56241
+ ]
56242
+ },
56243
+ "cardHeadline": {
56244
+ "anyOf": [
56245
+ {
56246
+ "type": "string"
56247
+ },
56248
+ {
56249
+ "type": "null"
56250
+ }
56251
+ ]
56252
+ },
56253
+ "crops": {
56254
+ "anyOf": [
56255
+ {
56256
+ "additionalProperties": false,
56257
+ "type": "object",
56258
+ "properties": {
56259
+ "100x100": {
56260
+ "anyOf": [
56261
+ {
56262
+ "minItems": 2,
56263
+ "maxItems": 2,
56264
+ "type": "array",
56265
+ "items": {
56266
+ "minItems": 2,
56267
+ "maxItems": 2,
56268
+ "type": "array",
56269
+ "items": {
56270
+ "type": "number"
56271
+ }
56272
+ }
56273
+ },
56274
+ {
56275
+ "type": "null"
56276
+ }
56277
+ ]
56278
+ },
56279
+ "191x100": {
56280
+ "anyOf": [
56281
+ {
56282
+ "minItems": 2,
56283
+ "maxItems": 2,
56284
+ "type": "array",
56285
+ "items": {
56286
+ "minItems": 2,
56287
+ "maxItems": 2,
56288
+ "type": "array",
56289
+ "items": {
56290
+ "type": "number"
56291
+ }
56292
+ }
56293
+ },
56294
+ {
56295
+ "type": "null"
56296
+ }
56297
+ ]
56298
+ },
56299
+ "400x500": {
56300
+ "anyOf": [
56301
+ {
56302
+ "minItems": 2,
56303
+ "maxItems": 2,
56304
+ "type": "array",
56305
+ "items": {
56306
+ "minItems": 2,
56307
+ "maxItems": 2,
56308
+ "type": "array",
56309
+ "items": {
56310
+ "type": "number"
56311
+ }
56312
+ }
56313
+ },
56314
+ {
56315
+ "type": "null"
56316
+ }
56317
+ ]
56318
+ }
56319
+ }
56320
+ },
56321
+ {
56322
+ "type": "null"
56323
+ }
56324
+ ]
56325
+ },
56326
+ "duration": {
56327
+ "anyOf": [
56328
+ {
56329
+ "type": "number"
56330
+ },
56331
+ {
56332
+ "type": "null"
56333
+ }
56334
+ ]
56335
+ },
56336
+ "fileSizeBytes": {
56337
+ "anyOf": [
56338
+ {
56339
+ "type": "number"
56340
+ },
56341
+ {
56342
+ "type": "null"
56343
+ }
56344
+ ]
56345
+ },
56346
+ "height": {
56347
+ "anyOf": [
56348
+ {
56349
+ "type": "number"
56350
+ },
56351
+ {
56352
+ "type": "null"
56353
+ }
56354
+ ]
56355
+ },
56356
+ "metaHash": {
56357
+ "anyOf": [
56358
+ {
56359
+ "type": "string"
56360
+ },
56361
+ {
56362
+ "type": "null"
56363
+ }
56364
+ ]
56365
+ },
56366
+ "metaVideoId": {
56367
+ "anyOf": [
56368
+ {
56369
+ "type": "string"
56370
+ },
56371
+ {
56372
+ "type": "null"
56373
+ }
56374
+ ]
56375
+ },
56376
+ "snapchatMediaId": {
56377
+ "anyOf": [
56378
+ {
56379
+ "type": "string"
56380
+ },
56381
+ {
56382
+ "type": "null"
56383
+ }
56384
+ ]
56385
+ },
56386
+ "sourceUrl": {
56387
+ "anyOf": [
56388
+ {
56389
+ "type": "string"
56390
+ },
56391
+ {
56392
+ "type": "null"
56393
+ }
56394
+ ]
56395
+ },
56396
+ "thumbnailUrl": {
56397
+ "anyOf": [
56398
+ {
56399
+ "type": "string"
56400
+ },
56401
+ {
56402
+ "type": "null"
56403
+ }
56404
+ ]
56405
+ },
56406
+ "tiktokVideoId": {
56407
+ "anyOf": [
56408
+ {
56409
+ "type": "string"
56410
+ },
56411
+ {
56412
+ "type": "null"
56413
+ }
56414
+ ]
56415
+ },
56416
+ "type": {
56417
+ "anyOf": [
56418
+ {
56419
+ "anyOf": [
56420
+ {
56421
+ "type": "string",
56422
+ "enum": [
56423
+ "image"
56424
+ ]
56425
+ },
56426
+ {
56427
+ "type": "string",
56428
+ "enum": [
56429
+ "video"
56430
+ ]
56431
+ }
56432
+ ]
56433
+ },
56434
+ {
56435
+ "type": "null"
56436
+ }
56437
+ ]
56438
+ },
56439
+ "videoId": {
56440
+ "anyOf": [
56441
+ {
56442
+ "type": "string"
56443
+ },
56444
+ {
56445
+ "type": "null"
56446
+ }
56447
+ ]
56448
+ },
56449
+ "width": {
56450
+ "anyOf": [
56451
+ {
56452
+ "type": "number"
56453
+ },
56454
+ {
56455
+ "type": "null"
56456
+ }
56457
+ ]
56458
+ }
56459
+ }
56460
+ },
56461
+ {
56462
+ "type": "null"
56463
+ }
56464
+ ]
56465
+ },
56466
+ "story": {
56467
+ "anyOf": [
56468
+ {
56469
+ "additionalProperties": false,
56470
+ "type": "object",
56471
+ "properties": {
56472
+ "aiGenerated": {
56473
+ "anyOf": [
56474
+ {
56475
+ "type": "boolean"
56049
56476
  },
56050
56477
  {
56051
56478
  "type": "null"
56052
56479
  }
56053
56480
  ]
56054
56481
  },
56055
- "crops": {
56056
- "anyOf": [
56057
- {
56058
- "additionalProperties": false,
56059
- "type": "object",
56060
- "properties": {
56061
- "100x100": {
56062
- "anyOf": [
56063
- {
56064
- "minItems": 2,
56065
- "maxItems": 2,
56066
- "type": "array",
56067
- "items": {
56068
- "minItems": 2,
56069
- "maxItems": 2,
56070
- "type": "array",
56071
- "items": {
56072
- "type": "number"
56073
- }
56074
- }
56075
- },
56076
- {
56077
- "type": "null"
56078
- }
56079
- ]
56080
- },
56081
- "191x100": {
56082
- "anyOf": [
56083
- {
56084
- "minItems": 2,
56085
- "maxItems": 2,
56086
- "type": "array",
56087
- "items": {
56088
- "minItems": 2,
56089
- "maxItems": 2,
56090
- "type": "array",
56091
- "items": {
56092
- "type": "number"
56093
- }
56094
- }
56095
- },
56096
- {
56097
- "type": "null"
56098
- }
56099
- ]
56100
- },
56101
- "400x500": {
56102
- "anyOf": [
56103
- {
56104
- "minItems": 2,
56105
- "maxItems": 2,
56106
- "type": "array",
56107
- "items": {
56108
- "minItems": 2,
56109
- "maxItems": 2,
56110
- "type": "array",
56111
- "items": {
56112
- "type": "number"
56113
- }
56114
- }
56115
- },
56116
- {
56117
- "type": "null"
56118
- }
56119
- ]
56120
- }
56121
- }
56122
- },
56123
- {
56124
- "type": "null"
56125
- }
56126
- ]
56127
- },
56128
- "duration": {
56129
- "anyOf": [
56130
- {
56131
- "type": "number"
56132
- },
56133
- {
56134
- "type": "null"
56135
- }
56136
- ]
56137
- },
56138
- "fileSizeBytes": {
56139
- "anyOf": [
56140
- {
56141
- "type": "number"
56142
- },
56143
- {
56144
- "type": "null"
56145
- }
56146
- ]
56147
- },
56148
- "height": {
56149
- "anyOf": [
56150
- {
56151
- "type": "number"
56152
- },
56153
- {
56154
- "type": "null"
56155
- }
56156
- ]
56157
- },
56158
- "metaHash": {
56159
- "anyOf": [
56160
- {
56161
- "type": "string"
56162
- },
56163
- {
56164
- "type": "null"
56165
- }
56166
- ]
56167
- },
56168
- "metaVideoId": {
56169
- "anyOf": [
56170
- {
56171
- "type": "string"
56172
- },
56173
- {
56174
- "type": "null"
56175
- }
56176
- ]
56177
- },
56178
- "snapchatMediaId": {
56179
- "anyOf": [
56180
- {
56181
- "type": "string"
56182
- },
56183
- {
56184
- "type": "null"
56185
- }
56186
- ]
56187
- },
56188
- "sourceUrl": {
56189
- "anyOf": [
56190
- {
56191
- "type": "string"
56192
- },
56193
- {
56194
- "type": "null"
56195
- }
56196
- ]
56197
- },
56198
- "thumbnailUrl": {
56199
- "anyOf": [
56200
- {
56201
- "type": "string"
56202
- },
56203
- {
56204
- "type": "null"
56205
- }
56206
- ]
56207
- },
56208
- "tiktokVideoId": {
56209
- "anyOf": [
56210
- {
56211
- "type": "string"
56212
- },
56213
- {
56214
- "type": "null"
56215
- }
56216
- ]
56217
- },
56218
- "type": {
56219
- "anyOf": [
56220
- {
56221
- "anyOf": [
56222
- {
56223
- "type": "string",
56224
- "enum": [
56225
- "image"
56226
- ]
56227
- },
56228
- {
56229
- "type": "string",
56230
- "enum": [
56231
- "video"
56232
- ]
56233
- }
56234
- ]
56235
- },
56236
- {
56237
- "type": "null"
56238
- }
56239
- ]
56240
- },
56241
- "videoId": {
56242
- "anyOf": [
56243
- {
56244
- "type": "string"
56245
- },
56246
- {
56247
- "type": "null"
56248
- }
56249
- ]
56250
- },
56251
- "width": {
56252
- "anyOf": [
56253
- {
56254
- "type": "number"
56255
- },
56256
- {
56257
- "type": "null"
56258
- }
56259
- ]
56260
- }
56261
- }
56262
- },
56263
- {
56264
- "type": "null"
56265
- }
56266
- ]
56267
- },
56268
- "story": {
56269
- "anyOf": [
56270
- {
56271
- "additionalProperties": false,
56272
- "type": "object",
56273
- "properties": {
56274
56482
  "cardDescription": {
56275
56483
  "anyOf": [
56276
56484
  {
@@ -56595,6 +56803,16 @@
56595
56803
  "additionalProperties": false,
56596
56804
  "type": "object",
56597
56805
  "properties": {
56806
+ "aiGenerated": {
56807
+ "anyOf": [
56808
+ {
56809
+ "type": "boolean"
56810
+ },
56811
+ {
56812
+ "type": "null"
56813
+ }
56814
+ ]
56815
+ },
56598
56816
  "cardDescription": {
56599
56817
  "anyOf": [
56600
56818
  {
@@ -57851,6 +58069,19 @@
57851
58069
  }
57852
58070
  ]
57853
58071
  },
58072
+ "locales": {
58073
+ "anyOf": [
58074
+ {
58075
+ "type": "array",
58076
+ "items": {
58077
+ "type": "number"
58078
+ }
58079
+ },
58080
+ {
58081
+ "type": "null"
58082
+ }
58083
+ ]
58084
+ },
57854
58085
  "locations": {
57855
58086
  "anyOf": [
57856
58087
  {
@@ -63389,6 +63620,16 @@
63389
63620
  "additionalProperties": false,
63390
63621
  "type": "object",
63391
63622
  "properties": {
63623
+ "aiGenerated": {
63624
+ "anyOf": [
63625
+ {
63626
+ "type": "boolean"
63627
+ },
63628
+ {
63629
+ "type": "null"
63630
+ }
63631
+ ]
63632
+ },
63392
63633
  "cardDescription": {
63393
63634
  "anyOf": [
63394
63635
  {
@@ -63673,6 +63914,16 @@
63673
63914
  "additionalProperties": false,
63674
63915
  "type": "object",
63675
63916
  "properties": {
63917
+ "aiGenerated": {
63918
+ "anyOf": [
63919
+ {
63920
+ "type": "boolean"
63921
+ },
63922
+ {
63923
+ "type": "null"
63924
+ }
63925
+ ]
63926
+ },
63676
63927
  "cardDescription": {
63677
63928
  "anyOf": [
63678
63929
  {
@@ -63959,6 +64210,16 @@
63959
64210
  "additionalProperties": false,
63960
64211
  "type": "object",
63961
64212
  "properties": {
64213
+ "aiGenerated": {
64214
+ "anyOf": [
64215
+ {
64216
+ "type": "boolean"
64217
+ },
64218
+ {
64219
+ "type": "null"
64220
+ }
64221
+ ]
64222
+ },
63962
64223
  "cardDescription": {
63963
64224
  "anyOf": [
63964
64225
  {
@@ -64198,6 +64459,16 @@
64198
64459
  "additionalProperties": false,
64199
64460
  "type": "object",
64200
64461
  "properties": {
64462
+ "aiGenerated": {
64463
+ "anyOf": [
64464
+ {
64465
+ "type": "boolean"
64466
+ },
64467
+ {
64468
+ "type": "null"
64469
+ }
64470
+ ]
64471
+ },
64201
64472
  "cardDescription": {
64202
64473
  "anyOf": [
64203
64474
  {
@@ -64522,6 +64793,16 @@
64522
64793
  "additionalProperties": false,
64523
64794
  "type": "object",
64524
64795
  "properties": {
64796
+ "aiGenerated": {
64797
+ "anyOf": [
64798
+ {
64799
+ "type": "boolean"
64800
+ },
64801
+ {
64802
+ "type": "null"
64803
+ }
64804
+ ]
64805
+ },
64525
64806
  "cardDescription": {
64526
64807
  "anyOf": [
64527
64808
  {
@@ -65778,6 +66059,19 @@
65778
66059
  }
65779
66060
  ]
65780
66061
  },
66062
+ "locales": {
66063
+ "anyOf": [
66064
+ {
66065
+ "type": "array",
66066
+ "items": {
66067
+ "type": "number"
66068
+ }
66069
+ },
66070
+ {
66071
+ "type": "null"
66072
+ }
66073
+ ]
66074
+ },
65781
66075
  "locations": {
65782
66076
  "anyOf": [
65783
66077
  {
@@ -89410,19 +89704,33 @@
89410
89704
  "key",
89411
89705
  "label",
89412
89706
  "available",
89707
+ "allowed_by_plan",
89708
+ "available_now",
89413
89709
  "default"
89414
89710
  ],
89415
89711
  "properties": {
89416
89712
  "key": {
89713
+ "description": "Opaque capability mode: fast | smart | expert.",
89417
89714
  "type": "string"
89418
89715
  },
89419
89716
  "label": {
89717
+ "description": "Human-readable label for the mode.",
89420
89718
  "type": "string"
89421
89719
  },
89422
89720
  "available": {
89721
+ "description": "DEPRECATED legacy field, now `allowed_by_plan && available_now` — i.e. the mode is usable. Read allowed_by_plan (upsell) and available_now (temporary unavailability) instead: this single boolean cannot say WHICH of the two failed.",
89722
+ "type": "boolean"
89723
+ },
89724
+ "allowed_by_plan": {
89725
+ "description": "Whether the caller plan unlocks the mode. false → upsell.",
89726
+ "type": "boolean"
89727
+ },
89728
+ "available_now": {
89729
+ "description": "Whether the mode can run right now (its lane is configured and not switched off). false → temporary unavailability, not an upgrade prompt.",
89423
89730
  "type": "boolean"
89424
89731
  },
89425
89732
  "default": {
89733
+ "description": "Whether this is the default mode.",
89426
89734
  "type": "boolean"
89427
89735
  }
89428
89736
  }
@@ -102718,231 +103026,1022 @@
102718
103026
  "schema": {
102719
103027
  "type": "object",
102720
103028
  "required": [
102721
- "error"
103029
+ "error"
103030
+ ],
103031
+ "properties": {
103032
+ "code": {
103033
+ "type": "string"
103034
+ },
103035
+ "error": {
103036
+ "type": "string"
103037
+ },
103038
+ "message": {
103039
+ "type": "string"
103040
+ }
103041
+ }
103042
+ }
103043
+ }
103044
+ }
103045
+ },
103046
+ "404": {
103047
+ "description": "Resource not found",
103048
+ "content": {
103049
+ "application/json": {
103050
+ "schema": {
103051
+ "type": "object",
103052
+ "required": [
103053
+ "error"
103054
+ ],
103055
+ "properties": {
103056
+ "code": {
103057
+ "type": "string"
103058
+ },
103059
+ "error": {
103060
+ "type": "string"
103061
+ },
103062
+ "message": {
103063
+ "type": "string"
103064
+ }
103065
+ }
103066
+ }
103067
+ }
103068
+ }
103069
+ },
103070
+ "429": {
103071
+ "description": "Too many requests - rate limit exceeded",
103072
+ "content": {
103073
+ "application/json": {
103074
+ "schema": {
103075
+ "type": "object",
103076
+ "required": [
103077
+ "error"
103078
+ ],
103079
+ "properties": {
103080
+ "code": {
103081
+ "type": "string"
103082
+ },
103083
+ "error": {
103084
+ "type": "string"
103085
+ },
103086
+ "message": {
103087
+ "type": "string"
103088
+ }
103089
+ }
103090
+ }
103091
+ }
103092
+ }
103093
+ }
103094
+ }
103095
+ }
103096
+ },
103097
+ "/api/v1/competitive-intelligence/search-page": {
103098
+ "get": {
103099
+ "operationId": "getApiV1CompetitiveIntelligenceSearchPage",
103100
+ "summary": "Search competitor Meta pages",
103101
+ "tags": [
103102
+ "competitive-intelligence"
103103
+ ],
103104
+ "description": "Search Meta Ad Library pages to add a trackable competitor. Accepts an exact page name, a numeric Meta page ID, or a facebook.com URL carrying the page ID; countries scope which ad-delivery markets are searched.",
103105
+ "parameters": [
103106
+ {
103107
+ "schema": {
103108
+ "type": "array",
103109
+ "items": {
103110
+ "type": "string"
103111
+ }
103112
+ },
103113
+ "in": "query",
103114
+ "name": "countries",
103115
+ "required": false
103116
+ },
103117
+ {
103118
+ "schema": {
103119
+ "minLength": 1,
103120
+ "maxLength": 300,
103121
+ "type": "string"
103122
+ },
103123
+ "in": "query",
103124
+ "name": "q",
103125
+ "required": true
103126
+ }
103127
+ ],
103128
+ "security": [
103129
+ {
103130
+ "bearerAuth": []
103131
+ },
103132
+ {
103133
+ "apiKeyAuth": []
103134
+ }
103135
+ ],
103136
+ "responses": {
103137
+ "200": {
103138
+ "description": "Successful response",
103139
+ "content": {
103140
+ "application/json": {
103141
+ "schema": {
103142
+ "type": "object",
103143
+ "required": [
103144
+ "items"
103145
+ ],
103146
+ "properties": {
103147
+ "items": {
103148
+ "type": "array",
103149
+ "items": {
103150
+ "type": "object",
103151
+ "required": [
103152
+ "ad_count",
103153
+ "page_id",
103154
+ "page_name",
103155
+ "source"
103156
+ ],
103157
+ "properties": {
103158
+ "ad_count": {
103159
+ "type": "number"
103160
+ },
103161
+ "page_id": {
103162
+ "type": "string"
103163
+ },
103164
+ "page_name": {
103165
+ "type": "string"
103166
+ },
103167
+ "source": {
103168
+ "type": "string"
103169
+ }
103170
+ }
103171
+ }
103172
+ }
103173
+ }
103174
+ }
103175
+ }
103176
+ }
103177
+ },
103178
+ "400": {
103179
+ "description": "Invalid request - schema validation failed",
103180
+ "content": {
103181
+ "application/json": {
103182
+ "schema": {
103183
+ "type": "object",
103184
+ "required": [
103185
+ "error"
103186
+ ],
103187
+ "properties": {
103188
+ "code": {
103189
+ "type": "string"
103190
+ },
103191
+ "error": {
103192
+ "type": "string"
103193
+ },
103194
+ "message": {
103195
+ "type": "string"
103196
+ }
103197
+ }
103198
+ }
103199
+ }
103200
+ }
103201
+ },
103202
+ "401": {
103203
+ "description": "Unauthorized - missing or invalid bearer token",
103204
+ "content": {
103205
+ "application/json": {
103206
+ "schema": {
103207
+ "$ref": "#/components/schemas/ErrorResponse"
103208
+ }
103209
+ }
103210
+ }
103211
+ },
103212
+ "403": {
103213
+ "description": "Forbidden - caller lacks the required role/permission",
103214
+ "content": {
103215
+ "application/json": {
103216
+ "schema": {
103217
+ "type": "object",
103218
+ "required": [
103219
+ "error"
103220
+ ],
103221
+ "properties": {
103222
+ "code": {
103223
+ "type": "string"
103224
+ },
103225
+ "error": {
103226
+ "type": "string"
103227
+ },
103228
+ "message": {
103229
+ "type": "string"
103230
+ }
103231
+ }
103232
+ }
103233
+ }
103234
+ }
103235
+ },
103236
+ "404": {
103237
+ "description": "Resource not found",
103238
+ "content": {
103239
+ "application/json": {
103240
+ "schema": {
103241
+ "type": "object",
103242
+ "required": [
103243
+ "error"
103244
+ ],
103245
+ "properties": {
103246
+ "code": {
103247
+ "type": "string"
103248
+ },
103249
+ "error": {
103250
+ "type": "string"
103251
+ },
103252
+ "message": {
103253
+ "type": "string"
103254
+ }
103255
+ }
103256
+ }
103257
+ }
103258
+ }
103259
+ }
103260
+ }
103261
+ }
103262
+ },
103263
+ "/api/v1/creative-ai-register": {
103264
+ "get": {
103265
+ "operationId": "creativeAiRegisterList",
103266
+ "summary": "List the AI-creatives register",
103267
+ "tags": [
103268
+ "creative-hub",
103269
+ "ai-register"
103270
+ ],
103271
+ "description": "Lists the workspace AI-creatives register required by EU AI Act art. 50(2) traceability: Creative Hub library assets (generated, uploaded, imported) with their AI classification and provenance evidence, plus the caller's own completed AI generation jobs, from the chat and the legacy hub endpoints (media transforms — resize, background removal — and Creatomate composite renders of user footage are not generations and are excluded). `is_ai_generated` is tri-state — NULL means unknown, never human-made. Use the /export sibling for the CSV attachment.",
103272
+ "parameters": [
103273
+ {
103274
+ "schema": {
103275
+ "minimum": 1,
103276
+ "maximum": 100,
103277
+ "default": 1,
103278
+ "type": "integer"
103279
+ },
103280
+ "in": "query",
103281
+ "name": "page",
103282
+ "required": false,
103283
+ "description": "1-based page index."
103284
+ },
103285
+ {
103286
+ "schema": {
103287
+ "minimum": 1,
103288
+ "maximum": 200,
103289
+ "default": 50,
103290
+ "type": "integer"
103291
+ },
103292
+ "in": "query",
103293
+ "name": "page_size",
103294
+ "required": false,
103295
+ "description": "Rows per page."
103296
+ },
103297
+ {
103298
+ "schema": {
103299
+ "default": "all",
103300
+ "anyOf": [
103301
+ {
103302
+ "type": "string",
103303
+ "enum": [
103304
+ "all"
103305
+ ]
103306
+ },
103307
+ {
103308
+ "type": "string",
103309
+ "enum": [
103310
+ "ai"
103311
+ ]
103312
+ },
103313
+ {
103314
+ "type": "string",
103315
+ "enum": [
103316
+ "unknown"
103317
+ ]
103318
+ }
103319
+ ]
103320
+ },
103321
+ "in": "query",
103322
+ "name": "classified",
103323
+ "required": false,
103324
+ "description": "Classification slice: `ai` = classified as AI-generated, `unknown` = still unclassified assets (chat jobs are excluded, they are AI by construction), `all` = everything."
103325
+ }
103326
+ ],
103327
+ "security": [
103328
+ {
103329
+ "bearerAuth": []
103330
+ },
103331
+ {
103332
+ "apiKeyAuth": []
103333
+ }
103334
+ ],
103335
+ "responses": {
103336
+ "200": {
103337
+ "description": "Successful response",
103338
+ "content": {
103339
+ "application/json": {
103340
+ "schema": {
103341
+ "additionalProperties": false,
103342
+ "type": "object",
103343
+ "required": [
103344
+ "items",
103345
+ "total",
103346
+ "page",
103347
+ "page_size"
103348
+ ],
103349
+ "properties": {
103350
+ "items": {
103351
+ "type": "array",
103352
+ "items": {
103353
+ "additionalProperties": false,
103354
+ "type": "object",
103355
+ "required": [
103356
+ "id",
103357
+ "entry_type",
103358
+ "kind",
103359
+ "name",
103360
+ "prompt",
103361
+ "url",
103362
+ "result_urls",
103363
+ "provider",
103364
+ "source",
103365
+ "is_ai_generated",
103366
+ "ai_provenance",
103367
+ "generation_id",
103368
+ "created_at"
103369
+ ],
103370
+ "properties": {
103371
+ "id": {
103372
+ "description": "Row id: creative_asset.id or creative_job.id.",
103373
+ "type": "string"
103374
+ },
103375
+ "entry_type": {
103376
+ "description": "Origin table: `asset` = Creative Hub library asset, `generation_job` = completed AI generation job (chat or legacy hub).",
103377
+ "anyOf": [
103378
+ {
103379
+ "type": "string",
103380
+ "enum": [
103381
+ "asset"
103382
+ ]
103383
+ },
103384
+ {
103385
+ "type": "string",
103386
+ "enum": [
103387
+ "generation_job"
103388
+ ]
103389
+ }
103390
+ ]
103391
+ },
103392
+ "kind": {
103393
+ "description": "Media kind (asset.kind) or generation type (job.type).",
103394
+ "type": "string"
103395
+ },
103396
+ "name": {
103397
+ "description": "Asset name; always null for generation jobs.",
103398
+ "anyOf": [
103399
+ {
103400
+ "type": "string"
103401
+ },
103402
+ {
103403
+ "type": "null"
103404
+ }
103405
+ ]
103406
+ },
103407
+ "prompt": {
103408
+ "description": "Generation prompt of a job, truncated to 300 characters. Null for assets.",
103409
+ "anyOf": [
103410
+ {
103411
+ "type": "string"
103412
+ },
103413
+ {
103414
+ "type": "null"
103415
+ }
103416
+ ]
103417
+ },
103418
+ "url": {
103419
+ "description": "Primary media URL.",
103420
+ "anyOf": [
103421
+ {
103422
+ "type": "string"
103423
+ },
103424
+ {
103425
+ "type": "null"
103426
+ }
103427
+ ]
103428
+ },
103429
+ "result_urls": {
103430
+ "description": "Every media URL produced by the row.",
103431
+ "type": "array",
103432
+ "items": {
103433
+ "type": "string"
103434
+ }
103435
+ },
103436
+ "provider": {
103437
+ "description": "AI provider that produced the media.",
103438
+ "anyOf": [
103439
+ {
103440
+ "type": "string"
103441
+ },
103442
+ {
103443
+ "type": "null"
103444
+ }
103445
+ ]
103446
+ },
103447
+ "source": {
103448
+ "description": "Asset source (`generated` | `uploaded` | `imported`), or the job origin: `chat` (AI chat) | `creative_hub` (legacy hub generate endpoints).",
103449
+ "anyOf": [
103450
+ {
103451
+ "type": "string"
103452
+ },
103453
+ {
103454
+ "type": "null"
103455
+ }
103456
+ ]
103457
+ },
103458
+ "is_ai_generated": {
103459
+ "description": "AI Act classification. NULL = unknown (no marker found); it never means \"human-made\".",
103460
+ "anyOf": [
103461
+ {
103462
+ "type": "boolean"
103463
+ },
103464
+ {
103465
+ "type": "null"
103466
+ }
103467
+ ]
103468
+ },
103469
+ "ai_provenance": {
103470
+ "description": "JSON object with nested arrays and objects.",
103471
+ "type": "object",
103472
+ "additionalProperties": {
103473
+ "$comment": "json-value",
103474
+ "description": "Arbitrary JSON value with nested arrays and objects."
103475
+ }
103476
+ },
103477
+ "generation_id": {
103478
+ "description": "Wevion generation this asset came from. Non-null rows are immutable AI facts.",
103479
+ "anyOf": [
103480
+ {
103481
+ "type": "string"
103482
+ },
103483
+ {
103484
+ "type": "null"
103485
+ }
103486
+ ]
103487
+ },
103488
+ "created_at": {
103489
+ "format": "date-time",
103490
+ "description": "Creation timestamp (ISO 8601).",
103491
+ "type": "string"
103492
+ }
103493
+ }
103494
+ }
103495
+ },
103496
+ "total": {
103497
+ "description": "Total rows matching the filter across both sources.",
103498
+ "type": "integer"
103499
+ },
103500
+ "page": {
103501
+ "description": "Requested page (1-based).",
103502
+ "type": "integer"
103503
+ },
103504
+ "page_size": {
103505
+ "description": "Requested page size.",
103506
+ "type": "integer"
103507
+ }
103508
+ }
103509
+ }
103510
+ }
103511
+ }
103512
+ },
103513
+ "400": {
103514
+ "description": "Invalid request - schema validation failed",
103515
+ "content": {
103516
+ "application/json": {
103517
+ "schema": {
103518
+ "type": "object",
103519
+ "required": [
103520
+ "statusCode",
103521
+ "error",
103522
+ "message"
103523
+ ],
103524
+ "properties": {
103525
+ "statusCode": {
103526
+ "type": "integer"
103527
+ },
103528
+ "error": {
103529
+ "type": "string"
103530
+ },
103531
+ "message": {
103532
+ "type": "string"
103533
+ },
103534
+ "code": {
103535
+ "type": "string"
103536
+ },
103537
+ "request_id": {
103538
+ "type": "string"
103539
+ },
103540
+ "details": {
103541
+ "type": "object",
103542
+ "additionalProperties": {}
103543
+ }
103544
+ }
103545
+ }
103546
+ }
103547
+ }
103548
+ },
103549
+ "401": {
103550
+ "description": "Unauthorized - missing or invalid bearer token",
103551
+ "content": {
103552
+ "application/json": {
103553
+ "schema": {
103554
+ "$ref": "#/components/schemas/ErrorResponse"
103555
+ }
103556
+ }
103557
+ }
103558
+ },
103559
+ "403": {
103560
+ "description": "Forbidden - caller lacks the required role/permission",
103561
+ "content": {
103562
+ "application/json": {
103563
+ "schema": {
103564
+ "type": "object",
103565
+ "required": [
103566
+ "statusCode",
103567
+ "error",
103568
+ "message"
103569
+ ],
103570
+ "properties": {
103571
+ "statusCode": {
103572
+ "type": "integer"
103573
+ },
103574
+ "error": {
103575
+ "type": "string"
103576
+ },
103577
+ "message": {
103578
+ "type": "string"
103579
+ },
103580
+ "code": {
103581
+ "type": "string"
103582
+ },
103583
+ "request_id": {
103584
+ "type": "string"
103585
+ },
103586
+ "details": {
103587
+ "type": "object",
103588
+ "additionalProperties": {}
103589
+ }
103590
+ }
103591
+ }
103592
+ }
103593
+ }
103594
+ },
103595
+ "404": {
103596
+ "description": "Resource not found",
103597
+ "content": {
103598
+ "application/json": {
103599
+ "schema": {
103600
+ "type": "object",
103601
+ "required": [
103602
+ "statusCode",
103603
+ "error",
103604
+ "message"
103605
+ ],
103606
+ "properties": {
103607
+ "statusCode": {
103608
+ "type": "integer"
103609
+ },
103610
+ "error": {
103611
+ "type": "string"
103612
+ },
103613
+ "message": {
103614
+ "type": "string"
103615
+ },
103616
+ "code": {
103617
+ "type": "string"
103618
+ },
103619
+ "request_id": {
103620
+ "type": "string"
103621
+ },
103622
+ "details": {
103623
+ "type": "object",
103624
+ "additionalProperties": {}
103625
+ }
103626
+ }
103627
+ }
103628
+ }
103629
+ }
103630
+ }
103631
+ }
103632
+ }
103633
+ },
103634
+ "/api/v1/creative-ai-register/export": {
103635
+ "get": {
103636
+ "operationId": "creativeAiRegisterExport",
103637
+ "summary": "Export the AI-creatives register as CSV",
103638
+ "tags": [
103639
+ "creative-hub",
103640
+ "ai-register"
103641
+ ],
103642
+ "description": "Same rows as the register list (newest first, up to the newest 5000), as a `text/csv` attachment. Formula-leading cells are prefixed to neutralise spreadsheet formula injection.",
103643
+ "parameters": [
103644
+ {
103645
+ "schema": {
103646
+ "default": "all",
103647
+ "anyOf": [
103648
+ {
103649
+ "type": "string",
103650
+ "enum": [
103651
+ "all"
103652
+ ]
103653
+ },
103654
+ {
103655
+ "type": "string",
103656
+ "enum": [
103657
+ "ai"
103658
+ ]
103659
+ },
103660
+ {
103661
+ "type": "string",
103662
+ "enum": [
103663
+ "unknown"
103664
+ ]
103665
+ }
103666
+ ]
103667
+ },
103668
+ "in": "query",
103669
+ "name": "classified",
103670
+ "required": false,
103671
+ "description": "Classification slice: `ai` = classified as AI-generated, `unknown` = still unclassified assets (chat jobs are excluded, they are AI by construction), `all` = everything."
103672
+ }
103673
+ ],
103674
+ "security": [
103675
+ {
103676
+ "bearerAuth": []
103677
+ },
103678
+ {
103679
+ "apiKeyAuth": []
103680
+ }
103681
+ ],
103682
+ "responses": {
103683
+ "200": {
103684
+ "description": "CSV file content",
103685
+ "content": {
103686
+ "application/json": {
103687
+ "schema": {
103688
+ "description": "CSV file content",
103689
+ "type": "string"
103690
+ }
103691
+ }
103692
+ }
103693
+ },
103694
+ "400": {
103695
+ "description": "Invalid request - schema validation failed",
103696
+ "content": {
103697
+ "application/json": {
103698
+ "schema": {
103699
+ "type": "object",
103700
+ "required": [
103701
+ "statusCode",
103702
+ "error",
103703
+ "message"
103704
+ ],
103705
+ "properties": {
103706
+ "statusCode": {
103707
+ "type": "integer"
103708
+ },
103709
+ "error": {
103710
+ "type": "string"
103711
+ },
103712
+ "message": {
103713
+ "type": "string"
103714
+ },
103715
+ "code": {
103716
+ "type": "string"
103717
+ },
103718
+ "request_id": {
103719
+ "type": "string"
103720
+ },
103721
+ "details": {
103722
+ "type": "object",
103723
+ "additionalProperties": {}
103724
+ }
103725
+ }
103726
+ }
103727
+ }
103728
+ }
103729
+ },
103730
+ "401": {
103731
+ "description": "Unauthorized - missing or invalid bearer token",
103732
+ "content": {
103733
+ "application/json": {
103734
+ "schema": {
103735
+ "$ref": "#/components/schemas/ErrorResponse"
103736
+ }
103737
+ }
103738
+ }
103739
+ },
103740
+ "403": {
103741
+ "description": "Forbidden - caller lacks the required role/permission",
103742
+ "content": {
103743
+ "application/json": {
103744
+ "schema": {
103745
+ "type": "object",
103746
+ "required": [
103747
+ "statusCode",
103748
+ "error",
103749
+ "message"
103750
+ ],
103751
+ "properties": {
103752
+ "statusCode": {
103753
+ "type": "integer"
103754
+ },
103755
+ "error": {
103756
+ "type": "string"
103757
+ },
103758
+ "message": {
103759
+ "type": "string"
103760
+ },
103761
+ "code": {
103762
+ "type": "string"
103763
+ },
103764
+ "request_id": {
103765
+ "type": "string"
103766
+ },
103767
+ "details": {
103768
+ "type": "object",
103769
+ "additionalProperties": {}
103770
+ }
103771
+ }
103772
+ }
103773
+ }
103774
+ }
103775
+ },
103776
+ "404": {
103777
+ "description": "Resource not found",
103778
+ "content": {
103779
+ "application/json": {
103780
+ "schema": {
103781
+ "type": "object",
103782
+ "required": [
103783
+ "statusCode",
103784
+ "error",
103785
+ "message"
103786
+ ],
103787
+ "properties": {
103788
+ "statusCode": {
103789
+ "type": "integer"
103790
+ },
103791
+ "error": {
103792
+ "type": "string"
103793
+ },
103794
+ "message": {
103795
+ "type": "string"
103796
+ },
103797
+ "code": {
103798
+ "type": "string"
103799
+ },
103800
+ "request_id": {
103801
+ "type": "string"
103802
+ },
103803
+ "details": {
103804
+ "type": "object",
103805
+ "additionalProperties": {}
103806
+ }
103807
+ }
103808
+ }
103809
+ }
103810
+ }
103811
+ }
103812
+ }
103813
+ }
103814
+ },
103815
+ "/api/v1/creative-ai-register/assets/{assetId}": {
103816
+ "patch": {
103817
+ "operationId": "creativeAiRegisterReclassifyAsset",
103818
+ "summary": "Reclassify an uploaded asset in the AI register",
103819
+ "tags": [
103820
+ "creative-hub",
103821
+ "ai-register"
103822
+ ],
103823
+ "description": "Manually records whether an uploaded or imported asset is AI-generated, for the cases automatic detection cannot decide (an unmarked upload is stored as unknown). Only rows without a generation_id can be reclassified: an asset produced by a Wevion generation is a recorded fact and answers 409. The change is stamped in `ai_provenance.manual_override`.",
103824
+ "requestBody": {
103825
+ "required": true,
103826
+ "content": {
103827
+ "application/json": {
103828
+ "schema": {
103829
+ "additionalProperties": false,
103830
+ "type": "object",
103831
+ "required": [
103832
+ "is_ai_generated"
103833
+ ],
103834
+ "properties": {
103835
+ "is_ai_generated": {
103836
+ "description": "True when the media is AI-generated, false when it is not.",
103837
+ "type": "boolean"
103838
+ }
103839
+ }
103840
+ }
103841
+ }
103842
+ }
103843
+ },
103844
+ "parameters": [
103845
+ {
103846
+ "schema": {
103847
+ "format": "uuid",
103848
+ "type": "string"
103849
+ },
103850
+ "in": "path",
103851
+ "name": "assetId",
103852
+ "required": true,
103853
+ "description": "creative_asset.id to reclassify."
103854
+ }
103855
+ ],
103856
+ "security": [
103857
+ {
103858
+ "bearerAuth": []
103859
+ },
103860
+ {
103861
+ "apiKeyAuth": []
103862
+ }
103863
+ ],
103864
+ "responses": {
103865
+ "200": {
103866
+ "description": "Successful response",
103867
+ "content": {
103868
+ "application/json": {
103869
+ "schema": {
103870
+ "additionalProperties": false,
103871
+ "type": "object",
103872
+ "required": [
103873
+ "id",
103874
+ "is_ai_generated",
103875
+ "ai_provenance"
103876
+ ],
103877
+ "properties": {
103878
+ "id": {
103879
+ "type": "string"
103880
+ },
103881
+ "is_ai_generated": {
103882
+ "type": "boolean"
103883
+ },
103884
+ "ai_provenance": {
103885
+ "description": "JSON object with nested arrays and objects.",
103886
+ "type": "object",
103887
+ "additionalProperties": {
103888
+ "$comment": "json-value",
103889
+ "description": "Arbitrary JSON value with nested arrays and objects."
103890
+ }
103891
+ }
103892
+ }
103893
+ }
103894
+ }
103895
+ }
103896
+ },
103897
+ "400": {
103898
+ "description": "Invalid request - schema validation failed",
103899
+ "content": {
103900
+ "application/json": {
103901
+ "schema": {
103902
+ "type": "object",
103903
+ "required": [
103904
+ "statusCode",
103905
+ "error",
103906
+ "message"
103907
+ ],
103908
+ "properties": {
103909
+ "statusCode": {
103910
+ "type": "integer"
103911
+ },
103912
+ "error": {
103913
+ "type": "string"
103914
+ },
103915
+ "message": {
103916
+ "type": "string"
103917
+ },
103918
+ "code": {
103919
+ "type": "string"
103920
+ },
103921
+ "request_id": {
103922
+ "type": "string"
103923
+ },
103924
+ "details": {
103925
+ "type": "object",
103926
+ "additionalProperties": {}
103927
+ }
103928
+ }
103929
+ }
103930
+ }
103931
+ }
103932
+ },
103933
+ "401": {
103934
+ "description": "Unauthorized - missing or invalid bearer token",
103935
+ "content": {
103936
+ "application/json": {
103937
+ "schema": {
103938
+ "$ref": "#/components/schemas/ErrorResponse"
103939
+ }
103940
+ }
103941
+ }
103942
+ },
103943
+ "403": {
103944
+ "description": "Forbidden - caller lacks the required role/permission",
103945
+ "content": {
103946
+ "application/json": {
103947
+ "schema": {
103948
+ "type": "object",
103949
+ "required": [
103950
+ "statusCode",
103951
+ "error",
103952
+ "message"
102722
103953
  ],
102723
103954
  "properties": {
102724
- "code": {
102725
- "type": "string"
103955
+ "statusCode": {
103956
+ "type": "integer"
102726
103957
  },
102727
103958
  "error": {
102728
103959
  "type": "string"
102729
103960
  },
102730
103961
  "message": {
102731
103962
  "type": "string"
102732
- }
102733
- }
102734
- }
102735
- }
102736
- }
102737
- },
102738
- "404": {
102739
- "description": "Resource not found",
102740
- "content": {
102741
- "application/json": {
102742
- "schema": {
102743
- "type": "object",
102744
- "required": [
102745
- "error"
102746
- ],
102747
- "properties": {
103963
+ },
102748
103964
  "code": {
102749
103965
  "type": "string"
102750
103966
  },
102751
- "error": {
103967
+ "request_id": {
102752
103968
  "type": "string"
102753
103969
  },
102754
- "message": {
102755
- "type": "string"
103970
+ "details": {
103971
+ "type": "object",
103972
+ "additionalProperties": {}
102756
103973
  }
102757
103974
  }
102758
103975
  }
102759
103976
  }
102760
103977
  }
102761
103978
  },
102762
- "429": {
102763
- "description": "Too many requests - rate limit exceeded",
103979
+ "404": {
103980
+ "description": "Resource not found",
102764
103981
  "content": {
102765
103982
  "application/json": {
102766
103983
  "schema": {
102767
103984
  "type": "object",
102768
103985
  "required": [
102769
- "error"
103986
+ "statusCode",
103987
+ "error",
103988
+ "message"
102770
103989
  ],
102771
103990
  "properties": {
102772
- "code": {
102773
- "type": "string"
103991
+ "statusCode": {
103992
+ "type": "integer"
102774
103993
  },
102775
103994
  "error": {
102776
103995
  "type": "string"
102777
103996
  },
102778
103997
  "message": {
102779
103998
  "type": "string"
102780
- }
102781
- }
102782
- }
102783
- }
102784
- }
102785
- }
102786
- }
102787
- }
102788
- },
102789
- "/api/v1/competitive-intelligence/search-page": {
102790
- "get": {
102791
- "operationId": "getApiV1CompetitiveIntelligenceSearchPage",
102792
- "summary": "Search competitor Meta pages",
102793
- "tags": [
102794
- "competitive-intelligence"
102795
- ],
102796
- "description": "Search Meta Ad Library pages to add a trackable competitor. Accepts an exact page name, a numeric Meta page ID, or a facebook.com URL carrying the page ID; countries scope which ad-delivery markets are searched.",
102797
- "parameters": [
102798
- {
102799
- "schema": {
102800
- "type": "array",
102801
- "items": {
102802
- "type": "string"
102803
- }
102804
- },
102805
- "in": "query",
102806
- "name": "countries",
102807
- "required": false
102808
- },
102809
- {
102810
- "schema": {
102811
- "minLength": 1,
102812
- "maxLength": 300,
102813
- "type": "string"
102814
- },
102815
- "in": "query",
102816
- "name": "q",
102817
- "required": true
102818
- }
102819
- ],
102820
- "security": [
102821
- {
102822
- "bearerAuth": []
102823
- },
102824
- {
102825
- "apiKeyAuth": []
102826
- }
102827
- ],
102828
- "responses": {
102829
- "200": {
102830
- "description": "Successful response",
102831
- "content": {
102832
- "application/json": {
102833
- "schema": {
102834
- "type": "object",
102835
- "required": [
102836
- "items"
102837
- ],
102838
- "properties": {
102839
- "items": {
102840
- "type": "array",
102841
- "items": {
102842
- "type": "object",
102843
- "required": [
102844
- "ad_count",
102845
- "page_id",
102846
- "page_name",
102847
- "source"
102848
- ],
102849
- "properties": {
102850
- "ad_count": {
102851
- "type": "number"
102852
- },
102853
- "page_id": {
102854
- "type": "string"
102855
- },
102856
- "page_name": {
102857
- "type": "string"
102858
- },
102859
- "source": {
102860
- "type": "string"
102861
- }
102862
- }
102863
- }
102864
- }
102865
- }
102866
- }
102867
- }
102868
- }
102869
- },
102870
- "400": {
102871
- "description": "Invalid request - schema validation failed",
102872
- "content": {
102873
- "application/json": {
102874
- "schema": {
102875
- "type": "object",
102876
- "required": [
102877
- "error"
102878
- ],
102879
- "properties": {
103999
+ },
102880
104000
  "code": {
102881
104001
  "type": "string"
102882
104002
  },
102883
- "error": {
104003
+ "request_id": {
102884
104004
  "type": "string"
102885
104005
  },
102886
- "message": {
102887
- "type": "string"
104006
+ "details": {
104007
+ "type": "object",
104008
+ "additionalProperties": {}
102888
104009
  }
102889
104010
  }
102890
104011
  }
102891
104012
  }
102892
104013
  }
102893
104014
  },
102894
- "401": {
102895
- "description": "Unauthorized - missing or invalid bearer token",
102896
- "content": {
102897
- "application/json": {
102898
- "schema": {
102899
- "$ref": "#/components/schemas/ErrorResponse"
102900
- }
102901
- }
102902
- }
102903
- },
102904
- "403": {
102905
- "description": "Forbidden - caller lacks the required role/permission",
104015
+ "409": {
104016
+ "description": "Conflict - resource state prevents the operation",
102906
104017
  "content": {
102907
104018
  "application/json": {
102908
104019
  "schema": {
102909
104020
  "type": "object",
102910
104021
  "required": [
102911
- "error"
104022
+ "statusCode",
104023
+ "error",
104024
+ "message"
102912
104025
  ],
102913
104026
  "properties": {
102914
- "code": {
102915
- "type": "string"
104027
+ "statusCode": {
104028
+ "type": "integer"
102916
104029
  },
102917
104030
  "error": {
102918
104031
  "type": "string"
102919
104032
  },
102920
104033
  "message": {
102921
104034
  "type": "string"
102922
- }
102923
- }
102924
- }
102925
- }
102926
- }
102927
- },
102928
- "404": {
102929
- "description": "Resource not found",
102930
- "content": {
102931
- "application/json": {
102932
- "schema": {
102933
- "type": "object",
102934
- "required": [
102935
- "error"
102936
- ],
102937
- "properties": {
104035
+ },
102938
104036
  "code": {
102939
104037
  "type": "string"
102940
104038
  },
102941
- "error": {
104039
+ "request_id": {
102942
104040
  "type": "string"
102943
104041
  },
102944
- "message": {
102945
- "type": "string"
104042
+ "details": {
104043
+ "type": "object",
104044
+ "additionalProperties": {}
102946
104045
  }
102947
104046
  }
102948
104047
  }
@@ -146189,7 +147288,8 @@
146189
147288
  "account_currency",
146190
147289
  "account_timezone",
146191
147290
  "account_timezone_offset_hours_utc",
146192
- "account_status"
147291
+ "account_status",
147292
+ "validated_tokens_missing"
146193
147293
  ],
146194
147294
  "properties": {
146195
147295
  "account_id": {
@@ -146249,7 +147349,18 @@
146249
147349
  ]
146250
147350
  },
146251
147351
  "account_status": {
146252
- "type": "integer"
147352
+ "anyOf": [
147353
+ {
147354
+ "type": "integer"
147355
+ },
147356
+ {
147357
+ "type": "null"
147358
+ }
147359
+ ]
147360
+ },
147361
+ "validated_tokens_missing": {
147362
+ "description": "True when the ad account was synced but never connected (validated_tokens is SQL NULL). This is the only state the publish worker rejects outright; a connected=false flag or an empty token array do NOT prevent publishing, because the token is also resolved from token_resource_permission.",
147363
+ "type": "boolean"
146253
147364
  }
146254
147365
  }
146255
147366
  }
@@ -148128,6 +149239,161 @@
148128
149239
  }
148129
149240
  }
148130
149241
  },
149242
+ "/api/v1/locale-search": {
149243
+ "get": {
149244
+ "operationId": "getApiV1LocaleSearch",
149245
+ "summary": "List or search Meta locales for ad-set language targeting",
149246
+ "tags": [
149247
+ "targeting"
149248
+ ],
149249
+ "description": "Proxies Meta Marketing API `search?type=adlocale`, returning the numeric locale IDs accepted by `targeting.locales` on an ad set. Meta owns the list, so it is queried live rather than mirrored in code — a copy in the repo goes stale and only ever covers part of it. With `q` omitted Meta returns its COMPLETE list (92 locales as of 2026-08-20), which is small enough for the client to hold and filter locally; `q` is still accepted for narrower lookups. Returns `degraded: true` with an empty list when the ad account has no usable token or Meta is unreachable, so the caller can distinguish an outage from a query that matched nothing.",
149250
+ "parameters": [
149251
+ {
149252
+ "schema": {
149253
+ "maxLength": 100,
149254
+ "type": "string"
149255
+ },
149256
+ "in": "query",
149257
+ "name": "q",
149258
+ "required": false,
149259
+ "description": "Search query (e.g. \"eng\"). Omit or leave empty to get Meta's complete locale list."
149260
+ },
149261
+ {
149262
+ "schema": {
149263
+ "type": "string"
149264
+ },
149265
+ "in": "query",
149266
+ "name": "account_id",
149267
+ "required": true,
149268
+ "description": "Ad account ID to resolve token"
149269
+ }
149270
+ ],
149271
+ "security": [
149272
+ {
149273
+ "bearerAuth": []
149274
+ }
149275
+ ],
149276
+ "responses": {
149277
+ "200": {
149278
+ "description": "Successful response",
149279
+ "content": {
149280
+ "application/json": {
149281
+ "schema": {
149282
+ "type": "object",
149283
+ "required": [
149284
+ "degraded",
149285
+ "locales"
149286
+ ],
149287
+ "properties": {
149288
+ "degraded": {
149289
+ "type": "boolean"
149290
+ },
149291
+ "locales": {
149292
+ "type": "array",
149293
+ "items": {
149294
+ "type": "object",
149295
+ "required": [
149296
+ "key",
149297
+ "name"
149298
+ ],
149299
+ "properties": {
149300
+ "key": {
149301
+ "description": "Meta locale ID, sent verbatim in targeting.locales",
149302
+ "type": "integer"
149303
+ },
149304
+ "name": {
149305
+ "description": "Display name, e.g. \"English (All)\"",
149306
+ "type": "string"
149307
+ }
149308
+ }
149309
+ }
149310
+ }
149311
+ }
149312
+ }
149313
+ }
149314
+ }
149315
+ },
149316
+ "401": {
149317
+ "description": "Unauthorized - missing or invalid bearer token",
149318
+ "content": {
149319
+ "application/json": {
149320
+ "schema": {
149321
+ "type": "object",
149322
+ "required": [
149323
+ "statusCode",
149324
+ "error",
149325
+ "message"
149326
+ ],
149327
+ "properties": {
149328
+ "statusCode": {
149329
+ "type": "integer"
149330
+ },
149331
+ "error": {
149332
+ "type": "string"
149333
+ },
149334
+ "message": {
149335
+ "type": "string"
149336
+ }
149337
+ }
149338
+ }
149339
+ }
149340
+ }
149341
+ },
149342
+ "404": {
149343
+ "description": "Resource not found",
149344
+ "content": {
149345
+ "application/json": {
149346
+ "schema": {
149347
+ "type": "object",
149348
+ "required": [
149349
+ "statusCode",
149350
+ "error",
149351
+ "message"
149352
+ ],
149353
+ "properties": {
149354
+ "statusCode": {
149355
+ "type": "integer"
149356
+ },
149357
+ "error": {
149358
+ "type": "string"
149359
+ },
149360
+ "message": {
149361
+ "type": "string"
149362
+ }
149363
+ }
149364
+ }
149365
+ }
149366
+ }
149367
+ },
149368
+ "500": {
149369
+ "description": "Internal server error",
149370
+ "content": {
149371
+ "application/json": {
149372
+ "schema": {
149373
+ "type": "object",
149374
+ "required": [
149375
+ "statusCode",
149376
+ "error",
149377
+ "message"
149378
+ ],
149379
+ "properties": {
149380
+ "statusCode": {
149381
+ "type": "integer"
149382
+ },
149383
+ "error": {
149384
+ "type": "string"
149385
+ },
149386
+ "message": {
149387
+ "type": "string"
149388
+ }
149389
+ }
149390
+ }
149391
+ }
149392
+ }
149393
+ }
149394
+ }
149395
+ }
149396
+ },
148131
149397
  "/api/v1/market-intelligence/benchmarks": {
148132
149398
  "get": {
148133
149399
  "operationId": "getApiV1MarketIntelligenceBenchmarks",
@@ -156564,7 +157830,7 @@
156564
157830
  "properties": {
156565
157831
  "preferences": {
156566
157832
  "minItems": 1,
156567
- "maxItems": 45,
157833
+ "maxItems": 47,
156568
157834
  "type": "array",
156569
157835
  "items": {
156570
157836
  "additionalProperties": false,
@@ -159205,31 +160471,31 @@
159205
160471
  "tags": [
159206
160472
  "partner"
159207
160473
  ],
159208
- "description": "Applica un codice partner a un account registrato da meno di 7 giorni, SOLO se la cascata L1-L3 non ha già prodotto un vincitore. Un’attribuzione esistente non viene mai sovrascritta. La risposta normale è 200: `applied` dice se il codice ha attribuito e `reason` perché no. `already_attributed` e `grace_expired` sono restituiti PRIMA di qualunque lookup del codice, così la rotta non può essere usata per scoprire quali codici esistono. Il 409 è l’unico esito che non è di dominio: il database ha rifiutato la scrittura per un conflitto che lo stato non spiega (collisione tecnica), nulla è stato scritto e la richiesta si può ritentare.",
160474
+ "description": "Applica un codice partner (o lo slug vanity del suo link) a un account registrato da meno di 7 giorni, SOLO se la cascata L1-L3 non ha già prodotto un vincitore. Un’attribuzione esistente non viene mai sovrascritta. La risposta normale è 200: `applied` dice se il codice ha attribuito e `reason` perché no. `already_attributed` e `grace_expired` sono restituiti PRIMA di qualunque lookup del codice, così la rotta non può essere usata per scoprire quali codici esistono. Il 409 è l’unico esito che non è di dominio: il database ha rifiutato la scrittura per un conflitto che lo stato non spiega (collisione tecnica), nulla è stato scritto e la richiesta si può ritentare.",
159209
160475
  "requestBody": {
159210
160476
  "required": true,
159211
160477
  "content": {
159212
160478
  "application/json": {
159213
160479
  "schema": {
159214
160480
  "additionalProperties": false,
159215
- "description": "Codice da riscattare entro la finestra di grazia.",
160481
+ "description": "Codice o slug da riscattare entro la finestra di grazia.",
159216
160482
  "type": "object",
159217
160483
  "required": [
159218
160484
  "code"
159219
160485
  ],
159220
160486
  "properties": {
159221
160487
  "code": {
159222
- "description": "Codice invito del partner: base32 Crockford maiuscolo, 8-20 caratteri. È lo stesso valore normalizzato dal campo \"Codice invito\" del frontend.",
159223
- "maxLength": 20,
159224
- "minLength": 8,
159225
- "pattern": "^[0-9A-HJKMNP-TV-Z]{8,20}$",
160488
+ "description": "Codice invito del partner (base32 Crockford maiuscolo, 8-20 caratteri) OPPURE lo slug vanity del suo link (3-30 caratteri, minuscolo, trattini solo interni: `marco-ads`). Sono le due cose che una persona può avere in mano senza aver cliccato: il codice dettato a voce e l’indirizzo stampato su un volantino.",
160489
+ "maxLength": 30,
160490
+ "minLength": 3,
160491
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9-]{1,28}[A-Za-z0-9]$",
159226
160492
  "type": "string"
159227
160493
  }
159228
160494
  }
159229
160495
  }
159230
160496
  }
159231
160497
  },
159232
- "description": "Codice da riscattare entro la finestra di grazia."
160498
+ "description": "Codice o slug da riscattare entro la finestra di grazia."
159233
160499
  },
159234
160500
  "security": [
159235
160501
  {
@@ -159559,8 +160825,379 @@
159559
160825
  "description": "Messaggio leggibile.",
159560
160826
  "type": "string"
159561
160827
  },
159562
- "request_id": {
159563
- "description": "Id della richiesta, per il supporto.",
160828
+ "request_id": {
160829
+ "description": "Id della richiesta, per il supporto.",
160830
+ "type": "string"
160831
+ },
160832
+ "statusCode": {
160833
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
160834
+ "type": "integer"
160835
+ }
160836
+ }
160837
+ }
160838
+ }
160839
+ }
160840
+ }
160841
+ }
160842
+ }
160843
+ },
160844
+ "/api/v1/referral/bridge-offer": {
160845
+ "get": {
160846
+ "operationId": "getPartnerBridgeOffer",
160847
+ "summary": "L’offerta di passaggio al Binario B che mi aspetta",
160848
+ "tags": [
160849
+ "partner"
160850
+ ],
160851
+ "description": "L’offerta di passaggio al Programma Partner che aspetta chi chiama, se ce n’è una ancora da accettare. `204` quando non c’è nulla da accettare — indistintamente perché non esiste alcuna offerta o perché è già stata accettata: distinguere i due casi renderebbe questa rotta un oracolo sull’esistenza di un’offerta. La risposta porta il documento e la versione da accettare, mai il token della pratica.",
160852
+ "security": [
160853
+ {
160854
+ "bearerAuth": []
160855
+ }
160856
+ ],
160857
+ "responses": {
160858
+ "200": {
160859
+ "description": "L’offerta di passaggio al Binario B che aspetta chi chiama. ⚠️ Non porta il token della pratica: quello è la chiave di lettura del fascicolo e non ha ragione di uscire da qui.",
160860
+ "content": {
160861
+ "application/json": {
160862
+ "schema": {
160863
+ "additionalProperties": false,
160864
+ "description": "L’offerta di passaggio al Binario B che aspetta chi chiama. ⚠️ Non porta il token della pratica: quello è la chiave di lettura del fascicolo e non ha ragione di uscire da qui.",
160865
+ "type": "object",
160866
+ "required": [
160867
+ "offered_at",
160868
+ "reason",
160869
+ "tc_document_id",
160870
+ "tc_version"
160871
+ ],
160872
+ "properties": {
160873
+ "offered_at": {
160874
+ "description": "Quando l’offerta è nata. È l’unica data che esiste finché non la si accetta.",
160875
+ "format": "date-time",
160876
+ "type": "string"
160877
+ },
160878
+ "reason": {
160879
+ "description": "Perché è nata: `cap_reached` (tetto del Binario A) o `third_matured_conversion`.",
160880
+ "anyOf": [
160881
+ {
160882
+ "type": "string"
160883
+ },
160884
+ {
160885
+ "type": "null"
160886
+ }
160887
+ ]
160888
+ },
160889
+ "tc_document_id": {
160890
+ "description": "Il documento da accettare. Oggi sempre `partnerTerms`.",
160891
+ "type": "string"
160892
+ },
160893
+ "tc_version": {
160894
+ "description": "La versione proposta: è quella che va rimandata all’accettazione.",
160895
+ "type": "string"
160896
+ }
160897
+ }
160898
+ }
160899
+ }
160900
+ }
160901
+ },
160902
+ "204": {
160903
+ "description": "Nessuna offerta da accettare."
160904
+ },
160905
+ "401": {
160906
+ "description": "Errore standard del backend.",
160907
+ "content": {
160908
+ "application/json": {
160909
+ "schema": {
160910
+ "additionalProperties": false,
160911
+ "description": "Errore standard del backend.",
160912
+ "type": "object",
160913
+ "required": [
160914
+ "error",
160915
+ "message",
160916
+ "statusCode"
160917
+ ],
160918
+ "properties": {
160919
+ "code": {
160920
+ "description": "Codice macchina dell’errore, quando disponibile.",
160921
+ "type": "string"
160922
+ },
160923
+ "error": {
160924
+ "description": "Etichetta breve dell’errore.",
160925
+ "type": "string"
160926
+ },
160927
+ "message": {
160928
+ "description": "Messaggio leggibile.",
160929
+ "type": "string"
160930
+ },
160931
+ "statusCode": {
160932
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
160933
+ "type": "integer"
160934
+ }
160935
+ }
160936
+ }
160937
+ }
160938
+ }
160939
+ },
160940
+ "429": {
160941
+ "description": "Errore standard del backend.",
160942
+ "content": {
160943
+ "application/json": {
160944
+ "schema": {
160945
+ "additionalProperties": false,
160946
+ "description": "Errore standard del backend.",
160947
+ "type": "object",
160948
+ "required": [
160949
+ "error",
160950
+ "message",
160951
+ "statusCode"
160952
+ ],
160953
+ "properties": {
160954
+ "code": {
160955
+ "description": "Codice macchina dell’errore, quando disponibile.",
160956
+ "type": "string"
160957
+ },
160958
+ "error": {
160959
+ "description": "Etichetta breve dell’errore.",
160960
+ "type": "string"
160961
+ },
160962
+ "message": {
160963
+ "description": "Messaggio leggibile.",
160964
+ "type": "string"
160965
+ },
160966
+ "statusCode": {
160967
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
160968
+ "type": "integer"
160969
+ }
160970
+ }
160971
+ }
160972
+ }
160973
+ }
160974
+ }
160975
+ }
160976
+ }
160977
+ },
160978
+ "/api/v1/referral/bridge-offer/accept": {
160979
+ "post": {
160980
+ "operationId": "acceptPartnerBridgeOffer",
160981
+ "summary": "Accetto i termini e passo al Binario B",
160982
+ "tags": [
160983
+ "partner"
160984
+ ],
160985
+ "description": "Accetta i termini dell’offerta di passaggio al Binario B. ★ È l’ATTO che il ponte non aveva: registra `tc_accepted_at`, l’IP, lo user-agent, l’impronta del testo e la versione — gli stessi cinque campi che la candidatura pubblica raccoglie, perché una prova di consenso non può avere due forme a seconda di dove entra — e porta la pratica in `received`, cioè nella coda normale. Finché questo atto non avviene l’approvazione risponde `409 tc_not_accepted` e il vincolo `ck_papp_approved_needs_consent` rifiuta comunque la transizione: nessuno può essere approvato senza aver accettato. `404` quando non c’è nulla da accettare (nessuna offerta, o già accettata: i due casi rispondono identico). `409 stale_version` quando la versione inviata non è quella corrente. `403` quando il programma è chiuso: accettare a porta chiusa scriverebbe un consenso write-once su un percorso che non può proseguire.",
160986
+ "requestBody": {
160987
+ "required": true,
160988
+ "content": {
160989
+ "application/json": {
160990
+ "schema": {
160991
+ "additionalProperties": false,
160992
+ "type": "object",
160993
+ "required": [
160994
+ "tos_version"
160995
+ ],
160996
+ "properties": {
160997
+ "tos_version": {
160998
+ "description": "La versione dei T&C partner che si sta accettando. Deve essere quella CORRENTE: accettare una versione vecchia scriverebbe una prova di consenso su un testo diverso da quello mostrato.",
160999
+ "maxLength": 20,
161000
+ "minLength": 1,
161001
+ "type": "string"
161002
+ }
161003
+ }
161004
+ }
161005
+ }
161006
+ }
161007
+ },
161008
+ "security": [
161009
+ {
161010
+ "bearerAuth": []
161011
+ }
161012
+ ],
161013
+ "responses": {
161014
+ "200": {
161015
+ "description": "Successful response",
161016
+ "content": {
161017
+ "application/json": {
161018
+ "schema": {
161019
+ "additionalProperties": false,
161020
+ "type": "object",
161021
+ "required": [
161022
+ "status"
161023
+ ],
161024
+ "properties": {
161025
+ "status": {
161026
+ "description": "La pratica è entrata nella coda normale: da qui in poi è una candidatura come le altre.",
161027
+ "type": "string",
161028
+ "enum": [
161029
+ "received"
161030
+ ]
161031
+ }
161032
+ }
161033
+ }
161034
+ }
161035
+ }
161036
+ },
161037
+ "401": {
161038
+ "description": "Errore standard del backend.",
161039
+ "content": {
161040
+ "application/json": {
161041
+ "schema": {
161042
+ "additionalProperties": false,
161043
+ "description": "Errore standard del backend.",
161044
+ "type": "object",
161045
+ "required": [
161046
+ "error",
161047
+ "message",
161048
+ "statusCode"
161049
+ ],
161050
+ "properties": {
161051
+ "code": {
161052
+ "description": "Codice macchina dell’errore, quando disponibile.",
161053
+ "type": "string"
161054
+ },
161055
+ "error": {
161056
+ "description": "Etichetta breve dell’errore.",
161057
+ "type": "string"
161058
+ },
161059
+ "message": {
161060
+ "description": "Messaggio leggibile.",
161061
+ "type": "string"
161062
+ },
161063
+ "statusCode": {
161064
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
161065
+ "type": "integer"
161066
+ }
161067
+ }
161068
+ }
161069
+ }
161070
+ }
161071
+ },
161072
+ "403": {
161073
+ "description": "Errore standard del backend.",
161074
+ "content": {
161075
+ "application/json": {
161076
+ "schema": {
161077
+ "additionalProperties": false,
161078
+ "description": "Errore standard del backend.",
161079
+ "type": "object",
161080
+ "required": [
161081
+ "error",
161082
+ "message",
161083
+ "statusCode"
161084
+ ],
161085
+ "properties": {
161086
+ "code": {
161087
+ "description": "Codice macchina dell’errore, quando disponibile.",
161088
+ "type": "string"
161089
+ },
161090
+ "error": {
161091
+ "description": "Etichetta breve dell’errore.",
161092
+ "type": "string"
161093
+ },
161094
+ "message": {
161095
+ "description": "Messaggio leggibile.",
161096
+ "type": "string"
161097
+ },
161098
+ "statusCode": {
161099
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
161100
+ "type": "integer"
161101
+ }
161102
+ }
161103
+ }
161104
+ }
161105
+ }
161106
+ },
161107
+ "404": {
161108
+ "description": "Errore standard del backend.",
161109
+ "content": {
161110
+ "application/json": {
161111
+ "schema": {
161112
+ "additionalProperties": false,
161113
+ "description": "Errore standard del backend.",
161114
+ "type": "object",
161115
+ "required": [
161116
+ "error",
161117
+ "message",
161118
+ "statusCode"
161119
+ ],
161120
+ "properties": {
161121
+ "code": {
161122
+ "description": "Codice macchina dell’errore, quando disponibile.",
161123
+ "type": "string"
161124
+ },
161125
+ "error": {
161126
+ "description": "Etichetta breve dell’errore.",
161127
+ "type": "string"
161128
+ },
161129
+ "message": {
161130
+ "description": "Messaggio leggibile.",
161131
+ "type": "string"
161132
+ },
161133
+ "statusCode": {
161134
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
161135
+ "type": "integer"
161136
+ }
161137
+ }
161138
+ }
161139
+ }
161140
+ }
161141
+ },
161142
+ "409": {
161143
+ "description": "Errore standard del backend.",
161144
+ "content": {
161145
+ "application/json": {
161146
+ "schema": {
161147
+ "additionalProperties": false,
161148
+ "description": "Errore standard del backend.",
161149
+ "type": "object",
161150
+ "required": [
161151
+ "error",
161152
+ "message",
161153
+ "statusCode"
161154
+ ],
161155
+ "properties": {
161156
+ "code": {
161157
+ "description": "Codice macchina dell’errore, quando disponibile.",
161158
+ "type": "string"
161159
+ },
161160
+ "error": {
161161
+ "description": "Etichetta breve dell’errore.",
161162
+ "type": "string"
161163
+ },
161164
+ "message": {
161165
+ "description": "Messaggio leggibile.",
161166
+ "type": "string"
161167
+ },
161168
+ "statusCode": {
161169
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
161170
+ "type": "integer"
161171
+ }
161172
+ }
161173
+ }
161174
+ }
161175
+ }
161176
+ },
161177
+ "429": {
161178
+ "description": "Errore standard del backend.",
161179
+ "content": {
161180
+ "application/json": {
161181
+ "schema": {
161182
+ "additionalProperties": false,
161183
+ "description": "Errore standard del backend.",
161184
+ "type": "object",
161185
+ "required": [
161186
+ "error",
161187
+ "message",
161188
+ "statusCode"
161189
+ ],
161190
+ "properties": {
161191
+ "code": {
161192
+ "description": "Codice macchina dell’errore, quando disponibile.",
161193
+ "type": "string"
161194
+ },
161195
+ "error": {
161196
+ "description": "Etichetta breve dell’errore.",
161197
+ "type": "string"
161198
+ },
161199
+ "message": {
161200
+ "description": "Messaggio leggibile.",
159564
161201
  "type": "string"
159565
161202
  },
159566
161203
  "statusCode": {
@@ -159748,6 +161385,8 @@
159748
161385
  "id",
159749
161386
  "opened_on",
159750
161387
  "reason_code",
161388
+ "resolution_code",
161389
+ "resolved_on",
159751
161390
  "status"
159752
161391
  ],
159753
161392
  "properties": {
@@ -159821,8 +161460,78 @@
159821
161460
  }
159822
161461
  ]
159823
161462
  },
161463
+ "resolution_code": {
161464
+ "description": "Esito, quando la pratica è chiusa; `null` finché è viva. È un CODICE e l’insieme è **chiuso**: `partner_dispute.resolution_code` è una `VARCHAR(40)` senza `CHECK` e chi chiude un caso dal backoffice ci scrive un codice deciso da un operatore.",
161465
+ "anyOf": [
161466
+ {
161467
+ "type": "string",
161468
+ "enum": [
161469
+ "our_error"
161470
+ ]
161471
+ },
161472
+ {
161473
+ "type": "string",
161474
+ "enum": [
161475
+ "evidence_accepted"
161476
+ ]
161477
+ },
161478
+ {
161479
+ "type": "string",
161480
+ "enum": [
161481
+ "goodwill"
161482
+ ]
161483
+ },
161484
+ {
161485
+ "type": "string",
161486
+ "enum": [
161487
+ "data_confirmed"
161488
+ ]
161489
+ },
161490
+ {
161491
+ "type": "string",
161492
+ "enum": [
161493
+ "out_of_scope"
161494
+ ]
161495
+ },
161496
+ {
161497
+ "type": "string",
161498
+ "enum": [
161499
+ "no_response"
161500
+ ]
161501
+ },
161502
+ {
161503
+ "type": "string",
161504
+ "enum": [
161505
+ "withdrawn_by_partner"
161506
+ ]
161507
+ },
161508
+ {
161509
+ "type": "string",
161510
+ "enum": [
161511
+ "unknown"
161512
+ ]
161513
+ },
161514
+ {
161515
+ "type": "null"
161516
+ }
161517
+ ]
161518
+ },
161519
+ "resolved_on": {
161520
+ "description": "Giorno in cui la pratica è stata chiusa; `null` finché è viva.",
161521
+ "anyOf": [
161522
+ {
161523
+ "description": "Giorno della risposta.",
161524
+ "format": "date",
161525
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
161526
+ "type": "string"
161527
+ },
161528
+ {
161529
+ "type": "null"
161530
+ }
161531
+ ]
161532
+ },
159824
161533
  "status": {
159825
- "description": "`open` oppure `in_review`. Gli stati terminali non arrivano qui.",
161534
+ "description": "`open` · `in_review` · `upheld` · `rejected`. Gli stati TERMINALI arrivano eccome, da oggi: prima la pratica spariva dalla riga nel momento in cui riceveva una risposta, e il partner — a cui avevamo promesso «Ti rispondiamo entro il …» — non vedeva né esito né motivo.",
159826
161535
  "type": "string"
159827
161536
  }
159828
161537
  }
@@ -160535,6 +162244,186 @@
160535
162244
  }
160536
162245
  }
160537
162246
  },
162247
+ "/api/v1/partner/statements": {
162248
+ "get": {
162249
+ "operationId": "listPartnerStatements",
162250
+ "summary": "Rendiconti mensili",
162251
+ "tags": [
162252
+ "partner"
162253
+ ],
162254
+ "description": "Rendiconti mensili del partner, dal più recente. I link sono firmati a 15 minuti e si rigenerano a ogni chiamata: è ciò che rende vera la promessa dell’email («se scadono, li ritrovi nel pannello»), che prima non lo era nei mesi senza bonifico.",
162255
+ "security": [
162256
+ {
162257
+ "bearerAuth": []
162258
+ }
162259
+ ],
162260
+ "responses": {
162261
+ "200": {
162262
+ "description": "Successful response",
162263
+ "content": {
162264
+ "application/json": {
162265
+ "schema": {
162266
+ "additionalProperties": false,
162267
+ "type": "object",
162268
+ "required": [
162269
+ "rows"
162270
+ ],
162271
+ "properties": {
162272
+ "rows": {
162273
+ "type": "array",
162274
+ "items": {
162275
+ "additionalProperties": false,
162276
+ "type": "object",
162277
+ "required": [
162278
+ "closing_minor",
162279
+ "csv_url",
162280
+ "currency",
162281
+ "generated_on",
162282
+ "pdf_url",
162283
+ "period",
162284
+ "sent_on"
162285
+ ],
162286
+ "properties": {
162287
+ "closing_minor": {
162288
+ "description": "Saldo di chiusura del periodo, come stampato sul documento. Minor units (centesimi) come stringa decimale.",
162289
+ "pattern": "^-?[0-9]+$",
162290
+ "type": "string"
162291
+ },
162292
+ "csv_url": {
162293
+ "description": "Link firmato al CSV, TTL 15 minuti. `null` quando il file non è ancora stato prodotto.",
162294
+ "anyOf": [
162295
+ {
162296
+ "format": "uri",
162297
+ "type": "string"
162298
+ },
162299
+ {
162300
+ "type": "null"
162301
+ }
162302
+ ]
162303
+ },
162304
+ "currency": {
162305
+ "description": "Valuta del rendiconto.",
162306
+ "type": "string"
162307
+ },
162308
+ "generated_on": {
162309
+ "description": "Giorno di emissione del documento.",
162310
+ "format": "date",
162311
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
162312
+ "type": "string"
162313
+ },
162314
+ "pdf_url": {
162315
+ "description": "Link firmato al PDF, TTL 15 minuti. `null` quando il file non è ancora stato prodotto.",
162316
+ "anyOf": [
162317
+ {
162318
+ "format": "uri",
162319
+ "type": "string"
162320
+ },
162321
+ {
162322
+ "type": "null"
162323
+ }
162324
+ ]
162325
+ },
162326
+ "period": {
162327
+ "description": "Mese di competenza, primo giorno.",
162328
+ "format": "date",
162329
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
162330
+ "type": "string"
162331
+ },
162332
+ "sent_on": {
162333
+ "description": "`null` = documento generato ma non ancora consegnato. Distingue «non gli è arrivato» da «non l’ha aperto», che portano ad azioni diverse.",
162334
+ "anyOf": [
162335
+ {
162336
+ "description": "Giorno di invio dell’email.",
162337
+ "format": "date",
162338
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
162339
+ "type": "string"
162340
+ },
162341
+ {
162342
+ "type": "null"
162343
+ }
162344
+ ]
162345
+ }
162346
+ }
162347
+ }
162348
+ }
162349
+ }
162350
+ }
162351
+ }
162352
+ }
162353
+ },
162354
+ "401": {
162355
+ "description": "Errore standard del backend.",
162356
+ "content": {
162357
+ "application/json": {
162358
+ "schema": {
162359
+ "additionalProperties": false,
162360
+ "description": "Errore standard del backend.",
162361
+ "type": "object",
162362
+ "required": [
162363
+ "error",
162364
+ "message",
162365
+ "statusCode"
162366
+ ],
162367
+ "properties": {
162368
+ "code": {
162369
+ "description": "Codice macchina dell’errore, quando disponibile.",
162370
+ "type": "string"
162371
+ },
162372
+ "error": {
162373
+ "description": "Etichetta breve dell’errore.",
162374
+ "type": "string"
162375
+ },
162376
+ "message": {
162377
+ "description": "Messaggio leggibile.",
162378
+ "type": "string"
162379
+ },
162380
+ "statusCode": {
162381
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
162382
+ "type": "integer"
162383
+ }
162384
+ }
162385
+ }
162386
+ }
162387
+ }
162388
+ },
162389
+ "403": {
162390
+ "description": "Errore standard del backend.",
162391
+ "content": {
162392
+ "application/json": {
162393
+ "schema": {
162394
+ "additionalProperties": false,
162395
+ "description": "Errore standard del backend.",
162396
+ "type": "object",
162397
+ "required": [
162398
+ "error",
162399
+ "message",
162400
+ "statusCode"
162401
+ ],
162402
+ "properties": {
162403
+ "code": {
162404
+ "description": "Codice macchina dell’errore, quando disponibile.",
162405
+ "type": "string"
162406
+ },
162407
+ "error": {
162408
+ "description": "Etichetta breve dell’errore.",
162409
+ "type": "string"
162410
+ },
162411
+ "message": {
162412
+ "description": "Messaggio leggibile.",
162413
+ "type": "string"
162414
+ },
162415
+ "statusCode": {
162416
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
162417
+ "type": "integer"
162418
+ }
162419
+ }
162420
+ }
162421
+ }
162422
+ }
162423
+ }
162424
+ }
162425
+ }
162426
+ },
160538
162427
  "/api/v1/partner/exports/quota": {
160539
162428
  "get": {
160540
162429
  "operationId": "getPartnerExportQuota",
@@ -160657,7 +162546,7 @@
160657
162546
  "tags": [
160658
162547
  "partner"
160659
162548
  ],
160660
- "description": "Crea un link di export firmato, valido 15 minuti. L’export contiene SOLO l’id opaco: nessun nome, nessuna email, nessuna azienda — a T0 come a T1. 429 quando la quota giornaliera è esaurita.",
162549
+ "description": "Crea un link di export firmato, valido 15 minuti e **monouso**. L’export contiene SOLO l’id opaco: nessun nome, nessuna email, nessuna azienda — a T0 come a T1. La finestra `from`/`to` è firmata nel token e viene applicata al contenuto. Il tetto è di 10.000 righe: oltre, il file dichiara il troncamento in una riga dedicata. 429 quando la quota giornaliera è esaurita.",
160661
162550
  "requestBody": {
160662
162551
  "required": true,
160663
162552
  "content": {
@@ -160953,7 +162842,7 @@
160953
162842
  "tags": [
160954
162843
  "partner"
160955
162844
  ],
160956
- "description": "Scarica un export creato da `POST /partner/exports`. Il token viaggia in QUERY e non in path: un parametro di path è limitato a 100 caratteri da Fastify e un token firmato ne supera 200, quindi in path il link consegnato risponderebbe 404. Il token è firmato, scade in 15 minuti e porta il `partner_id` dentro la firma: viene riverificato contro la sessione, quindi un link condiviso non apre i dati di nessun altro. Un token scaduto, manomesso o di un altro partner risponde 403 con lo stesso corpo. Il CSV contiene solo l’ID opaco e un watermark per-partner in coda.",
162845
+ "description": "Scarica un export creato da `POST /partner/exports`. Il token viaggia in QUERY e non in path: un parametro di path è limitato a 100 caratteri da Fastify e un token firmato ne supera 200, quindi in path il link consegnato risponderebbe 404. Il token è firmato, scade in 15 minuti e porta il `partner_id` dentro la firma: viene riverificato contro la sessione, quindi un link condiviso non apre i dati di nessun altro. È **monouso** (§4.6): il primo download lo consuma e ogni tentativo successivo risponde 403 con lo stesso corpo di un token scaduto, manomesso o di un altro partner i quattro casi sono indistinguibili di proposito. Ogni emissione e ogni download lasciano una riga nel registro `partner_export_audit` (§13.2). Il CSV contiene solo l’ID opaco e un watermark per-partner in coda; se il tetto di righe morde, il file lo DICHIARA con una riga `# wevion-partner-export-truncated,<righe>,<tetto>,<dal>,<al>` prima del watermark.",
160957
162846
  "parameters": [
160958
162847
  {
160959
162848
  "schema": {
@@ -161020,7 +162909,7 @@
161020
162909
  }
161021
162910
  },
161022
162911
  "403": {
161023
- "description": "Token scaduto, manomesso o appartenente a un altro partner: stesso corpo in tutti i casi.",
162912
+ "description": "Token scaduto, manomesso, già scaricato (monouso) o appartenente a un altro partner: stesso corpo in tutti i casi.",
161024
162913
  "content": {
161025
162914
  "application/json": {
161026
162915
  "schema": {
@@ -288872,7 +290761,7 @@
288872
290761
  "tags": [
288873
290762
  "wavo"
288874
290763
  ],
288875
- "description": "Applies the reverse operation for a successful reversible AI action when the caller still has team access and the configured undo window has not expired.",
290764
+ "description": "Applies the reverse operation for a successful reversible AI action when the caller still has team access and the configured undo window has not expired. Refused with 423 while WAVO autonomy is stopped (kill-switch down or paused): the undo is a platform write of the same size as the action it reverses.",
288876
290765
  "parameters": [
288877
290766
  {
288878
290767
  "schema": {
@@ -289008,6 +290897,29 @@
289008
290897
  }
289009
290898
  }
289010
290899
  },
290900
+ "423": {
290901
+ "description": "Response 423",
290902
+ "content": {
290903
+ "application/json": {
290904
+ "schema": {
290905
+ "additionalProperties": false,
290906
+ "type": "object",
290907
+ "required": [
290908
+ "error",
290909
+ "code"
290910
+ ],
290911
+ "properties": {
290912
+ "error": {
290913
+ "type": "string"
290914
+ },
290915
+ "code": {
290916
+ "type": "string"
290917
+ }
290918
+ }
290919
+ }
290920
+ }
290921
+ }
290922
+ },
289011
290923
  "500": {
289012
290924
  "description": "Internal server error",
289013
290925
  "content": {
@@ -293230,6 +295142,13 @@
293230
295142
  }
293231
295143
  }
293232
295144
  },
295145
+ "locales": {
295146
+ "description": "Meta locale IDs for ad-set language targeting (targeting.locales). Restricts delivery to people whose Facebook language matches; omit or leave empty for no restriction. Discoverable via GET /api/v1/locale-search.",
295147
+ "type": "array",
295148
+ "items": {
295149
+ "type": "integer"
295150
+ }
295151
+ },
293233
295152
  "included_audiences": {
293234
295153
  "description": "Custom audience IDs to include",
293235
295154
  "type": "array",