@whooshbang/contracts 1.0.0-rc.21 → 1.0.0-rc.22

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 (97) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/contract-manifest.json +34 -32
  3. package/dist/generated/artifact-index.d.ts +34 -34
  4. package/dist/generated/artifact-index.js +34 -32
  5. package/dist/generated/artifact-index.js.map +1 -1
  6. package/dist/generated/validators-standalone.d.ts +340 -288
  7. package/dist/generated/validators-standalone.js +5459 -2824
  8. package/dist/generated/validators-standalone.js.map +1 -1
  9. package/dist/generated/validators.d.ts +5 -1
  10. package/dist/generated/validators.js +5 -1
  11. package/dist/generated/validators.js.map +1 -1
  12. package/dist/generated/whooshbang-v1.d.ts +89 -3
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/fixtures/core-v1/fixture-index.json +17 -1
  17. package/fixtures/core-v1/problems/live-simulator-refused.json +16 -0
  18. package/fixtures/core-v1/requests/update-project.json +3 -0
  19. package/fixtures/core-v1/scenarios/api-credential-invalid-indistinguishable.json +1 -1
  20. package/fixtures/core-v1/scenarios/api-credential-one-time-reveal.json +1 -1
  21. package/fixtures/core-v1/scenarios/api-credential-revocation-replay.json +1 -1
  22. package/fixtures/core-v1/scenarios/api-credential-rotation-overlap.json +1 -1
  23. package/fixtures/core-v1/scenarios/cancellation-too-late.json +1 -1
  24. package/fixtures/core-v1/scenarios/cross-account-project.json +1 -1
  25. package/fixtures/core-v1/scenarios/cross-project-resource.json +1 -1
  26. package/fixtures/core-v1/scenarios/environment-mismatch.json +1 -1
  27. package/fixtures/core-v1/scenarios/idempotency-conflict.json +1 -1
  28. package/fixtures/core-v1/scenarios/idempotency-equivalent-replay.json +1 -1
  29. package/fixtures/core-v1/scenarios/malformed-bearer.json +1 -1
  30. package/fixtures/core-v1/scenarios/metadata-overrun.json +1 -1
  31. package/fixtures/core-v1/scenarios/missing-scope.json +1 -1
  32. package/fixtures/core-v1/scenarios/project-create-equivalent-replay.json +1 -1
  33. package/fixtures/core-v1/scenarios/project-slug-conflict.json +1 -1
  34. package/fixtures/core-v1/scenarios/provider-outcome-unknown.json +1 -1
  35. package/fixtures/core-v1/scenarios/subscription-activation-replay.json +1 -1
  36. package/fixtures/core-v1/scenarios/subscription-authorization-capability-opacity.json +1 -1
  37. package/fixtures/core-v1/scenarios/subscription-cross-connection-callback-rejected.json +1 -1
  38. package/fixtures/core-v1/scenarios/subscription-expired-replay.json +1 -1
  39. package/fixtures/core-v1/scenarios/subscription-selected-connection-replay.json +1 -1
  40. package/fixtures/core-v1/success/project-collection.json +2 -1
  41. package/fixtures/core-v1/success/project-created.json +2 -1
  42. package/fixtures/interaction-machine-v1/scenarios/ack-conflict.json +1 -1
  43. package/fixtures/interaction-machine-v1/scenarios/ack-cross-machine.json +1 -1
  44. package/fixtures/interaction-machine-v1/scenarios/ack-out-of-order.json +1 -1
  45. package/fixtures/interaction-machine-v1/scenarios/ack-replay.json +1 -1
  46. package/fixtures/interaction-machine-v1/scenarios/ambiguous-free-text.json +1 -1
  47. package/fixtures/interaction-machine-v1/scenarios/callback-token-opacity.json +1 -1
  48. package/fixtures/interaction-machine-v1/scenarios/credential-registration-conflict.json +1 -1
  49. package/fixtures/interaction-machine-v1/scenarios/credential-registration-replay.json +1 -1
  50. package/fixtures/interaction-machine-v1/scenarios/credential-revocation-replay.json +1 -1
  51. package/fixtures/interaction-machine-v1/scenarios/credential-rotation.json +1 -1
  52. package/fixtures/interaction-machine-v1/scenarios/first-credential-activates.json +1 -1
  53. package/fixtures/interaction-machine-v1/scenarios/interaction-duplicate.json +1 -1
  54. package/fixtures/interaction-machine-v1/scenarios/interaction-expired.json +1 -1
  55. package/fixtures/interaction-machine-v1/scenarios/interaction-mismatch.json +1 -1
  56. package/fixtures/interaction-machine-v1/scenarios/interaction-retired.json +1 -1
  57. package/fixtures/interaction-machine-v1/scenarios/interaction-stale.json +1 -1
  58. package/fixtures/interaction-machine-v1/scenarios/machine-admin-denied.json +1 -1
  59. package/fixtures/interaction-machine-v1/scenarios/machine-bound-message-create.json +1 -1
  60. package/fixtures/interaction-machine-v1/scenarios/machine-cancel-denied.json +1 -1
  61. package/fixtures/interaction-machine-v1/scenarios/machine-crash-before-ack.json +1 -1
  62. package/fixtures/interaction-machine-v1/scenarios/machine-notifier-mismatch.json +1 -1
  63. package/fixtures/interaction-machine-v1/scenarios/machine-other-message-read.json +1 -1
  64. package/fixtures/interaction-machine-v1/scenarios/machine-owned-message-read.json +1 -1
  65. package/fixtures/interaction-machine-v1/scenarios/machine-subscriber-mismatch.json +1 -1
  66. package/fixtures/interaction-machine-v1/scenarios/poll-uncommitted-cursor-rejected.json +1 -1
  67. package/fixtures/interaction-machine-v1/scenarios/project-credential-machine-endpoint-denied.json +1 -1
  68. package/fixtures/interaction-machine-v1/scenarios/quarantine-integrity-rejected.json +1 -1
  69. package/fixtures/interaction-machine-v1/scenarios/quarantine-signature-rejected.json +1 -1
  70. package/fixtures/interaction-machine-v1/scenarios/quarantine-valid.json +1 -1
  71. package/fixtures/interaction-machine-v1/scenarios/revoked-machine-credential.json +1 -1
  72. package/fixtures/recipient-experience-v1/scenarios/membership-broadcast-snapshot.json +1 -1
  73. package/fixtures/recipient-experience-v1/scenarios/preferred-binding-resolution.json +1 -1
  74. package/fixtures/recipient-experience-v1/scenarios/recipient-session-security.json +1 -1
  75. package/fixtures/recipient-experience-v1/scenarios/subscriber-initial-groups-transaction.json +1 -1
  76. package/openapi/generated/whooshbang-v1.bundle.json +360 -11
  77. package/openapi/whooshbang-v1.yaml +216 -2
  78. package/package.json +1 -1
  79. package/schemas/core-scenario.schema.json +1 -1
  80. package/schemas/events/agent-binding-degraded-v1.schema.json +1 -1
  81. package/schemas/events/interaction-expired-v1.schema.json +1 -1
  82. package/schemas/events/interaction-received-v1.schema.json +1 -1
  83. package/schemas/events/message-delivered-v1.schema.json +1 -1
  84. package/schemas/events/message-expired-v1.schema.json +1 -1
  85. package/schemas/events/message-failed-v1.schema.json +1 -1
  86. package/schemas/events/message-provider-accepted-v1.schema.json +1 -1
  87. package/schemas/events/subscription-activated-v1.schema.json +1 -1
  88. package/schemas/events/subscription-revoked-v1.schema.json +1 -1
  89. package/schemas/events/whooshbang-event-v1.schema.json +1 -1
  90. package/schemas/fixture-index.schema.json +1 -1
  91. package/schemas/interaction-machine-scenario.schema.json +1 -1
  92. package/schemas/interaction-v1.schema.json +1 -1
  93. package/schemas/machine-v1.schema.json +1 -1
  94. package/schemas/provider-capabilities-v1.schema.json +1 -1
  95. package/schemas/webhooks/webhook-delivery-case-v1.schema.json +1 -1
  96. package/schemas/webhooks/webhook-signing-vector-v1.schema.json +1 -1
  97. package/schemas/whooshbang-v1.schema.json +225 -3
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.1",
3
3
  "info": {
4
4
  "title": "WhooshBang API",
5
- "version": "1.0.0-rc.21",
5
+ "version": "1.0.0-rc.22",
6
6
  "description": "The V1 contract for human account/project administration, project-scoped\nsubscription links, and asynchronous text messages. A Clerk session selects\none account for administration. A project credential selects one account,\nproject, and `test` or `live` environment for product operations; request\nbodies cannot override either authenticated scope.\n\nA person's OAuth grant selects one account 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": {
@@ -123,6 +123,51 @@
123
123
  }
124
124
  }
125
125
  },
126
+ "/v1/account/close": {
127
+ "post": {
128
+ "operationId": "closeAccount",
129
+ "summary": "Close the current customer account",
130
+ "description": "Terminally closes the account selected by the verified Clerk\norganization session. Only an administrator may close it. OAuth grants\nand API credentials are deliberately excluded: delegated authority must\nnot be able to erase the account that granted it.\n\nThe request requires the exact confirmation `close-account`. Repeating a\ncompleted closure is safe and returns the original `closed_at`. The\nresult names provider-owned resources the administrator must still retire\noutside WhooshBang, such as revoking a customer-managed Telegram bot token\nin BotFather; no provider credential is returned.\n",
131
+ "tags": ["Account"],
132
+ "security": [{ "clerkSession": [] }],
133
+ "x-account-membership": "required",
134
+ "x-required-membership-role": "admin",
135
+ "x-repeat-semantics": {
136
+ "same_target": "idempotent",
137
+ "secret_returned": false
138
+ },
139
+ "requestBody": {
140
+ "required": true,
141
+ "content": {
142
+ "application/json": {
143
+ "schema": { "$ref": "#/components/schemas/CloseAccountRequest" }
144
+ }
145
+ }
146
+ },
147
+ "responses": {
148
+ "200": {
149
+ "description": "The account is closed, with any manual provider retirement still required.",
150
+ "headers": {
151
+ "WhooshBang-Diagnostic-Id": {
152
+ "$ref": "#/components/headers/DiagnosticId"
153
+ }
154
+ },
155
+ "content": {
156
+ "application/json": {
157
+ "schema": {
158
+ "$ref": "#/components/schemas/AccountClosureResult"
159
+ }
160
+ }
161
+ }
162
+ },
163
+ "400": { "$ref": "#/components/responses/BadRequest" },
164
+ "401": { "$ref": "#/components/responses/Unauthorized" },
165
+ "403": { "$ref": "#/components/responses/Forbidden" },
166
+ "409": { "$ref": "#/components/responses/Conflict" },
167
+ "429": { "$ref": "#/components/responses/RateLimited" }
168
+ }
169
+ }
170
+ },
126
171
  "/v1/account/credentials": {
127
172
  "get": {
128
173
  "operationId": "listAccountCredentials",
@@ -475,7 +520,8 @@
475
520
  ],
476
521
  "created_at": "2026-07-28T12:05:00Z",
477
522
  "updated_at": "2026-07-28T12:05:00Z",
478
- "diagnostic_id": "diag_project_synthetic_001"
523
+ "diagnostic_id": "diag_project_synthetic_001",
524
+ "privacy_mode": "minimal"
479
525
  }
480
526
  ],
481
527
  "page": 1,
@@ -576,7 +622,8 @@
576
622
  ],
577
623
  "created_at": "2026-07-28T12:05:00Z",
578
624
  "updated_at": "2026-07-28T12:05:00Z",
579
- "diagnostic_id": "diag_project_synthetic_001"
625
+ "diagnostic_id": "diag_project_synthetic_001",
626
+ "privacy_mode": "minimal"
580
627
  }
581
628
  }
582
629
  }
@@ -655,7 +702,8 @@
655
702
  ],
656
703
  "created_at": "2026-07-28T12:05:00Z",
657
704
  "updated_at": "2026-07-28T12:05:00Z",
658
- "diagnostic_id": "diag_project_synthetic_001"
705
+ "diagnostic_id": "diag_project_synthetic_001",
706
+ "privacy_mode": "minimal"
659
707
  }
660
708
  }
661
709
  }
@@ -667,6 +715,51 @@
667
715
  "404": { "$ref": "#/components/responses/NotFound" },
668
716
  "429": { "$ref": "#/components/responses/RateLimited" }
669
717
  }
718
+ },
719
+ "patch": {
720
+ "operationId": "updateProject",
721
+ "summary": "Set a project's privacy policy",
722
+ "description": "Changes profile collection for both project environments. minimal is the\ndefault for new and existing projects. standard permits messenger profiles;\nminimal keeps recipient language only; private keeps delivery routing and\nthe customer-supplied subscriber identifier, with no profile data.\nMoving standard to minimal erases existing identifying profile fields.\nMoving to private also erases recipient language. Increasing collection\ndoes not restore erased data. The operation is naturally idempotent.\nAn absent project and one outside the account return the same 404.\n",
723
+ "tags": ["Projects"],
724
+ "security": [
725
+ { "clerkSession": [] },
726
+ { "bearerGrant": [] },
727
+ { "bearerCredential": [] },
728
+ { "bearerAccountCredential": [] }
729
+ ],
730
+ "x-required-scopes": ["projects:write"],
731
+ "x-account-membership": "required",
732
+ "requestBody": {
733
+ "required": true,
734
+ "content": {
735
+ "application/json": {
736
+ "schema": { "$ref": "#/components/schemas/UpdateProjectRequest" },
737
+ "examples": {
738
+ "updateProject": { "value": { "privacy_mode": "private" } }
739
+ }
740
+ }
741
+ }
742
+ },
743
+ "responses": {
744
+ "200": {
745
+ "description": "The project after changing its privacy policy and clearing disallowed profile fields.",
746
+ "headers": {
747
+ "WhooshBang-Diagnostic-Id": {
748
+ "$ref": "#/components/headers/DiagnosticId"
749
+ }
750
+ },
751
+ "content": {
752
+ "application/json": {
753
+ "schema": { "$ref": "#/components/schemas/Project" }
754
+ }
755
+ }
756
+ },
757
+ "400": { "$ref": "#/components/responses/BadRequest" },
758
+ "401": { "$ref": "#/components/responses/Unauthorized" },
759
+ "403": { "$ref": "#/components/responses/Forbidden" },
760
+ "404": { "$ref": "#/components/responses/NotFound" },
761
+ "429": { "$ref": "#/components/responses/RateLimited" }
762
+ }
670
763
  }
671
764
  },
672
765
  "/v1/projects/{project_id}/recipient-copy-overrides": {
@@ -1469,7 +1562,7 @@
1469
1562
  "post": {
1470
1563
  "operationId": "createMessage",
1471
1564
  "summary": "Create an asynchronous message",
1472
- "description": "Durably accepts one logical text message for one subscriber and one\nresolved channel binding. `202` proves API acceptance only; it does not\nclaim provider acceptance or end-device delivery.\n",
1565
+ "description": "Durably accepts one logical text message for one subscriber and one\nresolved channel binding. `202` proves API acceptance only; it does not\nclaim provider acceptance or end-device delivery.\nThe reserved `test:` subscriber prefix and `delivery_target: simulator`\nare test-environment-only. Live sends are refused before acceptance or\nidempotent replay with `400 request_invalid`; reserved subscriber IDs\ncarry a field error at `/to/subscriber_id`.\n",
1473
1566
  "tags": ["Messages"],
1474
1567
  "security": [{ "bearerCredential": [] }, { "machineCredential": [] }],
1475
1568
  "x-required-scopes": ["messages:write"],
@@ -2010,7 +2103,7 @@
2010
2103
  "post": {
2011
2104
  "operationId": "createMachineClient",
2012
2105
  "summary": "Create a destination-bound machine client",
2013
- "description": "Creates one machine client in the project/environment selected by the\nproject credential. The notifier, subscriber, and active binding become\nimmutable authorization bounds. The response never contains a readable\nsecret or digest.\n",
2106
+ "description": "Creates one machine client in the project/environment selected by the\nproject credential. The notifier, subscriber, and active binding become\nimmutable authorization bounds. The response never contains a readable\nsecret or digest.\nLive environments reject the reserved `test:` subscriber prefix with\n`400 request_invalid` and a field error at `/subscriber_id` before creation.\n",
2014
2107
  "tags": ["Machine clients"],
2015
2108
  "security": [{ "bearerCredential": [] }],
2016
2109
  "x-required-scopes": ["machine-clients:write"],
@@ -6692,6 +6785,97 @@
6692
6785
  }
6693
6786
  }
6694
6787
  },
6788
+ "/v1/projects/{project_id}/subscribers/{subscriber_id}": {
6789
+ "parameters": [
6790
+ { "$ref": "#/components/parameters/ProjectId" },
6791
+ {
6792
+ "name": "subscriber_id",
6793
+ "in": "path",
6794
+ "required": true,
6795
+ "schema": { "$ref": "#/components/schemas/OpaqueIdentifier" }
6796
+ }
6797
+ ],
6798
+ "delete": {
6799
+ "operationId": "eraseSubscriber",
6800
+ "summary": "Erase one subscriber across the project",
6801
+ "description": "Erases the person represented by this customer-supplied subscriber id\nacross both project environments. Personal content, answers, identities,\nand identifiers are removed while non-identifying delivery and usage\nshells remain. Pending work and old capabilities cannot restore or send\ndata for the erased person.\n\nRepeating the operation is safe, including when the subscriber is already\nabsent. Project-environment credentials cannot call this project-wide\noperation. A provider action that has already begun returns\n`privacy_operation_in_progress` rather than claiming erasure won the race;\nretry after that operation finishes.\n",
6802
+ "tags": ["Subscribers"],
6803
+ "security": [
6804
+ { "clerkSession": [] },
6805
+ { "bearerGrant": [] },
6806
+ { "bearerAccountCredential": [] }
6807
+ ],
6808
+ "x-required-scopes": [
6809
+ "subscriptions:write",
6810
+ "messages:write",
6811
+ "machine-clients:write"
6812
+ ],
6813
+ "x-account-membership": "required",
6814
+ "x-repeat-semantics": {
6815
+ "same_target": "idempotent",
6816
+ "secret_returned": false
6817
+ },
6818
+ "responses": {
6819
+ "204": {
6820
+ "description": "The subscriber's personal data is erased or was already absent."
6821
+ },
6822
+ "401": { "$ref": "#/components/responses/Unauthorized" },
6823
+ "403": { "$ref": "#/components/responses/Forbidden" },
6824
+ "404": { "$ref": "#/components/responses/NotFound" },
6825
+ "409": { "$ref": "#/components/responses/Conflict" },
6826
+ "429": { "$ref": "#/components/responses/RateLimited" }
6827
+ }
6828
+ }
6829
+ },
6830
+ "/v1/projects/{project_id}/subscribers/{subscriber_id}/data-export": {
6831
+ "parameters": [
6832
+ { "$ref": "#/components/parameters/ProjectId" },
6833
+ {
6834
+ "name": "subscriber_id",
6835
+ "in": "path",
6836
+ "required": true,
6837
+ "schema": { "$ref": "#/components/schemas/OpaqueIdentifier" }
6838
+ }
6839
+ ],
6840
+ "get": {
6841
+ "operationId": "getSubscriberDataExport",
6842
+ "summary": "Export all customer-controlled data held for one subscriber",
6843
+ "description": "Returns one complete, machine-readable artifact across every environment\nin the project. `provided_by_subscriber` is the Article 20 portable subset;\nthe three provenance sections together provide the Article 15 access copy.\nWhooshBang-controller audit and service log data is identified as excluded\nand requires a separate recipient request. Project-environment credentials\ncannot call this project-wide operation.\n",
6844
+ "tags": ["Subscribers"],
6845
+ "security": [
6846
+ { "clerkSession": [] },
6847
+ { "bearerGrant": [] },
6848
+ { "bearerAccountCredential": [] }
6849
+ ],
6850
+ "x-required-scopes": [
6851
+ "subscriptions:read",
6852
+ "messages:read",
6853
+ "machine-clients:read"
6854
+ ],
6855
+ "x-account-membership": "required",
6856
+ "responses": {
6857
+ "200": {
6858
+ "description": "Complete project-wide customer-controller subscriber data export.",
6859
+ "headers": {
6860
+ "Content-Disposition": {
6861
+ "schema": { "type": "string" },
6862
+ "description": "Fixed safe attachment filename."
6863
+ }
6864
+ },
6865
+ "content": {
6866
+ "application/json": {
6867
+ "schema": {
6868
+ "$ref": "#/components/schemas/SubscriberDataExport"
6869
+ }
6870
+ }
6871
+ }
6872
+ },
6873
+ "401": { "$ref": "#/components/responses/Unauthorized" },
6874
+ "403": { "$ref": "#/components/responses/Forbidden" },
6875
+ "404": { "$ref": "#/components/responses/NotFound" }
6876
+ }
6877
+ }
6878
+ },
6695
6879
  "/v1/projects/{project_id}/environments/{environment_id}/recipient-groups": {
6696
6880
  "parameters": [
6697
6881
  { "$ref": "#/components/parameters/ProjectId" },
@@ -8328,6 +8512,20 @@
8328
8512
  },
8329
8513
  "additionalProperties": false
8330
8514
  },
8515
+ "UpdateProjectRequest": {
8516
+ "type": "object",
8517
+ "description": "Sets the project privacy policy. Moving from standard to minimal erases stored identifying profile data; moving to private also erases recipient language. Increasing collection does not restore erased data.",
8518
+ "required": ["privacy_mode"],
8519
+ "properties": {
8520
+ "privacy_mode": { "$ref": "#/components/schemas/PrivacyMode" }
8521
+ },
8522
+ "additionalProperties": false
8523
+ },
8524
+ "PrivacyMode": {
8525
+ "type": "string",
8526
+ "enum": ["minimal", "standard", "private"],
8527
+ "description": "Project profile collection policy. minimal (the default for new and existing projects) keeps recipient language only; standard permits messenger profile data; private retains delivery routing and the customer-supplied subscriber identifier, with no profile data. Lowering collection erases existing fields the new mode disallows."
8528
+ },
8331
8529
  "CreateProjectRequest": {
8332
8530
  "type": "object",
8333
8531
  "description": "Creates one project inside the account selected by the authenticated human session.",
@@ -8344,6 +8542,10 @@
8344
8542
  "$ref": "#/components/schemas/RecipientLanguage",
8345
8543
  "default": "en",
8346
8544
  "description": "The application fallback locale for recipient-owned surfaces when no session, subscriber, or supported provider locale is available."
8545
+ },
8546
+ "privacy_mode": {
8547
+ "$ref": "#/components/schemas/PrivacyMode",
8548
+ "default": "minimal"
8347
8549
  }
8348
8550
  },
8349
8551
  "additionalProperties": false
@@ -8395,7 +8597,8 @@
8395
8597
  "environments",
8396
8598
  "created_at",
8397
8599
  "updated_at",
8398
- "diagnostic_id"
8600
+ "diagnostic_id",
8601
+ "privacy_mode"
8399
8602
  ],
8400
8603
  "properties": {
8401
8604
  "id": { "$ref": "#/components/schemas/OpaqueIdentifier" },
@@ -8420,7 +8623,8 @@
8420
8623
  },
8421
8624
  "created_at": { "$ref": "#/components/schemas/Timestamp" },
8422
8625
  "updated_at": { "$ref": "#/components/schemas/Timestamp" },
8423
- "diagnostic_id": { "$ref": "#/components/schemas/DiagnosticId" }
8626
+ "diagnostic_id": { "$ref": "#/components/schemas/DiagnosticId" },
8627
+ "privacy_mode": { "$ref": "#/components/schemas/PrivacyMode" }
8424
8628
  },
8425
8629
  "additionalProperties": false
8426
8630
  },
@@ -9284,7 +9488,7 @@
9284
9488
  },
9285
9489
  "delivery_target": {
9286
9490
  "$ref": "#/components/schemas/MessageDeliveryTarget",
9287
- "description": "Optional routing override. Omit for notifier-default connection delivery, except reserved simulator destinations retained for compatibility."
9491
+ "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 notifier-default connection delivery or the reserved test-environment simulator default."
9288
9492
  },
9289
9493
  "connection_id": {
9290
9494
  "allOf": [{ "$ref": "#/components/schemas/OpaqueIdentifier" }],
@@ -9824,6 +10028,18 @@
9824
10028
  "retryable": { "const": false }
9825
10029
  }
9826
10030
  },
10031
+ {
10032
+ "type": "object",
10033
+ "properties": {
10034
+ "type": {
10035
+ "const": "https://whooshbang.flowxo.com/problems/privacy_operation_in_progress"
10036
+ },
10037
+ "title": { "const": "Privacy operation in progress" },
10038
+ "status": { "const": 409 },
10039
+ "code": { "const": "privacy_operation_in_progress" },
10040
+ "retryable": { "const": true }
10041
+ }
10042
+ },
9827
10043
  {
9828
10044
  "type": "object",
9829
10045
  "properties": {
@@ -10962,6 +11178,92 @@
10962
11178
  },
10963
11179
  "additionalProperties": false
10964
11180
  },
11181
+ "SubscriberDataExport": {
11182
+ "type": "object",
11183
+ "description": "A complete customer-controller access artifact for one subscriber across every environment in one project. provided_by_subscriber is the Article 20 portable subset; all three record groups together are the Article 15 access copy. WhooshBang-controller records are named but never mixed into the customer export.",
11184
+ "required": [
11185
+ "format",
11186
+ "generated_at",
11187
+ "controller_scope",
11188
+ "project_id",
11189
+ "environment_ids",
11190
+ "subscriber_id",
11191
+ "provided_by_subscriber",
11192
+ "provided_by_customer",
11193
+ "derived_by_service",
11194
+ "excluded_controller_data"
11195
+ ],
11196
+ "properties": {
11197
+ "format": {
11198
+ "type": "string",
11199
+ "const": "whooshbang.subscriber-data-export.v1"
11200
+ },
11201
+ "generated_at": { "$ref": "#/components/schemas/Timestamp" },
11202
+ "controller_scope": { "type": "string", "const": "customer" },
11203
+ "project_id": { "$ref": "#/components/schemas/OpaqueIdentifier" },
11204
+ "environment_ids": {
11205
+ "type": "array",
11206
+ "minItems": 1,
11207
+ "uniqueItems": true,
11208
+ "items": { "$ref": "#/components/schemas/OpaqueIdentifier" }
11209
+ },
11210
+ "subscriber_id": { "$ref": "#/components/schemas/OpaqueIdentifier" },
11211
+ "provided_by_subscriber": {
11212
+ "type": "array",
11213
+ "items": {
11214
+ "$ref": "#/components/schemas/SubscriberDataExportRecord"
11215
+ }
11216
+ },
11217
+ "provided_by_customer": {
11218
+ "type": "array",
11219
+ "items": {
11220
+ "$ref": "#/components/schemas/SubscriberDataExportRecord"
11221
+ }
11222
+ },
11223
+ "derived_by_service": {
11224
+ "type": "array",
11225
+ "items": {
11226
+ "$ref": "#/components/schemas/SubscriberDataExportRecord"
11227
+ }
11228
+ },
11229
+ "excluded_controller_data": {
11230
+ "type": "array",
11231
+ "minItems": 2,
11232
+ "maxItems": 2,
11233
+ "uniqueItems": true,
11234
+ "items": {
11235
+ "$ref": "#/components/schemas/SubscriberDataExportExcludedControllerData"
11236
+ }
11237
+ }
11238
+ },
11239
+ "additionalProperties": false
11240
+ },
11241
+ "CloseAccountRequest": {
11242
+ "type": "object",
11243
+ "description": "Exact, explicit confirmation that the current account administrator intends to close the whole account.",
11244
+ "required": ["confirmation"],
11245
+ "properties": {
11246
+ "confirmation": { "type": "string", "const": "close-account" }
11247
+ },
11248
+ "additionalProperties": false
11249
+ },
11250
+ "AccountClosureResult": {
11251
+ "type": "object",
11252
+ "description": "Terminal account-closure result. Repeating closure returns the same closed_at and any provider-owned resources that still require manual retirement.",
11253
+ "required": ["status", "closed_at", "provider_actions_required"],
11254
+ "properties": {
11255
+ "status": { "type": "string", "const": "closed" },
11256
+ "closed_at": { "$ref": "#/components/schemas/Timestamp" },
11257
+ "provider_actions_required": {
11258
+ "type": "array",
11259
+ "uniqueItems": true,
11260
+ "items": {
11261
+ "$ref": "#/components/schemas/AccountClosureProviderAction"
11262
+ }
11263
+ }
11264
+ },
11265
+ "additionalProperties": false
11266
+ },
10965
11267
  "CreateRecipientGroupRequest": {
10966
11268
  "type": "object",
10967
11269
  "description": "Creates one static, developer-managed recipient group.",
@@ -11219,6 +11521,7 @@
11219
11521
  "environment_mismatch",
11220
11522
  "idempotency_key_required",
11221
11523
  "idempotency_conflict",
11524
+ "privacy_operation_in_progress",
11222
11525
  "project_slug_conflict",
11223
11526
  "request_invalid",
11224
11527
  "replay_unavailable",
@@ -11355,6 +11658,20 @@
11355
11658
  }
11356
11659
  ]
11357
11660
  },
11661
+ "AccountClosureProviderAction": {
11662
+ "type": "object",
11663
+ "description": "One provider-owned resource the customer must retire outside WhooshBang after account closure. It contains safe identifiers only, never provider credentials.",
11664
+ "required": ["provider", "action", "connection_id"],
11665
+ "properties": {
11666
+ "provider": { "type": "string", "enum": ["telegram", "slack"] },
11667
+ "action": {
11668
+ "type": "string",
11669
+ "enum": ["revoke_bot_token", "delete_provider_application"]
11670
+ },
11671
+ "connection_id": { "$ref": "#/components/schemas/OpaqueIdentifier" }
11672
+ },
11673
+ "additionalProperties": false
11674
+ },
11358
11675
  "AccountCredentialPrefix": {
11359
11676
  "type": "string",
11360
11677
  "pattern": "^wb_ac1\\.acred_[A-Za-z0-9_-]{8}$",
@@ -12783,7 +13100,7 @@
12783
13100
  "provider-capabilities-v1.schema": {
12784
13101
  "$schema": "https://json-schema.org/draft/2020-12/schema",
12785
13102
  "$id": "https://whooshbang.flowxo.com/schemas/provider-capabilities-v1.schema.json",
12786
- "x-contract-version": "1.0.0-rc.21",
13103
+ "x-contract-version": "1.0.0-rc.22",
12787
13104
  "title": "ProviderCapabilitiesV1",
12788
13105
  "description": "Provider-neutral, renderer-facing delivery and interaction capabilities with explicit degradation.",
12789
13106
  "type": "object",
@@ -12986,6 +13303,38 @@
12986
13303
  }
12987
13304
  },
12988
13305
  "additionalProperties": false
13306
+ },
13307
+ "SubscriberDataExportRecord": {
13308
+ "type": "object",
13309
+ "description": "One semantic record held about the subscriber. The source names the durable store or recovered semantic value; data contains plaintext business fields and excludes custody metadata and secrets.",
13310
+ "required": ["source", "data"],
13311
+ "properties": {
13312
+ "source": {
13313
+ "type": "string",
13314
+ "minLength": 1,
13315
+ "maxLength": 96,
13316
+ "pattern": "^[a-z][a-z0-9_.-]*$"
13317
+ },
13318
+ "data": { "type": "object", "additionalProperties": true }
13319
+ },
13320
+ "additionalProperties": false
13321
+ },
13322
+ "SubscriberDataExportExcludedControllerData": {
13323
+ "type": "object",
13324
+ "description": "A category deliberately outside the customer-controller artifact because WhooshBang is controller for it.",
13325
+ "required": ["category", "controller", "access"],
13326
+ "properties": {
13327
+ "category": {
13328
+ "type": "string",
13329
+ "enum": ["consent_lifecycle_audit", "service_logs"]
13330
+ },
13331
+ "controller": { "type": "string", "const": "whooshbang" },
13332
+ "access": {
13333
+ "type": "string",
13334
+ "const": "separate_recipient_request_required"
13335
+ }
13336
+ },
13337
+ "additionalProperties": false
12989
13338
  }
12990
13339
  },
12991
13340
  "responses": {
@@ -13435,5 +13784,5 @@
13435
13784
  }
13436
13785
  }
13437
13786
  },
13438
- "x-contract-version": "1.0.0-rc.21"
13787
+ "x-contract-version": "1.0.0-rc.22"
13439
13788
  }