Was der Ablauf leistet: Menschen, die sich fuer ein Webinar angemeldet und es
nicht besucht haben, per WhatsApp zum naechsten Termin einladen und mit einem
Klick dort anmelden.
Zwei Phasen, nicht vermischen:
Dieses Runbook beschreibt Phase 1.
Lies zuerst diesen Abschnitt zu Ende, dann Station 1 bis 10 der Reihe nach.
Die Stationen bauen aufeinander auf. Station 7 (die Kette) muss stimmen, bevor
der erste Batch rausgeht, sonst laufen Zusagen ins Leere und man merkt es erst,
wenn Menschen sich beschweren.
Reihenfolge fuer einen kompletten Lauf: 1 → 2 → 3 → 4 → 5 → 7 → 8 →
6 (mit wachsenden Batches) → 9 laeuft nebenher → 10 vor jedem Batch.
Was Du auf keinen Fall tust:
⚠️ Alles, was ein <Datum> im Namen traegt, wird pro Lauf NEU angelegt.
Die Zeilen ohne Datum sind dauerhaft.
Superchat-Kontaktlisten
| Rolle | ID | Anzahl 02.08. |
|---|---|---|
Kohorte AW_NT (30.06.2026) | cl_IKgNIECJ0aZM88a01FwHj | 1.785 |
Batch AW_NT_zu_senden | cl_5GTatu9ROxvYg4StuUIfb | 0 (nach Versand leer) |
Buchfuehrung AW_NT_gesendet (30.06.) | cl_Vb0sN8sQ5aEDwSBwB2NI8 | 32 |
Sperre EW_Anmeldung (04.08.2026) | cl_wB1rUZGwR0eYGS5ZNLmJ3 | 1.751 |
Sperre Whatsapp OptOut | cl_Ud85EpLOJ9sH124cwpHPN | 65 |
Sperre AW_Optout | cl_d2FFMkdAwKtjSukmQurTF | 134 |
Sperre Kein Optin | cl_S60u79592V4UeykKb05Md | 214 |
Sperre Kontakt nicht auf Whatsapp | cl_81meqYaFUXBmgdWfRcV0T | 1.101 |
Sperre NUMMER NICHT MEHR KONTAKTIEREN | cl_w8MxyooN31biL4qIGhLU6 | 2 |
⚠️ EW_Anmeldung stand hier bis 01.08.2026 als „Anmeldungen" statt als Sperre.
Das ist die Tabelle, aus der man beim Bauen die IDs kopiert. Wer die fuenf fett
markierten nahm, bekam einen Pool von 1.677 statt 1.574 — also **103 Menschen,
die bereits fuer den 04.08. eingetragen sind**, haetten „Du warst leider nicht dabei,
melde Dich an" bekommen. Zum Vergleich: die Falle, vor der Station 5 ausdruecklich
warnt (AW_Optout vergessen), kostet eine Person. Diese kostete 103, und es gab
keine Warnung.
Superchat-Workflows (GET /v1/workflow-file-nodes?type=WORKFLOW)
| Workflow | ID | Zustand |
|---|---|---|
Riegel AW_Automations // Webinarjam (Zapier) -> Superchat | wffn_IuaPOdZg9qRk4ugCNEfI3 | ACTIVE |
Konversion 2026-08-04 Webinar-Einladung zu Zapier | wffn_0cdLaw4o32tUMMPj7qW2M | ACTIVE |
AW Anmeldung // Opt-in Verwaltung | wffn_t86e1ZoYfjvAfmc17OrOg | ACTIVE |
Allgemein WhatsApp // Opt-in Opt-Out Verwaltung | wffn_z6KrdoUOek7HVWZvS0i2K | ACTIVE |
⚠️ TEST Automation - 25.06.2026 | wffn_qqZMzxmWF2niBPAyzRNvf | ACTIVE — vor dem Lauf pruefen, ob die mitfeuert |
⚠️ Die Route braucht zwingend ?type=WORKFLOW. Ohne den Parameter antwortet sie
200 mit leerem Array, und man haelt es fuer „es gibt keine Workflows". GET /v1/workflows
und /v2/workflows sind 410 Gone. Ein Kaltstart-Pruefer ist am 01.08.2026 genau
darueber gestolpert und kam an Station 7 nicht weiter.
Zapier (Ordner Superchat, 0195b328-ea70-bb9c-cd10-96b7370d5da9)
| Zap | ID | Zustand |
|---|---|---|
| Antwort auf Webinar-Einladung → Anmeldung | 367085449 | AN |
| Template sent → gesendet-Liste | 370195944 | AN |
| Sending Failed → „nicht auf Whatsapp" | 367463088 | AN |
| (EW) AW_angemeldet → Kontaktliste | 371000532 | AN |
| Abmeldung // Wortvarianten → Opt-out | 374885742 | AN |
Webinare, beide braucht man:
| Rolle | ID | Wofuer |
|---|---|---|
| Quelle (woher die Kohorte kommt) | Webinar 67, Schedule 644, Termin 30.06.2026 | Station 1, Export der Nicht-Teilnehmer |
| Ziel (wohin angemeldet wird) | EverWebinar 62, Session 650, Termin 04.08.2026 20:00 | Station 7, Anmelde-Zap |
⚠️ Die Quell-ID fehlte hier bis 01.08.2026 komplett. Ein falsches webinar= liefert
still eine falsche Kohorte, und das merkt man erst, wenn 1.800 falsche Menschen
angeschrieben sind.
⚠️ Es ist ein EverWebinar, wird aber ueber die WebinarJam-Zapier-App
eingetragen. Das verwirrt zuverlaessig, ist aber richtig so.
Zugaenge: liegen in ClientShare, nicht in dieser Datei und nicht im Chat.
Hinterlegt sind Superchat (API-Key, Mail, Passwort) und WebinarJam (Mail, Passwort).
⚠️ WIDERLEGT 01.08.2026: clientshare secrets --kunde domi gibt es NICHT. Die CLI
kennt nur publish|new|ls|rm|mv|versions|rollback|redirect. Der Lesezugriff laeuft ueber
die Management-API (/_api/kunden/<kunde>/vars) und braucht einen Bearer-Key, oder ueber
das Cockpit im Browser. Der falsche Befehl stand hier genau an der Stelle, an der man
unter Zeitdruck ist.
| Was | Wo | Fuer wen |
|---|---|---|
| Diese Datei | 03-runbook-reaktivierung.md | die Quelle. Wer arbeitet, liest hier. |
| Lesbare Seite | https://domi.share.benediktglass.com/carmen-runbook/ | zum Weitergeben |
| Kennzahlen-Dashboard | https://domi.share.benediktglass.com/carmen-dashboard/ | Domi, Ueberblick |
Die Seite wird aus dieser Datei erzeugt, nicht gepflegt:
python3 render-doku.py && clientshare publish /tmp/carmen-doku --kunde domi --slug carmen-runbook
⚠️ Wer die HTML-Seite direkt bearbeitet, verliert es beim naechsten Rendern.
| Zweck | Aufruf |
|---|---|
| Superchat-API | node ~/api-lab/cdp/scapi.mjs METHOD /pfad '<json>' |
| Zapier-API | ZAPI_CDP=9243 node ~/api-lab/cdp/zapi.mjs METHOD /pfad '<json>' |
| WebinarJam | eingeloggte Sitzung im CDP-Chrome domi-ai (:9262), fetch aus dem Seiten-Kontext |
| WhatsApp (Testen) | python3 ~/.claude/skills/whatsapp-melden/wa.py senden --text "<Text>" "<Name>" |
⚠️ Vorbedingung fuer scapi.mjs, sonst passiert gar nichts: es zieht den Bearer aus
dem Mitschnitt des Browsers arc-bene. Dafuer muss (a) der Recorder laufen
(cdp_capture.py --port 9280 --name arc-bene) und (b) in Arc eine Superchat-Sitzung
offen sein. Der Bearer lebt nur rund 143 Minuten, der Refresh-Weg ist seit 25.06.2026
tot. Wer morgens weiterarbeitet, braucht zuerst eine frische Sitzung. Ohne das meldet
das Skript einen Fehler, der leicht als „Superchat ist kaputt" fehlgedeutet wird.
⚠️ wa.py senden nimmt den Text als FLAG, nicht als zweites Argument. Die frueher
hier stehende Form wa.py senden "<Name>" "<Text>" schlaegt fehl. Zusaetzlich verlangt
es --wirklich-senden. Immer wa.py senden -h gegenlesen.
⚠️ bxwj.mjs ist NICHT das WebinarJam-Werkzeug fuer diesen Kunden — es haengt fest
an Port 9257. Der Name legt etwas anderes nahe und hat schon Zeit gekostet.
Die Detail-Dokumentation liegt woanders und wird hier gebraucht:
| Thema | Datei |
|---|---|
Kampagnen, filterQuery, PUT, send, duplicate | ~/api-lab/superchat/04-campaigns.md |
| Workflows und ihr Publish-Weg | ~/api-lab/superchat/03-automations-workflows.md |
| Zaps anlegen, aendern, publizieren, loeschen | ~/api-lab/zapier/02-zaps.md |
| Master-Index aller inoffiziellen APIs | ~/api-lab/INDEX-unofficial-apis.md |
**Bis zum 01.08. war jeder Batch Handarbeit. Seit dem 02.08. laeuft der Takt ohne
Menschen — und ohne Chat-Sitzung.** Wer den Ablauf kennenlernen will, liest die
Stationen unten; wer ihn BETREIBT, braucht diesen Abschnitt.
| Werkzeug | Wozu |
|---|---|
batches-anlegen.py | legt alle Batches im Voraus als benannte Entwuerfe an, jeder mit festen Empfaengern (STATIC) |
takt-einrichten.sh | macht aus dem Plan launchd-Wecker, einen je Sendezeit |
batch-feuern.py | prueft und sendet EINEN Batch. Das ist, was der Wecker startet |
lauf-beobachten.py | misst alle 14 min, baut und veroeffentlicht das Dashboard |
dashboard-bauen.py | erzeugt die Seite aus dem Messprotokoll |
pool-gegenrechnen.py | zaehlt den Pool unabhaengig vom gespeicherten Filter |
selbsttest.py | prueft die Sicherungen einzeln gegen echte Zustaende |
FEHLERLOG.md | jeder real aufgetretene Fehler samt Gegenmassnahme |
batches-anlegen.py → daten/batch-plan.json → takt-einrichten.sh
↓ launchd
batch-feuern.py <nr> --senden
↓
lauf-beobachten.py (launchd, alle 14 min) → daten/lauf-protokoll.jsonl
↓
dashboard-bauen.py → ClientShare
python3 batches-anlegen.py # zeigen, was entstuende
python3 batches-anlegen.py --anlegen # Entwuerfe in Superchat anlegen
./takt-einrichten.sh # zeigen, welche Wecker entstuenden
./takt-einrichten.sh --setzen # Wecker laden — ab hier laeuft es allein
python3 selbsttest.py # alle Sicherungen pruefen (nur eigene Nummern)
⛔ selbsttest.py VOR dem ersten scharfen Batch laufen lassen. Am 02.08.2026
hat die Vorab-Pruefung „alles sauber" gemeldet, obwohl der Empfaenger abgemeldet
war (FEHLERLOG F-01). Sie sah nur deshalb richtig aus, weil niemand sie geprueft
hatte. Eine ungetestete Sicherung ist keine Sicherung, sondern eine Attrappe.
| Pruefung | Verhalten |
|---|---|
| Qualitaet ROT | ⛔ Not-Aus: alle weiteren Wecker werden entladen, ntfy mit Prioritaet urgent, Banner im Dashboard |
| Kontrollzahl unvollstaendig | Abbruch, Meldung. Die wichtigste Sicherung — siehe F-01 |
Status nicht DRAFT | Abbruch. Verhindert Doppelversand |
| Empfaenger inzwischen gesperrt | fliegen VOR dem Versand aus der Kampagne |
| Qualitaet GELB | laeuft weiter, Batchgroesse wird nicht erhoeht |
⚠️ Gestoppt wird ausschliesslich bei ROT. Hier stand kurzzeitig auch eine
Regel auf die Fehlzustellung („Fruehindikator") — die war **erfunden und nicht
gemessen** und wurde entfernt. Eine Abbruchregel auf einer unbelegten Annahme
stoppt entweder grundlos oder wiegt in falscher Sicherheit.
ntfy-App, Server https://ntfy.benediktglass.com, Topic carmen-lauf-83acea.
Bei einem Not-Aus kommt die Meldung mit Prioritaet urgent aufs Handy, zusaetzlich
Systemmeldung am Mac und ein rotes Banner oben im Dashboard.
launchctl list | grep carmen # laeuft alles?
./takt-einrichten.sh --loeschen # LAUF STOPPEN
./takt-einrichten.sh --setzen # fortsetzen …
rm daten/ALARM.json # … und den Alarm quittieren
python3 batch-feuern.py <nr> # einen Batch pruefen, ohne Versand
python3 batch-feuern.py <nr> --senden # einen Batch von Hand senden
cat /tmp/carmen-batch-<nr>.log # Protokoll eines Batches
cat /tmp/carmen-beobachter.log # Protokoll des Beobachters
⚠️ Zum Fortsetzen braucht es bewusst zwei Handgriffe (Wecker setzen UND Alarm
loeschen). Ein Not-Aus, der sich selbst zurueckstellt, waere keiner.
⛔ launchd startet mit einem minimalen PATH. node liegt unter
/opt/homebrew/bin und ist dort nicht auffindbar. Alle Skripte rufen es
deshalb absolut auf, und die Wecker bringen ein eigenes PATH mit. Real passiert
am 02.08.: der Wecker feuerte puenktlich und starb sofort, im Terminal lief
derselbe Befehl einwandfrei (F-02). **Jeder neue Wecker muss EINMAL unter launchd
gelaufen und sein Protokoll gelesen worden sein.**
⛔ Nichts Betriebsrelevantes an einer Chat-Sitzung haengen lassen. Der
Beobachter lief zuerst als nohup aus einem Chat — waere der geschlossen worden,
haette niemand mehr gemessen, und das Dashboard waere eingefroren, **ohne das
anzuzeigen**. Er ist jetzt ein LaunchAgent mit KeepAlive (F-10).
GET /analytics/webinarSchedules?webinar=<id> ist soNICHT reproduzierbar** (Kaltstart-Test 01.08.2026: sechs Varianten aus dem
Seiten-Kontext von :9262, mit und ohne x-requested-with, jedes Mal HTTP 200 mit
Redirect auf /home statt JSON). Es ist kein Sitzungsproblem, derselbe Tab
rendert die Registranten-Tabelle. Was fehlt, ist ungeklaert; CSRF-Header und ein
abweichender Parametername sind nicht ausgeschlossen.
Verlaesslicher Weg: die IDs stehen in der URL der Registranten-Ansicht
(webinar=67&schedule=644 fuer den Lauf vom 30.06.2026). Ablesen statt abfragen.
my-registrants: Webinar, Session, **Live room behavior =„Did not attend live session", Replay room behavior = „Did not attend replay room"**.
(serverseitig, bis 60 s). Datei landet mit Zufallsnamen in ~/Downloads.
Verifikation: Zeilenzahl der CSV muss dem total aus
GET /my-registrants/filter?webinar=&schedule=&attendedLive=2&attendedReplay=2 entsprechen.
Am 01.08.2026: 2.844 = 2.844 ✅
⚠️ Nicht per API durchblaettern. Die Tabelle laedt in 25er-Seiten; wer zusaetzlich
selbst blaettert, loest ein Cloudflare-Rate-Limit aus (HTTP 429, Error 1015, hielt
ueber 10 Minuten). Der Export-Knopf ist der richtige Weg.
Aus dem Export entfernen:
| Regel | Wirkung am 01.08.2026 |
|---|---|
| ohne Telefonnummer | −778 |
Subscribed = No | −97 |
| ungueltige Nummer (Laenge, Nicht-DACH) | −83 |
| Dublette auf normalisierter Nummer | −15 |
| bleibt | 1.871 von 2.844 |
Nummern normalisieren: fuehrende 0 nach der Laendervorwahl streichen. ⚠️ Und die
kaputte +1-Vorwahl heilen: WebinarJam liefert deutsche Nummern teils als
+1 49… (305 Faelle am 01.08.). Wenn Vorwahl 1 und die Nummer mit 49/43/41
beginnt, ist die echte Vorwahl die ersten zwei Ziffern der Nummer.
Import-CSV mit genau vier Spalten, Semikolon-getrennt:
Vorname;Nachname;Telefon;E-Mail
Pro Lauf vier Listen (POST /v1/contact-lists, Body {name, description, contactIds:[]}):
| Liste | Rolle |
|---|---|
AW_NT (<Quelldatum>) | die Kohorte |
AW_NT_zu_senden (<Quelldatum>) | der aktuelle Batch |
AW_NT_gesendet (<Quelldatum>) | Buchfuehrung |
<Zieldatum> - Workshop Eingetragen | ⚠️ nur bei WebinarJam-Terminen. Bei einem EverWebinar ist die richtige Liste EW_Anmeldung (<Zieldatum>), die vom EW-Anmelde-Zap gefuellt wird. |
POST /v2/contact-uploads
{"encoding":"UTF-8","delimiter":";","hasHeaderCells":true,
"contactListId":"<cl_ der Kohorte>",
"mappings":[{"type":"MAPPED_COLUMN","attribute":{"id":"builtin-firstName","name":"Vorname","type":"BUILTIN"}},
{"type":"MAPPED_COLUMN","attribute":{"id":"builtin-lastName","name":"Nachname","type":"BUILTIN"}},
{"type":"MAPPED_COLUMN","attribute":{"id":"builtin-phone","name":"Telefon","type":"BUILTIN"}},
{"type":"MAPPED_COLUMN","attribute":{"id":"builtin-mail","name":"E-Mail","type":"BUILTIN"}}]}
→ {"contactUploadId":"cu_…"}
POST /v2/contact-uploads/<cu_>/csv multipart, Feldname "file"
⚠️ Der Import laeuft ASYNCHRON. GET /v2/contact-uploads/<cu_> gibt 404, das ist
kein Fehler. Status steht in der Liste: GET /v2/contact-uploads → PENDING → DONE.
Am 01.08. dauerte er fuer 1.871 Zeilen etwa 25 Minuten.
⚠️ Verifikation, und „Liste zaehlen" reicht dafuer NICHT.
Der Import verwirft still Zeilen. Gemessen am 01.08.2026: 1.871 Zeilen in der CSV,
1.785 Kontakte in der Liste. Aufgeschluesselt durch Abgleich der Nummern:
| Zeilen in der Import-CSV | 1.871 |
|---|---|
| davon spaeter im Superchat-Bestand auffindbar | 1.774 |
| davon in der Kohorten-Liste | 1.769 |
| gar nicht angelegt (von Superchat verworfen) | 97 |
| angelegt, aber nicht in die Liste gehaengt | 5 |
Es sind keine Dubletten: die 1.871 Nummern sind sowohl nach einfacher als auch
nach strenger Normalisierung (Trunk-Null nach der Laendervorwahl) eindeutig — gepruefte
und widerlegte Hypothese. Superchat wirft die Zeilen bei seiner eigenen
Nummernpruefung weg und meldet das nirgends.
Deshalb: nach dem Import die Nummern der CSV gegen den Bestand abgleichen, nicht
nur die Liste zaehlen. Ein Verlust um 5 % ist normal; ein Verlust um 30 % heisst,
dass die Bereinigung in Station 2 etwas falsch macht — und ohne diesen Abgleich
sieht beides gleich aus.
Gespeicherte Filter heissen intern contact-views (POST /v1/contact-views,
Body {name, filter, pinned:true, visibility:"PRIVATE"}). Drei Stueck:
| Name | Wer drin ist |
|---|---|
AW_NT_noch_nicht_gesendet (<Ziel>) | in der Kohorte und in KEINER der Sperren, und nicht in gesendet, und nicht in zu_senden → der Pool |
AW_NT_zu_senden (<Ziel>) | in der Kohorte und in zu_senden, und in KEINER Sperre, und nicht in gesendet → die Kampagnen-Audience |
AW_NT_zugestellt (<Ziel>) | in gesendet, und nicht in „nicht auf WhatsApp" → die Kontrolle |
⚠️ Die Umschreibung „nicht in Sperren, gesendet, zu_senden" stand hier bis 01.08.2026
und laesst sich als „nicht in Sperren, ABER in gesendet und zu_senden" lesen. Gemeint
war immer „in keiner dieser Listen". Genau so ein Satz wird nachts falsch herum gebaut.
**⭐ Das Feld filter ist eine eigene Mini-Query-Sprache. Ohne diese Zeile kann niemand
den Filter bauen** (fehlte hier komplett, obwohl an zwei Stellen gebraucht: hier und als
filterQuery der Kampagne in Station 6):
and(
containsAll(contactListIds,[<Kohorte>,<zu_senden>]),
not(containsAny(contactListIds,[<Sperre1>,…,<Sperre6>,<gesendet>]))
)
Real gelaufen am 01.08.2026 (Kampagne cp_uexwxYwJBpBvLc3nKKSvT, Batch 02), in einer Zeile:
and(containsAll(contactListIds,[cl_IKgNIECJ0aZM88a01FwHj,cl_5GTatu9ROxvYg4StuUIfb]),not(containsAny(contactListIds,[cl_Ud85EpLOJ9sH124cwpHPN,cl_d2FFMkdAwKtjSukmQurTF,cl_S60u79592V4UeykKb05Md,cl_w8MxyooN31biL4qIGhLU6,cl_81meqYaFUXBmgdWfRcV0T,cl_wB1rUZGwR0eYGS5ZNLmJ3,cl_Vb0sN8sQ5aEDwSBwB2NI8])))
⚠️ Es sind SIEBEN ausgeschlossene Listen, nicht sechs: die sechs Sperren plus
die gesendet-Liste. Wer nach dem Merksatz „alle sechs" baut, schreibt bereits
Angeschriebene erneut an.
⚠️ GET /v1/contact-views liefert in der Listen-Antwort filter: null. Den echten
Ausdruck bekommt man nur ueber den Einzel-GET auf ctv_….
Die sechs Sperrlisten (im Filter kommt als SIEBTE die gesendet-Liste dazu, siehe oben):
Whatsapp OptOut · AW_Optout · Kein Optin · NUMMER NICHT MEHR KONTAKTIEREN ·
Kontakt nicht auf Whatsapp · EW_Anmeldung (<Zieldatum>)
⭐ Verifikation, und die ist NICHT optional:
python3 pool-gegenrechnen.py --batch
Das Skript zaehlt den Pool aus den rohen Kontaktdaten, **ohne die filterQuery
anzufassen**. Danach die Zahl mit validation.audienceContactsCount der Kampagne
vergleichen. Sie muessen uebereinstimmen.
⚠️ Warum das der wichtigste Check im ganzen Runbook ist: Filter und Kampagne
benutzen dieselbe filterQuery. Wer der Zahl in der Kampagne glaubt, glaubt dem
Filter, den er gerade selbst geschrieben hat. Ein Tippfehler in einer Listen-ID
faellt so nicht auf, und die Folge ist, dass Abgemeldete Werbung bekommen. Zwei
unabhaengige Wege zur selben Zahl sind der einzige Schutz.
Gemessen am 01.08.2026: Skript 1.574, Kampagne 1.574. ✅
⚠️ WIDERLEGT 01.08.2026: Whatsapp OptOut und AW_Optout sind NICHT disjunkt.
Hier stand „vollstaendig disjunkt, null Ueberschneidung" (und davor die alten Zahlen
39/109 ohne Datum). Live gemessen: 65 bzw. 134 Personen, 25 davon auf beiden Listen.
Das ist kein Fehler, sondern Folge des Abmelde-Zaps aus Station 9, der bewusst in
beide Listen schreibt. Die Aussage war schon in dem Moment veraltet, in dem sie
geschrieben wurde.
Praktisch bleibt es gleich: immer BEIDE ausschliessen. Wer nur eine nimmt, laesst
je nach Liste 40 bis 109 Abgemeldete durch. Wer nur eine davon ausschliesst, schreibt Opt-outs an.
AW_NT_zu_senden:```
PATCH /v1/contacts
{"contactIds":[…max 50…],
"changes":[{"operation":"ADD","changeType":"CONTACT_LIST","contactListIds":["<zu_senden>"]}]}
```
⭐ **Die Schreibform des PUT (kartiert 02.08.2026). Zwei Feldnamen unterscheiden
sich zwischen Lesen und Schreiben — daran scheitert jeder Versuch, der es raet:**
| GET liefert | PUT verlangt | |
|---|---|---|
| Kanal | messageChannelConfigId | channelId |
| Inhalt | content.template (ganzes Objekt) | content.templateId (nur die ID) |
{"name":"…",
"audience":{"filterQuery":"and(containsAll(…),not(containsAny(…)))","type":"DYNAMIC"},
"channelId":"mc_…",
"content":{"templateId":"tn_…","templateHeaderFileId":null,"wildcardValues":null},
"scheduling":{"type":"SCHEDULED","value":"2026-08-03T07:13:19Z","timezone":"Europe/Berlin"}}
⚠️ PUT ERSETZT. Wer nur name schickt, loescht Kanal, Inhalt und Zeitplan.
⚠️ value ist UTC, timezone steht daneben. 09:13 Berlin = 07:13Z.
⚠️ Eine gesendete Kampagne ist gesperrt (409). PATCH gibt es nicht (405).
Loeschen geht ueber die API gar nicht (405) — nur in der Oberflaeche.
Wie das gefunden wurde: vier geratene content-Formen ergaben alle 400 ohne
Feldangabe. Die Antwort lag in einer Minute vor, nachdem der Vorgang einmal ueber
die Oberflaeche im CDP-Browser geklickt und der Mitschnitt gelesen wurde.
**Bei einem 400 ohne Feldangabe nicht weiterraten, sondern einmal klicken und
mitschneiden.**
POST /v5/campaigns/<cp_>/duplicate⚠️ Welche ist „die letzte"? Es stehen rund 28 Kampagnen im Konto, darunter
mehrere Tests mit aehnlichem Namen. Die Vorlage des Laufs vom 01.08.2026 war
cp_uexwxYwJBpBvLc3nKKSvT („2026-08-04 - Webinareinladung V5 (Batch 02 - 24)").
Vor dem Duplizieren GET /v5/campaigns?size=30 und nach createdAt sortiert
die juengste ECHTE Kampagne nehmen, keine mit „TEST" im Namen.
⚠️ Beim Duplizieren wird die Audience auf leeres STATIC zurueckgesetzt und die
Conversion-Goals sind weg. Beides muss neu gesetzt werden (Schritte 3 und 4).
PUT /v5/campaigns/<cp_> mit DYNAMIC-Audience (filterQuery = derselbe Ausdruck wie im zu_senden-Filter), Kanal, Template, scheduling: IMMEDIATELY
PUT /v5/campaigns/<cp_>/conversion-goal auf den Quick-Reply-Buttonvalidation.audienceContactsCount muss der Batch-Groesse entsprechenPOST /v5/campaigns/<cp_>/send (leerer Body, 204)zu_senden entfernen.```
PATCH /v1/contacts
{"contactIds":[…],"changes":[{"operation":"REMOVE","changeType":"CONTACT_LIST",
"contactListIds":["<zu_senden>"]}]}
```
⚠️ **Dieser Schritt fehlte hier bis 01.08.2026, und die Lage ist unangenehmer als
sie aussieht.** Die beiden Laeufe machen es unterschiedlich: AW_NT_zu_senden (09.06.)
enthaelt bis heute 1.153 Kontakte (nie geleert), AW_NT_zu_senden (30.06.) ist
leer (geleert). Beides funktioniert, aber sie sind unterschiedlich sicher:
Schritt 5 faellt auf, wenn der gesendet-Zap kaputt ist, weil die Zahl dann zu gross ist.
der Zaehl-Check ist blind gegen einen kaputten gesendet-Zap.
Wer leert, muss den gesendet-Zap deshalb separat pruefen (Station 7 Zeile 3), sonst
gibt es keine zweite Sicherung mehr.
Verifikation: GET /v5/campaigns/<cp_>/recipients → Status je Empfaenger.
⚠️ Das Feld recipients in /v5/campaigns ist unbrauchbar (steht oft auf 0).
Die echte Zahl liefert GET /v5/campaigns/<cp_>/funnel → total.
Das ist die einzige Nachricht des ganzen Ablaufs, die je einen LINK enthielt.
Sie ging am 09.06.2026 an 296 Menschen und hatte 33 Konversionen —
und stand bis 02.08.2026 in keiner Station dieses Runbooks. Wer das Runbook
abarbeitet, baut sie nicht, und es faellt nicht auf, weil kein Punkt fehlt.
| Vorlage-Kampagne | cp_pU08UUNmBzAQtouxmgwif „09.06.2026 - Webinar Reminder" |
|---|---|
| Template | tn_fdPPPcWId9y0PCWr01KUM, Kategorie MARKETING, ohne Buttons |
| Zeitplan | SCHEDULED, 2026-06-09T17:57:02Z — also drei Minuten vor 20:00 Berlin |
| Audience | die „Eingetragen"-Liste des Laufs |
| Ergebnis | 296 zugestellt, 249 gelesen, 33 konvertiert |
Aufsetzen: duplizieren, Audience auf die neue Eingetragen-Liste,
scheduling: SCHEDULED auf drei Minuten vor Start.
⚠️ Und hier ist der Unterschied Live-Webinar gegen EverWebinar, nach dem
lange gesucht wurde. Beim Eintragen unterscheiden sich die beiden nicht:
derselbe Zapier-Konnektor, dieselbe Aktion, dieselben Felder webinar +
schedule, nur andere Werte. Auch der persoenliche Zugangslink ist bei beiden
gleich aufgebaut. Der Unterschied steckt allein in diesem Reminder:
Der Link darin ist kein persoenlicher, sondern ein generischer Channel-Link
(event.webinarjam.com/channel/aktien_workshop). Der gehoert fest zu
Live-Webinar 67 und zeigt heute auf …/ended/81p3ycy6hps0so —
81p3ycy6 ist genau dessen webinar_hash. Fuer das EverWebinar (Hash
2386ysl4) ist er tot. ⚠️ **Und „tot" heisst hier nicht Fehlermeldung, sondern
HTTP 200 auf eine „ist vorbei"-Seite.** Ein Link-Check auf den Status-Code
merkt davon nichts.
Warum ueberhaupt ein generischer Link: ein *persoenlicher* live_room_url
laesst sich nicht in die Vorlage schreiben, dafuer braeuchte die genehmigte
Meta-Vorlage eine URL-Variable (wildcardValues war in allen erfassten
Kampagnen null). Deshalb der Channel-Link.
⚠️ Ehrlich zur Ursache: dass der Reminder wegen des EverWebinar-Wechsels
entfiel, ist nicht belegt. Er fehlte schon beim Lauf am 30.06., und der war
noch live (67/644). Zwei andere Erklaerungen sind dokumentiert: Lauf II
wurde bei ~750 von 2.187 wegen der Meta-Qualitaetswarnung abgebrochen, und am
25.06. wurde von MARKETING- auf UTILITY-Vorlagen umgestellt — der Reminder ist
eine MARKETING-Vorlage. Belegt ist nur die Wirkung, nicht der Grund.
⚠️ Diese Tabelle hat bis 01.08.2026 nur die Haelfte geprueft. Ein Kaltstart-Pruefer
hat drei Stellen belegt, an denen man alles abhaken konnte und die Kette trotzdem kaputt
war. Die Spalte „woran es scheitert" ist der eigentliche Inhalt.
| # | Was | Pruefen | Woran es scheitert, wenn man nur „steht es?" fragt |
|---|---|---|---|
| 1 | Konversions-Workflow zeigt aufs neue Zielwebinar | ADD-Knoten → richtige Anmelde-Liste | — |
| 2 | Anmelde-Zap traegt ins richtige Webinar ein (367085449) | webinar + schedule im WebinarJam-Schritt | — |
| 3 | „Template sent"-Zap (370195944) schreibt in die neue gesendet-Liste | contactListId im letzten Schritt UND template_id im Filter | ⛔ Der Zap filtert auf template_id iexact tn_9y9pVoysZHjNTGAAIPCJJ. Wer eine neue Vorlage baut (bei neuem Datum ueblich) und nur die Liste umhaengt, hat einen Zap, der nie wieder feuert. Dann landet niemand in gesendet, die Audience schrumpft nie, und jeder Batch geht an alle vorherigen Empfaenger erneut. Bei 1.600 Menschen ist das kein Einzelfall, sondern ein Massen-Doppelversand. |
| 4 | Riegel gegen Doppel-Nachricht (wffn_IuaPOdZg9qRk4ugCNEfI3) | erster Zweig: in gesendet-Liste → ENDE, und die ID muss die DIESES Monats sein | ⛔ Die Listen-ID im Riegel ist pro Lauf neu. Sie zeigt heute auf cl_Vb0sN8sQ5aEDwSBwB2NI8 (30.06.). Ein Pruefer, der nur sieht „Zweig existiert, endet mit ENDE", hakt ab — auch wenn die ID auf den Vormonat zeigt. Dann bekommt jeder Reaktivierte beide Nachrichten. |
| 5 | Der zweite, dauerhafte Opt-in-Workflow AW Anmeldung // Opt-in Verwaltung (wffn_t86e1ZoYfjvAfmc17OrOg, ACTIVE) | schreibt er noch in die richtige Anmelde-Liste? | ⛔ Dieser Workflow stand hier nie. Er ist nicht datumsgebunden, hat aber die Listen-ID cl_wB1rUZGwR0eYGS5ZNLmJ3 (04.08.) hart verdrahtet. Naechsten Monat schreibt er weiter dort hinein, waehrend die Sperre auf die neue Liste zeigt. Beide Listen existieren, beide sehen gefuellt aus, niemand merkt es. |
| 6 | Automations-Kontingent | GET /v1/workflows/usage | ⛔ Bei erschoepftem Kontingent geht ein Workflow auf SUSPENDED und meldet sich nicht. Der Versand laeuft weiter, Riegel und Bestaetigungen fallen still aus. Stand 01.08.: 5 von 8 aktiven Workflows. |
⚠️ EW_Anmeldung ist keine Anmeldeliste im Wortsinn. Befuellt wird sie vom
dauerhaften Opt-in-Workflow (#5), nicht von AW_Automations. Sie ist damit eine
kumulierte Opt-in-Liste, keine Liste der fuer diesen Termin Angemeldeten. Der Vermerk
weiter unten („erfasst nur etwa die Haelfte") beschreibt das Symptom, aber die Ursache
ist eine andere als dort vermutet: es ist gar kein Anmelde-Mechanismus.
DONEsuccess, WebinarJam-Schritt success⛔ Und nach JEDER Aenderung an der Kette erneut testen, bevor der naechste Batch geht.
Das fehlte hier und ist im Lauf vom 01.08.2026 real schiefgegangen: der einzige
Konversionslauf (wr_wjbWvN46g87AlDPKuqjTG, 18:09 UTC) lief auf Workflow-Version
wfv_7NSBXNfk8vKXn5D5B5xC1. Live ging um 18:42 eine andere Version
(wfv_ivmG3KsxbAfqNUiU2oKKT). **Die produktiv laufende Version ist nie end-to-end
getestet worden.** „Vier Mal getestet" gilt fuer die getestete Version, nicht fuer die,
die danach veroeffentlicht wurde.
⚠️ Ebenfalls aus diesem Lauf, als Mahnung: die Batches 01 (6 Menschen, 18:20) und 02
(24 Menschen, 18:31) gingen raus, bevor Konversions-Workflow (18:42), Riegel (18:46)
und gesendet-Zap (18:53) fertig verdrahtet waren, und 75 Minuten bevor der
Abmelde-Zap ueberhaupt existierte (19:35). Die Reihenfolge-Regel ganz oben in diesem
Dokument wurde in genau dem Lauf gebrochen, fuer den sie geschrieben wurde. Sie steht
deshalb jetzt zusaetzlich hier, an der Stelle, an der man sie braucht.
Superchats eingebaute Behandlung erkennt nur exakt STOPP. Real geschrieben wird
aber fast immer STOP mit einem P. Deshalb laeuft seit dem 01.08. ein eigener Zap.
Zap 374885742 „Abmeldung // Wortvarianten → Opt-out-Listen" (Ordner Superchat)
| Schritt | Was |
|---|---|
| Trigger | Superchat new_inbound_message |
| Filter | Text enthaelt (ohne Gross/Klein) stop oder stopp oder abmelden oder abbestellen |
| Aktion | PATCH /v1/contacts, ADD auf beide Opt-out-Listen |
⚠️ Warum ein Zap und keine Superchat-Automation: eine Automation muesste bei
*jeder* eingehenden Nachricht anlaufen. Bei ~800 Antworten pro Lauf wird das teuer.
Der Zapier-Filter kostet keine Task, wenn er nicht zutrifft.
⚠️ Superchats eigene Dokumentation nennt dafuer eine Schlagwort-Funktion in den
Einstellungen. Die ist veraltet, Superchat verweist selbst auf Automations
(von Benedikt getestet, 01.08.2026).
Die vier Woerter sind gemessen, nicht geraten. Gegen den echten Bestand
(819 eingehende Nachrichten, Export siehe daten/export/) geprueft:
| Verfahren | Treffer | davon echte Abmeldungen | Fehlalarme |
|---|---|---|---|
| Teilstring, die vier Woerter | 43 | 41 | 2 |
| exakte Uebereinstimmung | 38 | 38 | 0 |
⚠️ WIDERLEGT 01.08.2026, und zwar durch mich selbst: „0 Fehlalarme" war falsch.
Hier stand zuerst „36 von 36, 0 Fehlalarme", dann „43 von 43, 0 Fehlalarme". Beides
entstand, weil ich Grenzfaelle von Hand aussortiert und danach trotzdem null
Fehlalarme gemeldet habe. Das ist zweierlei: „der Filter liefert keine Fehlalarme"
und „ich habe die Fehlalarme weggestrichen". Der Zap kann nicht von Hand aussortieren.
Die zwei Fehlalarme im Wortlaut (beide wuerden vom Zap ausgetragen):
> „Hallo Carmen Ich muss mich leider für heute abmelden. **Beim nächsten Mal bin ich
> gerne dabei**, wenn das geht." — Gudrun, 06.05.2025
> „STOPP habe vergessen das es Samstag ist und dann bin ich nicht da." — 01.07.2026
Beide heissen „diesmal nicht", nicht „schreib mich ab". Wer so schreibt, wird dauerhaft
ausgetragen und erfaehrt es nie.
Groessenordnung: 2 auf 1.234 eingehende Nachrichten, also rund 0,16 %.
Warum der Filter trotzdem so bleibt (bewusste Entscheidung, offen zur Revision):
Enger ziehen tauscht den harmlosen Fehler gegen den schaedlichen. Ein faelschlich
Ausgetragener kostet einen Lead. Eine faelschlich beworbene Abmeldung kostet Vertrauen
und ist rechtlich heikel. Die jetzige Richtung schuetzt den Empfaenger.
Wer es anders will, hat zwei Wege:
abmelden/abbestellen zusaetzlich „enthaelt nicht heute" und „enthaelt nicht nächste" — faengt Gudrun, nicht den Samstag-Fall.
entscheiden lassen. Sauber, aber nicht mehr autonom.
⚠️ Keiner der beiden Fehlalarm-Kontakte wurde ausgetragen: Gudrun steht auf Kein Optin
(faellt ohnehin raus), der Samstag-Fall wurde beim Nachtragen von Hand ausgenommen.
Basis: 1.234 eingehende Nachrichten aus 1.779 Verlaeufen. Kontrollzahl mitzaehlen:
756 dieser Verlaeufe enthielten ueberhaupt eine Kontakt-Nachricht. Ohne diese Zahl
waere ein Auswertungsfehler als „0 Abmeldungen" durchgegangen (siehe letzter Abschnitt).
Der Unterschied sind Schreibweisen wie "Stopp" in Anfuehrungszeichen oder
STOP. mit Punkt. Tatsaechlich gefunden: ganz ueberwiegend STOP mit EINEM P, dazu Stop, Stopp,
"Stopp" in Anfuehrungszeichen und drei ausformulierte Abmeldungen.
Nachtrag 01.08.2026: die Nachlese ueber den vollstaendigen lokalen Export fand
43 statt der zunaechst gemeldeten 36. 34 davon waren bereits ausgetragen, 7 nicht —
die wurden nachgetragen und gegengelesen. Wer den Filter neu aufsetzt, prueft immer
gegen den GANZEN Export, nicht gegen die erste Teilmenge.
⚠️ Bekannte Schwaeche: Teilstring heisst, ein Wort wie „Stopschild" wuerde
ebenfalls anschlagen. Auf 819 echten Nachrichten ist das null Mal passiert, deshalb
bewusst so belassen. Wer es haerten will, braucht Wortgrenzen, und die kann
Zapiers Filter nicht. Dann Code-Step statt Filter.
Grenzfaelle bewusst NICHT ausgetragen: Nachrichten wie
STOPP habe vergessen das es Samstag ist… sind keine Abmeldung, sondern ein Zuruf.
Wer den Bestand nachtraeglich bereinigt, liest die Treffer einzeln, bevor er schreibt.
Zwei eigene Nummern sind bei Unipile angebunden und duerfen beliebig oft
angeschrieben werden:
| Nummer | Unipile-Konto |
|---|---|
| +49 176 30159282 | 2w-h-4dLSOy8QuC4L3JOXQ |
| +49 160 92890232 | 4FL4ONSrSQeeqy0rB3rZow |
python3 ~/.claude/skills/whatsapp-melden/wa.py senden --text "<Text>" --wirklich-senden "<Name>"
⚠️ Der Text ist ein Flag, kein zweites Argument, und ohne --wirklich-senden
passiert nichts. Im Zweifel wa.py senden -h.
⛔ **Das Konto 4hMTWP2YS1iZQgG87JLPZA (+49 162 2859271) gehoert Danny Mittenzwey.
Niemals darueber senden.** wa.py hat dafuer eine Sperre (EIGENE_ACCOUNTS).
Nach jedem Test aufraeumen, sonst faelscht die Testnummer den naechsten Zaehlstand:
aus zu_senden und beiden Opt-out-Listen wieder entfernen
(PATCH /v1/contacts, operation:"REMOVE").
⛔ ABER NICHT aus der gesendet-Liste, solange die Testnummer in der Kohorte steht.
Hier stand bis 01.08.2026 „aus gesendet, zu_senden und beiden Opt-out-Listen
entfernen". Das ist eine Falle: der Testkontakt Bene -
(ct_yNEXuEydV0e0M92kre3nB) ist Mitglied von AW_NT (30.06.2026), also der echten
Kohorte. Er faellt heute nur deshalb nicht in den Live-Pool, weil er in
AW_NT_gesendet steht. Wer der alten Anweisung folgte, setzte die Testnummer in den
Produktions-Verteiler zurueck.
Richtig ist die Ursache zu beseitigen, nicht das Symptom:
der Kohorte nichts verloren. Diese Regel fehlte in der Bereinigungstabelle.
gesendet.⚠️ Auch Bene2 - (ct_1gNOZTcJsRxGBdKf5GuJm) steht in mehreren AW_NT-Listen frueherer
Laeufe. Vor dem naechsten Lauf beide Testkontakte durchsehen.
| Falle | Symptom | Erkennen |
|---|---|---|
| Zaehlfelder luegen | recipients, amountContacts, Zapier-tasks stehen auf 0 | nie aus Listen-Antworten zaehlen, immer Detail/Funnel/Run-History |
| Zapier-PATCH aendert nichts | HTTP 200, Live-Version unveraendert | PATCH schreibt nur den Entwurf, danach POST …/draft/publish-version |
| Superchat-Workflow-PATCH ebenso | Aenderung nicht wirksam | PUT /v2/workflows/<wf_id>/versions/save, dann POST /v1/workflow-versions/<wfv_id>/published. ⚠️ Anderer Namensraum UND andere ID-Sorte. Die frueher hier stehende Kurzform „versions/save → versions/<id>/published" baut man falsch zusammen. |
nachname fehlt im HTTP-Knoten | WebinarJam-Schritt error, Zusage laeuft ins Leere | seit dem Umbau am 25.06.; Fallback im Zapier-Code-Step eingebaut |
| Doppel-Nachricht an Reaktivierte | „Platz gesichert" und „freut mich, dass Du Dich angemeldet hast" | Riegel im AW_Automations-Filter |
| „Template sent"-Zap schreibt in die Vormonats-Liste | Empfaenger bleiben in zu_senden haengen | contactListId je Lauf umhaengen |
| Import scheinbar leer | Liste bleibt leer, GET /v2/contact-uploads/<id> = 404 | laeuft asynchron, Status ueber die Listen-Route |
| Cloudflare-Rate-Limit | HTTP 429 auf WebinarJam | nicht selbst blaettern, Export-Knopf nehmen, 10 min warten |
| EverWebinar vs. WebinarJam | falsche Zielliste, irrefuehrende Labels | Label im Zap sagt [EverWebinar] bzw. [WebinarJam] |
| Toter Reminder-Link, der wie ein lebender aussieht | Teilnehmer landen auf „Webinar ist vorbei" | Der Channel-Link gehoert einem bestimmten Live-Webinar. Bei EverWebinar oder neuem Live-Termin zeigt er auf …/ended/… und antwortet mit HTTP 200. Ein Status-Code-Check faengt das NICHT. Nur der Redirect verraet es: curl -sIL <link> und das Ziel ansehen. |
| Zwei Registrierungs-Trigger, einer davon falsch | Anmeldungen kommen doppelt oder gar nicht | Live-Variante 367401515 (webinar 67) und EW-Variante 371000532 (webinar 62). Immer genau eine aktiv. |
01-rekonstruktion / 02-befunde belegt sind und hier lange fehltenErgaenzt 01.08.2026 nach einem Kaltstart-Befund: wer nur dieses Runbook las, kannte
diese sechs nicht, obwohl sie real gefressen haben.
| Falle | Symptom | Ursache | Fix |
|---|---|---|---|
| Fallback wirkt nicht im HTTP-Knoten | Anmeldung schlaegt fehl, obwohl ein Nachname-Fallback existiert | Zapiers Fallback-Syntax greift in Nachrichten-Knoten, nicht in HTTP-Knoten | Fallback in einen Code-Step vorziehen und dessen Ausgabe im HTTP-Knoten verwenden |
| Zwei Workflows auf demselben Stichwort | Kontakt bekommt zwei Antworten auf eine Zusage | Beim Duplizieren bleibt der alte Workflow aktiv | Vor dem Lauf alle aktiven Workflows auf ihren Trigger pruefen, nicht nur den neuen |
CREDIT_USAGE_EXCEEDED | Ein Workflow steht auf SUSPENDED und meldet sich nicht | Automations-Kontingent des Tarifs erschoepft | Workflow-Status vor dem Lauf abfragen; SUSPENDED ist stiller Ausfall, kein Fehler im Log |
| Toter Refresh-Token | Auth laeuft mitten im Lauf ab, Aufrufe kippen auf 401 | Superchats Refresh-Weg ist seit 25.06.2026 tot, der Bearer lebt nur ~143 min | Vor jedem langen Abschnitt Token-Alter pruefen, Browser-Sitzung frisch halten |
| Laenderkennzahl-Heuristik verschiebt Land | Deutsche Nummern landen als oesterreichisch | Die Heilung der kaputten +1-Vorwahl raet die Vorwahl aus den ersten Ziffern | Nach der Normalisierung Stichprobe ziehen und Laenderverteilung gegen den Rohexport pruefen |
| Opt-in-Bestaetigung schlaegt fehl | Zusage kommt an, Bestaetigung nicht (real am 30.07.2026) | Folgeknoten scheitert still | Station 8 prueft alle vier Punkte, nicht nur „Lauf DONE" |
**Die Liste Kontakt nicht auf Whatsapp fuellt sich NUR, wenn der Sending-Failed-Zap
laeuft.** Fehlt der Zap, bleibt die Liste leer, alles sieht normal aus, und dieselben
toten Nummern werden jeden Monat neu beschossen. Genau das ist der Hauptverdaechtige
fuer eine sinkende Qualitaetsbewertung. Eine leere Sperrliste ist deshalb ein
Alarmzeichen, kein guter Zustand.
Kontaktlisten lassen sich ueber die API nicht loeschen (DELETE /v1/contact-lists/<cl_>
= 405, gemessen 01.08.2026). Vier neue Listen pro Lauf, zwoelf Laeufe im Jahr, mal die
Kundenzahl. Wer skaliert, braucht eine Namenskonvention, die das ertraegt, und muss
damit rechnen, dass alte Listen stehen bleiben.
GET /v4/contacts?size=1000&page=N durchblaettern und das Feld contactLists
je Kontakt auswerten. ⚠️ Ab etwa 13 schnellen Seiten kommt HTTP 429, deshalb
Pause zwischen den Seiten. Listen-Filter-Parameter auf /v3//v4/contacts
werden ignoriert (liefern immer die Gesamtzahl) und sind wertlos.
WhatsApp-Opt-in. Bewusste unternehmerische Entscheidung von Benedikt, hier nur vermerkt.
UTILITY, obwohl es eine Einladung ist. Kein Abmelde-Button,bewusst so (Benedikt: Abmelden soll nicht ein Klick sein).
⚠️ WIDERLEGT/erledigt 01.08.2026: hier stand „getipptes STOPP wird erkannt,
STOP mit einem P nicht" als offenes Problem. Das stimmt fuer Superchats
eingebaute Behandlung weiterhin, ist aber geloest durch den eigenen
Abmelde-Zap in Station 9 (36 von 36 Treffern, 0 Fehlalarme).
Wer diesen Absatz liest und Station 9 nicht kennt, baut die Loesung ein zweites Mal.
EW_Anmeldung (04.08.) erfasst nur etwa die Haelfte der echten Anmeldungen.Der Ausschluss „schon angemeldet" ist damit unvollstaendig; vollstaendig geht es
nur ueber die WebinarJam-Registrierungen.
TEST Automation - 25.06.2026, 14:12:48 (wffn_qqZMzxmWF2niBPAyzRNvf, angelegt von
Carmen Mayer selbst) steht auf ACTIVE und schickt per HTTP_REQUEST
CONTACT_FIRST_NAME, CONTACT_LAST_NAME und CONTACT_HANDLE (= die Telefonnummer)
an https://webhook.site/e398d880-…. Das ist ein oeffentlicher Endpunkt: wer die
Kennung hat, sieht die uebertragenen Daten.
Einordnung, damit niemand in Panik verfaellt: der Ausloeser ist MANUAL_TRIGGER und
numberOfRuns steht auf 0. Sie ist also nie gelaufen und feuert nicht von selbst.
Sie ist damit kein Doppelfeuer-Risiko fuer den Versand.
Trotzdem: ein aktiver Workflow, der Kundendaten an einen fremden oeffentlichen
Dienst sendet und den ein Klick ausloest, gehoert nicht in ein Produktivkonto.
⚠️ Nicht eigenmaechtig deaktivieren — er gehoert Carmen, nicht uns. Ansprechen und
sie oder Domi entscheiden lassen.
Am 01.08.2026 ist dasselbe Muster vier Mal aufgetreten. Jedes Mal sah es aus wie
ein Befund, jedes Mal war es ein Messfehler.
| Wo | Zeigte | Wahrheit |
|---|---|---|
Zapier GET /api/v4/zaps/{id} → tasks | 0 | Zap lief 20 Mal an dem Tag |
Superchat GET /v5/campaigns → recipients | 0 | 1.158 Empfaenger (steht im funnel) |
Superchat GET /v1/contact-lists → amountContacts | 0/null | Listen waren voll |
| Eigene Auswertung der Zeitleisten | 0 Abmeldungen | Feld hiess sentBy, nicht sentByActor |
Regel, die daraus folgt: Wer eine 0 bekommt, muss sie gegen einen Fall pruefen, der
garantiert NICHT 0 sein kann. Beispiele: eine Liste, von der man weiss dass sie voll ist;
ein Zap, den man selbst gerade ausgeloest hat; ein Verlauf, in dem man selbst geschrieben hat.
Erst wenn die Kontrolle anschlaegt, ist die 0 ein Ergebnis.
Zweite Regel: Auswertungen so bauen, dass sie die BASIS mitzaehlen, nicht nur die Treffer.
„0 Treffer aus 917 Verlaeufen" sieht gut aus. „0 Treffer, und 0 von 917 Verlaeufen enthielten
ueberhaupt eine Nachricht" entlarvt den Fehler sofort. Der Unterschied ist eine Zeile Code.
| Objekt | Richtig | Falsch geraten |
|---|---|---|
| Zeitleisten-Eintrag, Absender | sentBy (mit contactId / workflowId / campaignId) | sentByActor |
| Konversationsliste, Absender | lastActivity.sentByActor.type | — |
| Kontakt, Telefonnummer | mobileNumber (Objekt mit mobilePrefix/mobile) | handles |
| Zapier inbound, Absender | message.from.id | message["to[]contact_id"] |
| Zapier inbound, Text | message.content.body | message.text |
⚠️ Die Konversations-Liste und die Zeitleiste benutzen also UNTERSCHIEDLICHE
Absenderfelder. Wer den einen Namen vom anderen uebernimmt, bekommt still eine leere Menge.
Gerenderte Fassung. Die gepflegte Quelle liegt im Kundenordner als
03-runbook-reaktivierung.md. Aenderungen dort machen, nicht hier.
Kennzahlen zum laufenden Versand:
Dashboard