@openwop/spec-artifacts 2.35.1 → 2.36.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.
Files changed (101) hide show
  1. package/CORPUS-STAMP.json +103 -89
  2. package/api/openapi.yaml +325 -4
  3. package/api/seams-v2.yaml +342 -1
  4. package/api/v2/asyncapi.yaml +1 -1
  5. package/api/v2/openapi.yaml +564 -8
  6. package/package.json +1 -1
  7. package/schemas/a2a-task-state.schema.json +3 -3
  8. package/schemas/artifact-type-pack-manifest.schema.json +3 -3
  9. package/schemas/capabilities.schema.json +34 -1
  10. package/schemas/connection-pack-manifest.schema.json +14 -0
  11. package/schemas/debug-bundle.schema.json +20 -0
  12. package/schemas/dispatch-config.schema.json +1 -1
  13. package/schemas/localized-content-language-settings.schema.json +3 -3
  14. package/schemas/localized-content-page.schema.json +2 -2
  15. package/schemas/localized-content-section.schema.json +3 -3
  16. package/schemas/run-event-payloads.schema.json +4 -2
  17. package/schemas/suspend-request.schema.json +61 -4
  18. package/schemas/v2/a2a-task-state.schema.json +10 -9
  19. package/schemas/v2/agent-deployment-transition.schema.json +4 -4
  20. package/schemas/v2/agent-deployment.schema.json +7 -7
  21. package/schemas/v2/agent-eval-suite.schema.json +10 -10
  22. package/schemas/v2/agent-inventory-response.schema.json +8 -2
  23. package/schemas/v2/artifact-type-pack-manifest.schema.json +3 -3
  24. package/schemas/v2/artifact.schema.json +84 -0
  25. package/schemas/v2/capabilities.schema.json +82 -8
  26. package/schemas/v2/certification-bundle.schema.json +1 -1
  27. package/schemas/v2/channel-presence-payload.schema.json +3 -3
  28. package/schemas/v2/connection-pack-manifest.schema.json +14 -0
  29. package/schemas/v2/conversation-event.schema.json +9 -2
  30. package/schemas/v2/conversation-turn.schema.json +19 -12
  31. package/schemas/v2/dispatch-config.schema.json +1 -1
  32. package/schemas/v2/envelopes/ui.a2ui-surface.schema.json +920 -22
  33. package/schemas/v2/error-envelope.schema.json +11 -1
  34. package/schemas/v2/eval-summary.schema.json +1 -2
  35. package/schemas/v2/goal.schema.json +4 -4
  36. package/schemas/v2/localized-content-language-settings.schema.json +3 -3
  37. package/schemas/v2/localized-content-page.schema.json +2 -2
  38. package/schemas/v2/localized-content-section.schema.json +3 -3
  39. package/schemas/v2/node-pack-manifest.schema.json +105 -0
  40. package/schemas/v2/part.schema.json +81 -0
  41. package/schemas/v2/proposal.schema.json +6 -6
  42. package/schemas/v2/run-event-payloads.schema.json +5 -3
  43. package/schemas/v2/self-hosted-runner-dispatch-frame.schema.json +2 -2
  44. package/schemas/v2/self-hosted-runner-result-frame.schema.json +1 -1
  45. package/schemas/v2/suspend-request.schema.json +251 -6
  46. package/schemas/v2/tool-descriptor.schema.json +246 -2
  47. package/schemas/v2/trigger-event.schema.json +1 -2
  48. package/schemas/v2/trigger-subscription.schema.json +1 -2
  49. package/schemas/v2/webhook-verification.schema.json +22 -0
  50. package/schemas/v2/workflow-definition.schema.json +25 -25
  51. package/spec/v1/alias-detectors.json +13 -1
  52. package/spec/v1/core-standard-manifest.json +2 -2
  53. package/spec/v1/deprecations.json +45 -1
  54. package/spec/v1/deprecations.schema.json +119 -4
  55. package/spec/v1/gaps.json +1925 -4
  56. package/spec/v2/README.md +5 -2
  57. package/spec/v2/core/capabilities.md +13 -26
  58. package/spec/v2/core/conformance.md +5 -8
  59. package/spec/v2/core/connection-packs.md +1 -1
  60. package/spec/v2/core/conversation.md +1 -1
  61. package/spec/v2/core/errors.md +8 -3
  62. package/spec/v2/core/events.md +8 -20
  63. package/spec/v2/core/form-content-packs.md +2 -2
  64. package/spec/v2/core/headers.md +5 -4
  65. package/spec/v2/core/host-services.md +6 -2
  66. package/spec/v2/core/idempotency.md +1 -1
  67. package/spec/v2/core/identity.md +23 -12
  68. package/spec/v2/core/interop.md +34 -4
  69. package/spec/v2/core/interrupt.md +6 -3
  70. package/spec/v2/core/node-pack-runtimes.md +20 -0
  71. package/spec/v2/core/oauth.md +32 -0
  72. package/spec/v2/core/overview.md +19 -6
  73. package/spec/v2/core/packs.md +4 -6
  74. package/spec/v2/core/persistence.md +20 -55
  75. package/spec/v2/core/replay.md +5 -11
  76. package/spec/v2/core/runs.md +9 -8
  77. package/spec/v2/core/security-defaults.md +18 -20
  78. package/spec/v2/core/tool-catalog.md +22 -0
  79. package/spec/v2/core/versioning.md +10 -28
  80. package/spec/v2/core/webhooks.md +16 -4
  81. package/spec/v2/core/workflow-chain-packs.md +1 -1
  82. package/spec/v2/corrections.json +32 -0
  83. package/spec/v2/corrections.schema.json +49 -0
  84. package/spec/v2/declaration.json +18 -13
  85. package/spec/v2/declaration.schema.json +3 -1
  86. package/spec/v2/errors.json +46 -1
  87. package/spec/v2/ext/a2uiSurface/README.md +131 -17
  88. package/spec/v2/ext/dataIntegration/README.md +5 -0
  89. package/spec/v2/facets/a2a.schema.json +4 -0
  90. package/spec/v2/facets/auth.schema.json +24 -0
  91. package/spec/v2/facets/mcp.schema.json +4 -0
  92. package/spec/v2/facets/oauth.schema.json +70 -0
  93. package/spec/v2/facets/webhooks.schema.json +23 -2
  94. package/spec/v2/id-field-bindings.json +2 -0
  95. package/spec/v2/interop-map.json +639 -0
  96. package/spec/v2/interop-map.schema.json +458 -0
  97. package/spec/v2/migrations.json +7 -0
  98. package/spec/v2/migrations.schema.json +58 -0
  99. package/spec/v2/path-manifest.json +6 -1
  100. package/spec/v2/release.json +3 -3
  101. package/spec/v2/surface-baseline.json +7981 -0
@@ -20,9 +20,10 @@
20
20
  "conversation.start",
21
21
  "conversation.exchange",
22
22
  "conversation.close",
23
- "low-confidence"
23
+ "low-confidence",
24
+ "credential"
24
25
  ],
25
- "description": "Discriminator for resume-time routing + UI rendering + observability. Multi-Agent Shift Phase 4 adds `conversation.start` / `conversation.exchange` / `conversation.close` for multi-turn user interjections (see ConversationStartData / ConversationExchangeData / ConversationCloseData below). Phase 1 adds `low-confidence` for the confidence-escalation contract (orchestrator-supervisor suspends below threshold; see LowConfidenceData)."
26
+ "description": "Discriminator for resume-time routing + UI rendering + observability. Multi-Agent Shift Phase 4 adds `conversation.start` / `conversation.exchange` / `conversation.close` for multi-turn user interjections (see ConversationStartData / ConversationExchangeData / ConversationCloseData below). Phase 1 adds `low-confidence` for the confidence-escalation contract (orchestrator-supervisor suspends below threshold; see LowConfidenceData). RFC 0199 adds `credential` (see CredentialData), gated on `oauth.credentialInterrupt`."
26
27
  },
27
28
  "key": {
28
29
  "type": "string",
@@ -41,7 +42,8 @@
41
42
  "description": "Optional auto-reject after this duration. Engine throws InterruptTimeoutError when exceeded."
42
43
  },
43
44
  "data": {
44
- "oneOf": [
45
+ "description": "Discriminated payload data. The union below lists every per-kind shape; the root `allOf` binds each `kind` to exactly one of them (`interrupt.md` §Per-kind payloads). `anyOf`, not `oneOf`: the shapes are not mutually exclusive by content — a minimal `conversation.start` and `conversation.close` payload are both `{ conversationId }` — so `kind`, not the data, is the discriminator. Before 2.36.0 this was an unbound `oneOf`, which rejected those two minimal payloads and accepted a payload whose `data` matched a different kind's shape (COMPATIBILITY.md §3, 2026-09-22).",
46
+ "anyOf": [
45
47
  {
46
48
  "$ref": "#/$defs/ApprovalData"
47
49
  },
@@ -65,11 +67,208 @@
65
67
  },
66
68
  {
67
69
  "$ref": "#/$defs/LowConfidenceData"
70
+ },
71
+ {
72
+ "$ref": "#/$defs/CredentialData"
68
73
  }
69
74
  ]
70
75
  }
71
76
  },
72
77
  "additionalProperties": false,
78
+ "$comment": "Binds `data` to `kind`: one if/then per kind, so every kind accepts exactly its own per-kind shape and a payload whose `data` belongs to another kind fails.",
79
+ "allOf": [
80
+ {
81
+ "if": {
82
+ "properties": {
83
+ "kind": {
84
+ "const": "approval"
85
+ }
86
+ },
87
+ "required": [
88
+ "kind"
89
+ ]
90
+ },
91
+ "then": {
92
+ "properties": {
93
+ "data": {
94
+ "$ref": "#/$defs/ApprovalData"
95
+ }
96
+ }
97
+ }
98
+ },
99
+ {
100
+ "if": {
101
+ "properties": {
102
+ "kind": {
103
+ "const": "clarification"
104
+ }
105
+ },
106
+ "required": [
107
+ "kind"
108
+ ]
109
+ },
110
+ "then": {
111
+ "properties": {
112
+ "data": {
113
+ "$ref": "#/$defs/ClarificationData"
114
+ }
115
+ }
116
+ }
117
+ },
118
+ {
119
+ "if": {
120
+ "properties": {
121
+ "kind": {
122
+ "const": "external-event"
123
+ }
124
+ },
125
+ "required": [
126
+ "kind"
127
+ ]
128
+ },
129
+ "then": {
130
+ "properties": {
131
+ "data": {
132
+ "$ref": "#/$defs/ExternalEventData"
133
+ }
134
+ }
135
+ }
136
+ },
137
+ {
138
+ "if": {
139
+ "properties": {
140
+ "kind": {
141
+ "const": "custom"
142
+ }
143
+ },
144
+ "required": [
145
+ "kind"
146
+ ]
147
+ },
148
+ "then": {
149
+ "properties": {
150
+ "data": {
151
+ "$ref": "#/$defs/CustomData"
152
+ }
153
+ }
154
+ }
155
+ },
156
+ {
157
+ "if": {
158
+ "properties": {
159
+ "kind": {
160
+ "const": "conversation.start"
161
+ }
162
+ },
163
+ "required": [
164
+ "kind"
165
+ ]
166
+ },
167
+ "then": {
168
+ "properties": {
169
+ "data": {
170
+ "$ref": "#/$defs/ConversationStartData"
171
+ }
172
+ }
173
+ }
174
+ },
175
+ {
176
+ "if": {
177
+ "properties": {
178
+ "kind": {
179
+ "const": "conversation.exchange"
180
+ }
181
+ },
182
+ "required": [
183
+ "kind"
184
+ ]
185
+ },
186
+ "then": {
187
+ "properties": {
188
+ "data": {
189
+ "$ref": "#/$defs/ConversationExchangeData"
190
+ }
191
+ }
192
+ }
193
+ },
194
+ {
195
+ "if": {
196
+ "properties": {
197
+ "kind": {
198
+ "const": "conversation.close"
199
+ }
200
+ },
201
+ "required": [
202
+ "kind"
203
+ ]
204
+ },
205
+ "then": {
206
+ "properties": {
207
+ "data": {
208
+ "$ref": "#/$defs/ConversationCloseData"
209
+ }
210
+ }
211
+ }
212
+ },
213
+ {
214
+ "if": {
215
+ "properties": {
216
+ "kind": {
217
+ "const": "low-confidence"
218
+ }
219
+ },
220
+ "required": [
221
+ "kind"
222
+ ]
223
+ },
224
+ "then": {
225
+ "properties": {
226
+ "data": {
227
+ "$ref": "#/$defs/LowConfidenceData"
228
+ }
229
+ }
230
+ }
231
+ },
232
+ {
233
+ "if": {
234
+ "properties": {
235
+ "kind": {
236
+ "const": "credential"
237
+ }
238
+ },
239
+ "required": [
240
+ "kind"
241
+ ]
242
+ },
243
+ "then": {
244
+ "required": [
245
+ "resumeSchema"
246
+ ],
247
+ "properties": {
248
+ "data": {
249
+ "$ref": "#/$defs/CredentialData"
250
+ },
251
+ "resumeSchema": {
252
+ "const": {
253
+ "type": "object",
254
+ "additionalProperties": false,
255
+ "required": [
256
+ "outcome"
257
+ ],
258
+ "properties": {
259
+ "outcome": {
260
+ "enum": [
261
+ "authorized",
262
+ "declined"
263
+ ]
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ }
271
+ ],
73
272
  "$defs": {
74
273
  "ApprovalData": {
75
274
  "type": "object",
@@ -95,7 +294,11 @@
95
294
  },
96
295
  "onTimeout": {
97
296
  "type": "string",
98
- "enum": ["reject", "approve", "escalate"],
297
+ "enum": [
298
+ "reject",
299
+ "approve",
300
+ "escalate"
301
+ ],
99
302
  "description": "RFC 0186 §A.3 — the disposition applied when `timeoutMs` elapses with no resolution. Every gate with a timer needs one; two production hosts recorded it as a bare key on `approval.requested` (280 rows on one) because the seat did not exist. `escalate` pairs with a host-defined escalation target. A `timeoutMs` of `0` means no timer, and `onTimeout` is then meaningless."
100
303
  },
101
304
  "description": {
@@ -369,7 +572,49 @@
369
572
  }
370
573
  },
371
574
  "additionalProperties": false
575
+ },
576
+ "CredentialData": {
577
+ "type": "object",
578
+ "description": "Payload for kind='credential' (RFC 0199 §C.3). Closed: it names the provider, scopes and reason and carries the host-owned `connectUrl`; it NEVER carries credential material, the interrupt's token, or any value that resolves the interrupt. Gated on `oauth.credentialInterrupt`.",
579
+ "required": [
580
+ "provider",
581
+ "scopes",
582
+ "reason",
583
+ "connectUrl"
584
+ ],
585
+ "properties": {
586
+ "provider": {
587
+ "type": "string",
588
+ "minLength": 1,
589
+ "description": "An advertised `oauth.providers[].id`."
590
+ },
591
+ "scopes": {
592
+ "type": "array",
593
+ "items": {
594
+ "type": "string",
595
+ "minLength": 1
596
+ },
597
+ "uniqueItems": true
598
+ },
599
+ "reason": {
600
+ "enum": [
601
+ "missing",
602
+ "expired",
603
+ "insufficient_scope"
604
+ ]
605
+ },
606
+ "connectUrl": {
607
+ "type": "string",
608
+ "format": "uri",
609
+ "pattern": "^https://",
610
+ "description": "Host-owned https URL on the host's own origin that begins the authorization-code grant for the interrupt's initiating Subject. MUST NOT be pre-authenticated and MUST NOT embed the interrupt token."
611
+ },
612
+ "credentialRef": {
613
+ "$ref": "credential-reference.schema.json",
614
+ "description": "The reference being re-authorized; never material."
615
+ }
616
+ },
617
+ "additionalProperties": false
372
618
  }
373
- },
374
- "x-openwop-seeded-from": "v1"
619
+ }
375
620
  }
@@ -45,6 +45,31 @@
45
45
  "description": "MAY — JSON Schema for the tool's result.",
46
46
  "additionalProperties": true
47
47
  },
48
+ "annotations": {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "required": [
52
+ "readOnlyHint",
53
+ "destructiveHint",
54
+ "idempotentHint",
55
+ "openWorldHint"
56
+ ],
57
+ "description": "RFC 0204. Projection onto MCP ToolAnnotations (2026-07-28), computed from this descriptor's host-assigned safetyTier / replayPolicy / egress by the table in spec/v2/core/tool-catalog.md — never copied from an MCP server's annotations (untrusted upstream) and never left to MCP defaults. All four REQUIRED when present; `annotations.title` is not emitted (`title` is the display name).",
58
+ "properties": {
59
+ "readOnlyHint": {
60
+ "type": "boolean"
61
+ },
62
+ "destructiveHint": {
63
+ "type": "boolean"
64
+ },
65
+ "idempotentHint": {
66
+ "type": "boolean"
67
+ },
68
+ "openWorldHint": {
69
+ "type": "boolean"
70
+ }
71
+ }
72
+ },
48
73
  "auth": {
49
74
  "type": "object",
50
75
  "additionalProperties": false,
@@ -144,7 +169,226 @@
144
169
  "source"
145
170
  ]
146
171
  }
172
+ },
173
+ {
174
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): readOnlyHint is true iff safetyTier is pure or read.",
175
+ "if": {
176
+ "required": [
177
+ "annotations"
178
+ ],
179
+ "properties": {
180
+ "safetyTier": {
181
+ "enum": [
182
+ "pure",
183
+ "read"
184
+ ]
185
+ }
186
+ }
187
+ },
188
+ "then": {
189
+ "properties": {
190
+ "annotations": {
191
+ "properties": {
192
+ "readOnlyHint": {
193
+ "const": true
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ },
200
+ {
201
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): readOnlyHint is false for write and exec.",
202
+ "if": {
203
+ "required": [
204
+ "annotations"
205
+ ],
206
+ "properties": {
207
+ "safetyTier": {
208
+ "enum": [
209
+ "write",
210
+ "exec"
211
+ ]
212
+ }
213
+ }
214
+ },
215
+ "then": {
216
+ "properties": {
217
+ "annotations": {
218
+ "properties": {
219
+ "readOnlyHint": {
220
+ "const": false
221
+ }
222
+ }
223
+ }
224
+ }
225
+ }
226
+ },
227
+ {
228
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): destructiveHint is true iff safetyTier is write or exec (safetyTier does not distinguish additive from destructive writes).",
229
+ "if": {
230
+ "required": [
231
+ "annotations"
232
+ ],
233
+ "properties": {
234
+ "safetyTier": {
235
+ "enum": [
236
+ "write",
237
+ "exec"
238
+ ]
239
+ }
240
+ }
241
+ },
242
+ "then": {
243
+ "properties": {
244
+ "annotations": {
245
+ "properties": {
246
+ "destructiveHint": {
247
+ "const": true
248
+ }
249
+ }
250
+ }
251
+ }
252
+ }
253
+ },
254
+ {
255
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): destructiveHint is false for pure and read.",
256
+ "if": {
257
+ "required": [
258
+ "annotations"
259
+ ],
260
+ "properties": {
261
+ "safetyTier": {
262
+ "enum": [
263
+ "pure",
264
+ "read"
265
+ ]
266
+ }
267
+ }
268
+ },
269
+ "then": {
270
+ "properties": {
271
+ "annotations": {
272
+ "properties": {
273
+ "destructiveHint": {
274
+ "const": false
275
+ }
276
+ }
277
+ }
278
+ }
279
+ }
280
+ },
281
+ {
282
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): idempotentHint is true iff replayPolicy is deterministic or idempotent.",
283
+ "if": {
284
+ "required": [
285
+ "replayPolicy"
286
+ ],
287
+ "properties": {
288
+ "replayPolicy": {
289
+ "enum": [
290
+ "deterministic",
291
+ "idempotent"
292
+ ]
293
+ }
294
+ }
295
+ },
296
+ "then": {
297
+ "properties": {
298
+ "annotations": {
299
+ "properties": {
300
+ "idempotentHint": {
301
+ "const": true
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+ },
308
+ {
309
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): idempotentHint is false when replayPolicy is absent or non-deterministic.",
310
+ "if": {
311
+ "required": [
312
+ "annotations"
313
+ ],
314
+ "not": {
315
+ "properties": {
316
+ "replayPolicy": {
317
+ "enum": [
318
+ "deterministic",
319
+ "idempotent"
320
+ ]
321
+ }
322
+ },
323
+ "required": [
324
+ "replayPolicy"
325
+ ]
326
+ }
327
+ },
328
+ "then": {
329
+ "properties": {
330
+ "annotations": {
331
+ "properties": {
332
+ "idempotentHint": {
333
+ "const": false
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
339
+ },
340
+ {
341
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): openWorldHint is false iff egress is none.",
342
+ "if": {
343
+ "required": [
344
+ "egress"
345
+ ],
346
+ "properties": {
347
+ "egress": {
348
+ "const": "none"
349
+ }
350
+ }
351
+ },
352
+ "then": {
353
+ "properties": {
354
+ "annotations": {
355
+ "properties": {
356
+ "openWorldHint": {
357
+ "const": false
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ },
364
+ {
365
+ "$comment": "RFC 0204 §D.12 (tool-catalog.md §The descriptor): openWorldHint is true when egress is absent or not none.",
366
+ "if": {
367
+ "required": [
368
+ "annotations"
369
+ ],
370
+ "not": {
371
+ "properties": {
372
+ "egress": {
373
+ "const": "none"
374
+ }
375
+ },
376
+ "required": [
377
+ "egress"
378
+ ]
379
+ }
380
+ },
381
+ "then": {
382
+ "properties": {
383
+ "annotations": {
384
+ "properties": {
385
+ "openWorldHint": {
386
+ "const": true
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
147
392
  }
148
- ],
149
- "x-openwop-seeded-from": "v1"
393
+ ]
150
394
  }
@@ -503,6 +503,5 @@
503
503
  }
504
504
  }
505
505
  }
506
- ],
507
- "x-openwop-seeded-from": "v1"
506
+ ]
508
507
  }
@@ -73,6 +73,5 @@
73
73
  "maxLength": 32,
74
74
  "description": "MAY — for `source: \"webhook\"`, an identifier for the signing secret (the `(webhookId, secretFingerprint)` register key). It MUST be a **salted or host-keyed, TRUNCATED** one-way digest (e.g. the first 8–16 hex of `HMAC(hostKey, secret)`) — NOT the raw secret (SR-1) and NOT a full unsalted `SHA256(secret)` (a full unsalted hash of a low-entropy secret is an offline brute-force / confirmation oracle). The `maxLength: 32` ceiling structurally rejects a full 64-hex digest."
75
75
  }
76
- },
77
- "x-openwop-seeded-from": "v1"
76
+ }
78
77
  }
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v2/webhook-verification.schema.json",
4
+ "title": "WebhookVerificationRequest (webhooks.md §Standard Webhooks)",
5
+ "description": "RFC 0201 §D — the one request a host sends to a subscription URL before answering 201 to a registration that opted into `standard-webhooks-1`. It is not a delivery: it carries no `OpenWOP-Event-Type`, and it is signed with the three Standard Webhooks headers under the secret the registration supplied. The endpoint consents by answering 2xx within 10 s with a JSON body whose `challenge` equals the one sent; anything else refuses the registration `400 webhook_endpoint_unverified`. Served for both majors (v1 `webhooks.md` cites the same $id).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "type",
10
+ "challenge"
11
+ ],
12
+ "properties": {
13
+ "type": {
14
+ "const": "openwop.webhook.verification"
15
+ },
16
+ "challenge": {
17
+ "type": "string",
18
+ "pattern": "^[A-Za-z0-9_-]{22,128}$",
19
+ "description": "A fresh base64url value with at least 128 bits of entropy (22 characters), minted per registration."
20
+ }
21
+ }
22
+ }