A Structure connection runs inside the lead flow itself, while the customer is still filling in the form or the lead is still being processed, and it can shape or gate the data before the lead is finalized.
There are three common purposes for a Structure connection.
- Validation. Check a field against an external service and, if enabled, reject the lead when the value is invalid.
- Enrichment. Fill a field with a value pulled from an external source, based on data the customer already provided.
- Autosuggest. Offer typeahead suggestions while the customer is typing a field.
All three share the same building blocks (httpNode to call the external API, setNode to store the result, conditional edges to branch on the response), but they differ in how the flow ends.
Validation
Ask an external service whether a value the customer entered is valid (a national ID, a bank account, and so on), and use the result to either let the lead continue or reject it.
Pattern
startNode(structure).httpNode(GET) calling the validation endpoint, typically with the field value as a query parameter (for examplebirthId={data_nin}orbankAccount={data_account_number}/{data_bank_code}).- Three branches out of the
httpNode, based on{status}and{parsedBody.valid}.- Valid.
{status}equals200and{parsedBody.valid}equalstrue. This leads to anendNodetitledValidwithsuccess: "success". - Outage.
{status}matches a 4xx or 5xx pattern (regex\b[45]\d{2}\b). This leads to anendNodetitledOutagewithsuccess: "success", because a service outage should not automatically reject the lead. - Invalid.
{parsedBody.valid}equalsfalse. This leads to anendNodetitledInvalidwithsuccess: "failed".
- Valid.
The important detail: success on the end node
The success value on the terminal endNode is what actually decides whether the lead gets rejected. In both validation examples (national ID, bank account), the Invalid branch uses success: "failed", which is the setting that rejects the lead when the field does not validate. Valid and Outage both use success: "success", so neither blocks the lead, only a confirmed invalid value does.
This is easy to get wrong, so when building a validation connection, check that:
- The branch meant to reject the lead is the only one using
success: "failed". - An outage or an unexpected response does not accidentally inherit
success: "failed", or every temporary API hiccup will start rejecting real customers.
Modify (filling a field with an external value)
Take a value the customer already gave (a national ID, a name and birth date, and so on), call an external registry or lookup API, and use the response to fill a different field automatically, for example deriving a company number from a person’s name, or checking whether a person is in insolvency.
Pattern, simple version (insolvency check)
startNode(structure).httpNode(GET) calling the lookup endpoint (for examplecheckInsolvency?birthId={data_nin}).- Three branches:
- True.
{status}equals200and{parsedBody.liveRecords}equals1. AsetNodewrites{data_insolvency} = "yes", then anendNodetitledValidwithsuccess: "success". - False.
{status}equals200and{parsedBody.liveRecords}equals0. AsetNodewrites{data_insolvency} = "no", then anendNodetitledInvalidwithsuccess: "success". - Outage. Same 4xx/5xx regex as in validation.
endNodetitledOutagewithsuccess: "success".
- True.
Note that here, unlike in a strict validation connection, both outcomes (found and not found) use success: "success". Enrichment should not reject the lead just because the lookup came back empty, it should only fill (or not fill) a field. Only use success: "failed" when the absence of a value is itself a genuine reason to reject the lead.
Pattern, with a fallback field and a conditional prefill (company number lookup)
startNode(structure).modifyFieldNodeto prepare an input the API needs but the customer did not directly providehttpNode(GET) calling the lookup endpoint with the prepared parameters (name, birth date).- Three branches:
- Outage.
{status}matches the 4xx/5xx regex, or{parsedBody.status}equalserror.endNodetitledOutage. - True.
{status}equals200and{parsedBody.freelancers.1.ico}is not empty. AsetNodewrites{data_company_number_imported} = {parsedBody.freelancers.1.ico}. - False.
{status}equals200and{parsedBody.freelancers.1.ico}is empty. AsetNodewith no fields set (the field is simply left empty) leads directly to anendNodetitledInvalidwithsuccess: "success".
- Outage.
- On the True branch, before the final
endNode, amodifyFieldNodeapplies ado_not_sendmodification to{data_company_number_imported}as a safeguard. When configuring this kind of guard, make sure the condition actually compares against the live parsed value from the response, not against a hardcoded literal string that happens to look like the field path. If the condition is written as a literal string instead of a template reference, it will never match a real response and the guard becomes dead logic.
Autosuggest (typeahead)
While the customer types into a field (for example a company name), call an external suggestion API on each keystroke or debounce interval and return a list of matching values for the frontend to display as a dropdown.
Pattern
startNode(structure).httpNode(POST) sending the partial input to the suggestion API, for examplefieldType: COMPANY_NAME,values.COMPANY_NAME: {company_name}.setNodestoring the full suggestion list, for example{autocomplete_result} = {parsedBody.suggestions}.
This is the simplest of the three patterns: there is no branching and no rejection logic, the flow always ends in the same single setNode, and the frontend is responsible for rendering the returned list and letting the customer pick one.

