# 10 — Webhooks & Trigger

> n8n kann warten oder fragen.
> Warten ist eleganter — aber nur wenn man weiß wie.

---

## Zwei Arten zu starten: Poll vs. Push

**Polling (Schedule Trigger):** n8n fragt regelmäßig nach. "Gibt es neue Emails?" alle 5 Minuten.  
Einfach aufzusetzen. Aber: Latenz durch Polling-Intervall, unnötige API-Calls wenn nichts da ist.

**Webhook (Push):** n8n wartet. Der externe Dienst benachrichtigt n8n wenn etwas passiert.  
Echtzeit. Kein unnötiger Traffic. Komplexer aufzusetzen.

Für produktive Workflows: Webhook wenn verfügbar. Polling wenn der Dienst keine Webhooks anbietet.

---

## Der Webhook-Node

Der Webhook-Node öffnet eine öffentliche URL die auf Requests wartet.

```
Test URL:       http://localhost:5678/webhook-test/abc123
Production URL: https://dein-n8n.example.com/webhook/abc123
```

Zwei verschiedene URLs:
- **Test URL:** Nur aktiv wenn du "Listen for Test Event" drückst. Für Entwicklung.
- **Production URL:** Aktiv wenn der Workflow aktiviert ist. Für Betrieb.

**Häufiger Fehler:** Test URL beim externen Dienst eintragen, in Produktion gehen — und es funktioniert nicht. Immer die Production URL verwenden, bevor du aktivierst.

---

## HTTP-Methoden

Der Webhook-Node kann auf verschiedene HTTP-Methoden konfiguriert werden:

- **GET:** Einfache Abfragen, Query-Parameter
- **POST:** Häufigste für Webhooks — Payload im Body
- **PUT/PATCH:** Updates, je nach API-Design

Für die meisten Webhook-Use-Cases: POST.

---

## Webhook-Payload lesen

Wenn ein Dienst einen POST mit JSON-Body sendet:

```json
{
  "event": "user.created",
  "data": {
    "userId": 123,
    "email": "user@example.com"
  }
}
```

Im Workflow zugreifen:
```js
$json.body.event           // "user.created"
$json.body.data.userId     // 123
$json.body.data.email      // "user@example.com"
$json.headers["x-signature"]  // Signatur-Header falls vorhanden
$json.query.apiKey         // Query-Parameter ?apiKey=...
```

---

## Sofortige Response vs. Async

**Standard:** Der Webhook gibt `{ "success": true }` zurück sobald der Workflow startet — nicht wenn er fertig ist.

**Respond to Webhook Node:** Wenn du eine spezifische Response zurückgeben willst (z.B. bei einer API die eine Antwort erwartet), nutze den "Respond to Webhook" Node. Damit kontrollierst du was zurückgesendet wird.

```
[Webhook]
    ↓
[Verarbeitung]
    ↓
[Respond to Webhook: { "processed": true, "id": $json.result.id }]
```

Der rufende Dienst erhält dann die Response die du definierst.

**Timeout-Warnung:** Wenn die Verarbeitung länger als ~60 Sekunden dauert, kann der rufende Dienst einen Timeout bekommen. Für lange Verarbeitungen: Sofort mit `202 Accepted` antworten, Verarbeitung async fortführen.

**Wann "Respond to Webhook" keine Option ist — sondern Pflicht:**

Manche Dienste erwarten eine Response in einem bestimmten Format und innerhalb eines Zeitfensters. Kommt keine passende Antwort, interpretieren sie das als Fehler — und senden den Webhook erneut. Das Resultat: doppelte Ausführungen, doppelte Aktionen.

Konkrete Beispiele:
- **Telegram / WhatsApp:** Erwarten HTTP `200` innerhalb von ~5 Sekunden. Reagiert dein Workflow langsamer, sendet Telegram erneut. Typisches Symptom: jede Nachricht wird zweimal verarbeitet.
- **Stripe:** Webhook muss mit `200` bestätigt werden, sonst Retry bis zu 72 Stunden.
- **Typeform / Tally:** Erwarten `200` — kein Body nötig, aber der Status-Code muss stimmen.

Faustregel: Wenn ein Dienst "Retries" in seiner Webhook-Dokumentation erwähnt, ist eine explizite Response mit korrektem Status-Code Pflicht, keine Option.

---

## Webhook-Signatur validieren

Dienste wie Stripe, GitHub, Shopify senden eine Signatur mit dem Webhook — damit du prüfen kannst, dass der Request wirklich von ihnen kommt.

```js
// Code-Node: Stripe-Signatur prüfen
const crypto = require('crypto');
const payload = $json.rawBody;
const signature = $json.headers['stripe-signature'];
const secret = 'whsec_...';  // Besser: aus Credential

const hmac = crypto.createHmac('sha256', secret)
  .update(payload)
  .digest('hex');

const valid = signature.includes(hmac);
return [{ json: { ...$json, signatureValid: valid } }];
```

Dann im If-Node: `$json.signatureValid === true` als Bedingung.

---

## Lokale Entwicklung mit Webhooks

n8n auf `localhost` ist nicht von außen erreichbar. Für Tests:

**ngrok** (kostenlos für Einzelentwickler):
```bash
ngrok http 5678
# Gibt eine temporäre HTTPS-URL: https://abc123.ngrok.io
```

Diese URL beim externen Dienst eintragen. Tunnel lebt solange ngrok läuft.

**Cloudflare Tunnel:** Dauerhafter, kostenlos, keine Registrierung für Testbetrieb nötig.

---

## Trigger-Typen im Überblick

| Trigger | Wann nutzen |
|---------|-------------|
| Webhook | Dienst unterstützt Push-Events |
| Schedule (Cron) | Regelmäßige Aufgaben, kein Event-basiert |
| HTTP Request (Polling) | Dienst hat keine Webhooks |
| Chat Trigger | n8n AI-Feature, LLM-Konversationen |
| Integrierte Trigger (Slack, GitHub...) | Einfachere Konfiguration für unterstützte Dienste |

---

**Nächste Seite:** [11 — Debugging](11-debugging.md)
