Zum Inhalt springen

Technik

Eine Shopify-Flow-Integration bauen: Trigger, Aktionen und die Fallen, die uns einen Zyklus kosteten

By Jahangir Alam · 4. Juli 2026 · 11 Min. Lesezeit

Kurzfassung: Eine Shopify-Flow-Integration hat drei bewegliche Teile – Trigger (Ereignisse, die Ihre App in Flow ausgibt), Aktionen (Schritte, mit denen Flow in Ihre App zurückruft) und Vorlagen (fertige Workflows). Die Konfigurationen der Erweiterungen sind schlichtes TOML; die Fallen stecken in den undokumentierten Regeln der Plattform. Die beiden, die uns einen echten Debugging-Zyklus kosteten: Feldschlüssel von Triggern und Aktionen folgen entgegengesetzten Schreibweisen, und jedes Feld, das Sie an einem Trigger deklarieren, ist in jedem Payload Pflicht – ein „optionales Referenzfeld“ ist also ein Widerspruch, der Gast-Ereignisse still zerbricht. Hier die vollständige Landkarte, aus dem Ausliefern von 10 Triggern, 3 Aktionen und 6 Vorlagen in QuotWay.

Was eine Flow-Integration ist (und wer sie nutzen kann)

Shopify Flow ist Shopifys No-Code-Baukasten für Automatisierung. Ihre App klinkt sich auf drei Wegen ein:

  • Trigger (flow_trigger) – Ihre App gibt ein Ereignis aus („Angebot eingereicht“), und Händler bauen Workflows, die damit beginnen.
  • Aktionen (flow_action) – ein Flow-Workflow ruft Ihre App auf, damit sie etwas tut („Angebotsstatus aktualisieren“), und übergibt Felder, die die Händlerin konfiguriert hat.
  • Vorlagen (flow_template) – vorgefertigte Workflows, die in der Flow-Vorlagengalerie erscheinen, sodass Händler mit einem funktionierenden Beispiel statt einer leeren Leinwand starten.

Ein Mythos, den man zuerst töten sollte: Flow ist für app-seitige Erweiterungen nicht Plus-exklusiv. Trigger und Aktionen einer öffentlichen App-Store-App stehen Händlern in jedem kostenpflichtigen Shopify-Tarif zur Verfügung, nicht nur in Plus. (Von Händlern selbst geschriebene Flow-Workflows haben eigene Tarifregeln, das ist aber unabhängig von der Verfügbarkeit Ihrer Erweiterungen.) Wir grenzen unsere durch die Paketierung ab – Trigger in unserer Professional-Stufe, Aktionen in Enterprise – nicht, weil die Plattform es erzwingt.

Der dreiteilige Aufbau

Jeder Trigger, jede Aktion und jede Vorlage ist ein eigenes Erweiterungsverzeichnis mit einer shopify.extension.toml. Es gibt kein gemeinsames „Flow-App“-Objekt – Sie setzen die Integration aus vielen kleinen Erweiterungen zusammen.

Trigger: Ihre App → Flow

Ein Trigger deklariert einen Namen und eine Reihe von Feldern, die zu den verfügbaren Daten des Workflows werden. Feldschlüssel sind der öffentliche Payload-Vertrag:

# extensions/flow-quote-submitted/shopify.extension.toml
[[extensions]]
type = "flow_trigger"
name = "Quote submitted"
handle = "quote-submitted"

  [[settings.fields]]
  type = "single_line_text_field"
  key = "Quote id"            # ← Title Case, mit Leerzeichen

  [[settings.fields]]
  type = "number_decimal"
  key = "Total amount"        # Händler ergänzen Bedingungen wie "Total amount >= X"

  [[settings.fields]]
  type = "single_line_text_field"
  key = "Customer id"         # LEERER String bei Gästen — siehe Falle 2

Sie geben ein Ereignis aus, indem Sie die Mutation flowTriggerReceive mit dem Trigger-Handle und einem Payload aufrufen, dessen Schlüssel exakt diesen Feldnamen entsprechen. Wir geben aus einem kleinen Dienst flow/emit bei jedem Zustandswechsel aus (eingereicht, Angebot gesendet, angenommen, gekontert, abgelehnt, abgelaufen, umgewandelt und die drei Freigabeereignisse – insgesamt 10).

Aktionen: Flow → Ihre App

Eine Aktion deklariert die Felder, die eine Händlerin ausfüllt, und eine runtime_url, an die Flow beim Ausführen des Schritts POSTet. Wir leiten alle Aktionen an einen Endpunkt und verteilen nach Handle:

# extensions/flow-update-quote-status/shopify.extension.toml
[[extensions]]
type = "flow_action"
name = "Update quote status"
handle = "update-quote-status"
runtime_url = "/api/flow/action"     # ein Endpunkt für jede Aktion
validation_url = "/api/flow/validate" # Feldprüfung beim Speichern
schema = "./schema.graphql"
return_type_ref = "QuoteActionResult"

  [[settings.fields]]
  type = "single_line_text_field"
  key = "quote_id"            # ← snake_case (das Gegenteil von Triggern!)
  required = true

  [[settings.fields]]
  type = "single_line_text_field"
  key = "target_status"       # IN_REVIEW | DECLINED | EXPIRED
  required = true

Der Handler unter /api/flow/action prüft Shopifys HMAC, verteilt nach Aktions-Handle, ist idempotent bezogen auf action_run_id (Flow kann erneut versuchen) und gibt ein typisiertes Ergebnis passend zu return_type_ref zurück. Wir haben drei Aktionen ausgeliefert: Status aktualisieren, eine Benachrichtigung senden und einer Mitarbeiterin zuweisen – jede am Eingang des Dienstes auf Enterprise begrenzt, nicht an der Route.

Vorlagen: ein funktionierender Ausgangspunkt

Erweiterungen vom Typ flow_template bündeln eine .flow-Datei (die Workflow-Definition) samt Lokalisierungstexten. So bekommt eine Händlerin „Wenn ein hochwertiges Angebot eintrifft, poste nach Slack“, ohne es selbst zu verdrahten. Wir haben sechs ausgeliefert. Der Haken: Vorlagen erscheinen erst nach Prüfung durch das Flow-Team in der Galerie (ein paar Werktage), sie laufen also auf einer anderen Uhr als der Rest Ihrer App.

Die Fallen (jede davon eine Narbe)

Falle Was Sie beißt Die Lösung
Entgegengesetzte Schreibweise der Schlüssel Feldschlüssel von Triggern sind Title Case With Spaces („Total amount“); Feldschlüssel von Aktionen sind snake_case (quote_id). Verwechseln Sie sie, binden die Felder nie. Merken Sie sich die Teilung: Trigger Title Case, Aktionen snake_case.
Alle Trigger-Felder sind Pflicht Jedes Feld, das Sie deklarieren, muss in jedem Payload vorhanden sein. Ein „optionales Referenzfeld“ ist ein Widerspruch – lassen Sie es einmal weg (etwa bei einem Gastangebot ohne Kundin), wird das ganze Ereignis abgelehnt. Nutzen Sie einfache Textfelder, die "" sein dürfen, statt Referenzfeldern; lassen Sie Händler in Flow mit „ist nicht leer“ verzweigen.
Konfigurationsseiten können nicht speichern App-seitige Konfigurationsseiten für einen Schritt sind nur lesendintent.finish({properties}) ist wirkungslos (von Shopify-Mitarbeitenden bestätigt). Eine eigene Auswahl-Oberfläche kann ihre Auswahl nie sichern. Nutzen Sie native [[settings.fields]] plus eine validation_url, die schlechte Werte beim Speichern ablehnt.
Keine Lebenszyklus-Rückrufe für CLI-Trigger In TOML definierte Trigger bekommen keine Webhooks zum An- und Abmelden, Sie können also nicht wissen, wer zuhört. Koppeln Sie das Ausgeben an einen Abonnement-Datensatz, schlägt es geschlossen fehl – niemand bekommt Ereignisse. Geben Sie für jeden berechtigten Shop aus; flowTriggerReceive tut schlicht nichts, wenn niemand zuhört.
.flow-Dateien prüfen sich selbst Vorlagendateien tragen einen SHA-256-Abdruck ihrer selbst und sind Exporte aus dem Editor. Bearbeiten Sie eine von Hand, wird sie abgelehnt. Bearbeiten Sie .flow nie von Hand; exportieren Sie neu aus dem Flow-Editor und lassen Sie händlerspezifische Felder leer. preInstallNote steht in der Lokalisierungs-JSON, nicht im TOML.
Schema-Änderungen brauchen ein abgestimmtes Release Ändern Sie die Felder eines Triggers, müssen Ihre ausgegebenen Payloads zum ausgelieferten Schema passen. Deployen Sie die Erweiterung ohne den Emitter (oder umgekehrt), wird jedes Ereignis abgelehnt. Gemeinsam ausliefern: shopify app deploy und Ihr Backend-Push im Gleichschritt.
Typen sind streng number_decimal muss eine JSON-Zahl sein, kein String; ein Feld vom Typ *_reference will die numerische Legacy-ID, nicht die GID. Wandeln Sie an der Ausgabegrenze um; bevorzugen Sie einfache Felder gegenüber Referenzfeldern (siehe Falle 2).

Die ersten beiden haben uns Debugging-Zeit in Produktion gekostet. „Alle Felder sind Pflicht“ ist besonders hinterhältig, weil es nur die Teilmenge der Ereignisse zerbricht, denen ein Feld fehlt – bei uns Gastangebote (ohne Kunden-ID) und ein paar Randfälle – es sieht also nach einem sporadischen Fehler aus, bis Sie merken, dass er strukturell ist.

Flow in Produktion debuggen

Flow-Fehler sind leise – ein abgelehnter Payload erreicht die Händlerin nicht. Protokollieren Sie beide Seiten der Grenze und suchen Sie danach:

  • Ausgabeseite: Protokollieren Sie bei Erfolg ein flow.emit.sent und ein flow.emit.user_errors, wenn flowTriggerReceive userErrors zurückgibt (eine Schema-Abweichung taucht hier auf).
  • Aktionsseite: Protokollieren Sie das verteilte Handle, die action_run_id und das Ergebnis. HMAC-Fehler und Kurzschlüsse durch Idempotenz sollten je eine Zeile hinterlassen.

Wenn ein Trigger „nicht auslöst“, prüfen Sie zuerst das Ausgabeprotokoll: Sehen Sie sent ohne Fehler, wurde der Payload angenommen und das Problem liegt im Workflow der Händlerin; sehen Sie user_errors, passt Ihr Payload nicht zum ausgelieferten Trigger-Schema (fast immer Falle 6).

Ein vernünftiger erster Meilenstein

  1. Ein Trigger für Ihr wichtigstes Ereignis, mit nur den Feldern, die ein Workflow tatsächlich braucht (weniger Felder = weniger Pflichtfeld-Fallen). Schlüssel in Title Case.
  2. Geben Sie ihn für jeden berechtigten Shop aus Ihrem bestehenden Code für Zustandswechsel aus – ohne Abonnement-Abgrenzung.
  3. Eine Aktion, die an eine einzige runtime_url POSTet, nach Handle verteilt wird, HMAC-geprüft und idempotent bezogen auf action_run_id ist, mit einer validation_url statt einer Konfigurationsseite.
  4. Deployen Sie Erweiterung und Backend gemeinsam und prüfen Sie es in einem Entwicklungsshop mit einem echten Workflow.
  5. Ergänzen Sie Vorlagen zuletzt – sie hängen an der Prüfung durch das Flow-Team, lassen Sie sie also nicht den Start von Triggern und Aktionen blockieren.

Trigger und Aktionen sind einzeln klein; die Schwierigkeit der Integration liegt ganz in den obigen Plattformregeln. Bringen Sie die Schreibweise und den Pflichtfeld-Vertrag am ersten Tag in Ordnung, und der Rest ist das Verdrahten von Ereignissen, die Sie ohnehin schon ausgeben.

Weiterführendes

Verwandte Artikel

So funktioniert QuotWay in Ihrem Shop.

Wir möchten Analyse-Cookies setzen, um zu verstehen, wie die Website genutzt wird. Sie sind nicht erforderlich – eine Ablehnung ändert nichts an der Funktion der Website, und Sie können Ihre Entscheidung jederzeit ändern auf unserer Datenschutzseite.