@epilot/sdk 2.10.1 → 2.10.3

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 (131) hide show
  1. package/definitions/customer-portal-runtime.json +1 -1
  2. package/definitions/customer-portal.json +1180 -45
  3. package/definitions/focus-pocus-runtime.json +1 -0
  4. package/definitions/focus-pocus.json +757 -0
  5. package/dist/apis/access-token.cjs +6 -6
  6. package/dist/apis/access-token.js +1 -1
  7. package/dist/apis/address-suggestions.cjs +6 -6
  8. package/dist/apis/address-suggestions.js +1 -1
  9. package/dist/apis/address.cjs +6 -6
  10. package/dist/apis/address.js +1 -1
  11. package/dist/apis/ai-agents.cjs +6 -6
  12. package/dist/apis/ai-agents.js +1 -1
  13. package/dist/apis/app.cjs +6 -6
  14. package/dist/apis/app.js +1 -1
  15. package/dist/apis/audit-logs.cjs +6 -6
  16. package/dist/apis/audit-logs.js +1 -1
  17. package/dist/apis/automation.cjs +6 -6
  18. package/dist/apis/automation.js +1 -1
  19. package/dist/apis/billing.cjs +6 -6
  20. package/dist/apis/billing.js +1 -1
  21. package/dist/apis/blueprint-manifest.cjs +6 -6
  22. package/dist/apis/blueprint-manifest.js +1 -1
  23. package/dist/apis/calendar.cjs +6 -6
  24. package/dist/apis/calendar.js +1 -1
  25. package/dist/apis/configuration-hub.cjs +6 -6
  26. package/dist/apis/configuration-hub.js +1 -1
  27. package/dist/apis/consent.cjs +6 -6
  28. package/dist/apis/consent.js +1 -1
  29. package/dist/apis/customer-portal.cjs +8 -8
  30. package/dist/apis/customer-portal.d.cts +2 -2
  31. package/dist/apis/customer-portal.d.ts +2 -2
  32. package/dist/apis/customer-portal.js +2 -2
  33. package/dist/apis/dashboard.cjs +6 -6
  34. package/dist/apis/dashboard.js +1 -1
  35. package/dist/apis/data-governance.cjs +6 -6
  36. package/dist/apis/data-governance.js +1 -1
  37. package/dist/apis/deduplication.cjs +6 -6
  38. package/dist/apis/deduplication.js +1 -1
  39. package/dist/apis/design.cjs +6 -6
  40. package/dist/apis/design.js +1 -1
  41. package/dist/apis/document.cjs +6 -6
  42. package/dist/apis/document.js +1 -1
  43. package/dist/apis/email-settings.cjs +6 -6
  44. package/dist/apis/email-settings.js +1 -1
  45. package/dist/apis/email-template.cjs +6 -6
  46. package/dist/apis/email-template.js +1 -1
  47. package/dist/apis/entity-mapping.cjs +6 -6
  48. package/dist/apis/entity-mapping.js +1 -1
  49. package/dist/apis/entity.cjs +6 -6
  50. package/dist/apis/entity.js +1 -1
  51. package/dist/apis/environments.cjs +6 -6
  52. package/dist/apis/environments.js +1 -1
  53. package/dist/apis/event-catalog.cjs +6 -6
  54. package/dist/apis/event-catalog.js +1 -1
  55. package/dist/apis/file.cjs +6 -6
  56. package/dist/apis/file.js +1 -1
  57. package/dist/apis/iban.cjs +6 -6
  58. package/dist/apis/iban.js +1 -1
  59. package/dist/apis/integration-toolkit.cjs +6 -6
  60. package/dist/apis/integration-toolkit.js +1 -1
  61. package/dist/apis/journey.cjs +6 -6
  62. package/dist/apis/journey.js +1 -1
  63. package/dist/apis/kanban.cjs +6 -6
  64. package/dist/apis/kanban.js +1 -1
  65. package/dist/apis/message.cjs +6 -6
  66. package/dist/apis/message.js +1 -1
  67. package/dist/apis/metering.cjs +6 -6
  68. package/dist/apis/metering.js +1 -1
  69. package/dist/apis/notes.cjs +6 -6
  70. package/dist/apis/notes.js +1 -1
  71. package/dist/apis/notification.cjs +6 -6
  72. package/dist/apis/notification.js +1 -1
  73. package/dist/apis/organization.cjs +6 -6
  74. package/dist/apis/organization.js +1 -1
  75. package/dist/apis/partner-directory.cjs +6 -6
  76. package/dist/apis/partner-directory.js +1 -1
  77. package/dist/apis/permissions.cjs +6 -6
  78. package/dist/apis/permissions.js +1 -1
  79. package/dist/apis/pricing-tier.cjs +6 -6
  80. package/dist/apis/pricing-tier.js +1 -1
  81. package/dist/apis/pricing.cjs +6 -6
  82. package/dist/apis/pricing.js +1 -1
  83. package/dist/apis/purpose.cjs +6 -6
  84. package/dist/apis/purpose.js +1 -1
  85. package/dist/apis/query.cjs +6 -6
  86. package/dist/apis/query.js +1 -1
  87. package/dist/apis/sandbox.cjs +6 -6
  88. package/dist/apis/sandbox.js +1 -1
  89. package/dist/apis/sharing.cjs +6 -6
  90. package/dist/apis/sharing.js +1 -1
  91. package/dist/apis/snapshot.cjs +6 -6
  92. package/dist/apis/snapshot.js +1 -1
  93. package/dist/apis/submission.cjs +6 -6
  94. package/dist/apis/submission.js +1 -1
  95. package/dist/apis/target.cjs +6 -6
  96. package/dist/apis/target.js +1 -1
  97. package/dist/apis/targeting.cjs +6 -6
  98. package/dist/apis/targeting.js +1 -1
  99. package/dist/apis/template-variables.cjs +6 -6
  100. package/dist/apis/template-variables.js +1 -1
  101. package/dist/apis/user.cjs +6 -6
  102. package/dist/apis/user.js +1 -1
  103. package/dist/apis/validation-rules.cjs +6 -6
  104. package/dist/apis/validation-rules.js +1 -1
  105. package/dist/apis/webhooks.cjs +6 -6
  106. package/dist/apis/webhooks.js +1 -1
  107. package/dist/apis/workflow-definition.cjs +6 -6
  108. package/dist/apis/workflow-definition.js +1 -1
  109. package/dist/apis/workflow.cjs +6 -6
  110. package/dist/apis/workflow.js +1 -1
  111. package/dist/{chunk-HB6KHEKG.cjs → chunk-ESCPKTPT.cjs} +2 -2
  112. package/dist/chunk-JBPITLKN.cjs +14 -0
  113. package/dist/{chunk-H3ZV5T3V.js → chunk-K732EC6B.js} +2 -2
  114. package/dist/chunk-LSMVZMBY.js +14 -0
  115. package/dist/customer-portal-EJBJ4BNI.cjs +7 -0
  116. package/dist/customer-portal-ZVST2CTU.js +7 -0
  117. package/dist/{customer-portal-runtime-TDHV2YVY.js → customer-portal-runtime-C6ZIKX2V.js} +1 -1
  118. package/dist/{customer-portal-runtime-HA6CPWB4.cjs → customer-portal-runtime-M7O3RDJ5.cjs} +2 -2
  119. package/dist/{customer-portal.d-BRwiQehb.d.cts → customer-portal.d-JUlTCfGt.d.cts} +852 -8
  120. package/dist/{customer-portal.d-BRwiQehb.d.ts → customer-portal.d-JUlTCfGt.d.ts} +852 -8
  121. package/dist/index.cjs +10 -10
  122. package/dist/index.d.cts +1 -1
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.js +2 -2
  125. package/dist/js-yaml-DLCVPJ7G.js +0 -0
  126. package/docs/customer-portal.md +709 -35
  127. package/package.json +12 -11
  128. package/dist/chunk-5ZXGKLB6.cjs +0 -14
  129. package/dist/chunk-774ASAAH.js +0 -14
  130. package/dist/customer-portal-4DXHY42V.js +0 -7
  131. package/dist/customer-portal-5OSGSYGF.cjs +0 -7
@@ -2190,6 +2190,170 @@
2190
2190
  }
2191
2191
  }
2192
2192
  },
2193
+ "/v3/portal/email-templates:migrate-references": {
2194
+ "post": {
2195
+ "operationId": "migrateEmailTemplateReferences",
2196
+ "summary": "migrateEmailTemplateReferences",
2197
+ "description": "Walk every email-template config row in the caller's org and re-point any\nfield on `email_templates` that currently references `source_template_id`\nat `destination_template_id`. Intended to be called from the email-template\nmigration flow when a duplicated template is refined.\n\nOnly v3-shaped rows are migrated (those carrying `portal_sk_v3`). Returns\nthe portal IDs that were rewritten and any whose update failed.\n",
2198
+ "tags": [
2199
+ "ECP Admin"
2200
+ ],
2201
+ "security": [
2202
+ {
2203
+ "EpilotAuth": []
2204
+ }
2205
+ ],
2206
+ "requestBody": {
2207
+ "description": "Source and destination template ids",
2208
+ "required": true,
2209
+ "content": {
2210
+ "application/json": {
2211
+ "schema": {
2212
+ "type": "object",
2213
+ "required": [
2214
+ "source_template_id",
2215
+ "destination_template_id"
2216
+ ],
2217
+ "properties": {
2218
+ "source_template_id": {
2219
+ "type": "string",
2220
+ "description": "Template id currently referenced on portal rows"
2221
+ },
2222
+ "destination_template_id": {
2223
+ "type": "string",
2224
+ "description": "Template id to write in place of the source"
2225
+ }
2226
+ }
2227
+ }
2228
+ }
2229
+ }
2230
+ },
2231
+ "responses": {
2232
+ "200": {
2233
+ "description": "Migration completed (may have partial failures in failed_portal_ids).",
2234
+ "content": {
2235
+ "application/json": {
2236
+ "schema": {
2237
+ "type": "object",
2238
+ "required": [
2239
+ "migrated_portal_count",
2240
+ "migrated_portal_ids",
2241
+ "failed_portal_ids"
2242
+ ],
2243
+ "properties": {
2244
+ "migrated_portal_count": {
2245
+ "type": "integer",
2246
+ "example": 2
2247
+ },
2248
+ "migrated_portal_ids": {
2249
+ "type": "array",
2250
+ "items": {
2251
+ "type": "string"
2252
+ }
2253
+ },
2254
+ "failed_portal_ids": {
2255
+ "type": "array",
2256
+ "items": {
2257
+ "type": "string"
2258
+ }
2259
+ }
2260
+ }
2261
+ }
2262
+ }
2263
+ }
2264
+ },
2265
+ "401": {
2266
+ "$ref": "#/components/responses/Unauthorized"
2267
+ },
2268
+ "403": {
2269
+ "$ref": "#/components/responses/Forbidden"
2270
+ },
2271
+ "500": {
2272
+ "$ref": "#/components/responses/InternalServerError"
2273
+ }
2274
+ }
2275
+ }
2276
+ },
2277
+ "/v3/portal/email-templates:list-references": {
2278
+ "post": {
2279
+ "operationId": "listEmailTemplateReferences",
2280
+ "summary": "listEmailTemplateReferences",
2281
+ "description": "Read-only sibling of migrateEmailTemplateReferences. Lists every portal in\nthe caller's org whose `email_templates` config references `template_id`,\nwithout rewriting anything. Used by the email-template MFE to show which\nportals a template affects (in template settings and as a pre-migrate\npreview). Uses the same discovery as the migrate path.\n",
2282
+ "tags": [
2283
+ "ECP Admin"
2284
+ ],
2285
+ "security": [
2286
+ {
2287
+ "EpilotAuth": []
2288
+ }
2289
+ ],
2290
+ "requestBody": {
2291
+ "description": "Template id to look up references for",
2292
+ "required": true,
2293
+ "content": {
2294
+ "application/json": {
2295
+ "schema": {
2296
+ "type": "object",
2297
+ "required": [
2298
+ "template_id"
2299
+ ],
2300
+ "properties": {
2301
+ "template_id": {
2302
+ "type": "string",
2303
+ "description": "Email template id to find portal references for"
2304
+ }
2305
+ }
2306
+ }
2307
+ }
2308
+ }
2309
+ },
2310
+ "responses": {
2311
+ "200": {
2312
+ "description": "Portals referencing the template.",
2313
+ "content": {
2314
+ "application/json": {
2315
+ "schema": {
2316
+ "type": "object",
2317
+ "required": [
2318
+ "portals"
2319
+ ],
2320
+ "properties": {
2321
+ "portals": {
2322
+ "type": "array",
2323
+ "items": {
2324
+ "type": "object",
2325
+ "required": [
2326
+ "id"
2327
+ ],
2328
+ "properties": {
2329
+ "id": {
2330
+ "type": "string"
2331
+ },
2332
+ "name": {
2333
+ "type": "string",
2334
+ "nullable": true,
2335
+ "description": "Portal display name (or domain); falls back to id when unavailable"
2336
+ }
2337
+ }
2338
+ }
2339
+ }
2340
+ }
2341
+ }
2342
+ }
2343
+ }
2344
+ },
2345
+ "401": {
2346
+ "$ref": "#/components/responses/Unauthorized"
2347
+ },
2348
+ "403": {
2349
+ "$ref": "#/components/responses/Forbidden"
2350
+ },
2351
+ "500": {
2352
+ "$ref": "#/components/responses/InternalServerError"
2353
+ }
2354
+ }
2355
+ }
2356
+ },
2193
2357
  "/v3/portal/email-templates/{portal_id}": {
2194
2358
  "post": {
2195
2359
  "operationId": "upsertEmailTemplatesByPortalId",
@@ -3501,6 +3665,14 @@
3501
3665
  "contactId": {
3502
3666
  "$ref": "#/components/schemas/EntityId",
3503
3667
  "description": "ID of the contact if exists"
3668
+ },
3669
+ "reason": {
3670
+ "type": "string",
3671
+ "enum": [
3672
+ "TIMEOUT",
3673
+ "NOT_FOUND"
3674
+ ],
3675
+ "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"
3504
3676
  }
3505
3677
  }
3506
3678
  }
@@ -3579,6 +3751,14 @@
3579
3751
  "accountId": {
3580
3752
  "$ref": "#/components/schemas/EntityId",
3581
3753
  "description": "ID of the resolved account when the portal is configured for account-based registration"
3754
+ },
3755
+ "reason": {
3756
+ "type": "string",
3757
+ "enum": [
3758
+ "TIMEOUT",
3759
+ "NOT_FOUND"
3760
+ ],
3761
+ "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"
3582
3762
  }
3583
3763
  }
3584
3764
  }
@@ -3831,9 +4011,8 @@
3831
4011
  "properties": {
3832
4012
  "message": {
3833
4013
  "type": "string",
3834
- "enum": [
3835
- "User Succesfully Deleted"
3836
- ]
4014
+ "description": "`User Succesfully Deleted` when the user was deleted, or `Account deletion requested`\nwhen an asynchronous deleteAccount portal extension hook handed the deletion over to a third party.\n",
4015
+ "example": "User Succesfully Deleted"
3837
4016
  },
3838
4017
  "data": {
3839
4018
  "$ref": "#/components/schemas/EntityId"
@@ -3873,8 +4052,7 @@
3873
4052
  "schema": {
3874
4053
  "type": "object",
3875
4054
  "required": [
3876
- "email",
3877
- "password"
4055
+ "email"
3878
4056
  ],
3879
4057
  "properties": {
3880
4058
  "email": {
@@ -3884,7 +4062,7 @@
3884
4062
  },
3885
4063
  "password": {
3886
4064
  "type": "string",
3887
- "description": "Password of the portal user for confirmation"
4065
+ "description": "Password of the portal user for confirmation.\nRequired unless a `changeEmail` portal extension hook with `require_password_confirmation` disabled is configured for the portal.\n"
3888
4066
  }
3889
4067
  }
3890
4068
  }
@@ -3901,9 +4079,66 @@
3901
4079
  "properties": {
3902
4080
  "message": {
3903
4081
  "type": "string",
3904
- "enum": [
3905
- "You will receive a confirmation mail soon on your updated email address."
3906
- ]
4082
+ "description": "`You will receive a confirmation mail soon on your updated email address.` for the built-in flow,\nor `Your email change request has been received.` when a changeEmail portal extension hook handed\nthe change over to a third party.\n",
4083
+ "example": "You will receive a confirmation mail soon on your updated email address."
4084
+ }
4085
+ }
4086
+ }
4087
+ }
4088
+ }
4089
+ },
4090
+ "400": {
4091
+ "$ref": "#/components/responses/InvalidRequest"
4092
+ },
4093
+ "401": {
4094
+ "$ref": "#/components/responses/Unauthorized"
4095
+ },
4096
+ "500": {
4097
+ "$ref": "#/components/responses/InternalServerError"
4098
+ }
4099
+ }
4100
+ }
4101
+ },
4102
+ "/v2/portal/user/change/password": {
4103
+ "put": {
4104
+ "operationId": "changePortalUserPassword",
4105
+ "summary": "changePortalUserPassword",
4106
+ "description": "Hand over a password change to the third-party system configured via the `changePassword` portal extension hook.\nOnly available when such a hook is configured for the portal; the built-in password change flow does not use this endpoint.\n",
4107
+ "tags": [
4108
+ "ECP"
4109
+ ],
4110
+ "security": [
4111
+ {
4112
+ "PortalAuth": []
4113
+ }
4114
+ ],
4115
+ "requestBody": {
4116
+ "description": "Request payload",
4117
+ "required": false,
4118
+ "content": {
4119
+ "application/json": {
4120
+ "schema": {
4121
+ "type": "object",
4122
+ "properties": {
4123
+ "new_password": {
4124
+ "type": "string",
4125
+ "description": "New password chosen by the portal user.\nRequired when the configured `changePassword` hook has `require_new_password` enabled, ignored otherwise.\n"
4126
+ }
4127
+ }
4128
+ }
4129
+ }
4130
+ }
4131
+ },
4132
+ "responses": {
4133
+ "200": {
4134
+ "description": "The password change request was handed over to the third-party system.",
4135
+ "content": {
4136
+ "application/json": {
4137
+ "schema": {
4138
+ "type": "object",
4139
+ "properties": {
4140
+ "message": {
4141
+ "type": "string"
3907
4142
  }
3908
4143
  }
3909
4144
  }
@@ -3916,6 +4151,9 @@
3916
4151
  "401": {
3917
4152
  "$ref": "#/components/responses/Unauthorized"
3918
4153
  },
4154
+ "404": {
4155
+ "description": "No changePassword portal extension hook is configured for this portal."
4156
+ },
3919
4157
  "500": {
3920
4158
  "$ref": "#/components/responses/InternalServerError"
3921
4159
  }
@@ -7034,75 +7272,225 @@
7034
7272
  }
7035
7273
  }
7036
7274
  },
7037
- "/v2/portal/can-trigger-portal-flow": {
7275
+ "/v2/portal/entity/{slug}": {
7038
7276
  "post": {
7039
- "operationId": "canTriggerPortalFlow",
7040
- "summary": "canTriggerPortalFlow",
7041
- "description": "Returns whether the user can trigger a portal flow",
7277
+ "operationId": "createPortalUserEntity",
7278
+ "summary": "createPortalUserEntity",
7279
+ "description": "**EXPERIMENTAL do not rely on this endpoint.** It is unstable, currently limited to the `asset` schema, and may change or be removed without notice; third parties must not build on it yet.\nCreate a single entity on behalf of a portal user. The schema slug is passed in the path and must be one of the supported (experimental) schemas; field-level permissions are enforced by the caller's role grants. The request body is the entity to create (its attributes); the created entity is automatically related to the caller's contact.",
7280
+ "deprecated": true,
7042
7281
  "tags": [
7043
- "ECP Admin"
7282
+ "ECP"
7044
7283
  ],
7045
7284
  "security": [
7046
7285
  {
7047
- "EpilotAuth": []
7286
+ "PortalAuth": []
7048
7287
  }
7049
7288
  ],
7050
7289
  "parameters": [
7051
7290
  {
7052
- "in": "query",
7053
- "name": "origin",
7054
- "required": false,
7055
- "deprecated": true,
7056
- "schema": {
7057
- "$ref": "#/components/schemas/Origin"
7058
- },
7059
- "description": "Origin of the portal"
7060
- },
7061
- {
7062
- "in": "query",
7063
- "name": "portal_id",
7291
+ "in": "path",
7292
+ "name": "slug",
7293
+ "description": "Entity schema slug to create. Limited to the supported (experimental) schemas, currently `asset`.",
7064
7294
  "required": true,
7065
7295
  "schema": {
7066
7296
  "type": "string",
7067
- "description": "Portal ID",
7068
- "example": "123"
7297
+ "enum": [
7298
+ "asset"
7299
+ ],
7300
+ "example": "asset"
7069
7301
  }
7070
7302
  }
7071
7303
  ],
7072
7304
  "requestBody": {
7073
- "description": "Request of trigger portal flow",
7074
7305
  "required": true,
7075
7306
  "content": {
7076
7307
  "application/json": {
7077
7308
  "schema": {
7078
- "$ref": "#/components/schemas/TriggerPortalFlow"
7309
+ "$ref": "#/components/schemas/Entity"
7310
+ },
7311
+ "example": {
7312
+ "title": "PV Inverter",
7313
+ "manufacturer": "SMA",
7314
+ "external_id": "device-123"
7079
7315
  }
7080
7316
  }
7081
7317
  }
7082
7318
  },
7083
7319
  "responses": {
7084
- "200": {
7085
- "description": "Can Trigger Portal Flow",
7320
+ "201": {
7321
+ "description": "The entity has been created successfully for the portal user.",
7086
7322
  "content": {
7087
7323
  "application/json": {
7088
7324
  "schema": {
7089
- "type": "object",
7090
- "properties": {
7091
- "can_trigger": {
7092
- "type": "boolean",
7093
- "description": "Whether the flow can be triggered",
7094
- "example": true
7095
- }
7096
- }
7325
+ "$ref": "#/components/schemas/EntityResponse"
7097
7326
  }
7098
7327
  }
7099
7328
  }
7329
+ },
7330
+ "400": {
7331
+ "$ref": "#/components/responses/InvalidRequest"
7332
+ },
7333
+ "401": {
7334
+ "$ref": "#/components/responses/Unauthorized"
7335
+ },
7336
+ "403": {
7337
+ "$ref": "#/components/responses/Forbidden"
7338
+ },
7339
+ "500": {
7340
+ "$ref": "#/components/responses/InternalServerError"
7100
7341
  }
7101
7342
  }
7102
7343
  }
7103
7344
  },
7104
- "/v2/portal/automation-context": {
7105
- "get": {
7345
+ "/v2/portal/entity/{slug}/{id}": {
7346
+ "patch": {
7347
+ "operationId": "patchPortalUserEntity",
7348
+ "summary": "patchPortalUserEntity",
7349
+ "description": "**EXPERIMENTAL — do not rely on this endpoint.** It is unstable, currently limited to the `asset` schema, and may change or be removed without notice; third parties must not build on it yet.\nPartially update a single entity on behalf of a portal user. The schema slug and entity id are passed in the path; the schema must be one of the supported (experimental) schemas. Field-level permissions are enforced by the caller's role grants (use null to clear a field, e.g. external_id). The target entity must already be owned by the caller's contact.",
7350
+ "deprecated": true,
7351
+ "tags": [
7352
+ "ECP"
7353
+ ],
7354
+ "security": [
7355
+ {
7356
+ "PortalAuth": []
7357
+ }
7358
+ ],
7359
+ "parameters": [
7360
+ {
7361
+ "in": "path",
7362
+ "name": "slug",
7363
+ "description": "Entity schema slug to update. Limited to the supported (experimental) schemas, currently `asset`.",
7364
+ "required": true,
7365
+ "schema": {
7366
+ "type": "string",
7367
+ "enum": [
7368
+ "asset"
7369
+ ],
7370
+ "example": "asset"
7371
+ }
7372
+ },
7373
+ {
7374
+ "in": "path",
7375
+ "name": "id",
7376
+ "description": "ID of the entity to update. Must already be owned by the caller's contact.",
7377
+ "required": true,
7378
+ "schema": {
7379
+ "$ref": "#/components/schemas/EntityId"
7380
+ }
7381
+ }
7382
+ ],
7383
+ "requestBody": {
7384
+ "required": true,
7385
+ "content": {
7386
+ "application/json": {
7387
+ "schema": {
7388
+ "$ref": "#/components/schemas/Entity"
7389
+ },
7390
+ "example": {
7391
+ "external_id": null
7392
+ }
7393
+ }
7394
+ }
7395
+ },
7396
+ "responses": {
7397
+ "200": {
7398
+ "description": "The entity has been updated successfully for the portal user.",
7399
+ "content": {
7400
+ "application/json": {
7401
+ "schema": {
7402
+ "$ref": "#/components/schemas/EntityResponse"
7403
+ }
7404
+ }
7405
+ }
7406
+ },
7407
+ "400": {
7408
+ "$ref": "#/components/responses/InvalidRequest"
7409
+ },
7410
+ "401": {
7411
+ "$ref": "#/components/responses/Unauthorized"
7412
+ },
7413
+ "403": {
7414
+ "$ref": "#/components/responses/Forbidden"
7415
+ },
7416
+ "404": {
7417
+ "$ref": "#/components/responses/NotFound"
7418
+ },
7419
+ "500": {
7420
+ "$ref": "#/components/responses/InternalServerError"
7421
+ }
7422
+ }
7423
+ }
7424
+ },
7425
+ "/v2/portal/can-trigger-portal-flow": {
7426
+ "post": {
7427
+ "operationId": "canTriggerPortalFlow",
7428
+ "summary": "canTriggerPortalFlow",
7429
+ "description": "Returns whether the user can trigger a portal flow",
7430
+ "tags": [
7431
+ "ECP Admin"
7432
+ ],
7433
+ "security": [
7434
+ {
7435
+ "EpilotAuth": []
7436
+ }
7437
+ ],
7438
+ "parameters": [
7439
+ {
7440
+ "in": "query",
7441
+ "name": "origin",
7442
+ "required": false,
7443
+ "deprecated": true,
7444
+ "schema": {
7445
+ "$ref": "#/components/schemas/Origin"
7446
+ },
7447
+ "description": "Origin of the portal"
7448
+ },
7449
+ {
7450
+ "in": "query",
7451
+ "name": "portal_id",
7452
+ "required": true,
7453
+ "schema": {
7454
+ "type": "string",
7455
+ "description": "Portal ID",
7456
+ "example": "123"
7457
+ }
7458
+ }
7459
+ ],
7460
+ "requestBody": {
7461
+ "description": "Request of trigger portal flow",
7462
+ "required": true,
7463
+ "content": {
7464
+ "application/json": {
7465
+ "schema": {
7466
+ "$ref": "#/components/schemas/TriggerPortalFlow"
7467
+ }
7468
+ }
7469
+ }
7470
+ },
7471
+ "responses": {
7472
+ "200": {
7473
+ "description": "Can Trigger Portal Flow",
7474
+ "content": {
7475
+ "application/json": {
7476
+ "schema": {
7477
+ "type": "object",
7478
+ "properties": {
7479
+ "can_trigger": {
7480
+ "type": "boolean",
7481
+ "description": "Whether the flow can be triggered",
7482
+ "example": true
7483
+ }
7484
+ }
7485
+ }
7486
+ }
7487
+ }
7488
+ }
7489
+ }
7490
+ }
7491
+ },
7492
+ "/v2/portal/automation-context": {
7493
+ "get": {
7106
7494
  "operationId": "getAutomationContext",
7107
7495
  "summary": "getAutomationContext",
7108
7496
  "description": "Retrieves the automation context.",
@@ -9319,6 +9707,20 @@
9319
9707
  "example": "5da0a718-c822-403d-9f5d-20d4584e0528"
9320
9708
  },
9321
9709
  "description": "Portal ID (readonly UUID generated on portal creation)"
9710
+ },
9711
+ {
9712
+ "in": "query",
9713
+ "name": "page_upsert_mode",
9714
+ "required": false,
9715
+ "schema": {
9716
+ "type": "string",
9717
+ "enum": [
9718
+ "id",
9719
+ "slug"
9720
+ ],
9721
+ "default": "id"
9722
+ },
9723
+ "description": "Determines how pages are matched for upsert operations:\n- `id` (default): Match pages by their ID. Use this when page IDs are stable and known upfront.\n- `slug`: Match pages by their slug. When a request page has the same slug as an existing page, the existing page ID is adopted. Use this when page ids are unknown or when source page IDs differ from destination page IDs.\n"
9322
9724
  }
9323
9725
  ],
9324
9726
  "requestBody": {
@@ -10127,6 +10529,127 @@
10127
10529
  }
10128
10530
  }
10129
10531
  }
10532
+ },
10533
+ "/v1/portal/mobile-config": {
10534
+ "get": {
10535
+ "operationId": "getMobileConfig",
10536
+ "summary": "getMobileConfig",
10537
+ "description": "Returns the portal's mobile app configuration. By default the response is build-ready (resolved): base info (display_name from the portal name, app_host from the domain, environment) and branding (logo from the portal images, colors from the design palette) are filled in. Pass raw=true to get only the stored mobile_config without resolution.",
10538
+ "tags": [
10539
+ "ECP Admin"
10540
+ ],
10541
+ "security": [
10542
+ {
10543
+ "EpilotAuth": []
10544
+ }
10545
+ ],
10546
+ "parameters": [
10547
+ {
10548
+ "in": "query",
10549
+ "name": "portal_id",
10550
+ "required": true,
10551
+ "schema": {
10552
+ "type": "string"
10553
+ },
10554
+ "description": "Portal ID"
10555
+ },
10556
+ {
10557
+ "in": "query",
10558
+ "name": "raw",
10559
+ "required": false,
10560
+ "schema": {
10561
+ "type": "boolean"
10562
+ },
10563
+ "description": "Return only the stored mobile_config without resolving base info/branding."
10564
+ }
10565
+ ],
10566
+ "responses": {
10567
+ "200": {
10568
+ "description": "Mobile config retrieved successfully.",
10569
+ "content": {
10570
+ "application/json": {
10571
+ "schema": {
10572
+ "$ref": "#/components/schemas/MobileConfig"
10573
+ }
10574
+ }
10575
+ }
10576
+ },
10577
+ "401": {
10578
+ "$ref": "#/components/responses/Unauthorized"
10579
+ },
10580
+ "403": {
10581
+ "$ref": "#/components/responses/Forbidden"
10582
+ },
10583
+ "404": {
10584
+ "$ref": "#/components/responses/NotFound"
10585
+ },
10586
+ "500": {
10587
+ "$ref": "#/components/responses/InternalServerError"
10588
+ }
10589
+ }
10590
+ },
10591
+ "put": {
10592
+ "operationId": "putMobileConfig",
10593
+ "summary": "putMobileConfig",
10594
+ "description": "Merges the provided fields into the portal's mobile app configuration\n(deep merge). Only mobile_config is modified; all other portal settings\nare left untouched.\n",
10595
+ "tags": [
10596
+ "ECP Admin"
10597
+ ],
10598
+ "security": [
10599
+ {
10600
+ "EpilotAuth": []
10601
+ }
10602
+ ],
10603
+ "parameters": [
10604
+ {
10605
+ "in": "query",
10606
+ "name": "portal_id",
10607
+ "required": true,
10608
+ "schema": {
10609
+ "type": "string"
10610
+ },
10611
+ "description": "Portal ID"
10612
+ }
10613
+ ],
10614
+ "requestBody": {
10615
+ "description": "Editable mobile fields to merge into the existing mobile_config. Only mobile-relevant settings + app branding are applied; other fields are ignored.",
10616
+ "required": true,
10617
+ "content": {
10618
+ "application/json": {
10619
+ "schema": {
10620
+ "$ref": "#/components/schemas/MobileConfigUpdate"
10621
+ }
10622
+ }
10623
+ }
10624
+ },
10625
+ "responses": {
10626
+ "200": {
10627
+ "description": "Mobile config updated successfully.",
10628
+ "content": {
10629
+ "application/json": {
10630
+ "schema": {
10631
+ "$ref": "#/components/schemas/MobileConfig"
10632
+ }
10633
+ }
10634
+ }
10635
+ },
10636
+ "400": {
10637
+ "$ref": "#/components/responses/InvalidRequest"
10638
+ },
10639
+ "401": {
10640
+ "$ref": "#/components/responses/Unauthorized"
10641
+ },
10642
+ "403": {
10643
+ "$ref": "#/components/responses/Forbidden"
10644
+ },
10645
+ "404": {
10646
+ "$ref": "#/components/responses/NotFound"
10647
+ },
10648
+ "500": {
10649
+ "$ref": "#/components/responses/InternalServerError"
10650
+ }
10651
+ }
10652
+ }
10130
10653
  }
10131
10654
  },
10132
10655
  "components": {
@@ -10360,9 +10883,206 @@
10360
10883
  }
10361
10884
  },
10362
10885
  "schemas": {
10363
- "ContextEntity": {
10886
+ "MobileBuildStatus": {
10364
10887
  "type": "object",
10365
- "description": "An entity reference for context-aware operations",
10888
+ "description": "Latest build/upload status for a platform (system-written).",
10889
+ "additionalProperties": true,
10890
+ "properties": {
10891
+ "version": {
10892
+ "type": "string"
10893
+ },
10894
+ "build_number": {
10895
+ "type": "integer"
10896
+ },
10897
+ "track": {
10898
+ "type": "string",
10899
+ "description": "e.g. testflight | internal | beta"
10900
+ },
10901
+ "status": {
10902
+ "type": "string",
10903
+ "enum": [
10904
+ "building",
10905
+ "uploaded",
10906
+ "failed"
10907
+ ]
10908
+ },
10909
+ "updated_at": {
10910
+ "type": "string",
10911
+ "format": "date-time"
10912
+ },
10913
+ "error": {
10914
+ "type": "string"
10915
+ }
10916
+ }
10917
+ },
10918
+ "MobileBranding": {
10919
+ "type": "object",
10920
+ "additionalProperties": true,
10921
+ "properties": {
10922
+ "app_icon": {
10923
+ "type": "string"
10924
+ },
10925
+ "splash": {
10926
+ "type": "string"
10927
+ },
10928
+ "splash_dark": {
10929
+ "type": "string"
10930
+ },
10931
+ "icon_background_color": {
10932
+ "type": "string"
10933
+ },
10934
+ "splash_background_color": {
10935
+ "type": "string"
10936
+ },
10937
+ "splash_background_color_dark": {
10938
+ "type": "string"
10939
+ }
10940
+ }
10941
+ },
10942
+ "MobileConfig": {
10943
+ "type": "object",
10944
+ "description": "Mobile app configuration for the portal. Stored inside the portal's config object. Identifiers/branding are non-secret; signing credentials live in a secure store, never here.",
10945
+ "additionalProperties": true,
10946
+ "properties": {
10947
+ "portal_id": {
10948
+ "type": "string",
10949
+ "description": "Portal id (response-only; ignored on write)."
10950
+ },
10951
+ "enabled": {
10952
+ "type": "boolean"
10953
+ },
10954
+ "display_name": {
10955
+ "type": "string",
10956
+ "description": "App display name compiled into the binary."
10957
+ },
10958
+ "app_host": {
10959
+ "type": "string",
10960
+ "description": "Host the mobile shell loads (defaults to the portal domain)."
10961
+ },
10962
+ "environment": {
10963
+ "type": "string",
10964
+ "enum": [
10965
+ "prod",
10966
+ "staging",
10967
+ "dev"
10968
+ ]
10969
+ },
10970
+ "branding": {
10971
+ "$ref": "#/components/schemas/MobileBranding"
10972
+ },
10973
+ "ios": {
10974
+ "type": "object",
10975
+ "additionalProperties": true,
10976
+ "properties": {
10977
+ "bundle_id": {
10978
+ "type": "string",
10979
+ "description": "iOS bundle id (matches the App Store Connect app)."
10980
+ },
10981
+ "team_id": {
10982
+ "type": "string",
10983
+ "description": "Apple Developer Team ID."
10984
+ },
10985
+ "credentials_status": {
10986
+ "type": "string",
10987
+ "enum": [
10988
+ "not_configured",
10989
+ "configured"
10990
+ ]
10991
+ },
10992
+ "app_store_id": {
10993
+ "type": "string",
10994
+ "description": "Numeric App Store id (system-written after first upload)."
10995
+ },
10996
+ "store_url": {
10997
+ "type": "string",
10998
+ "description": "System-written App Store URL."
10999
+ },
11000
+ "last_build": {
11001
+ "$ref": "#/components/schemas/MobileBuildStatus"
11002
+ }
11003
+ }
11004
+ },
11005
+ "android": {
11006
+ "type": "object",
11007
+ "additionalProperties": true,
11008
+ "properties": {
11009
+ "package_name": {
11010
+ "type": "string",
11011
+ "description": "Android package name (matches the Play Console app)."
11012
+ },
11013
+ "credentials_status": {
11014
+ "type": "string",
11015
+ "enum": [
11016
+ "not_configured",
11017
+ "configured"
11018
+ ]
11019
+ },
11020
+ "upload_key_status": {
11021
+ "type": "string",
11022
+ "description": "Play App Signing upload-key state.",
11023
+ "enum": [
11024
+ "not_configured",
11025
+ "generated",
11026
+ "enrolled"
11027
+ ]
11028
+ },
11029
+ "store_url": {
11030
+ "type": "string",
11031
+ "description": "System-written Play Store URL."
11032
+ },
11033
+ "last_build": {
11034
+ "$ref": "#/components/schemas/MobileBuildStatus"
11035
+ }
11036
+ }
11037
+ }
11038
+ }
11039
+ },
11040
+ "MobileConfigUpdate": {
11041
+ "type": "object",
11042
+ "description": "Editable mobile fields for PUT. Only mobile-relevant settings + app branding can be changed. Portal-derived values (display_name, app_host), the portal logo, and system-written fields (credentials_status, app_store_id, last_build, …) are ignored if sent.",
11043
+ "additionalProperties": true,
11044
+ "properties": {
11045
+ "enabled": {
11046
+ "type": "boolean"
11047
+ },
11048
+ "ios": {
11049
+ "type": "object",
11050
+ "additionalProperties": true,
11051
+ "properties": {
11052
+ "bundle_id": {
11053
+ "type": "string"
11054
+ },
11055
+ "team_id": {
11056
+ "type": "string"
11057
+ },
11058
+ "store_url": {
11059
+ "type": "string"
11060
+ },
11061
+ "app_store_id": {
11062
+ "type": "string"
11063
+ }
11064
+ }
11065
+ },
11066
+ "android": {
11067
+ "type": "object",
11068
+ "additionalProperties": true,
11069
+ "properties": {
11070
+ "package_name": {
11071
+ "type": "string"
11072
+ },
11073
+ "store_url": {
11074
+ "type": "string"
11075
+ }
11076
+ }
11077
+ },
11078
+ "branding": {
11079
+ "$ref": "#/components/schemas/MobileBranding"
11080
+ }
11081
+ }
11082
+ },
11083
+ "ContextEntity": {
11084
+ "type": "object",
11085
+ "description": "An entity reference for context-aware operations",
10366
11086
  "properties": {
10367
11087
  "entity_schema": {
10368
11088
  "type": "string",
@@ -10969,6 +11689,10 @@
10969
11689
  "auto_redirect_to_sso": {
10970
11690
  "type": "boolean",
10971
11691
  "description": "Decide whether to automatically redirect to the provider page during login, which would completely bypass showing the portal authentication page."
11692
+ },
11693
+ "prevent_user_enumeration": {
11694
+ "type": "boolean",
11695
+ "description": "Opt-in. When true, suppresses responses that reveal whether a user exists for public, pre-authentication actions (the login entry-point check and self-registration), at the expense of some UX. Already-authenticated actions are unaffected. Default false.\n"
10972
11696
  }
10973
11697
  }
10974
11698
  },
@@ -11854,6 +12578,11 @@
11854
12578
  "contract_number": "123456"
11855
12579
  }
11856
12580
  }
12581
+ },
12582
+ "trigger_identifiers_check": {
12583
+ "type": "boolean",
12584
+ "default": true,
12585
+ "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"
11857
12586
  }
11858
12587
  }
11859
12588
  },
@@ -14282,6 +15011,111 @@
14282
15011
  "$ref": "#/components/schemas/PublicMeterReadingPlausibilityCheckDetails"
14283
15012
  }
14284
15013
  }
15014
+ },
15015
+ "changeEmail": {
15016
+ "type": "object",
15017
+ "properties": {
15018
+ "app": {
15019
+ "$ref": "#/components/schemas/PublicAppDetails"
15020
+ },
15021
+ "extension": {
15022
+ "$ref": "#/components/schemas/PublicExtensionDetails"
15023
+ },
15024
+ "hook": {
15025
+ "$ref": "#/components/schemas/PublicChangeEmailDetails"
15026
+ }
15027
+ }
15028
+ },
15029
+ "changePassword": {
15030
+ "type": "object",
15031
+ "properties": {
15032
+ "app": {
15033
+ "$ref": "#/components/schemas/PublicAppDetails"
15034
+ },
15035
+ "extension": {
15036
+ "$ref": "#/components/schemas/PublicExtensionDetails"
15037
+ },
15038
+ "hook": {
15039
+ "$ref": "#/components/schemas/PublicChangePasswordDetails"
15040
+ }
15041
+ }
15042
+ },
15043
+ "deleteAccount": {
15044
+ "type": "object",
15045
+ "properties": {
15046
+ "app": {
15047
+ "$ref": "#/components/schemas/PublicAppDetails"
15048
+ },
15049
+ "extension": {
15050
+ "$ref": "#/components/schemas/PublicExtensionDetails"
15051
+ },
15052
+ "hook": {
15053
+ "$ref": "#/components/schemas/PublicDeleteAccountDetails"
15054
+ }
15055
+ }
15056
+ }
15057
+ }
15058
+ },
15059
+ "PublicSelfManagementExplanation": {
15060
+ "type": "object",
15061
+ "properties": {
15062
+ "en": {
15063
+ "type": "string",
15064
+ "description": "Explanation of the functionality shown to the end user."
15065
+ }
15066
+ },
15067
+ "additionalProperties": {
15068
+ "type": "string",
15069
+ "description": "Explanation of the functionality in language denoted by ISO 3166-1 alpha-2 code."
15070
+ },
15071
+ "required": [
15072
+ "en"
15073
+ ],
15074
+ "description": "Explanation of the hook."
15075
+ },
15076
+ "PublicChangeEmailDetails": {
15077
+ "type": "object",
15078
+ "properties": {
15079
+ "id": {
15080
+ "type": "string",
15081
+ "description": "Identifier of the hook."
15082
+ },
15083
+ "require_password_confirmation": {
15084
+ "type": "boolean",
15085
+ "description": "Whether the portal user must confirm their current password before the email change is handed over to the third-party system.",
15086
+ "default": true
15087
+ },
15088
+ "explanation": {
15089
+ "$ref": "#/components/schemas/PublicSelfManagementExplanation"
15090
+ }
15091
+ }
15092
+ },
15093
+ "PublicChangePasswordDetails": {
15094
+ "type": "object",
15095
+ "properties": {
15096
+ "id": {
15097
+ "type": "string",
15098
+ "description": "Identifier of the hook."
15099
+ },
15100
+ "require_new_password": {
15101
+ "type": "boolean",
15102
+ "description": "Whether the portal user must provide a new password that is passed to the third-party system.",
15103
+ "default": false
15104
+ },
15105
+ "explanation": {
15106
+ "$ref": "#/components/schemas/PublicSelfManagementExplanation"
15107
+ }
15108
+ }
15109
+ },
15110
+ "PublicDeleteAccountDetails": {
15111
+ "type": "object",
15112
+ "properties": {
15113
+ "id": {
15114
+ "type": "string",
15115
+ "description": "Identifier of the hook."
15116
+ },
15117
+ "explanation": {
15118
+ "$ref": "#/components/schemas/PublicSelfManagementExplanation"
14285
15119
  }
14286
15120
  }
14287
15121
  },
@@ -14694,6 +15528,15 @@
14694
15528
  },
14695
15529
  {
14696
15530
  "$ref": "#/components/schemas/ExtensionHookVisualizationMetadata"
15531
+ },
15532
+ {
15533
+ "$ref": "#/components/schemas/ExtensionHookChangeEmail"
15534
+ },
15535
+ {
15536
+ "$ref": "#/components/schemas/ExtensionHookChangePassword"
15537
+ },
15538
+ {
15539
+ "$ref": "#/components/schemas/ExtensionHookDeleteAccount"
14697
15540
  }
14698
15541
  ]
14699
15542
  }
@@ -15558,6 +16401,289 @@
15558
16401
  "call"
15559
16402
  ]
15560
16403
  },
16404
+ "ExtensionHookChangeEmail": {
16405
+ "description": "Hook that replaces the built-in change email functionality for portal users. When configured, the portal does not change the user's login email itself. Instead, this hook makes an HTTP call to the third-party system, which is expected to handle the email change (most likely by sending the user instructions to confirm the new email address).\nThe expected response http status code to the call is:\n - 2xx if the request was accepted\n - non-2xx if the request failed (optionally with a human-readable message resolved via `resolved.error_message_path`)\n",
16406
+ "type": "object",
16407
+ "properties": {
16408
+ "type": {
16409
+ "type": "string",
16410
+ "enum": [
16411
+ "changeEmail"
16412
+ ]
16413
+ },
16414
+ "require_password_confirmation": {
16415
+ "type": "boolean",
16416
+ "description": "Whether the portal user must confirm their current password before the change email request is handed over to the third-party system. When true, the portal collects and verifies the current password before calling the hook.\n",
16417
+ "default": true
16418
+ },
16419
+ "explanation": {
16420
+ "type": "object",
16421
+ "properties": {
16422
+ "en": {
16423
+ "type": "string",
16424
+ "description": "Explanation of the functionality shown to the end user.",
16425
+ "example": "You will receive an email with instructions to confirm your new email address."
16426
+ }
16427
+ },
16428
+ "additionalProperties": {
16429
+ "type": "string",
16430
+ "description": "Explanation of the functionality in language denoted by ISO 3166-1 alpha-2 code."
16431
+ },
16432
+ "required": [
16433
+ "en"
16434
+ ],
16435
+ "description": "Optional explanation shown to the user in the change email confirmation dialog."
16436
+ },
16437
+ "auth": {
16438
+ "$ref": "#/components/schemas/ExtensionAuthBlock"
16439
+ },
16440
+ "call": {
16441
+ "type": "object",
16442
+ "properties": {
16443
+ "method": {
16444
+ "type": "string",
16445
+ "description": "HTTP method to use for the call",
16446
+ "default": "POST"
16447
+ },
16448
+ "url": {
16449
+ "type": "string",
16450
+ "description": "URL to call. Supports variable interpolation."
16451
+ },
16452
+ "params": {
16453
+ "type": "object",
16454
+ "description": "Parameters to append to the URL. Supports variable interpolation.",
16455
+ "additionalProperties": {
16456
+ "type": "string"
16457
+ },
16458
+ "default": {}
16459
+ },
16460
+ "headers": {
16461
+ "type": "object",
16462
+ "description": "Headers to use. Supports variable interpolation.",
16463
+ "additionalProperties": {
16464
+ "type": "string"
16465
+ },
16466
+ "default": {}
16467
+ },
16468
+ "body": {
16469
+ "type": "object",
16470
+ "description": "Optional JSON body to use for the call. Defaults to an object with the requested new email and portal user context. The requested new email is available as `{{Input.new_email}}` and the current account email as `{{Input.old_email}}`. Supports variable interpolation."
16471
+ }
16472
+ },
16473
+ "required": [
16474
+ "url",
16475
+ "headers"
16476
+ ]
16477
+ },
16478
+ "resolved": {
16479
+ "type": "object",
16480
+ "properties": {
16481
+ "error_message_path": {
16482
+ "type": "string",
16483
+ "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",
16484
+ "example": "error.message"
16485
+ }
16486
+ }
16487
+ },
16488
+ "secure_proxy": {
16489
+ "$ref": "#/components/schemas/SecureProxyConfig"
16490
+ }
16491
+ },
16492
+ "required": [
16493
+ "type",
16494
+ "call"
16495
+ ]
16496
+ },
16497
+ "ExtensionHookChangePassword": {
16498
+ "description": "Hook that replaces the built-in change password functionality for portal users. When configured, the portal does not change the user's password itself. Instead, this hook makes an HTTP call to the third-party system, which is expected to handle the password change (most likely by sending the user instructions to complete the process).\nThe expected response http status code to the call is:\n - 2xx if the request was accepted\n - non-2xx if the request failed (optionally with a human-readable message resolved via `resolved.error_message_path`)\n",
16499
+ "type": "object",
16500
+ "properties": {
16501
+ "type": {
16502
+ "type": "string",
16503
+ "enum": [
16504
+ "changePassword"
16505
+ ]
16506
+ },
16507
+ "require_new_password": {
16508
+ "type": "boolean",
16509
+ "description": "Whether the portal user must provide a new password. When false, the portal only asks the user to confirm (showing the configured explanation) and no new password is collected; the third-party system is expected to handle the password change. When true, the portal collects a new password and passes it to the third-party system as `{{Input.new_password}}`.\n",
16510
+ "default": false
16511
+ },
16512
+ "explanation": {
16513
+ "type": "object",
16514
+ "properties": {
16515
+ "en": {
16516
+ "type": "string",
16517
+ "description": "Explanation of the functionality shown to the end user.",
16518
+ "example": "You will receive an email with instructions to reset your password."
16519
+ }
16520
+ },
16521
+ "additionalProperties": {
16522
+ "type": "string",
16523
+ "description": "Explanation of the functionality in language denoted by ISO 3166-1 alpha-2 code."
16524
+ },
16525
+ "required": [
16526
+ "en"
16527
+ ],
16528
+ "description": "Optional explanation shown to the user in the change password confirmation dialog."
16529
+ },
16530
+ "auth": {
16531
+ "$ref": "#/components/schemas/ExtensionAuthBlock"
16532
+ },
16533
+ "call": {
16534
+ "type": "object",
16535
+ "properties": {
16536
+ "method": {
16537
+ "type": "string",
16538
+ "description": "HTTP method to use for the call",
16539
+ "default": "POST"
16540
+ },
16541
+ "url": {
16542
+ "type": "string",
16543
+ "description": "URL to call. Supports variable interpolation."
16544
+ },
16545
+ "params": {
16546
+ "type": "object",
16547
+ "description": "Parameters to append to the URL. Supports variable interpolation.",
16548
+ "additionalProperties": {
16549
+ "type": "string"
16550
+ },
16551
+ "default": {}
16552
+ },
16553
+ "headers": {
16554
+ "type": "object",
16555
+ "description": "Headers to use. Supports variable interpolation.",
16556
+ "additionalProperties": {
16557
+ "type": "string"
16558
+ },
16559
+ "default": {}
16560
+ },
16561
+ "body": {
16562
+ "type": "object",
16563
+ "description": "Optional JSON body to use for the call. Defaults to an object with portal user context (and the new password as `{{Input.new_password}}` when `require_new_password` is true). Supports variable interpolation."
16564
+ }
16565
+ },
16566
+ "required": [
16567
+ "url",
16568
+ "headers"
16569
+ ]
16570
+ },
16571
+ "resolved": {
16572
+ "type": "object",
16573
+ "properties": {
16574
+ "error_message_path": {
16575
+ "type": "string",
16576
+ "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",
16577
+ "example": "error.message"
16578
+ }
16579
+ }
16580
+ },
16581
+ "secure_proxy": {
16582
+ "$ref": "#/components/schemas/SecureProxyConfig"
16583
+ }
16584
+ },
16585
+ "required": [
16586
+ "type",
16587
+ "call"
16588
+ ]
16589
+ },
16590
+ "ExtensionHookDeleteAccount": {
16591
+ "description": "Hook that replaces the built-in delete account functionality for portal users. When configured, the portal does not delete the user itself. Instead, this hook makes an HTTP call to the third-party system, which is expected to handle the deletion.\nThe `deletion_mode` controls what the portal does after the call:\n - `synchronous`: The third-party system deletes the user immediately. The portal waits for a successful (2xx) response and then also deletes the epilot user.\n - `asynchronous`: The third-party system handles deletion out-of-band. The portal does not delete anything immediately; cleanup is expected to happen later (e.g. via the user deletion API or webhooks).\n\nThe expected response http status code to the call is:\n - 2xx if the request was accepted\n - non-2xx if the request failed (optionally with a human-readable message resolved via `resolved.error_message_path`)\n",
16592
+ "type": "object",
16593
+ "properties": {
16594
+ "type": {
16595
+ "type": "string",
16596
+ "enum": [
16597
+ "deleteAccount"
16598
+ ]
16599
+ },
16600
+ "deletion_mode": {
16601
+ "type": "string",
16602
+ "enum": [
16603
+ "synchronous",
16604
+ "asynchronous"
16605
+ ],
16606
+ "description": "Controls how the account deletion is handled. `synchronous` waits for the third-party system to respond and then also deletes the epilot user. `asynchronous` hands the deletion over entirely to the third-party system and the portal does not delete anything immediately.\n",
16607
+ "default": "synchronous"
16608
+ },
16609
+ "explanation": {
16610
+ "type": "object",
16611
+ "properties": {
16612
+ "en": {
16613
+ "type": "string",
16614
+ "description": "Explanation of the functionality shown to the end user.",
16615
+ "example": "Your account deletion will be processed by our system. This may take a few days."
16616
+ }
16617
+ },
16618
+ "additionalProperties": {
16619
+ "type": "string",
16620
+ "description": "Explanation of the functionality in language denoted by ISO 3166-1 alpha-2 code."
16621
+ },
16622
+ "required": [
16623
+ "en"
16624
+ ],
16625
+ "description": "Optional explanation shown to the user in the delete account confirmation dialog."
16626
+ },
16627
+ "auth": {
16628
+ "$ref": "#/components/schemas/ExtensionAuthBlock"
16629
+ },
16630
+ "call": {
16631
+ "type": "object",
16632
+ "properties": {
16633
+ "method": {
16634
+ "type": "string",
16635
+ "description": "HTTP method to use for the call",
16636
+ "default": "POST"
16637
+ },
16638
+ "url": {
16639
+ "type": "string",
16640
+ "description": "URL to call. Supports variable interpolation."
16641
+ },
16642
+ "params": {
16643
+ "type": "object",
16644
+ "description": "Parameters to append to the URL. Supports variable interpolation.",
16645
+ "additionalProperties": {
16646
+ "type": "string"
16647
+ },
16648
+ "default": {}
16649
+ },
16650
+ "headers": {
16651
+ "type": "object",
16652
+ "description": "Headers to use. Supports variable interpolation.",
16653
+ "additionalProperties": {
16654
+ "type": "string"
16655
+ },
16656
+ "default": {}
16657
+ },
16658
+ "body": {
16659
+ "type": "object",
16660
+ "description": "Optional JSON body to use for the call. Defaults to an object with portal user context, e.g. `{\"portal_user_id\": \"...\", \"email\": \"...\"}`. Supports variable interpolation."
16661
+ }
16662
+ },
16663
+ "required": [
16664
+ "url",
16665
+ "headers"
16666
+ ]
16667
+ },
16668
+ "resolved": {
16669
+ "type": "object",
16670
+ "properties": {
16671
+ "error_message_path": {
16672
+ "type": "string",
16673
+ "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",
16674
+ "example": "error.message"
16675
+ }
16676
+ }
16677
+ },
16678
+ "secure_proxy": {
16679
+ "$ref": "#/components/schemas/SecureProxyConfig"
16680
+ }
16681
+ },
16682
+ "required": [
16683
+ "type",
16684
+ "call"
16685
+ ]
16686
+ },
15561
16687
  "SecureProxyConfig": {
15562
16688
  "type": "object",
15563
16689
  "description": "Configuration for routing requests through the ERP Integration secure proxy. Mutually exclusive with use_static_ips.",
@@ -15886,6 +17012,11 @@
15886
17012
  },
15887
17013
  "mobile_oidc_config": {
15888
17014
  "$ref": "#/components/schemas/MoblieOIDCConfig"
17015
+ },
17016
+ "expose_client_secret": {
17017
+ "type": "boolean",
17018
+ "description": "Allow the resolved `client_secret` to be returned through the\npublic single-provider endpoint at SSO initiation. Only set this\nfor OIDC flows that require a public client secret in the\nbrowser (e.g. some PKCE-less authorization-code variants). When\nunset (default), the secret is kept server-side and only used at\nthe token exchange.\n",
17019
+ "example": false
15889
17020
  }
15890
17021
  },
15891
17022
  "required": [
@@ -16748,6 +17879,10 @@
16748
17879
  "auto_redirect_to_sso": {
16749
17880
  "type": "boolean",
16750
17881
  "description": "Decide whether to automatically redirect to the provider page during login, which would completely bypass showing the portal authentication page."
17882
+ },
17883
+ "prevent_user_enumeration": {
17884
+ "type": "boolean",
17885
+ "description": "Opt-in. When true, suppresses responses that reveal whether a user exists for public, pre-authentication actions (the login entry-point check and self-registration), at the expense of some UX. Already-authenticated actions are unaffected. Default false.\n"
16751
17886
  }
16752
17887
  }
16753
17888
  },