@whooshbang/contracts 2.5.0 → 2.6.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 (98) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +21 -21
  3. package/contract-manifest.json +32 -32
  4. package/dist/generated/artifact-index.d.ts +33 -33
  5. package/dist/generated/artifact-index.js +32 -32
  6. package/dist/generated/interaction-v1.d.ts +77 -4
  7. package/dist/generated/validators-standalone.d.ts +492 -492
  8. package/dist/generated/validators-standalone.js +6110 -4475
  9. package/dist/generated/validators-standalone.js.map +1 -1
  10. package/dist/generated/validators.d.ts +2 -2
  11. package/dist/generated/whooshbang-v1.d.ts +523 -116
  12. package/dist/index.d.ts +3 -0
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/input-defaults.d.ts +7 -0
  16. package/dist/input-defaults.js +59 -0
  17. package/dist/input-defaults.js.map +1 -0
  18. package/dist/interaction-expiry.js +2 -1
  19. package/dist/interaction-expiry.js.map +1 -1
  20. package/fixtures/core-v1/fixture-index.json +1 -1
  21. package/fixtures/core-v1/problems/idempotency-key-required.json +2 -2
  22. package/fixtures/core-v1/scenarios/api-credential-invalid-indistinguishable.json +1 -1
  23. package/fixtures/core-v1/scenarios/api-credential-one-time-reveal.json +1 -1
  24. package/fixtures/core-v1/scenarios/api-credential-revocation-replay.json +1 -1
  25. package/fixtures/core-v1/scenarios/api-credential-rotation-overlap.json +1 -1
  26. package/fixtures/core-v1/scenarios/cancellation-too-late.json +1 -1
  27. package/fixtures/core-v1/scenarios/cross-organization-project.json +1 -1
  28. package/fixtures/core-v1/scenarios/cross-project-resource.json +1 -1
  29. package/fixtures/core-v1/scenarios/environment-mismatch.json +1 -1
  30. package/fixtures/core-v1/scenarios/idempotency-conflict.json +1 -1
  31. package/fixtures/core-v1/scenarios/idempotency-equivalent-replay.json +1 -1
  32. package/fixtures/core-v1/scenarios/malformed-bearer.json +1 -1
  33. package/fixtures/core-v1/scenarios/metadata-overrun.json +1 -1
  34. package/fixtures/core-v1/scenarios/missing-scope.json +1 -1
  35. package/fixtures/core-v1/scenarios/project-create-equivalent-replay.json +1 -1
  36. package/fixtures/core-v1/scenarios/project-slug-conflict.json +1 -1
  37. package/fixtures/core-v1/scenarios/provider-outcome-unknown.json +1 -1
  38. package/fixtures/core-v1/scenarios/subscription-activation-replay.json +1 -1
  39. package/fixtures/core-v1/scenarios/subscription-authorization-capability-opacity.json +1 -1
  40. package/fixtures/core-v1/scenarios/subscription-cross-connection-callback-rejected.json +1 -1
  41. package/fixtures/core-v1/scenarios/subscription-expired-replay.json +1 -1
  42. package/fixtures/core-v1/scenarios/subscription-selected-connection-replay.json +1 -1
  43. package/fixtures/interaction-machine-v1/scenarios/ack-conflict.json +1 -1
  44. package/fixtures/interaction-machine-v1/scenarios/ack-cross-machine.json +1 -1
  45. package/fixtures/interaction-machine-v1/scenarios/ack-out-of-order.json +1 -1
  46. package/fixtures/interaction-machine-v1/scenarios/ack-replay.json +1 -1
  47. package/fixtures/interaction-machine-v1/scenarios/ambiguous-free-text.json +1 -1
  48. package/fixtures/interaction-machine-v1/scenarios/callback-token-opacity.json +1 -1
  49. package/fixtures/interaction-machine-v1/scenarios/credential-registration-conflict.json +1 -1
  50. package/fixtures/interaction-machine-v1/scenarios/credential-registration-replay.json +1 -1
  51. package/fixtures/interaction-machine-v1/scenarios/credential-revocation-replay.json +1 -1
  52. package/fixtures/interaction-machine-v1/scenarios/credential-rotation.json +1 -1
  53. package/fixtures/interaction-machine-v1/scenarios/first-credential-activates.json +1 -1
  54. package/fixtures/interaction-machine-v1/scenarios/interaction-duplicate.json +1 -1
  55. package/fixtures/interaction-machine-v1/scenarios/interaction-expired.json +1 -1
  56. package/fixtures/interaction-machine-v1/scenarios/interaction-mismatch.json +1 -1
  57. package/fixtures/interaction-machine-v1/scenarios/interaction-retired.json +1 -1
  58. package/fixtures/interaction-machine-v1/scenarios/interaction-stale.json +1 -1
  59. package/fixtures/interaction-machine-v1/scenarios/machine-admin-denied.json +1 -1
  60. package/fixtures/interaction-machine-v1/scenarios/machine-bound-message-create.json +1 -1
  61. package/fixtures/interaction-machine-v1/scenarios/machine-cancel-denied.json +1 -1
  62. package/fixtures/interaction-machine-v1/scenarios/machine-crash-before-ack.json +1 -1
  63. package/fixtures/interaction-machine-v1/scenarios/machine-notifier-mismatch.json +1 -1
  64. package/fixtures/interaction-machine-v1/scenarios/machine-other-message-read.json +1 -1
  65. package/fixtures/interaction-machine-v1/scenarios/machine-owned-message-read.json +1 -1
  66. package/fixtures/interaction-machine-v1/scenarios/machine-subscriber-mismatch.json +1 -1
  67. package/fixtures/interaction-machine-v1/scenarios/poll-uncommitted-cursor-rejected.json +1 -1
  68. package/fixtures/interaction-machine-v1/scenarios/project-credential-machine-endpoint-denied.json +1 -1
  69. package/fixtures/interaction-machine-v1/scenarios/quarantine-integrity-rejected.json +1 -1
  70. package/fixtures/interaction-machine-v1/scenarios/quarantine-signature-rejected.json +1 -1
  71. package/fixtures/interaction-machine-v1/scenarios/quarantine-valid.json +1 -1
  72. package/fixtures/interaction-machine-v1/scenarios/revoked-machine-credential.json +1 -1
  73. package/fixtures/recipient-experience-v1/scenarios/membership-broadcast-snapshot.json +1 -1
  74. package/fixtures/recipient-experience-v1/scenarios/preferred-binding-resolution.json +1 -1
  75. package/fixtures/recipient-experience-v1/scenarios/recipient-session-security.json +1 -1
  76. package/fixtures/recipient-experience-v1/scenarios/subscriber-initial-groups-transaction.json +1 -1
  77. package/openapi/generated/whooshbang-v1.bundle.json +998 -297
  78. package/openapi/whooshbang-v1.yaml +454 -73
  79. package/package.json +1 -1
  80. package/schemas/core-scenario.schema.json +1 -1
  81. package/schemas/events/agent-binding-degraded-v1.schema.json +1 -1
  82. package/schemas/events/interaction-expired-v1.schema.json +1 -1
  83. package/schemas/events/interaction-received-v1.schema.json +1 -1
  84. package/schemas/events/message-delivered-v1.schema.json +1 -1
  85. package/schemas/events/message-expired-v1.schema.json +1 -1
  86. package/schemas/events/message-failed-v1.schema.json +1 -1
  87. package/schemas/events/message-provider-accepted-v1.schema.json +1 -1
  88. package/schemas/events/subscription-activated-v1.schema.json +1 -1
  89. package/schemas/events/subscription-revoked-v1.schema.json +1 -1
  90. package/schemas/events/whooshbang-event-v1.schema.json +1 -1
  91. package/schemas/fixture-index.schema.json +1 -1
  92. package/schemas/interaction-machine-scenario.schema.json +1 -1
  93. package/schemas/interaction-v1.schema.json +192 -5
  94. package/schemas/machine-v1.schema.json +1 -1
  95. package/schemas/provider-capabilities-v1.schema.json +1 -1
  96. package/schemas/webhooks/webhook-delivery-case-v1.schema.json +1 -1
  97. package/schemas/webhooks/webhook-signing-vector-v1.schema.json +1 -1
  98. package/schemas/whooshbang-v1.schema.json +400 -63
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://whooshbang.flowxo.com/schemas/whooshbang-v1.schema.json",
4
- "x-contract-version": "2.5.0",
4
+ "x-contract-version": "2.6.0",
5
5
  "title": "WhooshBangV1ContractDocument",
6
6
  "description": "Public request, resource, summary, and Problem Details models for the WhooshBang V1 REST API.",
7
7
  "anyOf": [
@@ -403,6 +403,15 @@
403
403
  },
404
404
  {
405
405
  "$ref": "#/$defs/RedeemBillingPromotionRequest"
406
+ },
407
+ {
408
+ "$ref": "#/$defs/CanonicalCreateMessageRequest"
409
+ },
410
+ {
411
+ "$ref": "#/$defs/CanonicalCreateGroupBroadcastRequest"
412
+ },
413
+ {
414
+ "$ref": "#/$defs/CanonicalCreateOperatorMessageRequest"
406
415
  }
407
416
  ],
408
417
  "$defs": {
@@ -3724,7 +3733,7 @@
3724
3733
  "maxItems": 50,
3725
3734
  "uniqueItems": true,
3726
3735
  "items": {
3727
- "$ref": "#/$defs/DeveloperKey"
3736
+ "$ref": "#/$defs/GroupKey"
3728
3737
  }
3729
3738
  }
3730
3739
  },
@@ -3815,7 +3824,7 @@
3815
3824
  "uniqueItems": true,
3816
3825
  "description": "The keys of the static groups this subscriber belongs to in the environment asked about. Present when one subscriber is read.",
3817
3826
  "items": {
3818
- "$ref": "#/$defs/DeveloperKey"
3827
+ "$ref": "#/$defs/GroupKey"
3819
3828
  }
3820
3829
  },
3821
3830
  "last_activity_at": {
@@ -4049,10 +4058,10 @@
4049
4058
  "CreateSubscriberGroupRequest": {
4050
4059
  "type": "object",
4051
4060
  "description": "Creates one static, developer-managed subscriber group.",
4052
- "required": ["key", "display_name"],
4061
+ "required": ["key"],
4053
4062
  "properties": {
4054
4063
  "key": {
4055
- "$ref": "#/$defs/DeveloperKey"
4064
+ "$ref": "#/$defs/GroupKey"
4056
4065
  },
4057
4066
  "display_name": {
4058
4067
  "type": "string",
@@ -4069,8 +4078,8 @@
4069
4078
  "UpdateSubscriberGroupRequest": {
4070
4079
  "type": "object",
4071
4080
  "description": "Renames or redescribes an active group. Its key and static membership model cannot change.",
4072
- "required": ["row_version"],
4073
- "minProperties": 2,
4081
+ "required": [],
4082
+ "minProperties": 1,
4074
4083
  "properties": {
4075
4084
  "row_version": {
4076
4085
  "type": "integer",
@@ -4086,7 +4095,21 @@
4086
4095
  "maxLength": 500
4087
4096
  }
4088
4097
  },
4089
- "additionalProperties": false
4098
+ "additionalProperties": false,
4099
+ "anyOf": [
4100
+ {
4101
+ "required": ["display_name"],
4102
+ "properties": {
4103
+ "display_name": {}
4104
+ }
4105
+ },
4106
+ {
4107
+ "required": ["description"],
4108
+ "properties": {
4109
+ "description": {}
4110
+ }
4111
+ }
4112
+ ]
4090
4113
  },
4091
4114
  "SubscriberGroup": {
4092
4115
  "type": "object",
@@ -4120,7 +4143,7 @@
4120
4143
  "$ref": "#/$defs/Environment"
4121
4144
  },
4122
4145
  "key": {
4123
- "$ref": "#/$defs/DeveloperKey"
4146
+ "$ref": "#/$defs/GroupKey"
4124
4147
  },
4125
4148
  "display_name": {
4126
4149
  "type": "string",
@@ -4229,7 +4252,7 @@
4229
4252
  "$ref": "#/$defs/OpaqueIdentifier"
4230
4253
  },
4231
4254
  "group_key": {
4232
- "$ref": "#/$defs/DeveloperKey"
4255
+ "$ref": "#/$defs/GroupKey"
4233
4256
  },
4234
4257
  "subscriber_id": {
4235
4258
  "$ref": "#/$defs/OpaqueIdentifier"
@@ -4306,7 +4329,7 @@
4306
4329
  "required": ["group_key", "membership_revision", "items"],
4307
4330
  "properties": {
4308
4331
  "group_key": {
4309
- "$ref": "#/$defs/DeveloperKey"
4332
+ "$ref": "#/$defs/GroupKey"
4310
4333
  },
4311
4334
  "membership_revision": {
4312
4335
  "type": "integer",
@@ -4340,7 +4363,7 @@
4340
4363
  "CreateGroupBroadcastRequest": {
4341
4364
  "type": "object",
4342
4365
  "description": "Creates one group broadcast using the existing ordinary message envelope. The group target comes only from the path.",
4343
- "required": ["content"],
4366
+ "required": [],
4344
4367
  "properties": {
4345
4368
  "notifier_id": {
4346
4369
  "allOf": [
@@ -4351,10 +4374,11 @@
4351
4374
  "default": "default"
4352
4375
  },
4353
4376
  "content": {
4354
- "$ref": "#/$defs/MessageContent"
4377
+ "$ref": "#/$defs/MessageContentInput"
4355
4378
  },
4356
4379
  "expires_at": {
4357
- "$ref": "#/$defs/Timestamp"
4380
+ "$ref": "#/$defs/Timestamp",
4381
+ "description": "Optional server-authoritative expiry after acceptance, through year 9999. Omit for 24 hours."
4358
4382
  },
4359
4383
  "correlation_id": {
4360
4384
  "type": "string",
@@ -4373,7 +4397,31 @@
4373
4397
  "description": "Omitted means service. Marketing refuses service-only bindings before charging and at every delayed dispatch."
4374
4398
  }
4375
4399
  },
4376
- "additionalProperties": false
4400
+ "additionalProperties": false,
4401
+ "allOf": [
4402
+ {
4403
+ "anyOf": [
4404
+ {
4405
+ "required": ["content"],
4406
+ "properties": {
4407
+ "content": {
4408
+ "$ref": "#/$defs/MessageContentInput"
4409
+ }
4410
+ },
4411
+ "additionalProperties": true
4412
+ },
4413
+ {
4414
+ "required": ["interaction"],
4415
+ "properties": {
4416
+ "interaction": {
4417
+ "$ref": "interaction-v1.schema.json#/$defs/InteractionSendRequest"
4418
+ }
4419
+ },
4420
+ "additionalProperties": true
4421
+ }
4422
+ ]
4423
+ }
4424
+ ]
4377
4425
  },
4378
4426
  "BroadcastAggregate": {
4379
4427
  "type": "object",
@@ -4464,7 +4512,7 @@
4464
4512
  "$ref": "#/$defs/OpaqueIdentifier"
4465
4513
  },
4466
4514
  "group_key": {
4467
- "$ref": "#/$defs/DeveloperKey"
4515
+ "$ref": "#/$defs/GroupKey"
4468
4516
  },
4469
4517
  "audience_revision": {
4470
4518
  "type": "integer",
@@ -4499,7 +4547,7 @@
4499
4547
  "CreateSubscriptionLinkRequest": {
4500
4548
  "type": "object",
4501
4549
  "description": "Creates one project- and environment-scoped, single-use authorization link.",
4502
- "required": ["subscriber_id", "channels"],
4550
+ "required": ["subscriber_id"],
4503
4551
  "properties": {
4504
4552
  "subscriber_id": {
4505
4553
  "$ref": "#/$defs/OpaqueIdentifier"
@@ -4523,7 +4571,7 @@
4523
4571
  },
4524
4572
  "connection_id": {
4525
4573
  "$ref": "#/$defs/OpaqueIdentifier",
4526
- "description": "The exact channel connection to authorize. Required for Slack. For Telegram or email, omission resolves an unambiguous default or sole compatible connection; it never selects an arbitrary fallback."
4574
+ "description": "Optional exact connection. Otherwise the default or only compatible connection is used."
4527
4575
  },
4528
4576
  "address": {
4529
4577
  "$ref": "#/$defs/EmailAddress",
@@ -4572,22 +4620,6 @@
4572
4620
  }
4573
4621
  }
4574
4622
  }
4575
- },
4576
- {
4577
- "if": {
4578
- "properties": {
4579
- "channels": {
4580
- "const": ["slack"]
4581
- }
4582
- },
4583
- "required": ["channels"]
4584
- },
4585
- "then": {
4586
- "required": ["connection_id"],
4587
- "properties": {
4588
- "connection_id": {}
4589
- }
4590
- }
4591
4623
  }
4592
4624
  ],
4593
4625
  "additionalProperties": false
@@ -5078,7 +5110,7 @@
5078
5110
  "CreateCustomerEndpointRequest": {
5079
5111
  "type": "object",
5080
5112
  "description": "Creates one project/environment endpoint. The service validates the final normalized destination and never returns it from health or diagnostic reads.",
5081
- "required": ["url", "event_types"],
5113
+ "required": ["url"],
5082
5114
  "properties": {
5083
5115
  "url": {
5084
5116
  "type": "string",
@@ -5106,12 +5138,13 @@
5106
5138
  },
5107
5139
  "RotateCustomerEndpointRequest": {
5108
5140
  "type": "object",
5109
- "required": ["overlap_seconds"],
5141
+ "required": [],
5110
5142
  "properties": {
5111
5143
  "overlap_seconds": {
5112
5144
  "type": "integer",
5113
5145
  "minimum": 60,
5114
- "maximum": 86400
5146
+ "maximum": 86400,
5147
+ "default": 86400
5115
5148
  }
5116
5149
  },
5117
5150
  "additionalProperties": false
@@ -5370,10 +5403,17 @@
5370
5403
  "CreateMessageRequest": {
5371
5404
  "type": "object",
5372
5405
  "description": "Creates one logical message for one subscriber and one resolved channel binding.",
5373
- "required": ["to", "content"],
5406
+ "required": ["to"],
5374
5407
  "properties": {
5375
5408
  "to": {
5376
- "$ref": "#/$defs/MessageTarget"
5409
+ "oneOf": [
5410
+ {
5411
+ "$ref": "#/$defs/MessageTarget"
5412
+ },
5413
+ {
5414
+ "$ref": "#/$defs/OpaqueIdentifier"
5415
+ }
5416
+ ]
5377
5417
  },
5378
5418
  "notifier_id": {
5379
5419
  "allOf": [
@@ -5396,11 +5436,11 @@
5396
5436
  "description": "Optional channel connection to send through, from the environment's connections. The subscriber must be connected through it; the service never substitutes another connection or provider. A connection the subscriber has not connected through is refused as `subscriber_not_connected` when they are connected through another, and as an unchosen send would be (`subscriber_unbound` or `preferred_binding_unavailable`) when no connected channel can take the message. Omitted, the service chooses: the subscriber's preferred channel when they set one, otherwise the default connection when they are connected there, otherwise the connection they connected through most recently. The accepted message's `binding.connection_id` records the connection used. Implies `delivery_target: connection`."
5397
5437
  },
5398
5438
  "content": {
5399
- "$ref": "#/$defs/MessageContent"
5439
+ "$ref": "#/$defs/MessageContentInput"
5400
5440
  },
5401
5441
  "expires_at": {
5402
5442
  "$ref": "#/$defs/Timestamp",
5403
- "description": "Optional server-authoritative expiry no more than 24 hours after acceptance."
5443
+ "description": "Optional server-authoritative expiry after acceptance, through year 9999. Omit for 24 hours."
5404
5444
  },
5405
5445
  "correlation_id": {
5406
5446
  "type": "string",
@@ -5434,6 +5474,28 @@
5434
5474
  }
5435
5475
  }
5436
5476
  }
5477
+ },
5478
+ {
5479
+ "anyOf": [
5480
+ {
5481
+ "required": ["content"],
5482
+ "properties": {
5483
+ "content": {
5484
+ "$ref": "#/$defs/MessageContentInput"
5485
+ }
5486
+ },
5487
+ "additionalProperties": true
5488
+ },
5489
+ {
5490
+ "required": ["interaction"],
5491
+ "properties": {
5492
+ "interaction": {
5493
+ "$ref": "interaction-v1.schema.json#/$defs/InteractionSendRequest"
5494
+ }
5495
+ },
5496
+ "additionalProperties": true
5497
+ }
5498
+ ]
5437
5499
  }
5438
5500
  ],
5439
5501
  "additionalProperties": false
@@ -6511,7 +6573,7 @@
6511
6573
  "const": "https://whooshbang.flowxo.com/problems/idempotency_key_required"
6512
6574
  },
6513
6575
  "title": {
6514
- "const": "Idempotency key required"
6576
+ "enum": ["Invalid idempotency key", "Idempotency key required"]
6515
6577
  },
6516
6578
  "status": {
6517
6579
  "const": 400
@@ -9606,21 +9668,14 @@
9606
9668
  {
9607
9669
  "type": "object",
9608
9670
  "description": "Atomically create or resolve one subscriber and assert existing consent for an exact customer-owned email connection and domain. No verification message is sent. Revocation, suppression, recipient pause, holds and unhealthy authority take precedence. An omitted source is recorded as customer.",
9609
- "required": [
9610
- "subscriber_id",
9611
- "notifier_id",
9612
- "connection_id",
9613
- "domain_id",
9614
- "address",
9615
- "consented",
9616
- "consented_at"
9617
- ],
9671
+ "required": ["subscriber_id", "address", "consented", "consented_at"],
9618
9672
  "properties": {
9619
9673
  "subscriber_id": {
9620
9674
  "$ref": "#/$defs/OpaqueIdentifier"
9621
9675
  },
9622
9676
  "notifier_id": {
9623
- "$ref": "#/$defs/OpaqueIdentifier"
9677
+ "$ref": "#/$defs/OpaqueIdentifier",
9678
+ "default": "default"
9624
9679
  },
9625
9680
  "connection_id": {
9626
9681
  "$ref": "#/$defs/OpaqueIdentifier"
@@ -9653,9 +9708,6 @@
9653
9708
  "description": "Enroll an application-verified user for service email. This is relationship evidence, never consent or WhooshBang mailbox verification. An existing prior-consent binding with the same subscriber, address, notifier, connection and domain is reused with its original evidence and status.",
9654
9709
  "required": [
9655
9710
  "subscriber_id",
9656
- "notifier_id",
9657
- "connection_id",
9658
- "domain_id",
9659
9711
  "address",
9660
9712
  "basis",
9661
9713
  "source",
@@ -9666,7 +9718,8 @@
9666
9718
  "$ref": "#/$defs/OpaqueIdentifier"
9667
9719
  },
9668
9720
  "notifier_id": {
9669
- "$ref": "#/$defs/OpaqueIdentifier"
9721
+ "$ref": "#/$defs/OpaqueIdentifier",
9722
+ "default": "default"
9670
9723
  },
9671
9724
  "connection_id": {
9672
9725
  "$ref": "#/$defs/OpaqueIdentifier"
@@ -9830,9 +9883,7 @@
9830
9883
  "required": ["key", "count"],
9831
9884
  "properties": {
9832
9885
  "key": {
9833
- "type": "string",
9834
- "minLength": 1,
9835
- "maxLength": 128
9886
+ "$ref": "#/$defs/GroupKey"
9836
9887
  },
9837
9888
  "count": {
9838
9889
  "type": "integer",
@@ -11744,7 +11795,7 @@
11744
11795
  "CreateOperatorMessageRequest": {
11745
11796
  "type": "object",
11746
11797
  "description": "Send to a teammate by exact name or operator ID, or use me. Omitted recipient means the verified authenticated human only. Shared and service credentials must name a recipient. Preferred channel, service-email billing and marketing restrictions still apply.",
11747
- "required": ["content"],
11798
+ "required": [],
11748
11799
  "properties": {
11749
11800
  "recipient": {
11750
11801
  "type": "string",
@@ -11752,11 +11803,11 @@
11752
11803
  "maxLength": 128
11753
11804
  },
11754
11805
  "content": {
11755
- "$ref": "#/$defs/MessageContent"
11806
+ "$ref": "#/$defs/MessageContentInput"
11756
11807
  },
11757
11808
  "expires_at": {
11758
11809
  "$ref": "#/$defs/Timestamp",
11759
- "description": "Optional server-authoritative expiry no more than 24 hours after acceptance."
11810
+ "description": "Optional server-authoritative expiry after acceptance, through year 9999. Omit for 24 hours."
11760
11811
  },
11761
11812
  "correlation_id": {
11762
11813
  "type": "string",
@@ -11775,7 +11826,31 @@
11775
11826
  "description": "Omitted means service. Marketing refuses service-only bindings before charging and at every delayed dispatch."
11776
11827
  }
11777
11828
  },
11778
- "additionalProperties": false
11829
+ "additionalProperties": false,
11830
+ "allOf": [
11831
+ {
11832
+ "anyOf": [
11833
+ {
11834
+ "required": ["content"],
11835
+ "properties": {
11836
+ "content": {
11837
+ "$ref": "#/$defs/MessageContentInput"
11838
+ }
11839
+ },
11840
+ "additionalProperties": true
11841
+ },
11842
+ {
11843
+ "required": ["interaction"],
11844
+ "properties": {
11845
+ "interaction": {
11846
+ "$ref": "interaction-v1.schema.json#/$defs/InteractionSendRequest"
11847
+ }
11848
+ },
11849
+ "additionalProperties": true
11850
+ }
11851
+ ]
11852
+ }
11853
+ ]
11779
11854
  },
11780
11855
  "OperatorMessageResult": {
11781
11856
  "type": "object",
@@ -12264,6 +12339,268 @@
12264
12339
  }
12265
12340
  },
12266
12341
  "additionalProperties": false
12342
+ },
12343
+ "CanonicalCreateMessageRequest": {
12344
+ "type": "object",
12345
+ "description": "Creates one logical message for one subscriber and one resolved channel binding.",
12346
+ "required": ["to", "content"],
12347
+ "properties": {
12348
+ "to": {
12349
+ "$ref": "#/$defs/MessageTarget"
12350
+ },
12351
+ "notifier_id": {
12352
+ "allOf": [
12353
+ {
12354
+ "$ref": "#/$defs/OpaqueIdentifier"
12355
+ }
12356
+ ],
12357
+ "default": "default"
12358
+ },
12359
+ "delivery_target": {
12360
+ "$ref": "#/$defs/MessageDeliveryTarget",
12361
+ "description": "Optional routing override. Simulator delivery and the reserved test: subscriber prefix are test-environment-only; live requests are refused with 400 request_invalid. Omit for connection delivery, or for the reserved test-environment simulator default."
12362
+ },
12363
+ "connection_id": {
12364
+ "allOf": [
12365
+ {
12366
+ "$ref": "#/$defs/OpaqueIdentifier"
12367
+ }
12368
+ ],
12369
+ "description": "Optional channel connection to send through, from the environment's connections. The subscriber must be connected through it; the service never substitutes another connection or provider. A connection the subscriber has not connected through is refused as `subscriber_not_connected` when they are connected through another, and as an unchosen send would be (`subscriber_unbound` or `preferred_binding_unavailable`) when no connected channel can take the message. Omitted, the service chooses: the subscriber's preferred channel when they set one, otherwise the default connection when they are connected there, otherwise the connection they connected through most recently. The accepted message's `binding.connection_id` records the connection used. Implies `delivery_target: connection`."
12370
+ },
12371
+ "content": {
12372
+ "$ref": "#/$defs/MessageContent"
12373
+ },
12374
+ "expires_at": {
12375
+ "$ref": "#/$defs/Timestamp",
12376
+ "description": "Optional server-authoritative expiry within the representable range through year 9999 after acceptance."
12377
+ },
12378
+ "correlation_id": {
12379
+ "type": "string",
12380
+ "minLength": 1,
12381
+ "maxLength": 128
12382
+ },
12383
+ "metadata": {
12384
+ "$ref": "#/$defs/Metadata"
12385
+ },
12386
+ "interaction": {
12387
+ "$ref": "interaction-v1.schema.json#/$defs/CanonicalInteractionSendRequest"
12388
+ },
12389
+ "purpose": {
12390
+ "enum": ["service", "marketing"],
12391
+ "default": "service",
12392
+ "description": "Omitted means service. Marketing refuses service-only bindings before charging and at every delayed dispatch."
12393
+ }
12394
+ },
12395
+ "allOf": [
12396
+ {
12397
+ "if": {
12398
+ "required": ["connection_id"],
12399
+ "properties": {
12400
+ "connection_id": true
12401
+ }
12402
+ },
12403
+ "then": {
12404
+ "properties": {
12405
+ "delivery_target": {
12406
+ "const": "connection"
12407
+ }
12408
+ }
12409
+ }
12410
+ }
12411
+ ],
12412
+ "additionalProperties": false
12413
+ },
12414
+ "CanonicalCreateGroupBroadcastRequest": {
12415
+ "type": "object",
12416
+ "description": "Creates one group broadcast using the existing ordinary message envelope. The group target comes only from the path.",
12417
+ "required": ["content"],
12418
+ "properties": {
12419
+ "notifier_id": {
12420
+ "allOf": [
12421
+ {
12422
+ "$ref": "#/$defs/OpaqueIdentifier"
12423
+ }
12424
+ ],
12425
+ "default": "default"
12426
+ },
12427
+ "content": {
12428
+ "$ref": "#/$defs/MessageContent"
12429
+ },
12430
+ "expires_at": {
12431
+ "$ref": "#/$defs/Timestamp"
12432
+ },
12433
+ "correlation_id": {
12434
+ "type": "string",
12435
+ "minLength": 1,
12436
+ "maxLength": 128
12437
+ },
12438
+ "metadata": {
12439
+ "$ref": "#/$defs/Metadata"
12440
+ },
12441
+ "interaction": {
12442
+ "$ref": "interaction-v1.schema.json#/$defs/CanonicalInteractionSendRequest"
12443
+ },
12444
+ "purpose": {
12445
+ "enum": ["service", "marketing"],
12446
+ "default": "service",
12447
+ "description": "Omitted means service. Marketing refuses service-only bindings before charging and at every delayed dispatch."
12448
+ }
12449
+ },
12450
+ "additionalProperties": false
12451
+ },
12452
+ "CanonicalCreateOperatorMessageRequest": {
12453
+ "type": "object",
12454
+ "description": "Send to a teammate by exact name or operator ID, or use me. Omitted recipient means the verified authenticated human only. Shared and service credentials must name a recipient. Preferred channel, service-email billing and marketing restrictions still apply.",
12455
+ "required": ["content"],
12456
+ "properties": {
12457
+ "recipient": {
12458
+ "type": "string",
12459
+ "minLength": 1,
12460
+ "maxLength": 128
12461
+ },
12462
+ "content": {
12463
+ "$ref": "#/$defs/MessageContent"
12464
+ },
12465
+ "expires_at": {
12466
+ "$ref": "#/$defs/Timestamp",
12467
+ "description": "Optional server-authoritative expiry within the representable range through year 9999 after acceptance."
12468
+ },
12469
+ "correlation_id": {
12470
+ "type": "string",
12471
+ "minLength": 1,
12472
+ "maxLength": 128
12473
+ },
12474
+ "metadata": {
12475
+ "$ref": "#/$defs/Metadata"
12476
+ },
12477
+ "interaction": {
12478
+ "$ref": "interaction-v1.schema.json#/$defs/CanonicalInteractionSendRequest"
12479
+ },
12480
+ "purpose": {
12481
+ "enum": ["service", "marketing"],
12482
+ "default": "service",
12483
+ "description": "Omitted means service. Marketing refuses service-only bindings before charging and at every delayed dispatch."
12484
+ }
12485
+ },
12486
+ "additionalProperties": false
12487
+ },
12488
+ "MessageContentInput": {
12489
+ "oneOf": [
12490
+ {
12491
+ "type": "string",
12492
+ "minLength": 1,
12493
+ "maxLength": 8192,
12494
+ "x-max-utf8-bytes": 8192
12495
+ },
12496
+ {
12497
+ "$ref": "#/$defs/TextContentInput"
12498
+ },
12499
+ {
12500
+ "$ref": "#/$defs/DocumentContentInput"
12501
+ }
12502
+ ]
12503
+ },
12504
+ "TextContentInput": {
12505
+ "type": "object",
12506
+ "required": ["text"],
12507
+ "properties": {
12508
+ "type": {
12509
+ "const": "text"
12510
+ },
12511
+ "format": {
12512
+ "type": "string",
12513
+ "enum": ["plain", "markdown"],
12514
+ "description": "Text format. Omitted means plain text. Markdown supports headings, paragraphs, emphasis, strong emphasis, code, lists, quotes and safe HTTP(S) links; raw HTML and remote images are never executed or fetched."
12515
+ },
12516
+ "text": {
12517
+ "description": "The complete notification content. This remains authoritative and sufficient when an adapter cannot render optional structure.",
12518
+ "type": "string",
12519
+ "minLength": 1,
12520
+ "maxLength": 8192,
12521
+ "x-max-utf8-bytes": 8192
12522
+ },
12523
+ "title": {
12524
+ "description": "An optional semantic title. The adapter chooses its native presentation.",
12525
+ "type": "string",
12526
+ "minLength": 1,
12527
+ "maxLength": 200,
12528
+ "x-max-utf8-bytes": 800
12529
+ },
12530
+ "sections": {
12531
+ "description": "Optional ordered semantic sections that enhance, but never replace, the complete text.",
12532
+ "type": "array",
12533
+ "minItems": 1,
12534
+ "maxItems": 12,
12535
+ "items": {
12536
+ "$ref": "#/$defs/StructuredTextSection"
12537
+ }
12538
+ },
12539
+ "image": {
12540
+ "$ref": "#/$defs/NotificationImageInput"
12541
+ }
12542
+ },
12543
+ "additionalProperties": false
12544
+ },
12545
+ "DocumentContentInput": {
12546
+ "description": "An authoritative ordered portable notification document that every delivery adapter renders faithfully.",
12547
+ "type": "object",
12548
+ "required": ["blocks"],
12549
+ "properties": {
12550
+ "type": {
12551
+ "const": "document"
12552
+ },
12553
+ "title": {
12554
+ "description": "An optional semantic document title. The adapter chooses its native presentation.",
12555
+ "type": "string",
12556
+ "minLength": 1,
12557
+ "maxLength": 200,
12558
+ "x-max-utf8-bytes": 800
12559
+ },
12560
+ "blocks": {
12561
+ "description": "The complete portable document in exact authored order.",
12562
+ "type": "array",
12563
+ "minItems": 1,
12564
+ "maxItems": 24,
12565
+ "items": {
12566
+ "$ref": "#/$defs/DocumentBlock"
12567
+ }
12568
+ },
12569
+ "image": {
12570
+ "$ref": "#/$defs/NotificationImageInput"
12571
+ }
12572
+ },
12573
+ "additionalProperties": false
12574
+ },
12575
+ "NotificationImageInput": {
12576
+ "type": "object",
12577
+ "description": "One optional provider-neutral illustrative image. The notification content remains complete without the pixels.",
12578
+ "required": ["asset_id"],
12579
+ "properties": {
12580
+ "asset_id": {
12581
+ "$ref": "#/$defs/NotificationImageAssetId"
12582
+ },
12583
+ "purpose": {
12584
+ "const": "illustration",
12585
+ "default": "illustration"
12586
+ },
12587
+ "description": {
12588
+ "type": "string",
12589
+ "minLength": 1,
12590
+ "maxLength": 1000,
12591
+ "pattern": "^(?=.*\\S)[^\\u0000-\\u001F\\u007F]+$",
12592
+ "x-max-utf8-bytes": 4000,
12593
+ "description": "Optional accessible description preserved by every adapter. Omit it for a decorative illustration; notification text must remain complete without the image."
12594
+ }
12595
+ },
12596
+ "additionalProperties": false
12597
+ },
12598
+ "GroupKey": {
12599
+ "type": "string",
12600
+ "minLength": 1,
12601
+ "maxLength": 63,
12602
+ "pattern": "^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$",
12603
+ "description": "A stable, case-sensitive subscriber group key. Existing keys are preserved exactly."
12267
12604
  }
12268
12605
  }
12269
12606
  }