In dieser Anleitung baust du in n8n eine Outbound-Kampagne. Eine Kontaktliste in Google Sheets wird Zeile für Zeile abgearbeitet, dein smao Assistent ruft jeden Kontakt an, und das Ergebnis des Gesprächs landet automatisch zurück in der Tabelle. Am Ende steht bei jedem Kontakt, ob er erreicht wurde, was im Gespräch herausgekommen ist und wann der letzte Versuch war.
Die vier Teile des Workflows
Ein Google Sheet hält pro Kontakt die Rufnummer, den Status, die Zahl der Versuche und den Zeitpunkt des letzten Anrufs.
n8n läuft über alle offenen Kontakte und schickt pro Kontakt einen Anruf an die smao API. Zwischen zwei Anrufen liegt eine Pause.
Nach dem Gespräch fragt n8n die Anrufdaten ab und erkennt am Transkript, ob der Kontakt abgenommen und gesprochen hat.
Eine Anrufanalyse in smao kategorisiert das Gespräch und schickt das Ergebnis per Webhook an n8n, das damit die Tabelle aktualisiert.
Du brauchst einen Assistenten mit eigener Telefonnummer, einen n8n Account (Cloud oder selbst gehostet) und ein Google-Konto für die Kontaktliste.
Kontaktliste vorbereiten
Die Tabelle ist Datenquelle und Ergebnisspeicher in einem. n8n liest daraus die offenen Kontakte und schreibt nach jedem Anruf in dieselbe Zeile zurück.
Google Sheet anlegen

Lege ein Google Sheet mit den folgenden Spalten in der ersten Zeile an. Trage darunter deine Kontakte ein, jeweils mit dem Status pending und retry_count auf 0.
| Spalte | Inhalt |
|---|---|
| phone | Zielrufnummer, z. B. +49123673727 |
| status | Bearbeitungsstand des Kontakts, Startwert pending |
| retry_count | Zahl der Anrufversuche, Startwert 0 |
| last_attempt | Zeitstempel des letzten Versuchs, bleibt zunächst leer |
| Link | Link zum Anrufprotokoll, bleibt zunächst leer |
Die Rufnummern müssen im E.164-Format vorliegen: Pluszeichen, Ländervorwahl, Nummer ohne Leerzeichen und ohne führende Null, z. B. +49123673727. Nummern in anderen Formaten weist die API zurück.
Kontakte in n8n lesen
Der erste Teil des Workflows holt alle offenen Kontakte aus der Tabelle und übergibt sie einzeln an den weiteren Ablauf.
Google Sheets verbinden
Erstelle in n8n über new Credential ein Credential vom Typ Google Sheets OAuth2 API und melde dich mit deinem Google-Konto an. Erstelle anschließend einen neuen Workflow und wähle bei Add first step die Google Sheets Node mit der Action Get row(s) in sheet.
Dokument, Sheet und Filter setzen

Wähle unter Document deine Tabelle und unter Sheet das Tabellenblatt. Füge unter Filters einen Filter mit Column status und Value pending hinzu, damit nur offene Kontakte gelesen werden. Mit Execute step prüfst du direkt, ob die Zeilen ankommen.
Node umbenennen
Der Workflow bekommt später mehrere Google-Sheets-Nodes. Benenne diese Node deshalb um: Rechtsklick auf die Node, Rename, und als Namen Read contacts setzen. Auf diesen Namen greifen spätere Nodes zu.
Kontakte einzeln durchlaufen
Hänge dahinter eine Loop Over Items Node und benenne sie in Loop Over Contacts um. Sie hat zwei Ausgänge: done wird erreicht, wenn alle Kontakte abgearbeitet sind, loop gibt den jeweils nächsten Kontakt aus.
API-Schlüssel in smao erstellen
n8n spricht die smao API mit einem API-Schlüssel an. Diesen legst du in deinem smao Dashboard an.
API-Schlüssel-Seite öffnen

Wechsle in smao zu Einstellungen und dort zu API-Schlüssel. Details zu Rollen und Verwaltung findest du im Artikel API-Keys.
Schlüssel anlegen

Klicke auf + API-Schlüssel, gib einen Namen ein und wähle die Rolle Admin. Mit Erstellen wird der Schlüssel angelegt und angezeigt. Kopiere ihn.
Der API-Schlüssel wird nur einmal angezeigt. Speichere ihn direkt sicher ab, er lässt sich später nicht erneut einsehen.
Anruf über die API auslösen
Pro Kontakt schickt n8n eine Anfrage an die smao API, die den Anruf startet.
HTTP Request Node anhängen

Hänge an den loop-Ausgang der Loop Over Contacts Node eine HTTP Request Node. Setze Authentication auf Generic Credential Type und Generic Auth Type auf Bearer Auth.
Credential mit dem API-Schlüssel anlegen

Klicke auf Set up credential und trage als Bearer Token den kopierten API-Schlüssel ein, ohne das Wort „Bearer“ davor. n8n ergänzt das selbst. Speichere das Credential, du verwendest es später ein zweites Mal.
Methode und URL setzen

Setze in der Node die Methode auf POST und trage die URL des Anruf-Endpunkts ein.
Body befüllen

Schalte Send Body ein, setze Body Content Type auf JSON und Specify Body auf Using Fields Below. Lege zwei Body-Felder an. Benenne die Node danach in Outbound Call um.
| Feld | Wert |
|---|---|
| assistant_phone | Telefonnummer des Assistenten, der anrufen soll, z. B. +49302204402064 |
| to | {{ $('Read contacts').item.json.phone }} |
Ab hier löst jedes Execute step in dieser Node einen echten Anruf an die hinterlegte Nummer aus. Teste mit einer Nummer, die dir gehört.
Pause zwischen den Anrufen

Hänge hinter die Outbound Call Node eine Wait Node mit Wait Amount 2 und Wait Unit Minutes und benenne sie in Wait 2 min um. Verbinde ihren Ausgang zurück mit der Loop Over Contacts Node, damit der nächste Kontakt startet. Ohne diese Pause laufen die Anrufe in das Rate Limit der API.
Ergebnis des Anrufs auswerten
Der zweite Zweig hinter dem Anruf wartet das Gespräch ab, holt die Anrufdaten aus der API und schreibt einen ersten Status in die Tabelle. Er läuft parallel zur Kontaktschleife.
Gesprächsende abwarten
Ziehe vom Ausgang der Outbound Call Node eine zweite Verbindung in eine weitere Wait Node, diesmal mit 5 Minuten, und benenne sie Wait 5 min. Damit ist das Gespräch mit hoher Sicherheit beendet, bevor die Anrufdaten abgefragt werden.
Anrufdaten abfragen

Hänge dahinter eine HTTP Request Node mit der Methode GET. Setze Authentication wieder auf Generic Credential Type mit Bearer Auth und wähle das zuvor angelegte Credential aus. Die URL enthält die Call-ID aus der Antwort des Anrufs. Benenne die Node in Track Call um.
https://api.smao.ai/api/v1/calls/{{$('Outbound Call').item.json.data.call_id}}Tabellenzeile erneut lesen

Rechtsklick auf die Read contacts Node vom Anfang, Copy, und die Kopie hinter Track Call einfügen. Benenne sie in Reread contact data um und ändere den Filter: Column phone mit dem Wert {{ $('Loop Over Contacts').item.json.phone }}. Damit liegt der aktuelle Stand der Zeile vor, auch wenn sie zwischenzeitlich geändert wurde.
Erreichbarkeit aus dem Transkript ableiten

Füge eine Code Node mit der Action Code in JavaScript ein und benenne sie Evaluate if caller talked. Das Skript liest das Transkript des Anrufs und leitet daraus den Status ab.
const transcript = $('Track Call').first().json.data.transcript || [];
const notPickedUp = transcript.length === 0
const hasUserTurn = transcript.some(msg => msg.role === 'user');
return {status: (notPickedUp ? "not_picked_up" : !hasUserTurn ? 'not_talked' : $input.first().json.status)};| Status | Bedeutung |
|---|---|
| not_picked_up | Das Transkript ist leer, der Anruf wurde nicht angenommen |
| not_talked | Es gibt ein Transkript, aber keinen Beitrag des Angerufenen |
| bisheriger Status | Der Angerufene hat gesprochen. Der Status bleibt unverändert, bis die Anrufanalyse das Gesprächsergebnis liefert |
Status in die Tabelle schreiben

Füge eine Google Sheets Node mit der Action Update row in sheet ein und benenne sie Update status. Wähle Dokument und Tabellenblatt, setze Column to match on auf phone und trage unter Values to Update die folgenden Werte ein.
| Spalte | Wert |
|---|---|
| phone (using to match) | {{$('Loop Over Contacts').item.json.phone}} |
| status | {{ $('Evaluate if caller talked').item.json.status }} |
| last_attempt | {{$now.toISO()}} |
Zwischenstand

Der Workflow arbeitet jetzt die Kontaktliste ab, ruft an und hält fest, ob jemand erreicht wurde. Was im Gespräch besprochen wurde, kommt im nächsten Teil dazu.
Gesprächsergebnis per Webhook zurückgeben
Eine Anrufanalyse in smao wertet jedes Gespräch aus und schickt das Ergebnis an einen Webhook in n8n. Dieser zweite Workflow-Teil hat einen eigenen Trigger und läuft unabhängig von der Kontaktschleife.
Webhook-Trigger anlegen

Klicke im Canvas auf +, wähle Add another Trigger und füge einen On webhook call Trigger hinzu. Setze HTTP Method auf POST, Path auf smao-post-call und Authentication auf Header Auth. Lege über Set up credential ein Credential mit dem Namen X-Smao-Secret und einem selbst gewählten geheimen Wert an.
Der Trigger stellt zwei URLs bereit. Die Test URL nimmt Aufrufe nur an, solange in n8n Listen for test event aktiv ist. Die Production URL funktioniert erst, wenn der Workflow veröffentlicht ist. Für die Einrichtung nutzt du die Test URL.
Anrufanalyse in smao erstellen

Wechsle in smao zu Automationen und dort zu Anrufanalyse, erstelle eine neue Analyse und lege unter Eigene Felder die Variable call_outcome mit diesem Prompt an.
Analysiere das Gespräch und ordne das Ergebnis exakt einer der folgenden Kategorien zu. Gib ausschließlich den Kategorie-Schlüssel zurück, keinen weiteren Text:
callback_agreed, do_not_call, no_interest, wrong_number, other
Wähle callback_agreed nur, wenn ein konkreter Rückruftermin oder eine explizite Zusage genannt wurde.
Wähle do_not_call, wenn der Angerufene ausdrücklich sagt, dass er nicht mehr kontaktiert werden möchte.
Wähle wrong_number, wenn die erreichte Person nicht die Zielperson ist und die Nummer falsch zugeordnet ist.| Kategorie | Bedeutung |
|---|---|
| callback_agreed | Konkreter Rückruftermin oder explizite Zusage |
| do_not_call | Angerufener möchte nicht mehr kontaktiert werden |
| no_interest | Kein Interesse am Angebot |
| wrong_number | Erreichte Person ist nicht die Zielperson |
| other | Alle übrigen Gesprächsverläufe |
Füge im Editor die Node Webhook / Advanced Webhook hinzu und verbinde sie mit dem Startpunkt. Trage als URL die Test URL aus dem n8n-Trigger ein und setze die HTTP-Methode auf POST. Der Header trägt dasselbe Secret wie das Header-Auth-Credential in n8n.
{
"X-Smao-Secret": "dein-geheimes-secret"
}Im Body übergibst du die Rufnummer des Anrufers, den Link zum Anrufprotokoll und das Ergebnis der Analyse:
{
"phone": "@callerPhoneNumber",
"link": "@callLogUrl",
"call_outcome": "@call_outcome"
}Analyse dem Assistenten zuweisen

Speichere die Analyse. Öffne dann unter Assistenten den Assistenten, der die Anrufe führt, und hinterlege die neue Analyse unter Automationen bei Anrufanalysen. Erst danach wird sie nach Gesprächen dieses Assistenten ausgeführt.
Kontakt zum Webhook-Aufruf lesen

Zurück in n8n: Kopiere die Reread contact data Node und füge sie hinter den Webhook-Trigger ein. Ändere den Filterwert der Spalte phone auf {{$json.body.phone}} und benenne die Node in Read contact data um. Damit steht der aktuelle retry_count des Kontakts zur Verfügung.
Ergebnis in die Tabelle schreiben

Kopiere die Update status Node und füge sie hinter Read contact data ein. Passe die Werte an, sodass sie aus dem Webhook-Aufruf kommen.
| Spalte | Wert |
|---|---|
| phone (using to match) | {{$('Webhook').item.json.body.phone}} |
| Link | {{$('Webhook').item.json.body.link}} |
| status | {{$('Webhook').item.json.body.call_outcome}} |
| retry_count | {{ $json.retry_count + 1 }} |
| last_attempt | {{$now.toISO()}} |
Testen und live schalten
Beide Teile des Workflows sind fertig. Vor dem Livegang testest du sie einmal gemeinsam durch.
Workflow testen

Starte den oberen Teil über Execute workflow. Der erste Kontakt wird angerufen.
n8n lässt Listen for test event im Webhook-Trigger nicht anklicken, während der obere Teil noch läuft. Brich den Lauf deshalb ab, sobald er bei einer Wait Node angekommen ist, und klicke direkt danach Listen for test event. Der Webhook-Aufruf der Anrufanalyse kommt kurz nach Gesprächsende und trifft dann auf einen empfangsbereiten Trigger.
Production URL eintragen und veröffentlichen

Wenn der Test durchgelaufen ist, kopiere im Webhook-Trigger die Production URL und ersetze damit in der smao Anrufanalyse die Test URL. Klicke in n8n oben rechts auf Publish.
Kampagne starten

Ein Klick auf Execute workflow arbeitet die Kontaktliste ab. Nach jedem Gespräch stehen in der Tabelle das Gesprächsergebnis, der Zeitpunkt des Versuchs, die Zahl der Versuche und der Link zum Anrufprotokoll.