Formulare in Workflows

Zuletzt aktualisiert 25 May 2026

Ein Formular links löst rechts einen Workflow aus, wobei eine Form-Respond-Aktion innerhalb von 20 Sekunden eine eigene Antwort an den Absender zurückschreibt

Wenn Sie bereits mit Workflows und Flexie Scripting gearbeitet haben, wird Ihnen alles auf dieser Seite vertraut vorkommen. Es ist derselbe __data-Notizblock und dieselbe Art von Listener- und Aktions-Verdrahtung, nur speziell für Formulare.

Die drei Formular-Submit-Listener

Jedes Formular-Submit-Ereignis landet als Workflow-Listener, den Sie als Quelle eines Workflows nutzen können (der allererste Schritt). Welcher Listener gilt, hängt von der Art des Formulars ab:

EXTERN (ÖFFENTLICH) Listener virtual_workflow.form_submit INTERN · ENTITÄTSGEBUNDEN Listener form.internal_submit INTERN · VIRTUELL Listener virtual_workflow.internal_virtual_entity_submit DATENSATZTYP __virtual kein Datensatzkontext DATENSATZTYP der gebundene Typ Lead, Contact, Deal, … DATENSATZTYP __virtual kein Datensatzkontext FELDER UNTER __data. form_submission FELDER UNTER internal_form_ submission.data FELDER UNTER internal_form_ submission.data
Extern (öffentlich)
Listener-Schlüssel
virtual_workflow.form_submit
Workflow-Datensatztyp
__virtual
Felder landen unter
__data.form_submission.<key>
Intern, entitätsgebunden
Listener-Schlüssel
form.internal_submit
Workflow-Datensatztyp
Der Datensatztyp, an den das Formular gebunden ist (Lead, Contact, Deal, …)
Felder landen unter
__data.internal_form_submission.data.<key>
Intern, virtuell
Listener-Schlüssel
virtual_workflow.internal_virtual_entity_submit
Workflow-Datensatztyp
__virtual
Felder landen unter
__data.internal_form_submission.data.<key>

Wenn Sie einen Workflow bauen, dessen Quelle „Listener" ist, und einen dieser Listener auswählen, blendet der Builder die Listener aus, die nicht zum Datensatztyp des Workflows passen. So können Sie nicht versehentlich den falschen Listener mit dem falschen Datensatztyp kombinieren.

1. Der externe (öffentliche) Formular-Listener

Listener-Schlüssel: virtual_workflow.form_submit Workflow-Datensatztyp: __virtual

Was Sie in __data erhalten

{
  "form_submission": {
    "<form field key>": "<submitted value>",
    "<form field key>": "<submitted value>",
    "attachments": [
      { "...file metadata..." }
    ]
  }
}

Die Felder liegen direkt unter form_submission, ohne verschachtelten data-Wrapper und ohne Metadaten zum Absender, denn öffentliche Übermittlungen sind anonym.

Werte auslesen

{# Form had fields "First Name", "Email", "Notes" #}
Hi {{ __data.form_submission['First Name'] }},

We received your message:
{{ __data.form_submission.Notes }}

We'll reply to {{ __data.form_submission.Email }}.

(Klammer-Schreibweise für Schlüssel mit Leerzeichen, siehe Übermittlungen: Klammer-Schreibweise.)

Nützliche Muster

Aus einer öffentlichen Formularübermittlung einen Lead erstellen:

  1. Trigger: dieser Listener.
  2. Entscheidung: prüfen, dass {{ __data.form_submission['Email'] }} nicht leer ist.
  3. Aktion: einen Lead mit Feldwerten aus __data.form_submission.<key> erstellen.
  4. Aktion: eine eigene Antwort an den Absender zurückschreiben, siehe Eine eigene Antwort schreiben.

2. Der interne entitätsgebundene Formular-Listener

Listener-Schlüssel: form.internal_submit Workflow-Datensatztyp: Der Datensatztyp, an den das Formular gebunden ist (Lead, Contact, …).

Was Sie in __data erhalten

{
  "internal_form_submission": {
    "date_added": "2026-05-25 12:34:56",
    "__submitted_from_user_id": 7,
    "__submitted_from_user_full_name": "John Doe",
    "data": {
      "<form field key>": "<submitted value>",
      "<form field key>": "<submitted value>"
    }
  }
}

Beachten Sie die zwei Unterschiede gegenüber dem externen Formular:

  • Der Wurzelschlüssel ist internal_form_submission.
  • Die Felder sind unter einem data-Unterschlüssel verschachtelt, zusammen mit den Absender-Metadaten.

Außerdem sind, da der Workflow auf dem Datensatz läuft, gegen den das Formular geöffnet wurde, die Felder dieses Datensatzes ebenfalls auf der obersten Ebene verfügbar:

Contact's first name (from the record):    {{ first_name }}
Form's first-name field (from submission): {{ __data.internal_form_submission.data['First Name'] }}

Nützliche Muster

Den Datensatz aus dem Formular aktualisieren:

  1. Trigger: dieser Listener.
  2. Aktion: den Contact aktualisieren und die Felder aus __data.internal_form_submission.data.<key> setzen.

Festhalten, wer es war:

{# In a workflow step's "Add a note" action #}
Form "Qualification" submitted by
{{ __data.internal_form_submission.__submitted_from_user_full_name }}
on {{ date(__data.internal_form_submission.date_added, "M j, Y H:i") }}.

3. Der interne virtuelle Formular-Listener

Listener-Schlüssel: virtual_workflow.internal_virtual_entity_submit Workflow-Datensatztyp: __virtual

Was Sie in __data erhalten

{
  "internal_form_submission": {
    "__submitted_from_user_id": 7,
    "__submitted_from_user_full_name": "John Doe",
    "data": {
      "<form field key>": "<submitted value>"
    }
  }
}

Gleiche Wurzel und gleiche Verschachtelung wie beim entitätsgebundenen Formular, aber kein date_added und keine Felder des aktuellen Datensatzes (der Workflow läuft auf dem virtuellen Typ).

Nützliche Muster

Aus einem virtuellen Formular einen neuen Datensatz erzeugen:

  1. Trigger: dieser Listener.
  2. Aktion: einen Lead / Contact / Case mit den Feldern aus __data.internal_form_submission.data.<key> erstellen.
  3. Optional: die ID des neuen Datensatzes (__data.__entity_inserted_id) speichern und mit Schritten fortfahren, die sie benötigen.

Selbst einen Zeitstempel setzen:

Da dieser Listener kein date_added enthält, verwenden Sie now() in Ihrem ersten Schritt, um den Moment festzuhalten:

{% set submittedAt = now() %}

…und schreiben Sie diesen dann in jeden Datensatz, den Sie erstellen.

Direkter Vergleich: welche Wurzel, welche Verschachtelung, welche Metadaten?

Extern (öffentlich)
Listener-Schlüssel
virtual_workflow.form_submit
Workflow-Datensatztyp
__virtual
__data-Wurzel
form_submission
Felder verschachtelt unter
(der Wurzel, kein data-Wrapper)
date_added
Absender-Benutzer-ID / Name
Felder auf oberster Ebene
Intern, entitätsgebunden
Listener-Schlüssel
form.internal_submit
Workflow-Datensatztyp
Der gebundene Typ (Lead, Contact, …)
__data-Wurzel
internal_form_submission
Felder verschachtelt unter
data
date_added
Absender-Benutzer-ID / Name
Felder auf oberster Ebene
✓ (der gebundene Datensatz)
Intern, virtuell
Listener-Schlüssel
virtual_workflow.internal_virtual_entity_submit
Workflow-Datensatztyp
__virtual
__data-Wurzel
internal_form_submission
Felder verschachtelt unter
data
date_added
Absender-Benutzer-ID / Name
Felder auf oberster Ebene

Merken Sie sich das; es ist der Spickzettel, der den häufigsten Fehler bei Formular-Workflows verhindert (falscher Pfad zum Wert).

Mitten im Workflow ein Formular an einen Nutzer schicken

Die Aktion „Trigger Internal Form"

Ein Workflow kann während seiner Ausführung ein Formular an einen angemeldeten Nutzer schicken und dann fortfahren, sobald der Nutzer es übermittelt.

Die Einstellungen der Aktion:

Einstellung Was sie festlegt
Welches Formular Das interne Formular, das geschickt werden soll. (Muss ein internes Formular sein.)
Welcher Nutzer Der aktuelle Eigentümer, ein bestimmter Nutzer, der Nutzer, der den Workflow ausgelöst hat, oder eine beliebige regelbasierte Auswahl.
(Entitätsgebundene Formulare) Welcher Datensatz Der Datensatz, an den die Übermittlung angehängt werden soll, in der Regel der aktuelle Datensatz, auf dem der Workflow läuft.

Die Aktion ist sofortig, sie reiht den Schritt nicht in eine Warteschlange ein. Das Formular erscheint sofort beim gewählten Nutzer in seiner Oberfläche, und der nächste Schritt des Workflows läuft, sobald dieser Nutzer das Formular übermittelt. Wenn Sie ein langes Warten zeitlich begrenzen müssen (z. B. „wenn es niemand innerhalb von 24 Stunden ausfüllt, eskalieren"), kombinieren Sie dies mit einem Zweig im Stil eingeschränkter Zeiten.

Es gibt zwei Varianten der Aktion:

  • form.triggerinternal, für Workflows auf einem echten Datensatztyp (das Formular wird an diesen Datensatz angehängt).
  • form.triggerinternal.virtual, für Workflows auf dem virtuellen Datensatztyp.

Der Builder zeigt Ihnen die richtige für den Workflow, in dem Sie sich befinden.

Eine eigene Antwort pro Übermittlung schreiben

Das ist das Muster, das aus einem Formular eine kleine Request/Response-API macht: Der Absender wartet nach dem Klick auf Senden einen Moment, während der Workflow entscheidet, was er antworten soll, und sieht dann eine auf seine Eingaben zugeschnittene Antwort.

So funktioniert es

ABSENDER klickt auf Senden Browser fragt Flexie ab WORKFLOW Schritte laufen irgendwo im Baum Form Respond ≤ 20 Sek. EIGENE ANTWORT message / redirect / error / json FALLBACK Standardantwort des Formulars (nach 20 Sek.)
  1. Der Absender klickt auf Senden.
  2. Flexie speichert die Übermittlung und startet den Workflow.
  3. Das Frontend fragt bis zu 20 Sekunden lang ab und wartet darauf, dass der Workflow eine Antwort schreibt.
  4. Der Workflow hat irgendwo in seinem Baum eine Form-Respond-Aktion, die die Antwort erzeugt.
  5. Wenn diese Aktion läuft, wird die Antwort an den abfragenden Absender ausgeliefert, und er sieht sie.
  6. Vergehen 20 Sekunden, ohne dass eine Form-Respond-Aktion feuert, fällt das Formular auf sein Standardverhalten nach dem Absenden zurück (die Nachricht oder Weiterleitung, die in den Einstellungen des Formulars festgelegt ist).

Die Aktion „Form Respond"

Die Aktion hat zwei Varianten:

  • form.form_respond, für Workflows mit entitätsgebundenen internen Formularen.
  • virtual_workflow.form_respond, für Workflows mit externen und virtuellen Formularen.

Die Einstellungen:

Einstellung Was sie bewirkt
Antworttyp Einer von message, redirect, error, json (siehe unten).
Antwortwert Der Inhalt der Antwort, berechnet mit Flexie Scripting.

Form der Antwort

Es gibt genau vier Antworttypen. Wählen Sie den, der dem entspricht, was der Browser des Absenders tun soll:

Antworttyp Was der Absender sieht Nützlich für
message Eine Bestätigungsnachricht, die auf dem Formular angezeigt wird „Danke, wir melden uns bei Ihnen unter {{ __data.form_submission.Email }}."
redirect Der Browser navigiert zu einer URL Sie auf eine Danke-Seite zu schicken, die von ihren Eingaben abhängt
error Eine rote Fehlermeldung auf dem Formular (das Formular bleibt mit ihren Eingaben offen) Eine Übermittlung mit Begründung ablehnen („Diese E-Mail ist bereits hinterlegt, bitte melden Sie sich stattdessen an.")
json Ein roher JSON-Body Wenn Ihr Frontend die Submit-URL des Formulars per JavaScript aufruft und die Antwort programmatisch statt als gerenderte Nachricht möchte

Beispiel: verzweigte eigene Nachricht

Trigger:  Listener — virtual_workflow.form_submit
Step 1:   Decision — does {{ __data.form_submission['Email'] }}
          match an existing contact?

  Yes ─►  Form Respond (error):
          "An account already exists for that email,
           please reset your password."

  No  ─►  Step 2: Create a Contact
          Step 3: Form Respond (redirect):
          "https://www.yoursite.com/welcome
            ?id={{ __data.__entity_inserted_id }}"

Hinweise zum Timing

  • Das Polling-Fenster beträgt 20 Sekunden. Eine Form-Respond-Aktion, die später feuert, erreicht den Absender nicht; nur die Standardantwort tut das.
  • Wenn Ihr Workflow lange braucht, bevor er den Form-Respond-Schritt erreicht (z. B. macht er zuerst einen langsamen Webhook-Aufruf), lassen Sie das Formular besser seine Standardantwort zurückgeben, erledigen die lange Arbeit asynchron und benachrichtigen den Absender anschließend auf anderem Weg (E-Mail, SMS).
  • Die Standardantwort des Formulars (in den Formulareinstellungen festgelegt) ist immer der Fallback. Es lohnt sich, sie für sich genommen sinnvoll zu gestalten („Danke, wir melden uns bald"), statt sich darauf zu verlassen, dass Form Respond immer rechtzeitig feuert.

Formulare mit anderen Workflow-Bausteinen kombinieren

Formulare fügen sich in dieselben Workflow-Muster ein wie jeder andere Listener-Trigger:

  • Virtuelle Bedingungen: nach den Werten in __data.form_submission.* oder __data.internal_form_submission.data.* verzweigen.
  • Lookups: mit findOne / findMany prüfen, ob ein übermittelter Wert bereits in Ihren Daten existiert.
  • Die Webhook-Aktion: die Übermittlung an ein anderes System weiterleiten.
  • Der KI-Schritt: die KI die Übermittlung klassifizieren lassen („sieht das nach einem Vertriebs-Lead oder einer Support-Frage aus?") und verzweigen.

Schnellreferenzkarte

EXTERNAL public form
  listener:           virtual_workflow.form_submit
  record type:        __virtual
  read fields as:     {{ __data.form_submission['<key>'] }}
  no submitter info, no date

INTERNAL entity-bound form
  listener:           form.internal_submit
  record type:        the bound type (Lead, Contact, …)
  read fields as:     {{ __data.internal_form_submission.data['<key>'] }}
  read submitter as:  {{ __data.internal_form_submission.__submitted_from_user_full_name }}
  read timestamp as:  {{ __data.internal_form_submission.date_added }}
  top-level fields:   the record's own fields (e.g. {{ first_name }})

INTERNAL virtual form
  listener:           virtual_workflow.internal_virtual_entity_submit
  record type:        __virtual
  read fields as:     {{ __data.internal_form_submission.data['<key>'] }}
  read submitter as:  {{ __data.internal_form_submission.__submitted_from_user_full_name }}
  (no date_added — use now() if you need one)

WORKFLOW ACTIONS
  form.triggerinternal            push an internal entity-bound form to a user
  form.triggerinternal.virtual    push an internal virtual form to a user
  form.form_respond               write custom response (entity-bound)
  virtual_workflow.form_respond   write custom response (external / virtual)

RESPONSE TYPES (for *form_respond actions)
  message    — confirmation message on the form
  redirect   — send the browser to a URL
  error      — red error message, form stays open
  json       — raw JSON body for JS callers

RESPONSE WINDOW
  20 seconds from submit; after that, the form's default response is used.

Zurück zu