Diese Anleitung zeigt das Szenario, das wir dafür in Make bauen: Wahl des Triggers, Feldzuordnung, Bestellpositionen, Schutz vor Duplikaten, Erstattungen und Stornierungen und zum Schluss ein Slack-Alarm. Du kannst Schritt für Schritt mitbauen, auch wenn es dein erstes richtiges Szenario ist.
Zuerst entscheiden: eine Zeile pro Bestellung oder pro Position?
Kläre das, bevor du Make öffnest, denn es verändert die ganze Tabelle.
- Eine Zeile pro Bestellung passt, wenn es dir um Umsatz, Kunden und Bestellstatus geht. Bestellung #1042 ist eine Zeile, die Produkte stehen gesammelt in einer Zelle „Artikel“.
- Eine Zeile pro Position passt, wenn es dir um Produkte geht: Lagerplanung, Nachbestellungen beim Lieferanten, welche SKU mit welcher zusammen verkauft wird. Bestellung #1042 mit drei Produkten wird zu drei Zeilen mit derselben Bestellnummer.
Brauchst du beides, nimm zwei Tabellenblätter in derselben Datei und befülle sie aus demselben Szenario. Lass nicht ein Blatt beide Aufgaben erledigen.
Schritt 1: Trigger wählen: Watch orders oder Watch events
Die Shopify-App in Make bietet zwei sinnvolle Einstiege.
Shopify > Watch orders ist ein Polling-Trigger. Make fragt deinen Shop im Rhythmus des Szenario-Zeitplans ab (alle 15 Minuten, stündlich, wie du willst) und holt Bestellungen, die es noch nicht kennt. Am einfachsten einzurichten und für die meisten kleinen Shops völlig ausreichend. Zwei Dinge solltest du wissen:
- Es ist nicht sofort. Eine Bestellung von 10:01 Uhr landet vielleicht erst um 10:15 Uhr in der Tabelle.
- Jede geplante Abfrage verbraucht Credits, auch wenn keine neuen Bestellungen da sind. Ein 5-Minuten-Takt in einem ruhigen Shop verbrennt Credits für leere Durchläufe.
Shopify > Watch events ist der sofortige, webhook-basierte Trigger. Shopify schickt die Bestellung in dem Moment an Make, in dem das Ereignis passiert. Du wählst ein Shopify-Webhook-Topic wie orders/create, orders/paid, orders/cancelled oder refunds/create (Make listet sie eventuell im Enum-Stil, zum Beispiel ORDERS_CREATE). Keine leeren Abfragen, kein Warten. Der Haken: Jeder Trigger hört auf ein Topic, und wenn Shopify dasselbe Ereignis zweimal schickt (es wiederholt die Zustellung, wenn sie nicht bestätigt wird), brauchst du eine eigene Duplikatprüfung. Mehr dazu in Schritt 5.
Unser Standard: Watch events auf orders/paid, wenn die Tabelle für die Buchhaltung ist, orders/create, wenn sie für den Versand ist. Watch orders nur, wenn der Kunde die einfachste Lösung will und die Verzögerung egal ist.
Eine Falle bei Watch orders: Das Modul merkt sich, wo es aufgehört hat. Klickst du beim Testen zweimal auf „Run once“, liefert der zweite Lauf oft nichts. Klick mit rechts auf das Modul und wähle, ab wo es starten soll, oder lege eine neue Testbestellung an.
Schritt 2: Tabelle vorbereiten
Lege die Kopfzeile an, bevor du das Google-Sheets-Modul baust, damit Make die Spalten lesen kann. Ein Aufbau, der sich für das Protokoll auf Bestellebene bewährt:
| Spalte | Quellfeld |
|---|---|
| Bestell-ID | id |
| Bestellnummer | name (z. B. #1042) |
| Erstellt | created_at |
| Kunden-E-Mail | email |
| Gesamt | total_price |
| Währung | currency |
| Zahlungsstatus | financial_status |
| Versandstatus | fulfillment_status |
| Artikel | per Formel (siehe unten) |
| Status | wird vom Erstattungs-/Storno-Szenario geschrieben |
Die Bestell-ID gehört in Spalte A. Sie ist der Schlüssel, an dem alles andere hängt. Die Bestellnummer (#1042) sieht schöner aus, aber Shopify verwendet in Erstattungs- und Storno-Daten die numerische ID. Die Quellfelder sind die Namen aus Shopifys Bestell-Webhook, den Watch events liefert. Watch orders kann manche Felder anders benennen; wähle sie im Mapping-Panel aus.
Schritt 3: Felder zuordnen (eine Zeile pro Bestellung)
Füge Google Sheets > Add a Row hinzu, wähle Datei und Tabellenblatt, stelle „Table contains headers“ auf Yes. Dann erscheinen die Spalten als Felder.
Die meisten Felder ordnest du direkt zu. Ein paar brauchen eine Funktion:
- Erstellt:
formatDate(1.created_at; "YYYY-MM-DD HH:mm"; "Europe/Berlin"). Ersetze die Zeitzone durch die deines Shops. Rohe ISO-Daten lassen sich sortieren, sind aber schwer zu lesen. - Gesamt: Shopify schickt Preise als Text. Soll die Tabelle summieren, nutze
parseNumber(1.total_price; ".")oder formatiere die Spalte in Sheets als Zahl. - Artikel:
join(map(1.line_items; "title"); ", ")ergibt „Leinenhemd, Canvas-Tasche“ in einer Zelle. Mit Mengen? Dann ein Iterator plus Tools > Text aggregator mit{{quantity}} × {{title}}und den aggregierten Text zuordnen. - Versandstatus ist bei offenen Bestellungen leer. Fang das ab:
ifempty(1.fulfillment_status; "unfulfilled").
Lass das Szenario einmal mit einer echten Testbestellung laufen und prüf jede Spalte.
Schritt 4: Eine Zeile pro Position mit dem Iterator
Für ein Protokoll auf Produktebene setzt du Flow Control > Iterator zwischen Trigger und Sheets-Modul und ordnest line_items[] dem Feld Array zu. Jedes Produkt der Bestellung wird so zu einem eigenen Bundle.
Im Modul Add a Row ordnest du Bestellfelder aus dem Trigger zu (Bestellnummer, Datum, E-Mail) und Produktfelder aus dem Iterator (title, variant_title, sku, quantity, price). Ergänze eine Spalte Positions-ID mit der id aus dem Iterator. Bestell-ID plus Positions-ID ist hier dein eindeutiger Schlüssel.
Zu den Credits: Jedes Bundle, das Add a Row durchläuft, kostet Credits: Eine Bestellung mit 10 Artikeln heißt 10 Ausführungen dieses Moduls. Bei großen Bestellungen ersetzt du Add a Row durch einen Array aggregator (Source module: der Iterator) und danach Google Sheets > Bulk Add Rows (advanced). Ein Schreibvorgang pro Bestellung statt pro Artikel, und während eines Sales stößt du deutlich seltener an Googles Rate Limits.
Schritt 5: Doppelte Zeilen verhindern (erst suchen, dann hinzufügen)
Duplikate entstehen an drei Stellen: Webhook-Wiederholungen, jemand startet das Szenario erneut, oder ein Watch-Orders-Trigger wird auf einen früheren Punkt zurückgesetzt. Die Lösung ist immer dieselbe: vor dem Schreiben prüfen.
Naheliegend ist Google Sheets > Search Rows mit Filter auf die Bestell-ID und nur dann eine Zeile anlegen, wenn nichts gefunden wurde. Der Haken: Findet Search Rows nichts, gibt es nichts aus, und die Module danach laufen einfach nicht. Dein Zweig „hinzufügen, wenn nicht vorhanden“ wird nie ausgelöst.
Zwei Auswege:
- Aggregator-Trick. Setze direkt hinter Search Rows einen Array aggregator (Source module: Search Rows). Der Aggregator gibt auch bei leerer Suche ein Bundle aus. Dann ein Router: Route 1 mit Filter
length(Array) = 0→ Add a Row; Route 2 mitlength(Array) > 0→ Update a Row (mit der Zeilennummer aus dem Array) oder einfach Ende. - Data store. Leg in Make einen Data store mit der Bestell-ID als Schlüssel an. Vor dem Schreiben nutzt du Data store > Check the existence of a record; das liefert ein Ja/Nein, auf das du filtern kannst. Nach dem Schreiben Add/replace a record. Das ist schneller als die Suche in einer großen Tabelle und hängt nicht davon ab, dass niemand Spalte A bearbeitet.
Im Positionsmodus suchst du nach Bestell-ID + Positions-ID oder prüfst die Bestellung einmal vor dem Iterator und überspringst sie komplett, wenn sie schon da ist.
Schritt 6: Erstattungen und Stornierungen
Lösch keine Zeilen, wenn eine Bestellung erstattet wird. Gelöschte Zeilen zerstören Summen, die schon jemand gemeldet hat. Aktualisiere die Zeile stattdessen.
Bau ein zweites, kleines Szenario:
- Shopify > Watch events mit dem Topic
refunds/create(und eine Kopie mitorders/cancelled). - Google Sheets > Search Rows auf die Bestell-ID. Bei Erstattungen steht sie im Feld
order_idder Daten, bei Stornierungen ist es dieidder Bestellung selbst. - Google Sheets > Update a Row mit der gefundenen Zeilennummer: Status auf „Erstattet“, „Teilweise erstattet“ oder „Storniert“ setzen und den Erstattungsbetrag in eine eigene Spalte schreiben. Teilerstattungen sind häufig, also überschreib nicht den ursprünglichen Gesamtbetrag.
Wurde eine stornierte Bestellung nie eingetragen (storniert vor der Zahlung, während du auf orders/paid triggerst), findet die Suche nichts und das Szenario endet still. Meist genau richtig.
Schritt 7: Slack-Alarm hinzufügen
Häng Slack > Create a Message an das Ende des Hauptszenarios. Nicht bei jeder Bestellung alarmieren, sonst schaltet dein Team den Kanal nach einer Woche stumm. Setz stattdessen einen Filter auf die Route:
- Bestellsumme über einem Schwellenwert deiner Wahl,
- Bestellungen mit Kundennotiz (
noteist nicht leer), - oder ein bestimmtes Produkt bzw. eine bestimmte Versandart.
Eine brauchbare Nachricht: Neue Bestellung {{1.name}}, {{1.total_price}} {{1.currency}}, {{1.email}} plus Link zur Bestellung im Shopify-Admin.
Fehlerbehandlung, die wirklich hilft
Rechtsklick auf ein Modul, dann Add error handler:
- Am Google-Sheets-Modul: Retry (früher Break) mit automatischen Wiederholungen. Google meldet in Stoßzeiten Rate-Limit-Fehler, und ein neuer Versuch ein paar Minuten später klappt fast immer.
- Am Slack-Modul: Skip (früher Ignore). Ein fehlgeschlagener Alarm soll den Lauf nicht als Fehler markieren, wenn die Zeile geschrieben wurde.
- Resume ist praktisch, wenn eine Abfrage fehlschlägt und du lieber einen Ersatzwert („unbekannt“) schreibst als abzubrechen.
- Commit und Rollback spielen nur bei Modulen mit Transaktionen eine Rolle, etwa Data stores. Schreibvorgänge in Google Sheets lassen sich nicht zurückrollen. Ein Grund mehr, vorher auf Duplikate zu prüfen.
Aktiviere außerdem in den Szenario-Einstellungen Store incomplete executions, damit eine fehlgeschlagene Bestellung auf dich wartet, statt zu verschwinden; Retry setzt das voraus. Noch ein Grund für Fehlerbehandlung: Standardmäßig schaltet Make ein Szenario nach 3 Fehlern in Folge ab, und ein Szenario mit sofortigem Trigger wie Watch events schon nach dem ersten.
Kurze Test-Checkliste
- Testbestellung mit zwei verschiedenen Produkten anlegen und beide Tabellenblätter prüfen.
- Dasselbe Bundle erneut laufen lassen und sicherstellen, dass keine zweite Zeile entsteht.
- Einen Artikel erstatten und prüfen, ob Status- und Erstattungsspalte aktualisiert werden.
- Eine unbezahlte Bestellung stornieren und sicherstellen, dass nichts kaputtgeht.
- Nach einem Tag den Szenarioverlauf ansehen, um den Credit-Verbrauch zu prüfen.