@whooshbang/contracts 3.2.0 → 3.3.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 (86) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/contract-manifest.json +32 -32
  3. package/dist/generated/artifact-index.d.ts +33 -33
  4. package/dist/generated/artifact-index.js +32 -32
  5. package/dist/generated/validators-standalone.js +1273 -978
  6. package/dist/generated/validators-standalone.js.map +1 -1
  7. package/dist/generated/whooshbang-v1.d.ts +28 -7
  8. package/fixtures/core-v1/fixture-index.json +1 -1
  9. package/fixtures/core-v1/scenarios/api-credential-invalid-indistinguishable.json +1 -1
  10. package/fixtures/core-v1/scenarios/api-credential-one-time-reveal.json +1 -1
  11. package/fixtures/core-v1/scenarios/api-credential-revocation-replay.json +1 -1
  12. package/fixtures/core-v1/scenarios/api-credential-rotation-overlap.json +1 -1
  13. package/fixtures/core-v1/scenarios/cancellation-too-late.json +1 -1
  14. package/fixtures/core-v1/scenarios/cross-organization-project.json +1 -1
  15. package/fixtures/core-v1/scenarios/cross-project-resource.json +1 -1
  16. package/fixtures/core-v1/scenarios/environment-mismatch.json +1 -1
  17. package/fixtures/core-v1/scenarios/idempotency-conflict.json +1 -1
  18. package/fixtures/core-v1/scenarios/idempotency-equivalent-replay.json +1 -1
  19. package/fixtures/core-v1/scenarios/malformed-bearer.json +1 -1
  20. package/fixtures/core-v1/scenarios/metadata-overrun.json +1 -1
  21. package/fixtures/core-v1/scenarios/missing-scope.json +1 -1
  22. package/fixtures/core-v1/scenarios/project-create-equivalent-replay.json +1 -1
  23. package/fixtures/core-v1/scenarios/project-slug-conflict.json +1 -1
  24. package/fixtures/core-v1/scenarios/provider-outcome-unknown.json +1 -1
  25. package/fixtures/core-v1/scenarios/subscription-activation-replay.json +1 -1
  26. package/fixtures/core-v1/scenarios/subscription-authorization-capability-opacity.json +1 -1
  27. package/fixtures/core-v1/scenarios/subscription-cross-connection-callback-rejected.json +1 -1
  28. package/fixtures/core-v1/scenarios/subscription-expired-replay.json +1 -1
  29. package/fixtures/core-v1/scenarios/subscription-selected-connection-replay.json +1 -1
  30. package/fixtures/interaction-machine-v1/scenarios/ack-conflict.json +1 -1
  31. package/fixtures/interaction-machine-v1/scenarios/ack-cross-machine.json +1 -1
  32. package/fixtures/interaction-machine-v1/scenarios/ack-out-of-order.json +1 -1
  33. package/fixtures/interaction-machine-v1/scenarios/ack-replay.json +1 -1
  34. package/fixtures/interaction-machine-v1/scenarios/ambiguous-free-text.json +1 -1
  35. package/fixtures/interaction-machine-v1/scenarios/callback-token-opacity.json +1 -1
  36. package/fixtures/interaction-machine-v1/scenarios/credential-registration-conflict.json +1 -1
  37. package/fixtures/interaction-machine-v1/scenarios/credential-registration-replay.json +1 -1
  38. package/fixtures/interaction-machine-v1/scenarios/credential-revocation-replay.json +1 -1
  39. package/fixtures/interaction-machine-v1/scenarios/credential-rotation.json +1 -1
  40. package/fixtures/interaction-machine-v1/scenarios/first-credential-activates.json +1 -1
  41. package/fixtures/interaction-machine-v1/scenarios/interaction-duplicate.json +1 -1
  42. package/fixtures/interaction-machine-v1/scenarios/interaction-expired.json +1 -1
  43. package/fixtures/interaction-machine-v1/scenarios/interaction-mismatch.json +1 -1
  44. package/fixtures/interaction-machine-v1/scenarios/interaction-retired.json +1 -1
  45. package/fixtures/interaction-machine-v1/scenarios/interaction-stale.json +1 -1
  46. package/fixtures/interaction-machine-v1/scenarios/machine-admin-denied.json +1 -1
  47. package/fixtures/interaction-machine-v1/scenarios/machine-bound-message-create.json +1 -1
  48. package/fixtures/interaction-machine-v1/scenarios/machine-cancel-denied.json +1 -1
  49. package/fixtures/interaction-machine-v1/scenarios/machine-crash-before-ack.json +1 -1
  50. package/fixtures/interaction-machine-v1/scenarios/machine-notifier-mismatch.json +1 -1
  51. package/fixtures/interaction-machine-v1/scenarios/machine-other-message-read.json +1 -1
  52. package/fixtures/interaction-machine-v1/scenarios/machine-owned-message-read.json +1 -1
  53. package/fixtures/interaction-machine-v1/scenarios/machine-subscriber-mismatch.json +1 -1
  54. package/fixtures/interaction-machine-v1/scenarios/poll-uncommitted-cursor-rejected.json +1 -1
  55. package/fixtures/interaction-machine-v1/scenarios/project-credential-machine-endpoint-denied.json +1 -1
  56. package/fixtures/interaction-machine-v1/scenarios/quarantine-integrity-rejected.json +1 -1
  57. package/fixtures/interaction-machine-v1/scenarios/quarantine-signature-rejected.json +1 -1
  58. package/fixtures/interaction-machine-v1/scenarios/quarantine-valid.json +1 -1
  59. package/fixtures/interaction-machine-v1/scenarios/revoked-machine-credential.json +1 -1
  60. package/fixtures/recipient-experience-v1/scenarios/membership-broadcast-snapshot.json +1 -1
  61. package/fixtures/recipient-experience-v1/scenarios/preferred-binding-resolution.json +1 -1
  62. package/fixtures/recipient-experience-v1/scenarios/recipient-session-security.json +1 -1
  63. package/fixtures/recipient-experience-v1/scenarios/subscriber-initial-groups-transaction.json +1 -1
  64. package/fixtures/recipient-experience-v1/success/project-recipient-experience.json +2 -0
  65. package/openapi/generated/whooshbang-v1.bundle.json +67 -9
  66. package/openapi/whooshbang-v1.yaml +32 -3
  67. package/package.json +1 -1
  68. package/schemas/core-scenario.schema.json +1 -1
  69. package/schemas/events/agent-binding-degraded-v1.schema.json +1 -1
  70. package/schemas/events/interaction-expired-v1.schema.json +1 -1
  71. package/schemas/events/interaction-received-v1.schema.json +1 -1
  72. package/schemas/events/message-delivered-v1.schema.json +1 -1
  73. package/schemas/events/message-expired-v1.schema.json +1 -1
  74. package/schemas/events/message-failed-v1.schema.json +1 -1
  75. package/schemas/events/message-provider-accepted-v1.schema.json +1 -1
  76. package/schemas/events/subscription-activated-v1.schema.json +1 -1
  77. package/schemas/events/subscription-revoked-v1.schema.json +1 -1
  78. package/schemas/events/whooshbang-event-v1.schema.json +1 -1
  79. package/schemas/fixture-index.schema.json +1 -1
  80. package/schemas/interaction-machine-scenario.schema.json +1 -1
  81. package/schemas/interaction-v1.schema.json +1 -1
  82. package/schemas/machine-v1.schema.json +1 -1
  83. package/schemas/provider-capabilities-v1.schema.json +1 -1
  84. package/schemas/webhooks/webhook-delivery-case-v1.schema.json +1 -1
  85. package/schemas/webhooks/webhook-signing-vector-v1.schema.json +1 -1
  86. package/schemas/whooshbang-v1.schema.json +32 -6
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.1",
3
3
  "info": {
4
4
  "title": "WhooshBang API",
5
- "version": "3.2.0",
5
+ "version": "3.3.0",
6
6
  "description": "The V1 contract for human organization/project administration, project-scoped\nsubscription links, and asynchronous text messages. A Clerk session selects\none organization for administration. A project credential selects one organization,\nproject, and `test` or `live` environment for product operations; request\nbodies cannot override either authenticated scope.\n\nA person's OAuth grant selects one organization and carries scopes, but no\nproject. It names the project and environment it acts in through the URL\npath, on the environment-scoped form of each operation; the service checks\nthat path against the granting person's membership on every call. The flat\nforms remain credential-only and are unchanged.\n\nResource identifiers are opaque and are not authorization. Reads outside the\ncredential scope return the same `404` shape as absent resources. Provider\ncredentials, raw Telegram identity, and protected provider responses are\nnever part of this API.\n",
7
7
  "termsOfService": "https://flowxo.com/terms",
8
8
  "contact": {
@@ -103,6 +103,7 @@
103
103
  "get": {
104
104
  "operationId": "listMessageCategories",
105
105
  "summary": "List project message categories",
106
+ "description": "By default, only current categories are listed. Include archived categories when offering a filter over historical messages.",
106
107
  "tags": ["Message categories"],
107
108
  "security": [
108
109
  { "clerkSession": [] },
@@ -110,6 +111,14 @@
110
111
  { "bearerCredential": [] }
111
112
  ],
112
113
  "x-required-scopes": ["projects:read"],
114
+ "parameters": [
115
+ {
116
+ "in": "query",
117
+ "name": "include_archived",
118
+ "required": false,
119
+ "schema": { "type": "boolean", "default": false }
120
+ }
121
+ ],
113
122
  "responses": {
114
123
  "200": {
115
124
  "description": "Categories in this project.",
@@ -6899,6 +6908,8 @@
6899
6908
  "accent_color": "#4F46E5",
6900
6909
  "color_scheme": "system"
6901
6910
  },
6911
+ "show_service_category_switches": true,
6912
+ "show_marketing_category_switches": true,
6902
6913
  "row_version": 2,
6903
6914
  "updated_at": "2026-08-22T18:00:00Z",
6904
6915
  "diagnostic_id": "diag_n17_project_experience"
@@ -8939,7 +8950,7 @@
8939
8950
  "get": {
8940
8951
  "operationId": "listMessagesInEnvironment",
8941
8952
  "summary": "List accepted messages with filters",
8942
- "description": "Content-free message history. Filters combine. accepted_after is inclusive; accepted_before is exclusive. Supply after or page, never both. after accepts the opaque next_after continuation; history intentionally has no total.",
8953
+ "description": "Message history with a retained-content snippet. q searches retained text or an exact message or subscriber ID. After content expires, its message ID still finds it. Filters combine before pagination. accepted_after is inclusive; accepted_before is exclusive. Supply after or page, never both. after accepts the opaque next_after continuation; history intentionally has no total.",
8943
8954
  "tags": ["Administration"],
8944
8955
  "security": [
8945
8956
  { "clerkSession": [] },
@@ -8973,6 +8984,13 @@
8973
8984
  "required": false,
8974
8985
  "schema": { "$ref": "#/components/schemas/OpaqueIdentifier" }
8975
8986
  },
8987
+ {
8988
+ "in": "query",
8989
+ "name": "q",
8990
+ "required": false,
8991
+ "description": "Search retained message text or an exact message or subscriber ID. Expired content is found by message ID only.",
8992
+ "schema": { "type": "string", "minLength": 1, "maxLength": 256 }
8993
+ },
8976
8994
  {
8977
8995
  "in": "query",
8978
8996
  "name": "accepted_after",
@@ -8991,6 +9009,20 @@
8991
9009
  "required": false,
8992
9010
  "schema": { "$ref": "#/components/schemas/OpaqueIdentifier" }
8993
9011
  },
9012
+ {
9013
+ "in": "query",
9014
+ "name": "category_key",
9015
+ "required": false,
9016
+ "description": "Match the category key captured when the message was accepted.",
9017
+ "schema": { "$ref": "#/components/schemas/MessageCategoryKey" }
9018
+ },
9019
+ {
9020
+ "in": "query",
9021
+ "name": "no_category",
9022
+ "required": false,
9023
+ "description": "Match messages accepted before categories were recorded. Cannot be true with category_key.",
9024
+ "schema": { "type": "boolean", "default": false }
9025
+ },
8994
9026
  {
8995
9027
  "in": "query",
8996
9028
  "name": "state",
@@ -11993,7 +12025,16 @@
11993
12025
  "purpose": { "enum": ["service", "marketing"] },
11994
12026
  "level": { "enum": ["low", "normal", "high", "critical"] },
11995
12027
  "can_turn_off": { "type": "boolean" },
11996
- "is_default": { "type": "boolean" }
12028
+ "is_default": { "type": "boolean" },
12029
+ "opted_out_subscriber_count": {
12030
+ "type": "integer",
12031
+ "minimum": 0,
12032
+ "description": "Number of subscribers in this project who currently have this category switched off. Returned when listing a project's categories."
12033
+ },
12034
+ "archived_at": {
12035
+ "$ref": "#/components/schemas/Timestamp",
12036
+ "description": "Present only when this category has been archived. Historical messages retain their acceptance-time category snapshot."
12037
+ }
11997
12038
  },
11998
12039
  "additionalProperties": false
11999
12040
  },
@@ -12003,7 +12044,6 @@
12003
12044
  "properties": {
12004
12045
  "items": {
12005
12046
  "type": "array",
12006
- "maxItems": 100,
12007
12047
  "items": { "$ref": "#/components/schemas/MessageCategory" }
12008
12048
  },
12009
12049
  "total": { "$ref": "#/components/schemas/ListTotal" }
@@ -18550,11 +18590,13 @@
18550
18590
  },
18551
18591
  "ProjectRecipientExperience": {
18552
18592
  "type": "object",
18553
- "description": "The project-owned recipient identity, fallback locale, and email answer behavior. Email answers use one click when no setting has been saved.",
18593
+ "description": "The project-owned recipient identity, fallback locale, email answer behavior, and category switch visibility. Email answers use one click when no setting has been saved.",
18554
18594
  "required": [
18555
18595
  "project_id",
18556
18596
  "default_locale",
18557
18597
  "brand",
18598
+ "show_service_category_switches",
18599
+ "show_marketing_category_switches",
18558
18600
  "row_version",
18559
18601
  "updated_at",
18560
18602
  "diagnostic_id"
@@ -18570,6 +18612,14 @@
18570
18612
  "enum": ["one_click", "confirm"],
18571
18613
  "description": "How an email confirm or select button records its bound answer. Defaults to one_click for existing and new projects; free-text answers always use a form."
18572
18614
  },
18615
+ "show_service_category_switches": {
18616
+ "type": "boolean",
18617
+ "description": "Whether subscriber settings show service category switches. A subscriber who already turned a category off still sees its switch. Defaults to true."
18618
+ },
18619
+ "show_marketing_category_switches": {
18620
+ "type": "boolean",
18621
+ "description": "Whether subscriber settings show marketing category switches. A subscriber who already turned a category off still sees its switch. Defaults to true."
18622
+ },
18573
18623
  "row_version": { "type": "integer", "minimum": 1 },
18574
18624
  "updated_at": { "$ref": "#/components/schemas/Timestamp" },
18575
18625
  "diagnostic_id": { "$ref": "#/components/schemas/DiagnosticId" }
@@ -18704,8 +18754,8 @@
18704
18754
  },
18705
18755
  "UpdateProjectRecipientExperienceRequest": {
18706
18756
  "type": "object",
18707
- "description": "Replaces the project-owned recipient brand and fallback locale under the last observed row version. Omission of email_answer_confirmation preserves its current value, or one_click for an unwritten project.",
18708
- "required": ["default_locale", "brand", "row_version"],
18757
+ "description": "Updates supplied project recipient settings under the last observed row version. Omitted fields keep their current values or project defaults.",
18758
+ "required": ["row_version"],
18709
18759
  "properties": {
18710
18760
  "default_locale": {
18711
18761
  "$ref": "#/components/schemas/RecipientLanguage"
@@ -18716,6 +18766,14 @@
18716
18766
  "enum": ["one_click", "confirm"],
18717
18767
  "description": "Optional project-wide email answer behavior. Omission preserves the current value."
18718
18768
  },
18769
+ "show_service_category_switches": {
18770
+ "type": "boolean",
18771
+ "description": "Show service category switches in subscriber settings. A subscriber who already turned a category off still sees its switch. Omit to keep the current value."
18772
+ },
18773
+ "show_marketing_category_switches": {
18774
+ "type": "boolean",
18775
+ "description": "Show marketing category switches in subscriber settings. A subscriber who already turned a category off still sees its switch. Omit to keep the current value."
18776
+ },
18719
18777
  "row_version": { "type": "integer", "minimum": 1 }
18720
18778
  },
18721
18779
  "additionalProperties": false
@@ -22068,7 +22126,7 @@
22068
22126
  "provider-capabilities-v1.schema": {
22069
22127
  "$schema": "https://json-schema.org/draft/2020-12/schema",
22070
22128
  "$id": "https://whooshbang.flowxo.com/schemas/provider-capabilities-v1.schema.json",
22071
- "x-contract-version": "3.2.0",
22129
+ "x-contract-version": "3.3.0",
22072
22130
  "title": "ProviderCapabilitiesV1",
22073
22131
  "description": "Provider-neutral, renderer-facing delivery and interaction capabilities with explicit degradation.",
22074
22132
  "type": "object",
@@ -22870,5 +22928,5 @@
22870
22928
  }
22871
22929
  }
22872
22930
  },
22873
- "x-contract-version": "3.2.0"
22931
+ "x-contract-version": "3.3.0"
22874
22932
  }
@@ -1,10 +1,10 @@
1
1
  openapi: 3.1.1
2
2
  jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
3
3
  # whooshbang:public-origin production api https://api.whooshbang.com
4
- x-contract-version: 3.2.0
4
+ x-contract-version: 3.3.0
5
5
  info:
6
6
  title: WhooshBang API
7
- version: 3.2.0
7
+ version: 3.3.0
8
8
  description: |
9
9
  The V1 contract for human organization/project administration, project-scoped
10
10
  subscription links, and asynchronous text messages. A Clerk session selects
@@ -80,12 +80,20 @@ paths:
80
80
  get:
81
81
  operationId: listMessageCategories
82
82
  summary: List project message categories
83
+ description: By default, only current categories are listed. Include archived categories when offering a filter over historical messages.
83
84
  tags: [Message categories]
84
85
  security:
85
86
  - clerkSession: []
86
87
  - bearerGrant: []
87
88
  - bearerCredential: []
88
89
  x-required-scopes: [projects:read]
90
+ parameters:
91
+ - in: query
92
+ name: include_archived
93
+ required: false
94
+ schema:
95
+ type: boolean
96
+ default: false
89
97
  responses:
90
98
  "200":
91
99
  description: Categories in this project.
@@ -6882,7 +6890,7 @@ paths:
6882
6890
  get:
6883
6891
  operationId: listMessagesInEnvironment
6884
6892
  summary: List accepted messages with filters
6885
- description: "Content-free message history. Filters combine. accepted_after is inclusive; accepted_before is exclusive. Supply after or page, never both. after accepts the opaque next_after continuation; history intentionally has no total."
6893
+ description: "Message history with a retained-content snippet. q searches retained text or an exact message or subscriber ID. After content expires, its message ID still finds it. Filters combine before pagination. accepted_after is inclusive; accepted_before is exclusive. Supply after or page, never both. after accepts the opaque next_after continuation; history intentionally has no total."
6886
6894
  tags: [Administration]
6887
6895
  security:
6888
6896
  - clerkSession: []
@@ -6913,6 +6921,14 @@ paths:
6913
6921
  required: false
6914
6922
  schema:
6915
6923
  $ref: "#/components/schemas/OpaqueIdentifier"
6924
+ - in: query
6925
+ name: q
6926
+ required: false
6927
+ description: Search retained message text or an exact message or subscriber ID. Expired content is found by message ID only.
6928
+ schema:
6929
+ type: string
6930
+ minLength: 1
6931
+ maxLength: 256
6916
6932
  - in: query
6917
6933
  name: accepted_after
6918
6934
  required: false
@@ -6928,6 +6944,19 @@ paths:
6928
6944
  required: false
6929
6945
  schema:
6930
6946
  $ref: "#/components/schemas/OpaqueIdentifier"
6947
+ - in: query
6948
+ name: category_key
6949
+ required: false
6950
+ description: Match the category key captured when the message was accepted.
6951
+ schema:
6952
+ $ref: "#/components/schemas/MessageCategoryKey"
6953
+ - in: query
6954
+ name: no_category
6955
+ required: false
6956
+ description: Match messages accepted before categories were recorded. Cannot be true with category_key.
6957
+ schema:
6958
+ type: boolean
6959
+ default: false
6931
6960
  - in: query
6932
6961
  name: state
6933
6962
  required: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whooshbang/contracts",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Versioned public contracts for WhooshBang",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -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/core-scenario.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "CoreContractScenario",
6
6
  "description": "A deterministic C0-02 semantic, state, idempotency, or isolation scenario.",
7
7
  "type": "object",
@@ -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/events/agent-binding-degraded-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "AgentBindingDegradedEventV1",
6
6
  "description": "An agent binding entered a provider-neutral degraded state.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/AgentBindingDegradedEvent"
@@ -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/events/interaction-expired-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "InteractionExpiredEventV1",
6
6
  "description": "An interaction reached its terminal expiry without a valid answer.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/InteractionExpiredEvent"
@@ -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/events/interaction-received-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "InteractionReceivedEventV1",
6
6
  "description": "One authenticated, provider-neutral interaction answer was received.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/InteractionReceivedEvent"
@@ -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/events/message-delivered-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "MessageDeliveredEventV1",
6
6
  "description": "A provider supplied trustworthy evidence that a message was delivered.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/MessageDeliveredEvent"
@@ -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/events/message-expired-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "MessageExpiredEventV1",
6
6
  "description": "A message expired before reaching a later delivery state.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/MessageExpiredEvent"
@@ -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/events/message-failed-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "MessageFailedEventV1",
6
6
  "description": "A message reached a classified terminal failure.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/MessageFailedEvent"
@@ -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/events/message-provider-accepted-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "MessageProviderAcceptedEventV1",
6
6
  "description": "The provider accepted a message without implying delivery.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/MessageProviderAcceptedEvent"
@@ -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/events/subscription-activated-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "SubscriptionActivatedEventV1",
6
6
  "description": "A subscription became active with a safe public channel binding.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/SubscriptionActivatedEvent"
@@ -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/events/subscription-revoked-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "SubscriptionRevokedEventV1",
6
6
  "description": "A subscription and its safe public channel binding were revoked.",
7
7
  "$ref": "whooshbang-event-v1.schema.json#/$defs/SubscriptionRevokedEvent"
@@ -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/events/whooshbang-event-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "WhooshBangEventV1ContractDocument",
6
6
  "description": "Strict public customer-event envelope and initial WhooshBang event union.",
7
7
  "oneOf": [
@@ -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/fixture-index.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "CoreFixtureIndex",
6
6
  "description": "The machine-readable index of deterministic C0-02 through C0-04 golden fixtures.",
7
7
  "type": "object",
@@ -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/interaction-machine-scenario.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "InteractionMachineScenario",
6
6
  "description": "A deterministic C0-03 interaction, credential, authorization, polling, acknowledgement, or quarantine scenario.",
7
7
  "type": "object",
@@ -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/interaction-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "InteractionV1ContractDocument",
6
6
  "description": "Provider-neutral confirm, single-select, input, lifecycle, callback-token, and authenticated answer-event contracts.",
7
7
  "$defs": {
@@ -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/machine-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "MachineV1ContractDocument",
6
6
  "description": "Machine-client administration, locally generated credential metadata, durable long-poll, and contiguous acknowledgement contracts.",
7
7
  "oneOf": [
@@ -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/provider-capabilities-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "ProviderCapabilitiesV1",
6
6
  "description": "Provider-neutral, renderer-facing delivery and interaction capabilities with explicit degradation.",
7
7
  "type": "object",
@@ -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/webhooks/webhook-delivery-case-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "WebhookDeliveryCaseSetV1",
6
6
  "description": "Deterministic customer webhook response classification, Retry-After, and delivery-bound cases.",
7
7
  "type": "object",
@@ -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/webhooks/webhook-signing-vector-v1.schema.json",
4
- "x-contract-version": "3.2.0",
4
+ "x-contract-version": "3.3.0",
5
5
  "title": "WebhookSigningVectorSetV1",
6
6
  "description": "Language-neutral deterministic Standard Webhooks V1 verification vectors. All key material is public synthetic test data and must never be used outside fixtures.",
7
7
  "type": "object",
@@ -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": "3.2.0",
4
+ "x-contract-version": "3.3.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": [
@@ -2988,11 +2988,13 @@
2988
2988
  },
2989
2989
  "ProjectRecipientExperience": {
2990
2990
  "type": "object",
2991
- "description": "The project-owned recipient identity, fallback locale, and email answer behavior. Email answers use one click when no setting has been saved.",
2991
+ "description": "The project-owned recipient identity, fallback locale, email answer behavior, and category switch visibility. Email answers use one click when no setting has been saved.",
2992
2992
  "required": [
2993
2993
  "project_id",
2994
2994
  "default_locale",
2995
2995
  "brand",
2996
+ "show_service_category_switches",
2997
+ "show_marketing_category_switches",
2996
2998
  "row_version",
2997
2999
  "updated_at",
2998
3000
  "diagnostic_id"
@@ -3012,6 +3014,14 @@
3012
3014
  "enum": ["one_click", "confirm"],
3013
3015
  "description": "How an email confirm or select button records its bound answer. Defaults to one_click for existing and new projects; free-text answers always use a form."
3014
3016
  },
3017
+ "show_service_category_switches": {
3018
+ "type": "boolean",
3019
+ "description": "Whether subscriber settings show service category switches. A subscriber who already turned a category off still sees its switch. Defaults to true."
3020
+ },
3021
+ "show_marketing_category_switches": {
3022
+ "type": "boolean",
3023
+ "description": "Whether subscriber settings show marketing category switches. A subscriber who already turned a category off still sees its switch. Defaults to true."
3024
+ },
3015
3025
  "row_version": {
3016
3026
  "type": "integer",
3017
3027
  "minimum": 1
@@ -3027,8 +3037,8 @@
3027
3037
  },
3028
3038
  "UpdateProjectRecipientExperienceRequest": {
3029
3039
  "type": "object",
3030
- "description": "Replaces the project-owned recipient brand and fallback locale under the last observed row version. Omission of email_answer_confirmation preserves its current value, or one_click for an unwritten project.",
3031
- "required": ["default_locale", "brand", "row_version"],
3040
+ "description": "Updates supplied project recipient settings under the last observed row version. Omitted fields keep their current values or project defaults.",
3041
+ "required": ["row_version"],
3032
3042
  "properties": {
3033
3043
  "default_locale": {
3034
3044
  "$ref": "#/$defs/RecipientLanguage"
@@ -3041,6 +3051,14 @@
3041
3051
  "enum": ["one_click", "confirm"],
3042
3052
  "description": "Optional project-wide email answer behavior. Omission preserves the current value."
3043
3053
  },
3054
+ "show_service_category_switches": {
3055
+ "type": "boolean",
3056
+ "description": "Show service category switches in subscriber settings. A subscriber who already turned a category off still sees its switch. Omit to keep the current value."
3057
+ },
3058
+ "show_marketing_category_switches": {
3059
+ "type": "boolean",
3060
+ "description": "Show marketing category switches in subscriber settings. A subscriber who already turned a category off still sees its switch. Omit to keep the current value."
3061
+ },
3044
3062
  "row_version": {
3045
3063
  "type": "integer",
3046
3064
  "minimum": 1
@@ -5478,7 +5496,16 @@
5478
5496
  "purpose": { "enum": ["service", "marketing"] },
5479
5497
  "level": { "enum": ["low", "normal", "high", "critical"] },
5480
5498
  "can_turn_off": { "type": "boolean" },
5481
- "is_default": { "type": "boolean" }
5499
+ "is_default": { "type": "boolean" },
5500
+ "opted_out_subscriber_count": {
5501
+ "type": "integer",
5502
+ "minimum": 0,
5503
+ "description": "Number of subscribers in this project who currently have this category switched off. Returned when listing a project's categories."
5504
+ },
5505
+ "archived_at": {
5506
+ "$ref": "#/$defs/Timestamp",
5507
+ "description": "Present only when this category has been archived. Historical messages retain their acceptance-time category snapshot."
5508
+ }
5482
5509
  },
5483
5510
  "additionalProperties": false
5484
5511
  },
@@ -5488,7 +5515,6 @@
5488
5515
  "properties": {
5489
5516
  "items": {
5490
5517
  "type": "array",
5491
- "maxItems": 100,
5492
5518
  "items": { "$ref": "#/$defs/MessageCategory" }
5493
5519
  },
5494
5520
  "total": { "$ref": "#/$defs/ListTotal" }