@willyim/idp 0.1.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,1344 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "willy.im IdP — Management API",
5
+ "version": "1.0.0",
6
+ "description": "Management API for the willy.im identity provider. Authenticate with `Authorization: Bearer <token>`. Two kinds of token: the superadmin `ADMIN_API_TOKEN` (every app) and per-app **scoped API keys** minted in the admin console (one app, a fixed permission set). The cross-app list endpoints below require the superadmin token. Application registration is done in the admin console (better-auth ties client creation to an admin session)."
7
+ },
8
+ "servers": [
9
+ {
10
+ "url": "https://idp.willy.im"
11
+ }
12
+ ],
13
+ "components": {
14
+ "securitySchemes": {
15
+ "bearerAuth": {
16
+ "type": "http",
17
+ "scheme": "bearer",
18
+ "description": "Superadmin ADMIN_API_TOKEN or a scoped API key (wim_…)."
19
+ }
20
+ }
21
+ },
22
+ "paths": {
23
+ "/api/v1/applications": {
24
+ "get": {
25
+ "summary": "List registered applications",
26
+ "security": [
27
+ {
28
+ "bearerAuth": []
29
+ }
30
+ ],
31
+ "responses": {
32
+ "200": {
33
+ "description": "OK",
34
+ "content": {
35
+ "application/json": {
36
+ "schema": {
37
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
38
+ "type": "object",
39
+ "properties": {
40
+ "applications": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "object",
44
+ "properties": {
45
+ "clientId": {
46
+ "type": "string"
47
+ },
48
+ "name": {
49
+ "anyOf": [
50
+ {
51
+ "type": "string"
52
+ },
53
+ {
54
+ "type": "null"
55
+ }
56
+ ]
57
+ },
58
+ "app": {
59
+ "anyOf": [
60
+ {
61
+ "type": "string"
62
+ },
63
+ {
64
+ "type": "null"
65
+ }
66
+ ],
67
+ "description": "Application key; consumer workspace claims are filtered by this"
68
+ },
69
+ "redirectUris": {
70
+ "type": "array",
71
+ "items": {
72
+ "type": "string"
73
+ }
74
+ },
75
+ "disabled": {
76
+ "type": "boolean"
77
+ },
78
+ "createdAt": {
79
+ "type": "string",
80
+ "description": "ISO 8601 timestamp"
81
+ }
82
+ },
83
+ "required": [
84
+ "clientId",
85
+ "name",
86
+ "app",
87
+ "redirectUris",
88
+ "disabled",
89
+ "createdAt"
90
+ ],
91
+ "additionalProperties": false
92
+ }
93
+ }
94
+ },
95
+ "required": [
96
+ "applications"
97
+ ],
98
+ "additionalProperties": false
99
+ }
100
+ }
101
+ }
102
+ },
103
+ "401": {
104
+ "description": "Missing or invalid bearer token"
105
+ }
106
+ }
107
+ }
108
+ },
109
+ "/api/v1/users": {
110
+ "get": {
111
+ "summary": "List users",
112
+ "security": [
113
+ {
114
+ "bearerAuth": []
115
+ }
116
+ ],
117
+ "responses": {
118
+ "200": {
119
+ "description": "OK",
120
+ "content": {
121
+ "application/json": {
122
+ "schema": {
123
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
124
+ "type": "object",
125
+ "properties": {
126
+ "users": {
127
+ "type": "array",
128
+ "items": {
129
+ "type": "object",
130
+ "properties": {
131
+ "id": {
132
+ "type": "string"
133
+ },
134
+ "email": {
135
+ "type": "string"
136
+ },
137
+ "name": {
138
+ "anyOf": [
139
+ {
140
+ "type": "string"
141
+ },
142
+ {
143
+ "type": "null"
144
+ }
145
+ ]
146
+ },
147
+ "emailVerified": {
148
+ "type": "boolean"
149
+ },
150
+ "createdAt": {
151
+ "type": "string"
152
+ }
153
+ },
154
+ "required": [
155
+ "id",
156
+ "email",
157
+ "name",
158
+ "emailVerified",
159
+ "createdAt"
160
+ ],
161
+ "additionalProperties": false
162
+ }
163
+ }
164
+ },
165
+ "required": [
166
+ "users"
167
+ ],
168
+ "additionalProperties": false
169
+ }
170
+ }
171
+ }
172
+ },
173
+ "401": {
174
+ "description": "Missing or invalid bearer token"
175
+ }
176
+ }
177
+ }
178
+ },
179
+ "/api/v1/workspaces": {
180
+ "get": {
181
+ "summary": "List workspaces",
182
+ "security": [
183
+ {
184
+ "bearerAuth": []
185
+ }
186
+ ],
187
+ "responses": {
188
+ "200": {
189
+ "description": "OK",
190
+ "content": {
191
+ "application/json": {
192
+ "schema": {
193
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
194
+ "type": "object",
195
+ "properties": {
196
+ "workspaces": {
197
+ "type": "array",
198
+ "items": {
199
+ "type": "object",
200
+ "properties": {
201
+ "id": {
202
+ "type": "string"
203
+ },
204
+ "name": {
205
+ "type": "string"
206
+ },
207
+ "slug": {
208
+ "type": "string"
209
+ },
210
+ "applicationId": {
211
+ "anyOf": [
212
+ {
213
+ "type": "string"
214
+ },
215
+ {
216
+ "type": "null"
217
+ }
218
+ ]
219
+ },
220
+ "createdAt": {
221
+ "type": "string"
222
+ }
223
+ },
224
+ "required": [
225
+ "id",
226
+ "name",
227
+ "slug",
228
+ "applicationId",
229
+ "createdAt"
230
+ ],
231
+ "additionalProperties": false
232
+ }
233
+ }
234
+ },
235
+ "required": [
236
+ "workspaces"
237
+ ],
238
+ "additionalProperties": false
239
+ }
240
+ }
241
+ }
242
+ },
243
+ "401": {
244
+ "description": "Missing or invalid bearer token"
245
+ }
246
+ }
247
+ }
248
+ },
249
+ "/api/v1/apps/{app}/members": {
250
+ "get": {
251
+ "summary": "List app members",
252
+ "description": "Requires `member:read` on the path app (or the superadmin token).",
253
+ "security": [
254
+ {
255
+ "bearerAuth": []
256
+ }
257
+ ],
258
+ "parameters": [
259
+ {
260
+ "name": "app",
261
+ "in": "path",
262
+ "required": true,
263
+ "description": "Application key (oauth_client.metadata.app).",
264
+ "schema": {
265
+ "type": "string"
266
+ }
267
+ }
268
+ ],
269
+ "responses": {
270
+ "200": {
271
+ "description": "OK",
272
+ "content": {
273
+ "application/json": {
274
+ "schema": {
275
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
276
+ "type": "object",
277
+ "properties": {
278
+ "members": {
279
+ "type": "array",
280
+ "items": {
281
+ "type": "object",
282
+ "properties": {
283
+ "userId": {
284
+ "type": "string"
285
+ },
286
+ "email": {
287
+ "type": "string"
288
+ },
289
+ "name": {
290
+ "anyOf": [
291
+ {
292
+ "type": "string"
293
+ },
294
+ {
295
+ "type": "null"
296
+ }
297
+ ]
298
+ },
299
+ "role": {
300
+ "type": "string",
301
+ "enum": [
302
+ "admin",
303
+ "member"
304
+ ]
305
+ },
306
+ "permissions": {
307
+ "type": "array",
308
+ "items": {
309
+ "type": "string"
310
+ }
311
+ }
312
+ },
313
+ "required": [
314
+ "userId",
315
+ "email",
316
+ "name",
317
+ "role",
318
+ "permissions"
319
+ ],
320
+ "additionalProperties": false
321
+ }
322
+ }
323
+ },
324
+ "required": [
325
+ "members"
326
+ ],
327
+ "additionalProperties": false
328
+ }
329
+ }
330
+ }
331
+ },
332
+ "401": {
333
+ "description": "Missing or invalid bearer token"
334
+ },
335
+ "403": {
336
+ "description": "Key lacks the permission / is bound to another app"
337
+ }
338
+ }
339
+ },
340
+ "post": {
341
+ "summary": "Add or invite a member",
342
+ "description": "Requires `member:invite` on the path app (or the superadmin token).",
343
+ "security": [
344
+ {
345
+ "bearerAuth": []
346
+ }
347
+ ],
348
+ "parameters": [
349
+ {
350
+ "name": "app",
351
+ "in": "path",
352
+ "required": true,
353
+ "description": "Application key (oauth_client.metadata.app).",
354
+ "schema": {
355
+ "type": "string"
356
+ }
357
+ }
358
+ ],
359
+ "requestBody": {
360
+ "required": true,
361
+ "content": {
362
+ "application/json": {
363
+ "schema": {
364
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
365
+ "type": "object",
366
+ "properties": {
367
+ "email": {
368
+ "type": "string",
369
+ "format": "email",
370
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
371
+ },
372
+ "role": {
373
+ "default": "member",
374
+ "type": "string",
375
+ "enum": [
376
+ "admin",
377
+ "member"
378
+ ]
379
+ },
380
+ "permissions": {
381
+ "default": [],
382
+ "type": "array",
383
+ "items": {
384
+ "type": "string"
385
+ }
386
+ }
387
+ },
388
+ "required": [
389
+ "email"
390
+ ]
391
+ }
392
+ }
393
+ }
394
+ },
395
+ "responses": {
396
+ "201": {
397
+ "description": "OK",
398
+ "content": {
399
+ "application/json": {
400
+ "schema": {
401
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
402
+ "type": "object",
403
+ "properties": {
404
+ "result": {
405
+ "type": "string",
406
+ "enum": [
407
+ "added",
408
+ "invited"
409
+ ]
410
+ }
411
+ },
412
+ "required": [
413
+ "result"
414
+ ],
415
+ "additionalProperties": false
416
+ }
417
+ }
418
+ }
419
+ },
420
+ "401": {
421
+ "description": "Missing or invalid bearer token"
422
+ },
423
+ "403": {
424
+ "description": "Key lacks the permission / is bound to another app"
425
+ },
426
+ "405": {
427
+ "description": "Method not allowed on this resource (see the `Allow` header)"
428
+ },
429
+ "409": {
430
+ "description": "Conflict (already a member, last admin, slug taken, …)"
431
+ },
432
+ "422": {
433
+ "description": "Body failed validation"
434
+ }
435
+ }
436
+ }
437
+ },
438
+ "/api/v1/apps/{app}/members/{userId}": {
439
+ "patch": {
440
+ "summary": "Update a member's role + permissions",
441
+ "description": "Requires `member:manage` on the path app (or the superadmin token).",
442
+ "security": [
443
+ {
444
+ "bearerAuth": []
445
+ }
446
+ ],
447
+ "parameters": [
448
+ {
449
+ "name": "app",
450
+ "in": "path",
451
+ "required": true,
452
+ "description": "Application key (oauth_client.metadata.app).",
453
+ "schema": {
454
+ "type": "string"
455
+ }
456
+ },
457
+ {
458
+ "name": "userId",
459
+ "in": "path",
460
+ "required": true,
461
+ "schema": {
462
+ "type": "string"
463
+ }
464
+ }
465
+ ],
466
+ "requestBody": {
467
+ "required": true,
468
+ "content": {
469
+ "application/json": {
470
+ "schema": {
471
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
472
+ "type": "object",
473
+ "properties": {
474
+ "role": {
475
+ "type": "string",
476
+ "enum": [
477
+ "admin",
478
+ "member"
479
+ ]
480
+ },
481
+ "permissions": {
482
+ "default": [],
483
+ "type": "array",
484
+ "items": {
485
+ "type": "string"
486
+ }
487
+ }
488
+ },
489
+ "required": [
490
+ "role"
491
+ ]
492
+ }
493
+ }
494
+ }
495
+ },
496
+ "responses": {
497
+ "200": {
498
+ "description": "OK",
499
+ "content": {
500
+ "application/json": {
501
+ "schema": {
502
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
503
+ "type": "object",
504
+ "properties": {
505
+ "ok": {
506
+ "type": "boolean",
507
+ "const": true
508
+ }
509
+ },
510
+ "required": [
511
+ "ok"
512
+ ],
513
+ "additionalProperties": false
514
+ }
515
+ }
516
+ }
517
+ },
518
+ "401": {
519
+ "description": "Missing or invalid bearer token"
520
+ },
521
+ "403": {
522
+ "description": "Key lacks the permission / is bound to another app"
523
+ },
524
+ "405": {
525
+ "description": "Method not allowed on this resource (see the `Allow` header)"
526
+ },
527
+ "409": {
528
+ "description": "Conflict (already a member, last admin, slug taken, …)"
529
+ },
530
+ "422": {
531
+ "description": "Body failed validation"
532
+ }
533
+ }
534
+ },
535
+ "delete": {
536
+ "summary": "Remove a member",
537
+ "description": "Requires `member:manage` on the path app (or the superadmin token).",
538
+ "security": [
539
+ {
540
+ "bearerAuth": []
541
+ }
542
+ ],
543
+ "parameters": [
544
+ {
545
+ "name": "app",
546
+ "in": "path",
547
+ "required": true,
548
+ "description": "Application key (oauth_client.metadata.app).",
549
+ "schema": {
550
+ "type": "string"
551
+ }
552
+ },
553
+ {
554
+ "name": "userId",
555
+ "in": "path",
556
+ "required": true,
557
+ "schema": {
558
+ "type": "string"
559
+ }
560
+ }
561
+ ],
562
+ "responses": {
563
+ "200": {
564
+ "description": "OK",
565
+ "content": {
566
+ "application/json": {
567
+ "schema": {
568
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
569
+ "type": "object",
570
+ "properties": {
571
+ "ok": {
572
+ "type": "boolean",
573
+ "const": true
574
+ }
575
+ },
576
+ "required": [
577
+ "ok"
578
+ ],
579
+ "additionalProperties": false
580
+ }
581
+ }
582
+ }
583
+ },
584
+ "401": {
585
+ "description": "Missing or invalid bearer token"
586
+ },
587
+ "403": {
588
+ "description": "Key lacks the permission / is bound to another app"
589
+ },
590
+ "405": {
591
+ "description": "Method not allowed on this resource (see the `Allow` header)"
592
+ },
593
+ "409": {
594
+ "description": "Conflict (already a member, last admin, slug taken, …)"
595
+ },
596
+ "422": {
597
+ "description": "Body failed validation"
598
+ }
599
+ }
600
+ }
601
+ },
602
+ "/api/v1/apps/{app}/workspaces": {
603
+ "get": {
604
+ "summary": "List app workspaces",
605
+ "description": "Requires `workspace:read` on the path app (or the superadmin token).",
606
+ "security": [
607
+ {
608
+ "bearerAuth": []
609
+ }
610
+ ],
611
+ "parameters": [
612
+ {
613
+ "name": "app",
614
+ "in": "path",
615
+ "required": true,
616
+ "description": "Application key (oauth_client.metadata.app).",
617
+ "schema": {
618
+ "type": "string"
619
+ }
620
+ }
621
+ ],
622
+ "responses": {
623
+ "200": {
624
+ "description": "OK",
625
+ "content": {
626
+ "application/json": {
627
+ "schema": {
628
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
629
+ "type": "object",
630
+ "properties": {
631
+ "workspaces": {
632
+ "type": "array",
633
+ "items": {
634
+ "type": "object",
635
+ "properties": {
636
+ "id": {
637
+ "type": "string"
638
+ },
639
+ "name": {
640
+ "type": "string"
641
+ },
642
+ "slug": {
643
+ "type": "string"
644
+ },
645
+ "applicationId": {
646
+ "anyOf": [
647
+ {
648
+ "type": "string"
649
+ },
650
+ {
651
+ "type": "null"
652
+ }
653
+ ]
654
+ },
655
+ "createdAt": {
656
+ "type": "string"
657
+ }
658
+ },
659
+ "required": [
660
+ "id",
661
+ "name",
662
+ "slug",
663
+ "applicationId",
664
+ "createdAt"
665
+ ],
666
+ "additionalProperties": false
667
+ }
668
+ }
669
+ },
670
+ "required": [
671
+ "workspaces"
672
+ ],
673
+ "additionalProperties": false
674
+ }
675
+ }
676
+ }
677
+ },
678
+ "401": {
679
+ "description": "Missing or invalid bearer token"
680
+ },
681
+ "403": {
682
+ "description": "Key lacks the permission / is bound to another app"
683
+ }
684
+ }
685
+ },
686
+ "post": {
687
+ "summary": "Create a workspace",
688
+ "description": "Requires `workspace:create` on the path app (or the superadmin token).",
689
+ "security": [
690
+ {
691
+ "bearerAuth": []
692
+ }
693
+ ],
694
+ "parameters": [
695
+ {
696
+ "name": "app",
697
+ "in": "path",
698
+ "required": true,
699
+ "description": "Application key (oauth_client.metadata.app).",
700
+ "schema": {
701
+ "type": "string"
702
+ }
703
+ }
704
+ ],
705
+ "requestBody": {
706
+ "required": true,
707
+ "content": {
708
+ "application/json": {
709
+ "schema": {
710
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
711
+ "type": "object",
712
+ "properties": {
713
+ "name": {
714
+ "type": "string",
715
+ "minLength": 1
716
+ },
717
+ "slug": {
718
+ "type": "string",
719
+ "minLength": 1,
720
+ "pattern": "^[a-z0-9-]+$"
721
+ }
722
+ },
723
+ "required": [
724
+ "name",
725
+ "slug"
726
+ ]
727
+ }
728
+ }
729
+ }
730
+ },
731
+ "responses": {
732
+ "201": {
733
+ "description": "OK",
734
+ "content": {
735
+ "application/json": {
736
+ "schema": {
737
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
738
+ "type": "object",
739
+ "properties": {
740
+ "id": {
741
+ "type": "string"
742
+ },
743
+ "name": {
744
+ "type": "string"
745
+ },
746
+ "slug": {
747
+ "type": "string"
748
+ }
749
+ },
750
+ "required": [
751
+ "id",
752
+ "name",
753
+ "slug"
754
+ ],
755
+ "additionalProperties": false
756
+ }
757
+ }
758
+ }
759
+ },
760
+ "401": {
761
+ "description": "Missing or invalid bearer token"
762
+ },
763
+ "403": {
764
+ "description": "Key lacks the permission / is bound to another app"
765
+ },
766
+ "405": {
767
+ "description": "Method not allowed on this resource (see the `Allow` header)"
768
+ },
769
+ "409": {
770
+ "description": "Conflict (already a member, last admin, slug taken, …)"
771
+ },
772
+ "422": {
773
+ "description": "Body failed validation"
774
+ }
775
+ }
776
+ }
777
+ },
778
+ "/api/v1/apps/{app}/user-keys": {
779
+ "get": {
780
+ "summary": "List end-user API keys",
781
+ "description": "Requires `userkey:read` on the path app (or the superadmin token).",
782
+ "security": [
783
+ {
784
+ "bearerAuth": []
785
+ }
786
+ ],
787
+ "parameters": [
788
+ {
789
+ "name": "app",
790
+ "in": "path",
791
+ "required": true,
792
+ "description": "Application key (oauth_client.metadata.app).",
793
+ "schema": {
794
+ "type": "string"
795
+ }
796
+ },
797
+ {
798
+ "name": "userId",
799
+ "in": "query",
800
+ "required": false,
801
+ "description": "Only keys owned by this user.",
802
+ "schema": {
803
+ "type": "string"
804
+ }
805
+ },
806
+ {
807
+ "name": "workspaceId",
808
+ "in": "query",
809
+ "required": false,
810
+ "description": "Only keys bound to this workspace.",
811
+ "schema": {
812
+ "type": "string"
813
+ }
814
+ }
815
+ ],
816
+ "responses": {
817
+ "200": {
818
+ "description": "OK",
819
+ "content": {
820
+ "application/json": {
821
+ "schema": {
822
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
823
+ "type": "object",
824
+ "properties": {
825
+ "keys": {
826
+ "type": "array",
827
+ "items": {
828
+ "type": "object",
829
+ "properties": {
830
+ "id": {
831
+ "type": "string"
832
+ },
833
+ "userId": {
834
+ "type": "string"
835
+ },
836
+ "workspaceId": {
837
+ "anyOf": [
838
+ {
839
+ "type": "string"
840
+ },
841
+ {
842
+ "type": "null"
843
+ }
844
+ ]
845
+ },
846
+ "name": {
847
+ "type": "string"
848
+ },
849
+ "prefix": {
850
+ "type": "string",
851
+ "description": "Non-secret token prefix (wak_…) for display"
852
+ },
853
+ "scopes": {
854
+ "type": "array",
855
+ "items": {
856
+ "type": "string"
857
+ }
858
+ },
859
+ "status": {
860
+ "type": "string",
861
+ "enum": [
862
+ "active",
863
+ "expired",
864
+ "revoked"
865
+ ]
866
+ },
867
+ "createdAt": {
868
+ "type": "string"
869
+ },
870
+ "lastUsedAt": {
871
+ "anyOf": [
872
+ {
873
+ "type": "string"
874
+ },
875
+ {
876
+ "type": "null"
877
+ }
878
+ ]
879
+ },
880
+ "expiresAt": {
881
+ "anyOf": [
882
+ {
883
+ "type": "string"
884
+ },
885
+ {
886
+ "type": "null"
887
+ }
888
+ ]
889
+ }
890
+ },
891
+ "required": [
892
+ "id",
893
+ "userId",
894
+ "workspaceId",
895
+ "name",
896
+ "prefix",
897
+ "scopes",
898
+ "status",
899
+ "createdAt",
900
+ "lastUsedAt",
901
+ "expiresAt"
902
+ ],
903
+ "additionalProperties": false
904
+ }
905
+ }
906
+ },
907
+ "required": [
908
+ "keys"
909
+ ],
910
+ "additionalProperties": false
911
+ }
912
+ }
913
+ }
914
+ },
915
+ "401": {
916
+ "description": "Missing or invalid bearer token"
917
+ },
918
+ "403": {
919
+ "description": "Key lacks the permission / is bound to another app"
920
+ }
921
+ }
922
+ },
923
+ "post": {
924
+ "summary": "Mint an end-user API key (plaintext returned once)",
925
+ "description": "Requires `userkey:create` on the path app (or the superadmin token).",
926
+ "security": [
927
+ {
928
+ "bearerAuth": []
929
+ }
930
+ ],
931
+ "parameters": [
932
+ {
933
+ "name": "app",
934
+ "in": "path",
935
+ "required": true,
936
+ "description": "Application key (oauth_client.metadata.app).",
937
+ "schema": {
938
+ "type": "string"
939
+ }
940
+ }
941
+ ],
942
+ "requestBody": {
943
+ "required": true,
944
+ "content": {
945
+ "application/json": {
946
+ "schema": {
947
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
948
+ "type": "object",
949
+ "properties": {
950
+ "userId": {
951
+ "type": "string",
952
+ "minLength": 1
953
+ },
954
+ "name": {
955
+ "type": "string",
956
+ "minLength": 1
957
+ },
958
+ "scopes": {
959
+ "default": [],
960
+ "description": "Subset of the app's product permission catalog",
961
+ "type": "array",
962
+ "items": {
963
+ "type": "string"
964
+ }
965
+ },
966
+ "workspaceId": {
967
+ "type": "string"
968
+ },
969
+ "expiresAt": {
970
+ "description": "ISO 8601; omit for non-expiring",
971
+ "type": "string",
972
+ "format": "date-time",
973
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
974
+ }
975
+ },
976
+ "required": [
977
+ "userId",
978
+ "name"
979
+ ]
980
+ }
981
+ }
982
+ }
983
+ },
984
+ "responses": {
985
+ "201": {
986
+ "description": "OK",
987
+ "content": {
988
+ "application/json": {
989
+ "schema": {
990
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
991
+ "type": "object",
992
+ "properties": {
993
+ "id": {
994
+ "type": "string"
995
+ },
996
+ "token": {
997
+ "type": "string",
998
+ "description": "Plaintext key — shown exactly once, never stored"
999
+ },
1000
+ "prefix": {
1001
+ "type": "string"
1002
+ }
1003
+ },
1004
+ "required": [
1005
+ "id",
1006
+ "token",
1007
+ "prefix"
1008
+ ],
1009
+ "additionalProperties": false
1010
+ }
1011
+ }
1012
+ }
1013
+ },
1014
+ "401": {
1015
+ "description": "Missing or invalid bearer token"
1016
+ },
1017
+ "403": {
1018
+ "description": "Key lacks the permission / is bound to another app"
1019
+ },
1020
+ "405": {
1021
+ "description": "Method not allowed on this resource (see the `Allow` header)"
1022
+ },
1023
+ "409": {
1024
+ "description": "Conflict (already a member, last admin, slug taken, …)"
1025
+ },
1026
+ "422": {
1027
+ "description": "Body failed validation"
1028
+ }
1029
+ }
1030
+ }
1031
+ },
1032
+ "/api/v1/apps/{app}/user-keys/validate": {
1033
+ "post": {
1034
+ "summary": "Validate a presented end-user key (200 + valid discriminator)",
1035
+ "description": "Requires `userkey:validate` on the path app (or the superadmin token).",
1036
+ "security": [
1037
+ {
1038
+ "bearerAuth": []
1039
+ }
1040
+ ],
1041
+ "parameters": [
1042
+ {
1043
+ "name": "app",
1044
+ "in": "path",
1045
+ "required": true,
1046
+ "description": "Application key (oauth_client.metadata.app).",
1047
+ "schema": {
1048
+ "type": "string"
1049
+ }
1050
+ }
1051
+ ],
1052
+ "requestBody": {
1053
+ "required": true,
1054
+ "content": {
1055
+ "application/json": {
1056
+ "schema": {
1057
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1058
+ "type": "object",
1059
+ "properties": {
1060
+ "token": {
1061
+ "type": "string",
1062
+ "minLength": 1
1063
+ }
1064
+ },
1065
+ "required": [
1066
+ "token"
1067
+ ]
1068
+ }
1069
+ }
1070
+ }
1071
+ },
1072
+ "responses": {
1073
+ "200": {
1074
+ "description": "OK",
1075
+ "content": {
1076
+ "application/json": {
1077
+ "schema": {
1078
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1079
+ "anyOf": [
1080
+ {
1081
+ "type": "object",
1082
+ "properties": {
1083
+ "valid": {
1084
+ "type": "boolean",
1085
+ "const": true
1086
+ },
1087
+ "keyId": {
1088
+ "type": "string"
1089
+ },
1090
+ "userId": {
1091
+ "type": "string"
1092
+ },
1093
+ "workspaceId": {
1094
+ "anyOf": [
1095
+ {
1096
+ "type": "string"
1097
+ },
1098
+ {
1099
+ "type": "null"
1100
+ }
1101
+ ]
1102
+ },
1103
+ "scopes": {
1104
+ "type": "array",
1105
+ "items": {
1106
+ "type": "string"
1107
+ }
1108
+ },
1109
+ "name": {
1110
+ "type": "string"
1111
+ }
1112
+ },
1113
+ "required": [
1114
+ "valid",
1115
+ "keyId",
1116
+ "userId",
1117
+ "workspaceId",
1118
+ "scopes",
1119
+ "name"
1120
+ ],
1121
+ "additionalProperties": false
1122
+ },
1123
+ {
1124
+ "type": "object",
1125
+ "properties": {
1126
+ "valid": {
1127
+ "type": "boolean",
1128
+ "const": false
1129
+ },
1130
+ "reason": {
1131
+ "type": "string",
1132
+ "enum": [
1133
+ "not_found",
1134
+ "revoked",
1135
+ "expired"
1136
+ ]
1137
+ }
1138
+ },
1139
+ "required": [
1140
+ "valid",
1141
+ "reason"
1142
+ ],
1143
+ "additionalProperties": false
1144
+ }
1145
+ ]
1146
+ }
1147
+ }
1148
+ }
1149
+ },
1150
+ "401": {
1151
+ "description": "Missing or invalid bearer token"
1152
+ },
1153
+ "403": {
1154
+ "description": "Key lacks the permission / is bound to another app"
1155
+ },
1156
+ "405": {
1157
+ "description": "Method not allowed on this resource (see the `Allow` header)"
1158
+ },
1159
+ "409": {
1160
+ "description": "Conflict (already a member, last admin, slug taken, …)"
1161
+ },
1162
+ "422": {
1163
+ "description": "Body failed validation"
1164
+ }
1165
+ }
1166
+ }
1167
+ },
1168
+ "/api/v1/apps/{app}/user-keys/{id}": {
1169
+ "delete": {
1170
+ "summary": "Revoke an end-user API key (idempotent)",
1171
+ "description": "Requires `userkey:revoke` on the path app (or the superadmin token).",
1172
+ "security": [
1173
+ {
1174
+ "bearerAuth": []
1175
+ }
1176
+ ],
1177
+ "parameters": [
1178
+ {
1179
+ "name": "app",
1180
+ "in": "path",
1181
+ "required": true,
1182
+ "description": "Application key (oauth_client.metadata.app).",
1183
+ "schema": {
1184
+ "type": "string"
1185
+ }
1186
+ },
1187
+ {
1188
+ "name": "id",
1189
+ "in": "path",
1190
+ "required": true,
1191
+ "schema": {
1192
+ "type": "string"
1193
+ }
1194
+ }
1195
+ ],
1196
+ "responses": {
1197
+ "200": {
1198
+ "description": "OK",
1199
+ "content": {
1200
+ "application/json": {
1201
+ "schema": {
1202
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1203
+ "type": "object",
1204
+ "properties": {
1205
+ "ok": {
1206
+ "type": "boolean",
1207
+ "const": true
1208
+ }
1209
+ },
1210
+ "required": [
1211
+ "ok"
1212
+ ],
1213
+ "additionalProperties": false
1214
+ }
1215
+ }
1216
+ }
1217
+ },
1218
+ "401": {
1219
+ "description": "Missing or invalid bearer token"
1220
+ },
1221
+ "403": {
1222
+ "description": "Key lacks the permission / is bound to another app"
1223
+ },
1224
+ "405": {
1225
+ "description": "Method not allowed on this resource (see the `Allow` header)"
1226
+ },
1227
+ "409": {
1228
+ "description": "Conflict (already a member, last admin, slug taken, …)"
1229
+ },
1230
+ "422": {
1231
+ "description": "Body failed validation"
1232
+ }
1233
+ }
1234
+ }
1235
+ },
1236
+ "/api/v1/apps/{app}/audit": {
1237
+ "get": {
1238
+ "summary": "List recent audit entries",
1239
+ "description": "Requires `audit:read` on the path app (or the superadmin token).",
1240
+ "security": [
1241
+ {
1242
+ "bearerAuth": []
1243
+ }
1244
+ ],
1245
+ "parameters": [
1246
+ {
1247
+ "name": "app",
1248
+ "in": "path",
1249
+ "required": true,
1250
+ "description": "Application key (oauth_client.metadata.app).",
1251
+ "schema": {
1252
+ "type": "string"
1253
+ }
1254
+ }
1255
+ ],
1256
+ "responses": {
1257
+ "200": {
1258
+ "description": "OK",
1259
+ "content": {
1260
+ "application/json": {
1261
+ "schema": {
1262
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1263
+ "type": "object",
1264
+ "properties": {
1265
+ "entries": {
1266
+ "type": "array",
1267
+ "items": {
1268
+ "type": "object",
1269
+ "properties": {
1270
+ "id": {
1271
+ "type": "number"
1272
+ },
1273
+ "tableName": {
1274
+ "type": "string"
1275
+ },
1276
+ "operation": {
1277
+ "type": "string"
1278
+ },
1279
+ "rowId": {
1280
+ "anyOf": [
1281
+ {
1282
+ "type": "string"
1283
+ },
1284
+ {
1285
+ "type": "null"
1286
+ }
1287
+ ]
1288
+ },
1289
+ "userId": {
1290
+ "anyOf": [
1291
+ {
1292
+ "type": "string"
1293
+ },
1294
+ {
1295
+ "type": "null"
1296
+ }
1297
+ ]
1298
+ },
1299
+ "actor": {
1300
+ "anyOf": [
1301
+ {
1302
+ "type": "string"
1303
+ },
1304
+ {
1305
+ "type": "null"
1306
+ }
1307
+ ]
1308
+ },
1309
+ "createdAt": {
1310
+ "type": "string"
1311
+ }
1312
+ },
1313
+ "required": [
1314
+ "id",
1315
+ "tableName",
1316
+ "operation",
1317
+ "rowId",
1318
+ "userId",
1319
+ "actor",
1320
+ "createdAt"
1321
+ ],
1322
+ "additionalProperties": false
1323
+ }
1324
+ }
1325
+ },
1326
+ "required": [
1327
+ "entries"
1328
+ ],
1329
+ "additionalProperties": false
1330
+ }
1331
+ }
1332
+ }
1333
+ },
1334
+ "401": {
1335
+ "description": "Missing or invalid bearer token"
1336
+ },
1337
+ "403": {
1338
+ "description": "Key lacks the permission / is bound to another app"
1339
+ }
1340
+ }
1341
+ }
1342
+ }
1343
+ }
1344
+ }