@threnn/acap-sdk 0.2.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.
@@ -0,0 +1,1319 @@
1
+ openapi: 3.1.0
2
+ info:
3
+ title: ACAP — Agent Capability Attestation Protocol API
4
+ version: 0.1.0
5
+ description: |
6
+ The ACAP API enables attesting, certifying, and monitoring AI agent capabilities.
7
+ All endpoints require Bearer token authentication via an API key.
8
+ license:
9
+ name: MIT
10
+ contact:
11
+ url: https://threnn.ai
12
+
13
+ servers:
14
+ - url: https://app.threnn.ai/api/v1/acap
15
+ description: Production
16
+
17
+ security:
18
+ - bearerAuth: []
19
+
20
+ components:
21
+ securitySchemes:
22
+ bearerAuth:
23
+ type: http
24
+ scheme: bearer
25
+
26
+ schemas:
27
+ Error:
28
+ type: object
29
+ required: [error]
30
+ properties:
31
+ error:
32
+ type: string
33
+ description: Human-readable error message
34
+ code:
35
+ type: string
36
+ enum: [UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, VALIDATION_ERROR, RATE_LIMITED, INTERNAL_ERROR, INVALID_JSON]
37
+ description: Machine-readable error code
38
+ details:
39
+ type: array
40
+ items:
41
+ type: object
42
+ properties:
43
+ path:
44
+ type: string
45
+ message:
46
+ type: string
47
+ description: Validation error details (only for VALIDATION_ERROR)
48
+
49
+ AttestationRun:
50
+ type: object
51
+ properties:
52
+ id:
53
+ type: string
54
+ example: RUN-LQZP3K7MABCD1234
55
+ api_key_id:
56
+ type: string
57
+ agent_id:
58
+ type: string
59
+ example: my-agent-001
60
+ benchmark_suite_id:
61
+ type: string
62
+ format: uuid
63
+ status:
64
+ type: string
65
+ enum: [pending, running, completed, failed, cancelled]
66
+ started_at:
67
+ type: string
68
+ format: date-time
69
+ completed_at:
70
+ type: string
71
+ format: date-time
72
+ nullable: true
73
+ task_progress:
74
+ type: object
75
+ properties:
76
+ totalTasks:
77
+ type: integer
78
+ completedTasks:
79
+ type: integer
80
+ passedTasks:
81
+ type: integer
82
+ failedTasks:
83
+ type: integer
84
+ estimatedRemainingMs:
85
+ type: integer
86
+ elapsedMs:
87
+ type: integer
88
+ taskOrder:
89
+ type: array
90
+ items:
91
+ type: integer
92
+ description: Randomized task execution order (anti-gaming)
93
+ certificate_id:
94
+ type: string
95
+ nullable: true
96
+ warning:
97
+ type: string
98
+ description: Present when another run is already in progress for this agent
99
+
100
+ Certificate:
101
+ type: object
102
+ properties:
103
+ id:
104
+ type: string
105
+ agent_id:
106
+ type: string
107
+ organization_id:
108
+ type: string
109
+ nullable: true
110
+ benchmark_suite_id:
111
+ type: string
112
+ format: uuid
113
+ benchmark_suite_version:
114
+ type: string
115
+ benchmark_domain:
116
+ type: string
117
+ overall_score:
118
+ type: number
119
+ minimum: 0
120
+ maximum: 1
121
+ dimension_scores:
122
+ type: array
123
+ items:
124
+ type: object
125
+ properties:
126
+ dimension:
127
+ type: string
128
+ score:
129
+ type: number
130
+ confidence_interval:
131
+ type: object
132
+ properties:
133
+ lower:
134
+ type: number
135
+ upper:
136
+ type: number
137
+ nullable: true
138
+ task_results:
139
+ type: array
140
+ items:
141
+ type: object
142
+ attestation_context:
143
+ type: object
144
+ properties:
145
+ modelProvider:
146
+ type: string
147
+ modelVersion:
148
+ type: string
149
+ testEnvironment:
150
+ type: string
151
+ executionDuration_ms:
152
+ type: integer
153
+ capability_tier:
154
+ type: string
155
+ enum: [basic, intermediate, advanced, expert]
156
+ limitations:
157
+ type: array
158
+ items:
159
+ type: object
160
+ properties:
161
+ dimension:
162
+ type: string
163
+ severity:
164
+ type: string
165
+ description:
166
+ type: string
167
+ conditions:
168
+ type: array
169
+ items:
170
+ type: string
171
+ content_hash:
172
+ type: string
173
+ description: SHA-256 content hash for integrity verification
174
+ signature:
175
+ type: string
176
+ protocol_version:
177
+ type: string
178
+ issued_at:
179
+ type: string
180
+ format: date-time
181
+ expires_at:
182
+ type: string
183
+ format: date-time
184
+ status:
185
+ type: string
186
+ enum: [active, revoked, expired, superseded]
187
+ is_public:
188
+ type: boolean
189
+ tags:
190
+ type: array
191
+ items:
192
+ type: string
193
+ integrity_warning:
194
+ type: string
195
+ description: Present if content hash mismatch detected on read
196
+
197
+ VerificationResult:
198
+ type: object
199
+ properties:
200
+ valid:
201
+ type: boolean
202
+ checks:
203
+ type: array
204
+ items:
205
+ type: object
206
+ properties:
207
+ name:
208
+ type: string
209
+ enum: [content_hash, signature, not_expired, status, score_range, issued_date]
210
+ passed:
211
+ type: boolean
212
+ message:
213
+ type: string
214
+ warnings:
215
+ type: array
216
+ items:
217
+ type: string
218
+
219
+ NutritionLabel:
220
+ type: object
221
+ properties:
222
+ agentId:
223
+ type: string
224
+ certifiedAt:
225
+ type: string
226
+ format: date-time
227
+ expiresAt:
228
+ type: string
229
+ format: date-time
230
+ attestationType:
231
+ type: string
232
+ protocolVersion:
233
+ type: string
234
+ tier:
235
+ type: string
236
+ overallScore:
237
+ type: number
238
+ dimensions:
239
+ type: array
240
+ items:
241
+ type: object
242
+ properties:
243
+ dimension:
244
+ type: string
245
+ score:
246
+ type: number
247
+ strengths:
248
+ type: array
249
+ items:
250
+ type: object
251
+ properties:
252
+ dimension:
253
+ type: string
254
+ score:
255
+ type: number
256
+ description:
257
+ type: string
258
+ limitations:
259
+ type: array
260
+ items:
261
+ type: string
262
+ testConditions:
263
+ type: object
264
+ properties:
265
+ modelProvider:
266
+ type: string
267
+ modelVersion:
268
+ type: string
269
+ testEnvironment:
270
+ type: string
271
+ benchmarkSuite:
272
+ type: string
273
+ benchmarkVersion:
274
+ type: string
275
+ taskCount:
276
+ type: integer
277
+ executionDuration_ms:
278
+ type: integer
279
+
280
+ BenchmarkSuite:
281
+ type: object
282
+ properties:
283
+ id:
284
+ type: string
285
+ example: BS-LQZP3K7MABCD1234
286
+ api_key_id:
287
+ type: string
288
+ nullable: true
289
+ name:
290
+ type: string
291
+ domain:
292
+ type: string
293
+ version:
294
+ type: string
295
+ description:
296
+ type: string
297
+ tasks:
298
+ type: array
299
+ items:
300
+ type: object
301
+ properties:
302
+ name:
303
+ type: string
304
+ category:
305
+ type: string
306
+ difficulty:
307
+ type: integer
308
+ minimum: 1
309
+ maximum: 5
310
+ dimension:
311
+ type: string
312
+ weight:
313
+ type: number
314
+ evaluationMethod:
315
+ type: string
316
+ timeout_ms:
317
+ type: integer
318
+ description:
319
+ type: string
320
+ dimensions:
321
+ type: array
322
+ items:
323
+ type: string
324
+ difficulty:
325
+ type: string
326
+ estimated_duration_ms:
327
+ type: integer
328
+ is_public:
329
+ type: boolean
330
+ nist_alignment:
331
+ type: string
332
+ nullable: true
333
+ task_count:
334
+ type: integer
335
+ created_at:
336
+ type: string
337
+ format: date-time
338
+
339
+ RegistryListing:
340
+ type: object
341
+ properties:
342
+ id:
343
+ type: string
344
+ certificate_id:
345
+ type: string
346
+ api_key_id:
347
+ type: string
348
+ agent_name:
349
+ type: string
350
+ agent_description:
351
+ type: string
352
+ domain:
353
+ type: string
354
+ overall_score:
355
+ type: number
356
+ capability_tier:
357
+ type: string
358
+ listed_at:
359
+ type: string
360
+ format: date-time
361
+ delisted_at:
362
+ type: string
363
+ format: date-time
364
+ nullable: true
365
+
366
+ DriftEvent:
367
+ type: object
368
+ properties:
369
+ id:
370
+ type: string
371
+ api_key_id:
372
+ type: string
373
+ agent_id:
374
+ type: string
375
+ drift_type:
376
+ type: string
377
+ enum: [degradation, improvement, tier_change, dimension_shift, stable]
378
+ severity:
379
+ type: string
380
+ enum: [info, warning, critical]
381
+ previous_certificate_id:
382
+ type: string
383
+ current_certificate_id:
384
+ type: string
385
+ overall_score_delta:
386
+ type: number
387
+ acknowledged:
388
+ type: boolean
389
+ acknowledged_at:
390
+ type: string
391
+ format: date-time
392
+ nullable: true
393
+ acknowledged_note:
394
+ type: string
395
+ nullable: true
396
+ created_at:
397
+ type: string
398
+ format: date-time
399
+
400
+ ComparisonResult:
401
+ type: object
402
+ properties:
403
+ certificates:
404
+ type: array
405
+ items:
406
+ type: object
407
+ properties:
408
+ id:
409
+ type: string
410
+ agentId:
411
+ type: string
412
+ domain:
413
+ type: string
414
+ overallScore:
415
+ type: number
416
+ tier:
417
+ type: string
418
+ issuedAt:
419
+ type: string
420
+ dimensionComparisons:
421
+ type: array
422
+ items:
423
+ type: object
424
+ properties:
425
+ dimension:
426
+ type: string
427
+ scores:
428
+ type: array
429
+ items:
430
+ type: object
431
+ properties:
432
+ certificateId:
433
+ type: string
434
+ agentId:
435
+ type: string
436
+ score:
437
+ type: number
438
+ maxDelta:
439
+ type: number
440
+ overallRanking:
441
+ type: array
442
+ items:
443
+ type: object
444
+ properties:
445
+ certificateId:
446
+ type: string
447
+ agentId:
448
+ type: string
449
+ overallScore:
450
+ type: number
451
+ tier:
452
+ type: string
453
+
454
+ PaginatedResponse:
455
+ type: object
456
+ properties:
457
+ data:
458
+ type: array
459
+ items: {}
460
+ total:
461
+ type: integer
462
+ page:
463
+ type: integer
464
+ pageSize:
465
+ type: integer
466
+
467
+ HealthStats:
468
+ type: object
469
+ properties:
470
+ activeCertificates:
471
+ type: integer
472
+ avgScore:
473
+ type: number
474
+ expiringSoon:
475
+ type: integer
476
+ driftAlerts:
477
+ type: integer
478
+
479
+ paths:
480
+ /attest:
481
+ post:
482
+ summary: Start an attestation run
483
+ description: |
484
+ Creates a new attestation run for an agent against a benchmark suite.
485
+ Tasks are served in randomized order (Fisher-Yates shuffle) for anti-gaming.
486
+ Rate limit: 10 requests/minute.
487
+ requestBody:
488
+ required: true
489
+ content:
490
+ application/json:
491
+ schema:
492
+ type: object
493
+ required: [agentId, suiteId]
494
+ properties:
495
+ agentId:
496
+ type: string
497
+ minLength: 1
498
+ maxLength: 256
499
+ suiteId:
500
+ type: string
501
+ format: uuid
502
+ example:
503
+ agentId: my-customer-service-agent
504
+ suiteId: 550e8400-e29b-41d4-a716-446655440000
505
+ responses:
506
+ '201':
507
+ description: Attestation run created
508
+ content:
509
+ application/json:
510
+ schema:
511
+ $ref: '#/components/schemas/AttestationRun'
512
+ example:
513
+ id: RUN-LQZP3K7MABCD1234
514
+ agent_id: my-customer-service-agent
515
+ status: pending
516
+ warning: Another attestation run is already in progress for this agent
517
+ '400':
518
+ description: Validation error
519
+ content:
520
+ application/json:
521
+ schema:
522
+ $ref: '#/components/schemas/Error'
523
+ example:
524
+ error: Validation failed
525
+ code: VALIDATION_ERROR
526
+ details:
527
+ - path: suiteId
528
+ message: Invalid uuid
529
+ '401':
530
+ description: Unauthorized
531
+ '404':
532
+ description: Benchmark suite not found
533
+ '429':
534
+ description: Rate limited
535
+ headers:
536
+ Retry-After:
537
+ schema:
538
+ type: integer
539
+ X-RateLimit-Limit:
540
+ schema:
541
+ type: integer
542
+ X-RateLimit-Reset:
543
+ schema:
544
+ type: integer
545
+
546
+ /attest/{runId}:
547
+ parameters:
548
+ - name: runId
549
+ in: path
550
+ required: true
551
+ schema:
552
+ type: string
553
+ get:
554
+ summary: Get attestation run status
555
+ description: Poll this endpoint to track attestation progress.
556
+ responses:
557
+ '200':
558
+ description: Run status
559
+ content:
560
+ application/json:
561
+ schema:
562
+ $ref: '#/components/schemas/AttestationRun'
563
+ '403':
564
+ description: Not your run
565
+ '404':
566
+ description: Run not found
567
+ delete:
568
+ summary: Cancel an attestation run
569
+ description: Cancels a pending or running attestation. Cannot cancel completed or already cancelled runs.
570
+ responses:
571
+ '200':
572
+ description: Run cancelled
573
+ content:
574
+ application/json:
575
+ example:
576
+ success: true
577
+ id: RUN-LQZP3K7MABCD1234
578
+ status: cancelled
579
+ '409':
580
+ description: Cannot cancel a completed/cancelled run
581
+
582
+ /certificates:
583
+ get:
584
+ summary: List certificates
585
+ description: Returns paginated certificates owned by the authenticated user.
586
+ parameters:
587
+ - name: agentId
588
+ in: query
589
+ schema:
590
+ type: string
591
+ - name: domain
592
+ in: query
593
+ schema:
594
+ type: string
595
+ - name: status
596
+ in: query
597
+ schema:
598
+ type: string
599
+ enum: [active, revoked, expired, superseded]
600
+ - name: page
601
+ in: query
602
+ schema:
603
+ type: integer
604
+ default: 1
605
+ - name: pageSize
606
+ in: query
607
+ schema:
608
+ type: integer
609
+ default: 20
610
+ maximum: 100
611
+ responses:
612
+ '200':
613
+ description: Paginated certificate list
614
+ content:
615
+ application/json:
616
+ schema:
617
+ allOf:
618
+ - $ref: '#/components/schemas/PaginatedResponse'
619
+ - type: object
620
+ properties:
621
+ data:
622
+ type: array
623
+ items:
624
+ $ref: '#/components/schemas/Certificate'
625
+
626
+ /certificates/{id}:
627
+ parameters:
628
+ - name: id
629
+ in: path
630
+ required: true
631
+ schema:
632
+ type: string
633
+ get:
634
+ summary: Get a certificate
635
+ description: |
636
+ Fetches a single certificate. Accessible if you own it or if it's public.
637
+ Performs content hash integrity verification on read — if the hash doesn't match,
638
+ an `integrity_warning` field is included in the response.
639
+ responses:
640
+ '200':
641
+ description: Certificate data
642
+ content:
643
+ application/json:
644
+ schema:
645
+ $ref: '#/components/schemas/Certificate'
646
+ '403':
647
+ description: Certificate is private and not owned by you
648
+ '404':
649
+ description: Certificate not found
650
+
651
+ /certificates/{id}/verify:
652
+ parameters:
653
+ - name: id
654
+ in: path
655
+ required: true
656
+ schema:
657
+ type: string
658
+ get:
659
+ summary: Verify certificate integrity
660
+ description: |
661
+ Runs integrity and validity checks on a certificate:
662
+ content hash (cryptographic), signature, expiration (with 7-day grace period),
663
+ status, score range, and issue date.
664
+ responses:
665
+ '200':
666
+ description: Verification result
667
+ content:
668
+ application/json:
669
+ schema:
670
+ $ref: '#/components/schemas/VerificationResult'
671
+ example:
672
+ valid: true
673
+ checks:
674
+ - name: content_hash
675
+ passed: true
676
+ message: Content hash matches certificate data
677
+ - name: not_expired
678
+ passed: true
679
+ message: Expired at 2026-03-01T00:00:00Z — within 7-day grace period
680
+ warnings:
681
+ - Certificate expired 3 days ago — within 7-day grace period
682
+ '404':
683
+ description: Certificate not found
684
+
685
+ /certificates/{id}/revoke:
686
+ parameters:
687
+ - name: id
688
+ in: path
689
+ required: true
690
+ schema:
691
+ type: string
692
+ post:
693
+ summary: Revoke a certificate
694
+ description: Revokes an active certificate. Also delists from registry if published.
695
+ requestBody:
696
+ content:
697
+ application/json:
698
+ schema:
699
+ type: object
700
+ properties:
701
+ reason:
702
+ type: string
703
+ example:
704
+ reason: Model updated, re-attestation in progress
705
+ responses:
706
+ '200':
707
+ description: Certificate revoked
708
+ content:
709
+ application/json:
710
+ example:
711
+ success: true
712
+ id: CERT-ID
713
+ status: revoked
714
+ '403':
715
+ description: Not your certificate
716
+ '409':
717
+ description: Already revoked
718
+
719
+ /certificates/{id}/label:
720
+ parameters:
721
+ - name: id
722
+ in: path
723
+ required: true
724
+ schema:
725
+ type: string
726
+ get:
727
+ summary: Get nutrition label
728
+ description: Returns a human-readable nutrition label with strengths, test conditions, and limitations.
729
+ responses:
730
+ '200':
731
+ description: Nutrition label
732
+ content:
733
+ application/json:
734
+ schema:
735
+ $ref: '#/components/schemas/NutritionLabel'
736
+ '403':
737
+ description: Certificate is private and not owned by you
738
+ '404':
739
+ description: Certificate not found
740
+
741
+ /certificates/{id}/badge:
742
+ parameters:
743
+ - name: id
744
+ in: path
745
+ required: true
746
+ schema:
747
+ type: string
748
+ get:
749
+ summary: Get certificate badge (SVG)
750
+ description: |
751
+ Returns a shields.io-style SVG badge showing "ACAP | Tier Score%".
752
+ Public certificates are served without authentication.
753
+ Private certificates require Bearer token auth.
754
+ security: []
755
+ responses:
756
+ '200':
757
+ description: SVG badge image
758
+ content:
759
+ image/svg+xml:
760
+ schema:
761
+ type: string
762
+ headers:
763
+ Cache-Control:
764
+ schema:
765
+ type: string
766
+ example: public, max-age=3600
767
+
768
+ /agents/{agentId}/certificates:
769
+ parameters:
770
+ - name: agentId
771
+ in: path
772
+ required: true
773
+ schema:
774
+ type: string
775
+ get:
776
+ summary: List certificates for an agent
777
+ description: Returns paginated certificates for a specific agent.
778
+ parameters:
779
+ - name: domain
780
+ in: query
781
+ schema:
782
+ type: string
783
+ - name: status
784
+ in: query
785
+ schema:
786
+ type: string
787
+ default: active
788
+ - name: page
789
+ in: query
790
+ schema:
791
+ type: integer
792
+ default: 1
793
+ - name: pageSize
794
+ in: query
795
+ schema:
796
+ type: integer
797
+ default: 20
798
+ maximum: 100
799
+ responses:
800
+ '200':
801
+ description: Paginated certificate list
802
+ content:
803
+ application/json:
804
+ schema:
805
+ allOf:
806
+ - $ref: '#/components/schemas/PaginatedResponse'
807
+ - type: object
808
+ properties:
809
+ data:
810
+ type: array
811
+ items:
812
+ $ref: '#/components/schemas/Certificate'
813
+
814
+ /registry/publish:
815
+ post:
816
+ summary: Publish certificate to registry
817
+ description: |
818
+ Publishes a certificate to the public registry. Requirements:
819
+ - Certificate must be active
820
+ - Certificate must have at least 3 task results
821
+ - Certificate must not already be listed
822
+ Rate limit: 20 requests/minute.
823
+ requestBody:
824
+ required: true
825
+ content:
826
+ application/json:
827
+ schema:
828
+ type: object
829
+ required: [certificateId, agentName, agentDescription]
830
+ properties:
831
+ certificateId:
832
+ type: string
833
+ format: uuid
834
+ agentName:
835
+ type: string
836
+ minLength: 1
837
+ maxLength: 100
838
+ agentDescription:
839
+ type: string
840
+ minLength: 1
841
+ maxLength: 2000
842
+ example:
843
+ certificateId: 550e8400-e29b-41d4-a716-446655440000
844
+ agentName: My Customer Service Agent
845
+ agentDescription: Specialized agent for tier-1 support workflows
846
+ responses:
847
+ '201':
848
+ description: Listing created
849
+ content:
850
+ application/json:
851
+ schema:
852
+ $ref: '#/components/schemas/RegistryListing'
853
+ '400':
854
+ description: Validation error or insufficient task results
855
+ '403':
856
+ description: Not your certificate
857
+ '409':
858
+ description: Certificate already listed
859
+ '429':
860
+ description: Rate limited
861
+
862
+ /registry/search:
863
+ get:
864
+ summary: Search the public registry
865
+ parameters:
866
+ - name: domain
867
+ in: query
868
+ schema:
869
+ type: string
870
+ - name: minScore
871
+ in: query
872
+ schema:
873
+ type: number
874
+ - name: maxScore
875
+ in: query
876
+ schema:
877
+ type: number
878
+ - name: tier
879
+ in: query
880
+ schema:
881
+ type: string
882
+ enum: [basic, intermediate, advanced, expert]
883
+ - name: query
884
+ in: query
885
+ description: Search agent name and description
886
+ schema:
887
+ type: string
888
+ - name: sortBy
889
+ in: query
890
+ schema:
891
+ type: string
892
+ enum: [score, recent, name]
893
+ default: score
894
+ - name: page
895
+ in: query
896
+ schema:
897
+ type: integer
898
+ default: 1
899
+ - name: pageSize
900
+ in: query
901
+ schema:
902
+ type: integer
903
+ default: 20
904
+ maximum: 100
905
+ responses:
906
+ '200':
907
+ description: Paginated registry listings
908
+ content:
909
+ application/json:
910
+ schema:
911
+ allOf:
912
+ - $ref: '#/components/schemas/PaginatedResponse'
913
+ - type: object
914
+ properties:
915
+ data:
916
+ type: array
917
+ items:
918
+ $ref: '#/components/schemas/RegistryListing'
919
+
920
+ /registry/leaderboard/{domain}:
921
+ parameters:
922
+ - name: domain
923
+ in: path
924
+ required: true
925
+ schema:
926
+ type: string
927
+ get:
928
+ summary: Get domain leaderboard
929
+ description: Returns top agents for a domain, sorted by score descending.
930
+ parameters:
931
+ - name: limit
932
+ in: query
933
+ schema:
934
+ type: integer
935
+ default: 25
936
+ maximum: 100
937
+ responses:
938
+ '200':
939
+ description: Leaderboard entries
940
+ content:
941
+ application/json:
942
+ schema:
943
+ type: object
944
+ properties:
945
+ domain:
946
+ type: string
947
+ entries:
948
+ type: array
949
+ items:
950
+ type: object
951
+ properties:
952
+ rank:
953
+ type: integer
954
+ id:
955
+ type: string
956
+ certificate_id:
957
+ type: string
958
+ agent_name:
959
+ type: string
960
+ agent_description:
961
+ type: string
962
+ overall_score:
963
+ type: number
964
+ capability_tier:
965
+ type: string
966
+ listed_at:
967
+ type: string
968
+ format: date-time
969
+
970
+ /suites:
971
+ get:
972
+ summary: List benchmark suites
973
+ description: Returns public/system suites plus the authenticated user's own suites.
974
+ parameters:
975
+ - name: domain
976
+ in: query
977
+ schema:
978
+ type: string
979
+ - name: isPublic
980
+ in: query
981
+ schema:
982
+ type: string
983
+ enum: ['true', 'false']
984
+ responses:
985
+ '200':
986
+ description: Array of benchmark suites
987
+ content:
988
+ application/json:
989
+ schema:
990
+ type: array
991
+ items:
992
+ $ref: '#/components/schemas/BenchmarkSuite'
993
+ post:
994
+ summary: Create a benchmark suite
995
+ description: |
996
+ Creates a custom benchmark suite with 1-100 tasks.
997
+ Rate limit: 30 requests/minute.
998
+ requestBody:
999
+ required: true
1000
+ content:
1001
+ application/json:
1002
+ schema:
1003
+ type: object
1004
+ required: [name, domain, tasks]
1005
+ properties:
1006
+ name:
1007
+ type: string
1008
+ minLength: 1
1009
+ maxLength: 256
1010
+ domain:
1011
+ type: string
1012
+ minLength: 1
1013
+ version:
1014
+ type: string
1015
+ maxLength: 50
1016
+ default: '1.0'
1017
+ description:
1018
+ type: string
1019
+ maxLength: 2000
1020
+ tasks:
1021
+ type: array
1022
+ minItems: 1
1023
+ maxItems: 100
1024
+ items:
1025
+ type: object
1026
+ required: [name]
1027
+ properties:
1028
+ name:
1029
+ type: string
1030
+ minLength: 1
1031
+ maxLength: 256
1032
+ category:
1033
+ type: string
1034
+ difficulty:
1035
+ type: integer
1036
+ minimum: 1
1037
+ maximum: 5
1038
+ dimension:
1039
+ type: string
1040
+ weight:
1041
+ type: number
1042
+ minimum: 0
1043
+ maximum: 10
1044
+ evaluationMethod:
1045
+ type: string
1046
+ timeout_ms:
1047
+ type: integer
1048
+ minimum: 0
1049
+ description:
1050
+ type: string
1051
+ maxLength: 2000
1052
+ dimensions:
1053
+ type: array
1054
+ items:
1055
+ type: string
1056
+ difficulty:
1057
+ type: string
1058
+ estimatedDuration_ms:
1059
+ type: integer
1060
+ minimum: 0
1061
+ isPublic:
1062
+ type: boolean
1063
+ default: false
1064
+ nistAlignment:
1065
+ type: string
1066
+ nullable: true
1067
+ responses:
1068
+ '201':
1069
+ description: Suite created
1070
+ content:
1071
+ application/json:
1072
+ schema:
1073
+ $ref: '#/components/schemas/BenchmarkSuite'
1074
+ '400':
1075
+ description: Validation error
1076
+ '429':
1077
+ description: Rate limited
1078
+
1079
+ /suites/{id}:
1080
+ parameters:
1081
+ - name: id
1082
+ in: path
1083
+ required: true
1084
+ schema:
1085
+ type: string
1086
+ get:
1087
+ summary: Get a benchmark suite
1088
+ description: Accessible if public, system-owned, or owned by you.
1089
+ responses:
1090
+ '200':
1091
+ description: Benchmark suite
1092
+ content:
1093
+ application/json:
1094
+ schema:
1095
+ $ref: '#/components/schemas/BenchmarkSuite'
1096
+ '403':
1097
+ description: Private suite not owned by you
1098
+ '404':
1099
+ description: Suite not found
1100
+ put:
1101
+ summary: Update a benchmark suite
1102
+ description: Only the owner can update a suite. All fields are optional.
1103
+ requestBody:
1104
+ required: true
1105
+ content:
1106
+ application/json:
1107
+ schema:
1108
+ type: object
1109
+ properties:
1110
+ name:
1111
+ type: string
1112
+ minLength: 1
1113
+ maxLength: 256
1114
+ description:
1115
+ type: string
1116
+ maxLength: 2000
1117
+ version:
1118
+ type: string
1119
+ maxLength: 50
1120
+ tasks:
1121
+ type: array
1122
+ minItems: 1
1123
+ maxItems: 100
1124
+ dimensions:
1125
+ type: array
1126
+ items:
1127
+ type: string
1128
+ difficulty:
1129
+ type: string
1130
+ estimatedDuration_ms:
1131
+ type: integer
1132
+ isPublic:
1133
+ type: boolean
1134
+ nistAlignment:
1135
+ type: string
1136
+ nullable: true
1137
+ responses:
1138
+ '200':
1139
+ description: Suite updated
1140
+ content:
1141
+ application/json:
1142
+ schema:
1143
+ $ref: '#/components/schemas/BenchmarkSuite'
1144
+ '400':
1145
+ description: Validation error or no fields to update
1146
+ '403':
1147
+ description: Can only update your own suites
1148
+ '404':
1149
+ description: Suite not found
1150
+ delete:
1151
+ summary: Delete a benchmark suite
1152
+ description: Only the owner can delete a suite.
1153
+ responses:
1154
+ '200':
1155
+ description: Suite deleted
1156
+ content:
1157
+ application/json:
1158
+ example:
1159
+ success: true
1160
+ '403':
1161
+ description: Can only delete your own suites
1162
+ '404':
1163
+ description: Suite not found
1164
+
1165
+ /compare:
1166
+ get:
1167
+ summary: Compare certificates
1168
+ description: Compare 2-10 certificates side-by-side on all capability dimensions.
1169
+ parameters:
1170
+ - name: ids
1171
+ in: query
1172
+ required: true
1173
+ description: Comma-separated certificate IDs (2-10)
1174
+ schema:
1175
+ type: string
1176
+ example: cert-id-1,cert-id-2,cert-id-3
1177
+ responses:
1178
+ '200':
1179
+ description: Comparison result
1180
+ content:
1181
+ application/json:
1182
+ schema:
1183
+ $ref: '#/components/schemas/ComparisonResult'
1184
+ '400':
1185
+ description: Less than 2 or more than 10 IDs
1186
+ '403':
1187
+ description: One or more certificates are private and not owned by you
1188
+ '404':
1189
+ description: Could not find enough certificates
1190
+
1191
+ /drift:
1192
+ get:
1193
+ summary: List drift events
1194
+ description: Returns paginated capability drift events for the authenticated user.
1195
+ parameters:
1196
+ - name: agentId
1197
+ in: query
1198
+ schema:
1199
+ type: string
1200
+ - name: severity
1201
+ in: query
1202
+ schema:
1203
+ type: string
1204
+ enum: [info, warning, critical]
1205
+ - name: acknowledged
1206
+ in: query
1207
+ schema:
1208
+ type: string
1209
+ enum: ['true', 'false']
1210
+ - name: page
1211
+ in: query
1212
+ schema:
1213
+ type: integer
1214
+ default: 1
1215
+ - name: pageSize
1216
+ in: query
1217
+ schema:
1218
+ type: integer
1219
+ default: 50
1220
+ maximum: 100
1221
+ responses:
1222
+ '200':
1223
+ description: Paginated drift events
1224
+ content:
1225
+ application/json:
1226
+ schema:
1227
+ allOf:
1228
+ - $ref: '#/components/schemas/PaginatedResponse'
1229
+ - type: object
1230
+ properties:
1231
+ data:
1232
+ type: array
1233
+ items:
1234
+ $ref: '#/components/schemas/DriftEvent'
1235
+ patch:
1236
+ summary: Acknowledge drift events
1237
+ description: |
1238
+ Acknowledge one or more drift events. Two request body shapes are supported.
1239
+ Maximum 100 events per request.
1240
+ Rate limit: 30 requests/minute.
1241
+ requestBody:
1242
+ required: true
1243
+ content:
1244
+ application/json:
1245
+ schema:
1246
+ oneOf:
1247
+ - type: object
1248
+ required: [eventIds]
1249
+ properties:
1250
+ eventIds:
1251
+ type: array
1252
+ items:
1253
+ type: string
1254
+ minItems: 1
1255
+ maxItems: 100
1256
+ description: Bulk acknowledge with shared note
1257
+ note:
1258
+ type: string
1259
+ maxLength: 1000
1260
+ - type: object
1261
+ required: [events]
1262
+ properties:
1263
+ events:
1264
+ type: array
1265
+ items:
1266
+ type: object
1267
+ required: [id]
1268
+ properties:
1269
+ id:
1270
+ type: string
1271
+ note:
1272
+ type: string
1273
+ maxLength: 1000
1274
+ minItems: 1
1275
+ maxItems: 100
1276
+ description: Per-event acknowledge with individual notes
1277
+ examples:
1278
+ bulk:
1279
+ summary: Bulk acknowledge
1280
+ value:
1281
+ eventIds: [event-1, event-2, event-3]
1282
+ note: Acknowledged after review
1283
+ per-event:
1284
+ summary: Per-event notes
1285
+ value:
1286
+ events:
1287
+ - id: event-1
1288
+ note: Expected degradation after model swap
1289
+ - id: event-2
1290
+ note: Will re-attest next week
1291
+ responses:
1292
+ '200':
1293
+ description: Events acknowledged
1294
+ content:
1295
+ application/json:
1296
+ example:
1297
+ success: true
1298
+ acknowledged: 3
1299
+ '400':
1300
+ description: Validation error
1301
+ '429':
1302
+ description: Rate limited
1303
+
1304
+ /health:
1305
+ get:
1306
+ summary: Get ACAP health stats
1307
+ description: Lightweight dashboard stats for the overview page.
1308
+ responses:
1309
+ '200':
1310
+ description: Health stats
1311
+ content:
1312
+ application/json:
1313
+ schema:
1314
+ $ref: '#/components/schemas/HealthStats'
1315
+ example:
1316
+ activeCertificates: 12
1317
+ avgScore: 0.73
1318
+ expiringSoon: 2
1319
+ driftAlerts: 1