Save an onboarding flow's routing graph and editor layout
/onboarding/flows/{complianceId}/definitionRebuild the onboarding flow's routing graph from flows and persist the editor definition JSON verbatim.
Each entry in flows defines one route between two forms already attached to this flow:
fromFormId(form UUID) — the source form the respondent is coming from.toFormId(form UUID) — the destination form to route to.conditionSets— an array of condition groups; the route is taken when the groups evaluate true. Each group has:conditionType— one ofAND,OR,AT_LEAST_50,AT_LEAST_75,OTHER,NUMBER_MATCH.conditionValue— required whenconditionTypeisNUMBER_MATCH; otherwise optional.conditions— an array of individual conditions (ignored whenconditionTypeisOTHER, which is the catch-all/else branch). Each condition is either a form-field rule (formFieldIdform-field UUID,operator,value) or a custom rule (type,value).operatoris one of=,!=,>,<,>=,<=,??(has-value).
Rules: the flow's base (start) form must appear as at least one fromFormId; a form cannot route to itself; the base form cannot be a toFormId; and both forms in every route must already be attached to this flow. Sending an empty flows array clears the entire routing graph.
Publish the flow afterwards with PATCH /onboarding/flows/{complianceId}/status.
Deprecated: withdrawn on 2027-06-30. PATCH /onboarding-flows/{id} replaces it, which takes routes in a form that reads back and keeps definition unless sent. This route keeps its lossy behaviour: empty flows do not save definition, and flows without definition blank it.
Path parameters
The compliance flow's public uuid.
Request body
application/json, required
Route definitions (editor flow shape).
Opaque editor layout definition stored verbatim.
{
"flows": [
{
"fromFormId": "3f2a1b90-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"toFormId": "7b8c9d0e-2f3a-4b5c-9d0e-1a2b3c4d5e6f",
"conditionSets": [
{
"conditionType": "AND",
"conditionValue": null,
"conditions": [
{
"formFieldId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"operator": "=",
"value": "yes"
}
]
},
{
"conditionType": "OTHER",
"conditionValue": null,
"conditions": []
}
]
}
],
"definition": {
"nodes": [],
"edges": []
}
}Responses
{
"data": {
"id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"name": "Investor Suitability",
"status": "draft",
"expiry_type": "TWELVE_MONTH",
"mode_type": "Continuous",
"definition": {
"nodes": [
{
"id": "start",
"type": "form",
"form_id": "3f2b7c1a-9d4e-4a6b-8c1f-2e5d7a9b0c31",
"next": "classification"
},
{
"id": "classification",
"type": "classification",
"next": null
}
],
"edges": [
{
"from": "start",
"to": "classification"
}
]
},
"forms_count": 1,
"created_at": "2026-06-15T10:30:00+00:00",
"updated_at": "2026-07-06T14:12:45+00:00"
}
}Authorization failed. error.code is one of org_disabled,
ip_blocked, missing_scope, scope_disabled, user_disabled.
Request validation failed (HTTP 422). The body is either the Laravel
validation envelope (message + field-keyed errors) or the API error
envelope for domain rejections (e.g. form_type_not_supported,
folder_locked, parent_not_found, folder_not_empty).
Examples
curl -X PUT https://your-org-domain/kong/core/api/v2/onboarding/flows/{complianceId}/definition\
-H "Authorization: Bearer $HELM_API_KEY"\
-H "Content-Type: application/json"\
-d '{
"flows": [
{
"fromFormId": "3f2a1b90-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"toFormId": "7b8c9d0e-2f3a-4b5c-9d0e-1a2b3c4d5e6f",
"conditionSets": [
{
"conditionType": "AND",
"conditionValue": null,
"conditions": [
{
"formFieldId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"operator": "=",
"value": "yes"
}
]
},
{
"conditionType": "OTHER",
"conditionValue": null,
"conditions": []
}
]
}
],
"definition": {
"nodes": [],
"edges": []
}
}'