Integration hub

Overview
The hub moves data across system boundaries: out to external services and in from them. This is built as a flow — a chain of blocks that records travel through.
Two things distinguish the hub from automation: it works at the boundary to FOREIGN systems, and it processes lists of records rather than single events. Rules inside the system remain the business of automation — there is deliberately only one rule engine.
A block without incoming records does not run. That is not a fault but the rule: a flow without data has nothing to do.
Core tasks
Build a flow. In the editor you assemble blocks and connect their outputs: drag the dot below a card onto the target block and release — the line follows the pointer and the target lights up. Without a mouse, click the output first and then the target. Values are formed with formulas of the form {{= … }} — there is no code here.
Test a block on its own. Test alone on the selected block opens a sample input (a JSON list of records), prefilled with what reached this block in the last test run — at the start of the chain with the flow's test data. Test with this input runs only this block: no predecessor, no successor, but with a journal. The preview below then shows its output. The saved state is tested, so save first. Note: a sending block (email, webhook, writing in the system) really sends in a single test too. Permission: connect.flow.execute.
Blocks for lists, texts, archives and signals. Split into batches (batch) bundles N records into one — for interfaces that accept only a certain number per call. Remove duplicates (unique) lets only the first record per key through (without memory beyond the run; that is what Only let new ones through is for). Text from template (template_render) builds a text with placeholders per record, optionally HTML-escaped and as a file. Extract ZIP (zip_unpack) turns each entry of an archive into a record with the file in a slot, Create ZIP (zip_pack) puts the files of all records into one archive. Signal to automation (emit_signal) reports a name and payload to automation — trigger Signal from the integration hub, condition for example signal equals pricelist_imported. The decision is made there; the hub itself has no rules. A chain of signal, automation and another flow start ends after five levels.
React to dropped files. Trigger File dropped: you pick a folder of the file storage and a file pattern (default *.csv). Every matching file uploaded there starts the flow through the queue; it is attached to the first record in slot datei. The CSV block reads it if you enter datei under File from slot and leave Content empty. {{trigger.file.name}} and {{trigger.folder.name}} name file and folder. A flow without a brand reacts to every file, a flow with a brand only to files of its brand. Without a folder it cannot be enabled.
Maintain mappings. A mapping translates fields between two systems. A lookup table translates values (for example foreign status names into your own).
Start from a template. Templates bring ready-made flows for common tasks.
Trace runs. The run journal shows every pass with the data per block. A failed run can be resumed instead of started over.
Read from the store. The store keeps values between runs — for example the position of the last fetch, so a flow continues where it left off.
Start due flows now. Schedule and polling flows are started by the system every minute as soon as they are due. Start due flows now in the flow list runs exactly this pass immediately and then lists every started flow with its trigger and schedule; "No flow was due just now" is information, not an error. Flows of other brands stay untouched. Permission: connect.flow.execute.
Fields in detail
A flow connects system boundaries: it fetches records from outside, reshapes them and writes them in — or the other way round. Rules inside the system belong in automation; two rule engines side by side would be one too many.
| Field | Required | Values / format | What it does |
|---|---|---|---|
Key flowKey | yes | text, max. 100 characters | The flow's technical identifier. Do not change it once it runs. |
Name name | yes | text, max. 160 characters | What the flow is called in the list. |
Description description | no | text | What it does. The paragraph that answers, a year from now, whether it may be switched off. |
Trigger triggerType | yes | event, schedule, webhook, manual, polling, file dropped | When it runs. Webhook means a foreign system calls in; file dropped: a matching file lands in the chosen folder. |
Trigger settings triggerConfig | no | depending on the type | Which event, which schedule, which interval (intervalMinutes) or which folder and pattern (folderUlid, pattern). The time mechanics come from automation — here they are only named. |
Webhook secret webhookSecret | with webhook | text | How an incoming call identifies itself. Without a secret a flow cannot even be enabled — an open webhook would be a door without a lock. |
Signature scheme webhookScheme | no | text, max. 40 characters | How the signature is formed. |
Queue queueName | no | text, max. 60 characters | Which queue the flow runs in. A queue of its own stops a large import from holding up mail dispatch. |
Acting user runAsUserUlid | yes | an existing account | In whose name writing happens. Every writing block runs through this identity — the flow can do nothing this account may not, and the audit log says so. |
Brand brandId | no | one of your brands | Which brand the flow works for. |
Variables variables | no | label-to-value mapping | Values valid across the flow — addresses, identifiers, thresholds. Secrets belong here, not in individual blocks. |
Blocks nodes / connections edges | yes | list | The flow itself: what happens and in what order. A block with no incoming records does not run — empty does not mean "once without data" but not at all. |
Block node / after after | — | a single block and its predecessor | Inserts a block at a position while editing. |
Sample input inputItems | — | list of records | Input for Test alone (POST …/nodes/{nodeKey}/test). Empty means: one empty record. |
Blocks per flow (limit) maxNodes | — | number, read-only | The operator limit (see below). The editor warns as soon as the plan exceeds it. |
Test data testPayload | no | structure | Sample data for the trial run. The trial run shows per block what came in and what came out — the only usable way to develop a flow. |
Payload payload | — | structure | The data of a concrete run. |
Bundle bundle | — | structure | An exported flow for import and export. Secrets are not included; they are set anew at the destination. |
Settings & permissions
- Read:
connect.flow.view· Run journal including per-block data:connect.run.view - Build and change:
connect.flow.manage - Start, test, resume:
connect.flow.execute - Set the hub limits:
connect.config.manage(across brands only; by default only the admin)
Hub limits. Limits in the flow list (only with connect.config.manage) sets what applies to all flows of all brands:
| Field | Required | Values / format | What it does |
|---|---|---|---|
Steps per run maxSteps | no | 1 to 1,000,000, default 5,000 | Beyond this a run is aborted — protection against a plan that contains itself. Applies from the next run. |
Blocks per flow maxNodes | no | 1 to 10,000, default 200 | A larger plan is rejected on save, insert and import; an existing flow above it can no longer be enabled. |
Module flag: module.connect. Every writing block goes through the internal API in the name of a user — a flow can therefore never do more than the human it runs as.
FAQ & troubleshooting
The flow runs but nothing happens. Check whether any records arrive at the first block. Without incoming data the chain stands still.
The test run works, the real one does not. The test run uses sample data. Check the real values in the run journal.
A field arrives empty. Usually the mapping is missing, or the foreign system delivers a different field name than expected.