@epilot/sdk 2.20.61 → 2.20.62

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 (163) hide show
  1. package/definitions/app.json +17 -44
  2. package/definitions/customer-portal-runtime.json +1 -1
  3. package/definitions/customer-portal.json +566 -14
  4. package/definitions/integration-toolkit-runtime.json +1 -1
  5. package/definitions/integration-toolkit.json +656 -2
  6. package/dist/apis/access-token.cjs +6 -6
  7. package/dist/apis/access-token.js +1 -1
  8. package/dist/apis/address-suggestions.cjs +6 -6
  9. package/dist/apis/address-suggestions.js +1 -1
  10. package/dist/apis/address.cjs +6 -6
  11. package/dist/apis/address.js +1 -1
  12. package/dist/apis/ai-agents.cjs +6 -6
  13. package/dist/apis/ai-agents.js +1 -1
  14. package/dist/apis/app.cjs +6 -6
  15. package/dist/apis/app.d.cts +2 -2
  16. package/dist/apis/app.d.ts +2 -2
  17. package/dist/apis/app.js +1 -1
  18. package/dist/apis/audit-logs.cjs +6 -6
  19. package/dist/apis/audit-logs.js +1 -1
  20. package/dist/apis/automation.cjs +6 -6
  21. package/dist/apis/automation.js +1 -1
  22. package/dist/apis/billing.cjs +6 -6
  23. package/dist/apis/billing.js +1 -1
  24. package/dist/apis/blueprint-manifest.cjs +6 -6
  25. package/dist/apis/blueprint-manifest.js +1 -1
  26. package/dist/apis/calendar.cjs +6 -6
  27. package/dist/apis/calendar.js +1 -1
  28. package/dist/apis/chat.cjs +6 -6
  29. package/dist/apis/chat.js +1 -1
  30. package/dist/apis/configuration-hub.cjs +6 -6
  31. package/dist/apis/configuration-hub.js +1 -1
  32. package/dist/apis/consent.cjs +6 -6
  33. package/dist/apis/consent.js +1 -1
  34. package/dist/apis/customer-portal.cjs +8 -8
  35. package/dist/apis/customer-portal.d.cts +2 -2
  36. package/dist/apis/customer-portal.d.ts +2 -2
  37. package/dist/apis/customer-portal.js +2 -2
  38. package/dist/apis/dashboard.cjs +6 -6
  39. package/dist/apis/dashboard.js +1 -1
  40. package/dist/apis/data-governance.cjs +6 -6
  41. package/dist/apis/data-governance.js +1 -1
  42. package/dist/apis/deduplication.cjs +6 -6
  43. package/dist/apis/deduplication.js +1 -1
  44. package/dist/apis/design.cjs +6 -6
  45. package/dist/apis/design.js +1 -1
  46. package/dist/apis/document.cjs +6 -6
  47. package/dist/apis/document.js +1 -1
  48. package/dist/apis/email-settings.cjs +6 -6
  49. package/dist/apis/email-settings.js +1 -1
  50. package/dist/apis/email-template.cjs +6 -6
  51. package/dist/apis/email-template.js +1 -1
  52. package/dist/apis/entity-mapping.cjs +6 -6
  53. package/dist/apis/entity-mapping.js +1 -1
  54. package/dist/apis/entity.cjs +6 -6
  55. package/dist/apis/entity.js +1 -1
  56. package/dist/apis/environments.cjs +6 -6
  57. package/dist/apis/environments.js +1 -1
  58. package/dist/apis/event-catalog.cjs +6 -6
  59. package/dist/apis/event-catalog.js +1 -1
  60. package/dist/apis/external-values.cjs +6 -6
  61. package/dist/apis/external-values.js +1 -1
  62. package/dist/apis/file.cjs +6 -6
  63. package/dist/apis/file.js +1 -1
  64. package/dist/apis/iban.cjs +6 -6
  65. package/dist/apis/iban.js +1 -1
  66. package/dist/apis/identity.cjs +6 -6
  67. package/dist/apis/identity.js +1 -1
  68. package/dist/apis/integration-toolkit.cjs +61 -9
  69. package/dist/apis/integration-toolkit.d.cts +2 -2
  70. package/dist/apis/integration-toolkit.d.ts +2 -2
  71. package/dist/apis/integration-toolkit.js +55 -3
  72. package/dist/apis/journey.cjs +6 -6
  73. package/dist/apis/journey.js +1 -1
  74. package/dist/apis/kanban.cjs +6 -6
  75. package/dist/apis/kanban.js +1 -1
  76. package/dist/apis/message.cjs +6 -6
  77. package/dist/apis/message.js +1 -1
  78. package/dist/apis/metering.cjs +6 -6
  79. package/dist/apis/metering.js +1 -1
  80. package/dist/apis/notes.cjs +6 -6
  81. package/dist/apis/notes.js +1 -1
  82. package/dist/apis/notification.cjs +6 -6
  83. package/dist/apis/notification.js +1 -1
  84. package/dist/apis/organization.cjs +6 -6
  85. package/dist/apis/organization.js +1 -1
  86. package/dist/apis/partner-directory.cjs +6 -6
  87. package/dist/apis/partner-directory.js +1 -1
  88. package/dist/apis/permissions.cjs +6 -6
  89. package/dist/apis/permissions.js +1 -1
  90. package/dist/apis/phone-integration.cjs +6 -6
  91. package/dist/apis/phone-integration.js +1 -1
  92. package/dist/apis/pricing-tier.cjs +6 -6
  93. package/dist/apis/pricing-tier.js +1 -1
  94. package/dist/apis/pricing.cjs +6 -6
  95. package/dist/apis/pricing.js +1 -1
  96. package/dist/apis/purpose.cjs +6 -6
  97. package/dist/apis/purpose.js +1 -1
  98. package/dist/apis/query.cjs +6 -6
  99. package/dist/apis/query.js +1 -1
  100. package/dist/apis/sandbox.cjs +6 -6
  101. package/dist/apis/sandbox.js +1 -1
  102. package/dist/apis/sharing.cjs +6 -6
  103. package/dist/apis/sharing.js +1 -1
  104. package/dist/apis/snapshot.cjs +6 -6
  105. package/dist/apis/snapshot.js +1 -1
  106. package/dist/apis/submission.cjs +6 -6
  107. package/dist/apis/submission.js +1 -1
  108. package/dist/apis/target.cjs +6 -6
  109. package/dist/apis/target.js +1 -1
  110. package/dist/apis/targeting.cjs +6 -6
  111. package/dist/apis/targeting.js +1 -1
  112. package/dist/apis/template-variables.cjs +6 -6
  113. package/dist/apis/template-variables.js +1 -1
  114. package/dist/apis/user.cjs +6 -6
  115. package/dist/apis/user.js +1 -1
  116. package/dist/apis/validation-rules.cjs +6 -6
  117. package/dist/apis/validation-rules.js +1 -1
  118. package/dist/apis/webhooks.cjs +6 -6
  119. package/dist/apis/webhooks.js +1 -1
  120. package/dist/apis/workflow-definition.cjs +6 -6
  121. package/dist/apis/workflow-definition.js +1 -1
  122. package/dist/apis/workflow.cjs +6 -6
  123. package/dist/apis/workflow.js +1 -1
  124. package/dist/app-CKQAJ7EE.js +7 -0
  125. package/dist/app-ERJHXY64.cjs +7 -0
  126. package/dist/{app.d-DbOr4uIC.d.cts → app.d-CZELwNO3.d.cts} +51 -27
  127. package/dist/{app.d-DbOr4uIC.d.ts → app.d-CZELwNO3.d.ts} +51 -27
  128. package/dist/{chunk-6LYUL3EY.cjs → chunk-4EH2X5J6.cjs} +5 -5
  129. package/dist/chunk-I6IC54PD.js +14 -0
  130. package/dist/chunk-O2XK4VD5.js +14 -0
  131. package/dist/chunk-QDPZZUG3.cjs +14 -0
  132. package/dist/chunk-UP3ZIQHB.cjs +14 -0
  133. package/dist/{chunk-OEDN6Y5U.js → chunk-ZM6WXMH3.js} +5 -5
  134. package/dist/customer-portal-2OT5REK6.cjs +7 -0
  135. package/dist/customer-portal-AO2K6VW2.js +7 -0
  136. package/dist/{customer-portal-runtime-ZTLLE6CR.cjs → customer-portal-runtime-ATHDYPZM.cjs} +2 -2
  137. package/dist/{customer-portal-runtime-CNW7NSCT.js → customer-portal-runtime-XISRWE3I.js} +1 -1
  138. package/dist/{customer-portal.d-COI3Xe4x.d.cts → customer-portal.d-CTIzvirI.d.cts} +652 -17
  139. package/dist/{customer-portal.d-COI3Xe4x.d.ts → customer-portal.d-CTIzvirI.d.ts} +652 -17
  140. package/dist/index.cjs +12 -12
  141. package/dist/index.d.cts +3 -3
  142. package/dist/index.d.ts +3 -3
  143. package/dist/index.js +3 -3
  144. package/dist/integration-toolkit-FI32O7II.cjs +7 -0
  145. package/dist/integration-toolkit-MHULDW3E.js +7 -0
  146. package/dist/{integration-toolkit-runtime-3PM3MBEF.cjs → integration-toolkit-runtime-CPJT7YCA.cjs} +2 -2
  147. package/dist/{integration-toolkit-runtime-3LKW4ORQ.js → integration-toolkit-runtime-ZEH6X2OD.js} +1 -1
  148. package/dist/{integration-toolkit.d-oORkWs_H.d.cts → integration-toolkit.d-l5cgwHLa.d.cts} +658 -3
  149. package/dist/{integration-toolkit.d-oORkWs_H.d.ts → integration-toolkit.d-l5cgwHLa.d.ts} +658 -3
  150. package/docs/app.md +10 -39
  151. package/docs/customer-portal.md +440 -73
  152. package/docs/integration-toolkit.md +423 -7
  153. package/package.json +1 -1
  154. package/dist/app-R2RDF74T.js +0 -7
  155. package/dist/app-YIP3MOGW.cjs +0 -7
  156. package/dist/chunk-DQ346MRA.js +0 -14
  157. package/dist/chunk-FBRDBE4Y.cjs +0 -14
  158. package/dist/chunk-MBWCGRCK.js +0 -14
  159. package/dist/chunk-Y7KWK5H2.cjs +0 -14
  160. package/dist/customer-portal-TSJKBA37.js +0 -7
  161. package/dist/customer-portal-WOO2QDPR.cjs +0 -7
  162. package/dist/integration-toolkit-AB3GZDWM.cjs +0 -7
  163. package/dist/integration-toolkit-L745CJ5G.js +0 -7
@@ -4011,6 +4011,17 @@
4011
4011
  "NOT_FOUND"
4012
4012
  ],
4013
4013
  "description": "Present only when exists is false. NOT_FOUND means the given identifiers did\nnot match any contact (definitive - the client should not retry). TIMEOUT\nmeans the contact was not found within the processing window but may still be\ningesting; the client may retry (ideally with trigger_identifiers_check=false).\n"
4014
+ },
4015
+ "correlation_id": {
4016
+ "type": "string",
4017
+ "minLength": 1,
4018
+ "maxLength": 255,
4019
+ "pattern": "^[A-Za-z0-9_-]+$",
4020
+ "description": "Correlation id of the triggered ERP sync. Present only for portals waiting on\nthe Integration Toolkit (`wait_for_toolkit`). Send it back with\n`trigger_identifiers_check: false` to keep waiting on the same correlation.\n"
4021
+ },
4022
+ "message": {
4023
+ "type": "string",
4024
+ "description": "Human-readable reason the identifiers did not resolve, when the portal knows\none. Set when the ERP finished sending for this correlation without the\nentities the portal needs (e.g. \"account data arrived, no contract\"), so\nsupport can tell a silent timeout from an incomplete delivery.\n"
4014
4025
  }
4015
4026
  }
4016
4027
  }
@@ -4023,6 +4034,9 @@
4023
4034
  "404": {
4024
4035
  "$ref": "#/components/responses/NotFound"
4025
4036
  },
4037
+ "409": {
4038
+ "$ref": "#/components/responses/ContactAmbiguousMatch"
4039
+ },
4026
4040
  "429": {
4027
4041
  "$ref": "#/components/responses/TooManyRequests"
4028
4042
  },
@@ -4074,7 +4088,7 @@
4074
4088
  },
4075
4089
  "responses": {
4076
4090
  "200": {
4077
- "description": "The identification result. On a match, `contact_id` and `token` are present. When no\ncontact matched, only `reason` is present - the response is deliberately shaped the same\nway for every negative outcome so it cannot be used to enumerate contacts.\n",
4091
+ "description": "The identification result. On a match, `contact_id` and `token` are present. When no\ncontact matched, only `reason` is present - the response is deliberately shaped the same\nway for every negative outcome so it cannot be used to enumerate contacts. The one\naddition is `correlation_id` on a TIMEOUT from a portal waiting on the Integration\nToolkit, which a retry needs; what the ERP did or did not send is never part of it.\nThat includes an ERP delivery of several matching contacts: unlike\n`checkContactExistsV3`, which answers it with 409 `AMBIGUOUS_MATCH`, this endpoint\nanswers it as `NOT_FOUND`, because the 409 would confirm that the ERP knows the\nidentifiers.\n",
4078
4092
  "content": {
4079
4093
  "application/json": {
4080
4094
  "schema": {
@@ -6262,7 +6276,7 @@
6262
6276
  "post": {
6263
6277
  "operationId": "addContractByIdentifiers",
6264
6278
  "summary": "addContractByIdentifiers",
6265
- "description": "Self-assign contract(s) by pre-configured identifiers.",
6279
+ "description": "Self-assign contract(s) by pre-configured identifiers.\n\nWhen the portal is configured to wait on the Integration Toolkit\n(`extension_hooks.contractIdentification.wait_for_toolkit`) and the ERP has not finished\nsending within the request budget, the call fails with 404 and `reason: TIMEOUT`, carrying\nthe `correlation_id` of the triggered sync. Repeating the call with that `correlation_id`\nkeeps waiting on the same correlation without calling the third party again.\n",
6266
6280
  "tags": [
6267
6281
  "ECP"
6268
6282
  ],
@@ -6271,6 +6285,20 @@
6271
6285
  "PortalAuth": []
6272
6286
  }
6273
6287
  ],
6288
+ "parameters": [
6289
+ {
6290
+ "in": "query",
6291
+ "name": "correlation_id",
6292
+ "required": false,
6293
+ "schema": {
6294
+ "type": "string",
6295
+ "minLength": 1,
6296
+ "maxLength": 255,
6297
+ "pattern": "^[A-Za-z0-9_-]+$"
6298
+ },
6299
+ "description": "Correlation id of an already triggered ERP sync, as returned by a previous call that\nfailed with `reason: TIMEOUT`. Keeps waiting on the same correlation instead of calling\nthe contract identification hook again. Ignored unless the portal is configured with\n`extension_hooks.contractIdentification.wait_for_toolkit`. At most 255 letters, digits,\nhyphens and underscores: the toolkit's bound for a correlation id and the charset it\nenforces on its identifiers.\n"
6300
+ }
6301
+ ],
6274
6302
  "requestBody": {
6275
6303
  "description": "Identifiers to search by. Have to be pre-configured in Portal Configuration Permissions.",
6276
6304
  "required": true,
@@ -6332,6 +6360,9 @@
6332
6360
  "403": {
6333
6361
  "$ref": "#/components/responses/Forbidden"
6334
6362
  },
6363
+ "404": {
6364
+ "$ref": "#/components/responses/ContractAssignmentNotFound"
6365
+ },
6335
6366
  "409": {
6336
6367
  "$ref": "#/components/responses/ContractAssignmentConflict"
6337
6368
  },
@@ -10025,6 +10056,86 @@
10025
10056
  }
10026
10057
  }
10027
10058
  },
10059
+ "/v3/portal/public/user/temporary-password/complete": {
10060
+ "post": {
10061
+ "operationId": "completeTemporaryPassword",
10062
+ "summary": "completeTemporaryPassword",
10063
+ "description": "Replaces a portal user's temporary password with the password they chose.",
10064
+ "tags": [
10065
+ "Public"
10066
+ ],
10067
+ "security": [],
10068
+ "requestBody": {
10069
+ "required": true,
10070
+ "content": {
10071
+ "application/json": {
10072
+ "schema": {
10073
+ "type": "object",
10074
+ "required": [
10075
+ "org_id",
10076
+ "portal_id",
10077
+ "email",
10078
+ "temporary_password",
10079
+ "new_password"
10080
+ ],
10081
+ "properties": {
10082
+ "org_id": {
10083
+ "type": "string",
10084
+ "description": "Organization ID",
10085
+ "example": "123"
10086
+ },
10087
+ "portal_id": {
10088
+ "type": "string",
10089
+ "description": "ID of the portal the user belongs to",
10090
+ "example": "7hj28akg-97fb-4f5c-b2a1-3e4fbc1d8c7a"
10091
+ },
10092
+ "email": {
10093
+ "type": "string",
10094
+ "description": "Email address of the portal user",
10095
+ "example": "user@example.com"
10096
+ },
10097
+ "temporary_password": {
10098
+ "type": "string",
10099
+ "description": "Temporary password from the email"
10100
+ },
10101
+ "new_password": {
10102
+ "type": "string",
10103
+ "description": "New password, must match the portal's password policy"
10104
+ }
10105
+ }
10106
+ }
10107
+ }
10108
+ }
10109
+ },
10110
+ "responses": {
10111
+ "200": {
10112
+ "description": "The new password was set.",
10113
+ "content": {
10114
+ "application/json": {
10115
+ "schema": {
10116
+ "type": "object",
10117
+ "properties": {
10118
+ "message": {
10119
+ "type": "string",
10120
+ "example": "Password set successfully."
10121
+ }
10122
+ }
10123
+ }
10124
+ }
10125
+ }
10126
+ },
10127
+ "400": {
10128
+ "$ref": "#/components/responses/InvalidRequest"
10129
+ },
10130
+ "429": {
10131
+ "$ref": "#/components/responses/TooManyRequests"
10132
+ },
10133
+ "500": {
10134
+ "$ref": "#/components/responses/InternalServerError"
10135
+ }
10136
+ }
10137
+ }
10138
+ },
10028
10139
  "/v2/portal/campaign/{campaign_id}/entity:status": {
10029
10140
  "put": {
10030
10141
  "operationId": "updateCampaignPortalBlockStatus",
@@ -10997,6 +11108,80 @@
10997
11108
  "$ref": "#/components/responses/InternalServerError"
10998
11109
  }
10999
11110
  }
11111
+ },
11112
+ "patch": {
11113
+ "operationId": "updatePortalRevision",
11114
+ "summary": "updatePortalRevision",
11115
+ "description": "Renames a revision without publishing it. Any revision can be renamed, published or not. Only the revision's `name` changes: its content, `published_at`, `published_by` and which revision is live stay as they are.\n\nThe server trims `name`. An empty name after trimming removes the revision's name, and clients fall back to a label derived from `published_at` / `created_at`. A later publish without a `name` keeps the renamed name.\n",
11116
+ "tags": [
11117
+ "ECP Admin"
11118
+ ],
11119
+ "parameters": [
11120
+ {
11121
+ "in": "path",
11122
+ "name": "portal_id",
11123
+ "required": true,
11124
+ "schema": {
11125
+ "type": "string",
11126
+ "format": "uuid",
11127
+ "example": "5da0a718-c822-403d-9f5d-20d4584e0528"
11128
+ },
11129
+ "description": "Portal ID (readonly UUID generated on portal creation)"
11130
+ },
11131
+ {
11132
+ "in": "path",
11133
+ "name": "revision_id",
11134
+ "required": true,
11135
+ "schema": {
11136
+ "type": "string",
11137
+ "example": "2026-08-25T14:03:11.482Z-a7f3c1d9"
11138
+ },
11139
+ "description": "Revision ID. Contains `:` characters, so percent-encode it."
11140
+ }
11141
+ ],
11142
+ "requestBody": {
11143
+ "description": "The new revision name",
11144
+ "required": true,
11145
+ "content": {
11146
+ "application/json": {
11147
+ "schema": {
11148
+ "$ref": "#/components/schemas/UpdatePortalRevisionRequest"
11149
+ }
11150
+ }
11151
+ }
11152
+ },
11153
+ "security": [
11154
+ {
11155
+ "EpilotAuth": []
11156
+ }
11157
+ ],
11158
+ "responses": {
11159
+ "200": {
11160
+ "description": "Revision renamed successfully.",
11161
+ "content": {
11162
+ "application/json": {
11163
+ "schema": {
11164
+ "$ref": "#/components/schemas/PortalRevisionSummary"
11165
+ }
11166
+ }
11167
+ }
11168
+ },
11169
+ "400": {
11170
+ "$ref": "#/components/responses/InvalidRequest"
11171
+ },
11172
+ "401": {
11173
+ "$ref": "#/components/responses/Unauthorized"
11174
+ },
11175
+ "403": {
11176
+ "$ref": "#/components/responses/Forbidden"
11177
+ },
11178
+ "404": {
11179
+ "$ref": "#/components/responses/NotFound"
11180
+ },
11181
+ "500": {
11182
+ "$ref": "#/components/responses/InternalServerError"
11183
+ }
11184
+ }
11000
11185
  }
11001
11186
  },
11002
11187
  "/v3/portal/config/{portal_id}/publish": {
@@ -11163,7 +11348,7 @@
11163
11348
  "post": {
11164
11349
  "operationId": "swapPortalConfig",
11165
11350
  "summary": "swapPortalConfig",
11166
- "description": "Swaps the portal configuration of two portals.",
11351
+ "description": "Swaps the portal configuration of two portals. Without `mode` both portals exchange pages and experience config live, as before. With `mode: copy` (portal versioning only) nothing live changes: the source's setup is saved as an unpublished revision on the target to review and publish. Domain and access/security settings never move.",
11167
11352
  "tags": [
11168
11353
  "ECP Admin"
11169
11354
  ],
@@ -11195,7 +11380,14 @@
11195
11380
  "items": {
11196
11381
  "$ref": "#/components/schemas/SwappableConfig"
11197
11382
  },
11198
- "description": "Optional, opt-in configuration items to additionally swap on top of the always-swapped pages and functional config. Defaults to an empty list (nothing extra swapped). Domain and access/security settings can never be swapped."
11383
+ "description": "Optional, opt-in configuration items to additionally swap on top of the always-swapped pages and functional config. Defaults to an empty list (nothing extra swapped). Domain and access/security settings can never be swapped. With `mode` the listed items are included in the draft revisions."
11384
+ },
11385
+ "mode": {
11386
+ "type": "string",
11387
+ "enum": [
11388
+ "copy"
11389
+ ],
11390
+ "description": "Requires portal versioning (flag on, V3 target portal), otherwise 400. `copy` saves an unpublished revision on the target holding the source's setup; neither portal changes live and the source is untouched. Omit for the original live swap. Cannot be combined with the `portal_references` item, which only applies to a live swap."
11199
11391
  }
11200
11392
  }
11201
11393
  }
@@ -11213,6 +11405,24 @@
11213
11405
  "message": {
11214
11406
  "type": "string",
11215
11407
  "example": "Domain and users swapped successfully."
11408
+ },
11409
+ "portal_references": {
11410
+ "$ref": "#/components/schemas/SwapPortalReferencesResult"
11411
+ },
11412
+ "revisions": {
11413
+ "type": "array",
11414
+ "description": "Only with `mode`. The draft revision created on the target.",
11415
+ "items": {
11416
+ "type": "object",
11417
+ "properties": {
11418
+ "portal_id": {
11419
+ "$ref": "#/components/schemas/PortalId"
11420
+ },
11421
+ "revision_id": {
11422
+ "type": "string"
11423
+ }
11424
+ }
11425
+ }
11216
11426
  }
11217
11427
  }
11218
11428
  }
@@ -12019,13 +12229,31 @@
12019
12229
  },
12020
12230
  {
12021
12231
  "properties": {
12232
+ "status": {
12233
+ "type": "integer",
12234
+ "description": "The HTTP status code, repeated in the body.",
12235
+ "example": 409
12236
+ },
12237
+ "error": {
12238
+ "type": "string",
12239
+ "description": "Human-readable error message. For support, not for display to end customers."
12240
+ },
12022
12241
  "reason": {
12023
12242
  "type": "string",
12024
- "description": "Reason why the contract is not assignable. If the reason is \"MULTIPLE\", the contract is not assignable because multiple contracts were found and the business logic does not allow it.",
12243
+ "description": "Reason why the contract is not assignable.\n- `DRAFT`: the contract is still a draft.\n- `MULTIPLE`: multiple contracts were found and the business logic does not allow it.\n- `SELF_ASSIGNMENT_DISABLED`: the contract already has a contact assigned and\n self-assignment is disabled.\n- `AMBIGUOUS_MATCH`: the portal waited on the Integration Toolkit and the ERP\n delivered entities it cannot tell apart (several matching the selector, or\n contracts naming different customers). Nothing was assigned, and retrying\n will not help.\n",
12025
12244
  "enum": [
12026
12245
  "DRAFT",
12027
- "MULTIPLE"
12246
+ "MULTIPLE",
12247
+ "SELF_ASSIGNMENT_DISABLED",
12248
+ "AMBIGUOUS_MATCH"
12028
12249
  ]
12250
+ },
12251
+ "correlation_id": {
12252
+ "type": "string",
12253
+ "minLength": 1,
12254
+ "maxLength": 255,
12255
+ "pattern": "^[A-Za-z0-9_-]+$",
12256
+ "description": "Correlation id of the ERP sync that was waited on. Present only with `AMBIGUOUS_MATCH`."
12029
12257
  }
12030
12258
  },
12031
12259
  "required": [
@@ -12037,6 +12265,84 @@
12037
12265
  }
12038
12266
  }
12039
12267
  },
12268
+ "ContractAssignmentNotFound": {
12269
+ "description": "No contract could be assigned. Without a `reason`, the identifiers matched nothing. With\n`reason`, the portal waited on the Integration Toolkit\n(`extension_hooks.contractIdentification.wait_for_toolkit`):\n- `TIMEOUT`: the ERP has not finished sending yet. Repeat the request with the\n `correlation_id` query parameter set to the `correlation_id` of this body to keep waiting\n on the same ERP sync without calling the third party again.\n- `INCOMPLETE`: the ERP finished sending without the data needed. Definitive; `error` names\n what was missing, for support, not for display to end customers.\n",
12270
+ "content": {
12271
+ "application/json": {
12272
+ "schema": {
12273
+ "type": "object",
12274
+ "properties": {
12275
+ "status": {
12276
+ "type": "integer",
12277
+ "description": "The HTTP status code, repeated in the body.",
12278
+ "example": 404
12279
+ },
12280
+ "error": {
12281
+ "type": "string",
12282
+ "description": "Human-readable error message. For support, not for display to end customers."
12283
+ },
12284
+ "reason": {
12285
+ "type": "string",
12286
+ "enum": [
12287
+ "TIMEOUT",
12288
+ "INCOMPLETE"
12289
+ ]
12290
+ },
12291
+ "correlation_id": {
12292
+ "type": "string",
12293
+ "minLength": 1,
12294
+ "maxLength": 255,
12295
+ "pattern": "^[A-Za-z0-9_-]+$",
12296
+ "description": "Correlation id of the ERP sync that was waited on. Present with `TIMEOUT` and `INCOMPLETE`."
12297
+ }
12298
+ },
12299
+ "required": [
12300
+ "status",
12301
+ "error"
12302
+ ]
12303
+ }
12304
+ }
12305
+ }
12306
+ },
12307
+ "ContactAmbiguousMatch": {
12308
+ "description": "The portal waited on the Integration Toolkit\n(`extension_hooks.registrationIdentifiersCheck.wait_for_toolkit`) and the ERP delivered\nseveral contacts matching the identifiers. Nothing was linked; retrying will not help.\n",
12309
+ "content": {
12310
+ "application/json": {
12311
+ "schema": {
12312
+ "type": "object",
12313
+ "properties": {
12314
+ "status": {
12315
+ "type": "integer",
12316
+ "description": "The HTTP status code, repeated in the body.",
12317
+ "example": 409
12318
+ },
12319
+ "error": {
12320
+ "type": "string",
12321
+ "description": "Human-readable error message. For support, not for display to end customers."
12322
+ },
12323
+ "reason": {
12324
+ "type": "string",
12325
+ "enum": [
12326
+ "AMBIGUOUS_MATCH"
12327
+ ]
12328
+ },
12329
+ "correlation_id": {
12330
+ "type": "string",
12331
+ "minLength": 1,
12332
+ "maxLength": 255,
12333
+ "pattern": "^[A-Za-z0-9_-]+$",
12334
+ "description": "Correlation id of the ERP sync that was waited on."
12335
+ }
12336
+ },
12337
+ "required": [
12338
+ "status",
12339
+ "error",
12340
+ "reason"
12341
+ ]
12342
+ }
12343
+ }
12344
+ }
12345
+ },
12040
12346
  "NotFound": {
12041
12347
  "description": "The specified resource was not found",
12042
12348
  "content": {
@@ -14150,6 +14456,14 @@
14150
14456
  "type": "boolean",
14151
14457
  "default": true,
14152
14458
  "description": "Whether to (re)trigger the registration identifiers check hook, which issues a request\nto the connected ERP to (re)sync the contact, in addition to waiting for the entity to\narrive. Defaults to true to preserve existing behaviour. Set to false on retry attempts\nto only poll for an already-triggered sync to land, without issuing another upstream\nrequest to the ERP.\n"
14459
+ },
14460
+ "correlation_id": {
14461
+ "type": "string",
14462
+ "minLength": 1,
14463
+ "maxLength": 255,
14464
+ "pattern": "^[A-Za-z0-9_-]+$",
14465
+ "description": "Correlation id of an already triggered ERP sync, as returned by a previous call that\nanswered `reason: TIMEOUT`. Sent together with `trigger_identifiers_check: false` on a\nretry so the portal keeps waiting on the same correlation instead of starting over.\nOnly used by portals configured with\n`extension_hooks.registrationIdentifiersCheck.wait_for_toolkit`; ignored otherwise.\nAt most 255 letters, digits, hyphens and underscores: the toolkit's bound for a\ncorrelation id and the charset it enforces on its identifiers.\n",
14466
+ "example": "0199c0d5-6f1c-7a3b-9e21-9a9ce1d1b2c3"
14153
14467
  }
14154
14468
  }
14155
14469
  },
@@ -14216,6 +14530,11 @@
14216
14530
  },
14217
14531
  "example": []
14218
14532
  },
14533
+ "has_portal_user": {
14534
+ "type": "boolean",
14535
+ "description": "Whether the identified contact already has a portal user on this portal, so the caller\ncan skip offering account creation. Present only on a match; omitted when it could not\nbe determined.\n",
14536
+ "example": false
14537
+ },
14219
14538
  "reason": {
14220
14539
  "type": "string",
14221
14540
  "enum": [
@@ -14223,6 +14542,13 @@
14223
14542
  "NOT_FOUND"
14224
14543
  ],
14225
14544
  "description": "Present only when no token was issued. NOT_FOUND means the given identifiers did not\nmatch any contact (definitive - the client should not retry). TIMEOUT means the contact\nwas not found within the processing window but may still be ingesting; the client may\nretry (ideally with trigger_identifiers_check=false).\n"
14545
+ },
14546
+ "correlation_id": {
14547
+ "type": "string",
14548
+ "minLength": 1,
14549
+ "maxLength": 255,
14550
+ "pattern": "^[A-Za-z0-9_-]+$",
14551
+ "description": "Correlation id of the triggered ERP sync. Present only with `reason: TIMEOUT`, for\nportals waiting on the Integration Toolkit (`wait_for_toolkit`). Send it back with\n`trigger_identifiers_check: false` to keep waiting on the same correlation.\n"
14226
14552
  }
14227
14553
  }
14228
14554
  },
@@ -15968,8 +16294,7 @@
15968
16294
  "type": "string",
15969
16295
  "enum": [
15970
16296
  "portal-config",
15971
- "portal-block",
15972
- "portal-widget"
16297
+ "portal-block"
15973
16298
  ]
15974
16299
  },
15975
16300
  "resource": {
@@ -17302,6 +17627,36 @@
17302
17627
  "hook_id": {
17303
17628
  "type": "string",
17304
17629
  "description": "The ID of the selected hook."
17630
+ },
17631
+ "wait_for_toolkit": {
17632
+ "type": "boolean",
17633
+ "default": false,
17634
+ "description": "Opt in to waiting on the Integration Toolkit instead of polling entity search for the\ndata the ERP pushes after the hook returns. When true, the portal hands the hook a\ncorrelation id (`{{CorrelationId}}`) and then asks the toolkit whether the entities it\nneeds have landed under that correlation. Off by default: a portal that does not set it\nkeeps polling entity search exactly as before.\n\nOnly effective for hooks whose partner pushes through the Integration Toolkit and\nechoes the correlation id. A hook that answers with an epilot contact id is fetched\ndirectly, as today, whatever this flag says.\n"
17635
+ },
17636
+ "wait_for_entities": {
17637
+ "type": "object",
17638
+ "description": "The entities the portal waits for, keyed by entity slug. Configured explicitly per\nhook: nothing is derived from the hook type or from the portal's identifier\nconfiguration, and a hook that configures no requirement for the entity the portal\nlinks does not wait at all - it keeps polling entity search exactly as before.\n\nA selector may only name an attribute that is literally a member of that entity\ntarget's configured `unique_ids` in the inbound use case, because the toolkit reports\nexactly those and nothing else. A selector on any other attribute can never match. A\ntoolkit that validates selectors rejects such a wait (400) with the slug, the key and\nthe keys it accepts; the portal logs that at error level with the hook it came from\nand polls entity search for the request, so the customer is unaffected and never told.\n\nThe slug the portal resolves its link target from is fixed by the hook, and a\nrequirement for it must be configured for the wait to happen at all:\n`registrationIdentifiersCheck` resolves the contact, every `contractIdentification`\nassignment mode resolves the contract (in the contact modes the linked contact is the\ndelivered contract's `customer`). Every other configured slug is evidence that the push\ncarried what it promised, and is never linked.\n\nIgnored unless `wait_for_toolkit` is true.\n\nWorked examples, verified against the live integration configuration. Each block is the\n`wait_for_entities` of one hook selection, and each names the slug that hook links.\n\nRatingen / Wilken add-contract hook (`contractIdentification`, `contact_to_portal_user`).\nNo value the user types is a unique id anywhere in the org - every one is a Wilken\nsurrogate `external_id` - so the contact cannot be selected by attribute at all. Wait on\nthe contract and link its `customer`; the identity-keyed contact is evidence that the\nbusiness partner landed, and is never linked.\n\n```yaml\ncontract: {}\ncontact:\n key: external_id # the PROFILE contact's unique id is external_id\n from_caller_contact: external_id\n```\n\nWEMAG registration hook (`registrationIdentifiersCheck`). The contact's unique ids are\n`customer_pin` and `reenumber`; `meter.external_id` and `meter.meter_number` are both\nthe `ZNR` the user types.\n\n```yaml\ncontact:\n key: reenumber\n from_identifier: contact.complete_customer_number\n split_on: \"-\" # \"0002-<customer_pin>-<reenumber>\"\n part: 2\nmeter:\n key: external_id\n from_identifier: meter.meter_number\n```\n\nWEMAG add-contract hook (`contractIdentification`, `contact_to_portal_user`). The\ncontract's unique ids are `billing_account_number` (the `reenumber`, the same third\npart of `complete_customer_number`) and `customer_number` (the PIN). Wait on the\ncontract of the typed Rechnungseinheit and link its `customer`.\n\n```yaml\ncontract:\n key: billing_account_number\n from_identifier: contact.complete_customer_number\n split_on: \"-\" # \"0002-<customer_pin>-<reenumber>\"\n part: 2\nmeter:\n key: external_id\n from_identifier: meter.meter_number\n```\n\nNever `complete_customer_number` or `customer_number` on a WEMAG contact - neither is a\nunique id there - and never `customer_pin` alone on a contact or `customer_number` alone\non a contract, both of which are the PIN and ambiguous, because one person has one\ncontact and one contract per Rechnungseinheit. Never a key-less `contract` either: WEMAG's\n`EKM Anlagedaten` writes contracts of its own, keyed on `contract_number`.\n",
17639
+ "additionalProperties": {
17640
+ "$ref": "#/components/schemas/WaitForEntityRule"
17641
+ },
17642
+ "example": {
17643
+ "contract": {},
17644
+ "contact": {
17645
+ "key": "external_id",
17646
+ "from_caller_contact": "external_id"
17647
+ }
17648
+ }
17649
+ },
17650
+ "wait_for_use_cases": {
17651
+ "type": "array",
17652
+ "description": "Inbound use case slugs the portal additionally waits for. A requirement is met once at\nleast one event of that use case slug has finished processing, whether or not it\nproduced an entity, so it covers pushes whose entity set varies and pushes whose\noutcome is a file or a relation rather than an entity.\n\nEntity requirements stay primary - the portal links by entity id, so it always waits\nfor the entity it links. Use case slugs are an additional bar: when both are\nconfigured, both must be met. Empty by default. Ignored unless `wait_for_toolkit` is\ntrue.\n",
17653
+ "items": {
17654
+ "type": "string"
17655
+ },
17656
+ "default": [],
17657
+ "example": [
17658
+ "wilken_contract_changed"
17659
+ ]
17305
17660
  }
17306
17661
  },
17307
17662
  "required": [
@@ -17310,6 +17665,39 @@
17310
17665
  "hook_id"
17311
17666
  ]
17312
17667
  },
17668
+ "WaitForEntityRule": {
17669
+ "type": "object",
17670
+ "description": "One requirement of a hook's correlation wait, for the entity slug it is configured under.\n\nWithout `key` the requirement is satisfied by any entity of that slug. That is safe for\nevidence, and for a linked slug only where the inbound use case writes exactly one entity\nof it per push - Wilken's `BusinessPartnerChanged` always writes two contacts, and WEMAG's\n`DocumentChange` / `D3Metadata` write contacts under the same unique-id keys a registration\npush uses - so a second match answers 409 rather than linking a guess.\n\nWith `key`, the value comes from exactly one declared source, `from_identifier` or\n`from_caller_contact`. A rule whose source has no value produces no wait at all, so the\nhook keeps polling rather than waiting on a requirement that cannot be met.\n",
17671
+ "properties": {
17672
+ "key": {
17673
+ "type": "string",
17674
+ "description": "Unique-id attribute the selector matches on. Must be a member of that entity target's\nconfigured `unique_ids` in the inbound use case; the toolkit reports nothing else.\n",
17675
+ "example": "reenumber"
17676
+ },
17677
+ "from_identifier": {
17678
+ "type": "string",
17679
+ "description": "Identifier the user submitted to take the value from, as `<schema>.<name>` - the same\nschema and name the portal's `registration_identifiers` / `contract_identifiers` use.\nMutually exclusive with `from_caller_contact`.\n",
17680
+ "example": "contact.complete_customer_number"
17681
+ },
17682
+ "from_caller_contact": {
17683
+ "type": "string",
17684
+ "description": "Attribute of the calling portal user's own contact to take the value from. Only\navailable to hooks called by a signed-in user. Mutually exclusive with\n`from_identifier`.\n",
17685
+ "example": "external_id"
17686
+ },
17687
+ "split_on": {
17688
+ "type": "string",
17689
+ "description": "Separator the source value is split on before `part` is taken, for identifiers that\ncarry a unique id inside a larger value the user types. WEMAG's\n`complete_customer_number` is `\"0002-<customer_pin>-<reenumber>\"`, so splitting on `-`\nand taking part 2 yields the contact's `reenumber` unique id.\n",
17690
+ "example": "-"
17691
+ },
17692
+ "part": {
17693
+ "type": "integer",
17694
+ "minimum": 0,
17695
+ "default": 0,
17696
+ "description": "Zero-based index of the part to use after splitting on `split_on`.",
17697
+ "example": 2
17698
+ }
17699
+ }
17700
+ },
17313
17701
  "PublicExtensionCapabilities": {
17314
17702
  "type": "object",
17315
17703
  "properties": {
@@ -18048,6 +18436,10 @@
18048
18436
  "type": "string",
18049
18437
  "deprecated": true,
18050
18438
  "description": "Deprecated. Use `resolved.result` instead. Contact ID usually retrieved from the response body, e.g. `{{CallResponse.data.contact_id}}`. If no result is passed and the request suceeds, we attempt to resolve the Contact ID automatically. Supports variable interpolation."
18439
+ },
18440
+ "result_correlation_id": {
18441
+ "type": "string",
18442
+ "description": "Correlation id to wait for inbound ERP events under, resolved from the third-party\nresponse, e.g. `{{CallResponse.data.acknowledgeId}}`. Only read when the portal is\nconfigured to wait on the Integration Toolkit\n(`extension_hooks.<hook>.wait_for_toolkit`).\n\nThere is no default: unless a hook declares this, the portal waits on the id it\nminted and handed the hook as `{{CorrelationId}}`, whatever the response carries. A\npartner that pushes under that id leaves this unset; only a partner that pushes\nunder an id of its own declares where the response carries it. A declared id that\nis absent from the response falls back to the minted one; one that is not a valid\ncorrelation id (at most 255 letters, digits, `-` and `_`) is not waited on, and\nthe portal polls entity search instead.\n"
18051
18443
  }
18052
18444
  },
18053
18445
  "required": [
@@ -18062,6 +18454,10 @@
18062
18454
  "type": "string",
18063
18455
  "description": "Contact ID usually retrieved from the response body, e.g. `{{CallResponse.data.contact_id}}`. If no result is passed and the request suceeds, we attempt to resolve the Contact ID automatically. Supports variable interpolation. Supersedes the deprecated `call.result`."
18064
18456
  },
18457
+ "result_correlation_id": {
18458
+ "type": "string",
18459
+ "description": "Correlation id to wait for inbound ERP events under, resolved from the third-party\nresponse, e.g. `{{CallResponse.data.acknowledgeId}}`. Supersedes\n`call.result_correlation_id`. No default; see `call.result_correlation_id`.\n"
18460
+ },
18065
18461
  "error_message_path": {
18066
18462
  "type": "string",
18067
18463
  "description": "Optional path to a human-readable error message in the third-party response body, used when the call fails (non-2xx status).\nIf specified and the path resolves to a string, that message is forwarded to the end user instead of a generic error.\n",
@@ -18133,6 +18529,10 @@
18133
18529
  "type": "string",
18134
18530
  "deprecated": true,
18135
18531
  "description": "Deprecated. Use `resolved.result` instead. Contact ID usually retrieved from the response body, e.g. `{{CallResponse.data.contact_id}}`. If no result is passed and the request suceeds, we attempt to resolve the Contact ID automatically. Supports variable interpolation."
18532
+ },
18533
+ "result_correlation_id": {
18534
+ "type": "string",
18535
+ "description": "Correlation id to wait for inbound ERP events under, resolved from the third-party\nresponse, e.g. `{{CallResponse.data.acknowledgeId}}`. Only read when the portal is\nconfigured to wait on the Integration Toolkit\n(`extension_hooks.<hook>.wait_for_toolkit`).\n\nThere is no default: unless a hook declares this, the portal waits on the id it\nminted and handed the hook as `{{CorrelationId}}`, whatever the response carries. A\npartner that pushes under that id leaves this unset; only a partner that pushes\nunder an id of its own declares where the response carries it. A declared id that\nis absent from the response falls back to the minted one; one that is not a valid\ncorrelation id (at most 255 letters, digits, `-` and `_`) is not waited on, and\nthe portal polls entity search instead.\n"
18136
18536
  }
18137
18537
  },
18138
18538
  "required": [
@@ -18147,6 +18547,10 @@
18147
18547
  "type": "string",
18148
18548
  "description": "Contract or Contact ID usually retrieved from the response body, e.g. `{{CallResponse.data.contact_id}}`. If no result is passed and the request suceeds, we attempt to resolve the Contact ID automatically. Supports variable interpolation. Supersedes the deprecated `call.result`."
18149
18549
  },
18550
+ "result_correlation_id": {
18551
+ "type": "string",
18552
+ "description": "Correlation id to wait for inbound ERP events under, resolved from the third-party\nresponse, e.g. `{{CallResponse.data.acknowledgeId}}`. Supersedes\n`call.result_correlation_id`. No default; see `call.result_correlation_id`.\n"
18553
+ },
18150
18554
  "error_message_path": {
18151
18555
  "type": "string",
18152
18556
  "description": "Optional path to a human-readable error message in the third-party response body, used when the call fails (non-2xx status).\nIf specified and the path resolves to a string, that message is forwarded to the end user instead of a generic error.\n",
@@ -20900,15 +21304,23 @@
20900
21304
  "properties": {
20901
21305
  "start_page": {
20902
21306
  "type": "boolean",
20903
- "description": "Start page feature flag"
21307
+ "deprecated": true,
21308
+ "description": "Retired, not read. A portal shows a start page by having a `dashboard` page."
20904
21309
  },
20905
21310
  "billing": {
20906
21311
  "type": "boolean",
20907
- "description": "Billing feature flag"
21312
+ "deprecated": true,
21313
+ "description": "Retired, not read. Billing follows the organization's `commodity_billing` setting."
21314
+ },
21315
+ "commodity_billing": {
21316
+ "type": "boolean",
21317
+ "deprecated": true,
21318
+ "description": "Retired, not read. Billing pages and blocks follow the organization's `commodity_billing` setting."
20908
21319
  },
20909
21320
  "change_due_date": {
20910
21321
  "type": "boolean",
20911
- "description": "Change due date feature flag"
21322
+ "deprecated": true,
21323
+ "description": "Retired, not read."
20912
21324
  },
20913
21325
  "new_design": {
20914
21326
  "type": "boolean",
@@ -20924,6 +21336,15 @@
20924
21336
  "default": 0,
20925
21337
  "readOnly": true,
20926
21338
  "description": "Server-managed generation used to invalidate MCP grants after the connector is disabled or re-enabled"
21339
+ },
21340
+ "portal_copilot": {
21341
+ "type": "boolean",
21342
+ "default": false,
21343
+ "description": "Enable the portal copilot chat for this portal"
21344
+ },
21345
+ "portal_copilot_agent_id": {
21346
+ "type": "string",
21347
+ "description": "ID of the Agent Builder portal agent this portal's copilot chat runs, set by Agent Builder. When unset, or when the agent no longer exists in the portal's organization, the chat runs the default portal copilot."
20927
21348
  }
20928
21349
  }
20929
21350
  },
@@ -21098,6 +21519,24 @@
21098
21519
  "type": "string",
21099
21520
  "description": "The URL to redirect to",
21100
21521
  "example": "https://example.com"
21522
+ },
21523
+ "title": {
21524
+ "type": "string",
21525
+ "description": "Portal name, served as the document title before the app boots",
21526
+ "example": "Kundenportal"
21527
+ },
21528
+ "prevent_indexing": {
21529
+ "type": "boolean",
21530
+ "description": "Whether the served document should carry a `noindex, nofollow` robots meta tag"
21531
+ },
21532
+ "organization_id": {
21533
+ "type": "string",
21534
+ "description": "Organization of the portal, used to preload its design from the served document",
21535
+ "example": "123"
21536
+ },
21537
+ "design_id": {
21538
+ "type": "string",
21539
+ "description": "Design of the portal, used to preload it from the served document"
21101
21540
  }
21102
21541
  }
21103
21542
  },
@@ -21160,6 +21599,9 @@
21160
21599
  "based_on_revision_id": {
21161
21600
  "type": "string"
21162
21601
  },
21602
+ "revision_source": {
21603
+ "$ref": "#/components/schemas/RevisionSource"
21604
+ },
21163
21605
  "pages": {
21164
21606
  "type": "array",
21165
21607
  "items": {
@@ -21193,6 +21635,40 @@
21193
21635
  }
21194
21636
  }
21195
21637
  },
21638
+ "UpdatePortalRevisionRequest": {
21639
+ "type": "object",
21640
+ "required": [
21641
+ "name"
21642
+ ],
21643
+ "properties": {
21644
+ "name": {
21645
+ "type": "string",
21646
+ "maxLength": 255,
21647
+ "description": "New label for the revision. Trimmed by the server; an empty name after trimming removes the revision's name.\n",
21648
+ "example": "FAQ page launch"
21649
+ }
21650
+ }
21651
+ },
21652
+ "RevisionSource": {
21653
+ "type": "object",
21654
+ "description": "Where a revision came from, when it was not saved in the builder. Not part of the portal config. The builder renders it in the viewer's language for an unnamed revision.\n",
21655
+ "additionalProperties": false,
21656
+ "required": [
21657
+ "type"
21658
+ ],
21659
+ "properties": {
21660
+ "type": {
21661
+ "type": "string",
21662
+ "enum": [
21663
+ "blueprint_sync"
21664
+ ]
21665
+ },
21666
+ "blueprint_title": {
21667
+ "type": "string",
21668
+ "maxLength": 200
21669
+ }
21670
+ }
21671
+ },
21196
21672
  "PortalRevisionSummary": {
21197
21673
  "type": "object",
21198
21674
  "required": [
@@ -21216,12 +21692,15 @@
21216
21692
  },
21217
21693
  "name": {
21218
21694
  "type": "string",
21219
- "description": "Set at publish time only, and only when the publish request carried one. A revision can have been published and still have no name; `published_at` is the signal that a revision was live at some point, not this field.\n",
21695
+ "description": "Set at publish time when the publish request carries one, or by renaming the revision with `updatePortalRevision`. A revision can have been published and still have no name; `published_at` is the signal that a revision was live at some point, not this field.\n",
21220
21696
  "example": "FAQ page launch"
21221
21697
  },
21222
21698
  "description": {
21223
21699
  "type": "string"
21224
21700
  },
21701
+ "source": {
21702
+ "$ref": "#/components/schemas/RevisionSource"
21703
+ },
21225
21704
  "page_count": {
21226
21705
  "type": "number"
21227
21706
  },
@@ -21376,9 +21855,82 @@
21376
21855
  },
21377
21856
  "SwappableConfig": {
21378
21857
  "type": "string",
21379
- "description": "Optional configuration item that a portal swap can additionally include. The swap always transfers the pages and the functional experience config that keep the portal working. These items are opt-in on top of that and are OFF by default. Domain and access/security settings (domain, cognito_details, auth_settings) can never be swapped and are therefore not part of this enum.",
21858
+ "description": "Optional configuration item that a portal swap can additionally include. The swap always transfers the pages and the functional experience config that keep the portal working. These items are opt-in on top of that and are OFF by default. Domain and access/security settings (domain, cognito_details, auth_settings) can never be swapped and are therefore not part of this enum.\n- `email_templates`: swap the email templates of the two portals.\n- `portal_references`: after the swap, re-point configuration in other services from the source portal to the target portal: the portal on journey login (AuthControl) blocks and in file upload portal access, and the portal of automation flow portal triggers. One-directional: references to the target portal are left unchanged, because the target keeps its domain and users. System flows are not changed. Uses the caller's permissions; the outcome is returned in `portal_references`.",
21380
21859
  "enum": [
21381
- "email_templates"
21860
+ "email_templates",
21861
+ "portal_references"
21862
+ ]
21863
+ },
21864
+ "SwapPortalReferencesResult": {
21865
+ "type": "object",
21866
+ "description": "Outcome of the `portal_references` swap option. Only present when that option was requested. The swap itself has already succeeded when this is returned, so failures here do not undo it.",
21867
+ "properties": {
21868
+ "journeys": {
21869
+ "$ref": "#/components/schemas/SwapPortalReferenceGroup"
21870
+ },
21871
+ "automation_flows": {
21872
+ "$ref": "#/components/schemas/SwapPortalReferenceGroup"
21873
+ }
21874
+ },
21875
+ "required": [
21876
+ "journeys",
21877
+ "automation_flows"
21878
+ ]
21879
+ },
21880
+ "SwapPortalReferenceGroup": {
21881
+ "type": "object",
21882
+ "properties": {
21883
+ "updated": {
21884
+ "type": "array",
21885
+ "description": "Items whose references now point at the target portal.",
21886
+ "items": {
21887
+ "$ref": "#/components/schemas/SwapPortalReferenceItem"
21888
+ }
21889
+ },
21890
+ "failed": {
21891
+ "type": "array",
21892
+ "description": "Items that reference the source portal but could not be updated.",
21893
+ "items": {
21894
+ "$ref": "#/components/schemas/SwapPortalReferenceItem"
21895
+ }
21896
+ },
21897
+ "list_error": {
21898
+ "type": "string",
21899
+ "description": "Set when the items could not be listed, so none of them were checked."
21900
+ }
21901
+ },
21902
+ "required": [
21903
+ "updated",
21904
+ "failed"
21905
+ ]
21906
+ },
21907
+ "SwapPortalReferenceItem": {
21908
+ "type": "object",
21909
+ "properties": {
21910
+ "id": {
21911
+ "type": "string",
21912
+ "description": "Journey id or automation flow id."
21913
+ },
21914
+ "name": {
21915
+ "type": "string"
21916
+ },
21917
+ "paths": {
21918
+ "type": "array",
21919
+ "description": "Where the reference sat in the item.",
21920
+ "items": {
21921
+ "type": "string"
21922
+ },
21923
+ "example": [
21924
+ "steps[0].uischema.elements[2].options.portalId"
21925
+ ]
21926
+ },
21927
+ "error": {
21928
+ "type": "string",
21929
+ "description": "Why the update failed. Only set on failed items."
21930
+ }
21931
+ },
21932
+ "required": [
21933
+ "id"
21382
21934
  ]
21383
21935
  },
21384
21936
  "PortalUserRegistrationStatus": {