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 lesend – intent.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.sentund einflow.emit.user_errors, wennflowTriggerReceiveuserErrors zurückgibt (eine Schema-Abweichung taucht hier auf). - Aktionsseite: Protokollieren Sie das verteilte Handle, die
action_run_idund 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
- 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.
- Geben Sie ihn für jeden berechtigten Shop aus Ihrem bestehenden Code für Zustandswechsel aus – ohne Abonnement-Abgrenzung.
- Eine Aktion, die an eine einzige
runtime_urlPOSTet, nach Handle verteilt wird, HMAC-geprüft und idempotent bezogen aufaction_run_idist, mit einervalidation_urlstatt einer Konfigurationsseite. - Deployen Sie Erweiterung und Backend gemeinsam und prüfen Sie es in einem Entwicklungsshop mit einem echten Workflow.
- 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
- Shopify: Flow für App-Entwickler, Trigger, Aktionen, Vorlagen
- Schwesterbeitrag: Eine Shopify-Sidekick-App-Erweiterung bauen
Verwandte Artikel
So funktioniert QuotWay in Ihrem Shop.