Ausgehende Webhooks
Webhooks senden Manisma-Ereignisse an einen öffentlichen HTTPS-Endpunkt Ihrer Organisation.
Endpunkt einrichten
Öffnen Sie als Admin Verwaltung → Webhooks, erstellen Sie einen Endpunkt und wählen Sie Name, URL und Ereignisse. Das Signing-Geheimnis wird einmalig angezeigt. Bewahren Sie es sicher auf. Bei Rotation gilt das neue Geheimnis ab dem Speichern.
Die URL muss:
- HTTPS verwenden;
- öffentlich über DNS erreichbar sein;
- Port 443 oder 8443 verwenden;
- keinen Benutzernamen/Passwort in der URL enthalten;
- nicht auf Localhost, private IP, Link-Local oder Cloud-Metadaten verweisen.
Verwenden Sie Test, um ein ping zu senden, bevor Sie echte Ereignisse aktivieren.
Ereignisse
| Ereignis | Auslöser |
|---|---|
ping |
Manueller Endpunkttest. |
client.created |
Kunde angelegt. |
client.updated |
Kunde geändert. |
job.created |
Auftrag angelegt. |
job.planned |
Auftragsstatus auf gepland geändert. |
job.completed |
Auftragsstatus auf Voltooid geändert. |
job.cancelled |
Auftragsstatus auf geannuleerd geändert. |
approval.approved |
Kunde hat einen Vorschlag genehmigt. |
approval.declined |
Kunde hat einen Vorschlag abgelehnt. |
workorder.completed |
Abrechnungsfähige Arbeitsauftragsdaten bei Abschluss. |
Eine Änderung an einem anderen Feld eines bereits Voltoooiden Auftrags sendet job.completed nicht erneut; der Status selbst muss sich ändern.
Envelope und Header
{
"event": "job.completed",
"version": 1,
"tenant_id": "tenant-uuid",
"occurred_at": "2026-07-13T09:15:00.000Z",
"data": {}
}
Header:
X-Manisma-Event: Ereignisname;X-Manisma-Delivery: stabile ID dieser logischen Lieferung;X-Manisma-Signature:sha256=<hex HMAC-SHA256>über den exakten Rohe-Body.
Verifizieren Sie den HMAC vor dem JSON-Parsing und verwenden Sie einen Timing-sicheren Vergleich:
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verify(rawBody, header, secret) {
if (!header?.startsWith('sha256=')) return false
const expected = createHmac('sha256', secret).update(rawBody).digest('hex')
const supplied = header.slice(7)
const a = Buffer.from(expected, 'hex')
const b = Buffer.from(supplied, 'hex')
return a.length === b.length && timingSafeEqual(a, b)
}
Payloads
Kundenereignisse enthalten id, customer_number, name, client_type, email und phone. Interne Kundennotizen fehlen.
Auftragsereignisse enthalten Auftrags-ID/-Nummer, Titel, Status, Priorität, Planung und kompakte Objekte für Kunde, Serviceadresse und Haupttechniker. Ein nicht zugewiesener oder adressloser Auftrag verwendet null.
Genehmigungsereignisse enthalten Genehmigungs-ID, job_id, Status, gewählten Slot und Antwortzeit. chosen_slot kann ein JSON-String oder älterer Freitext sein; parsen Sie defensiv.
workorder.completed enthält:
- kompakten Auftrag und Kunde;
- den zuletzt Voltoooiden Besuch, falls verfügbar;
- verwendete Materialien mit SKU, Verkaufspreis, Menge und Zeilenbetrag;
- Arbeitsdauer;
- Materialsgesamtbetrag in EUR.
Der Materialpreis ist der Verkaufspreis zum Zeitpunkt der Erstellung der Webhook-Payload, nicht notwendigerweise ein historisch festgeschriebener Preis.
Lieferung und Retries
Webhooks sind at least once. Machen Sie Ihren Empfänger idempotent bezüglich X-Manisma-Delivery. Ein erfolgreicher Empfang ist jede 2xx-Antwort. Redirects werden nicht verfolgt und jeder Versuch hat ein Timeout von 10 Sekunden.
Bei einem vorübergehenden Fehler gibt es maximal drei Versuche: sofort, nach 60 Sekunden und erneut 300 Sekunden später. Dieselbe Delivery-ID bleibt erhalten. Retries laufen derzeit im Serviceprozess und überleben kein Redeploy; prüfen Sie daher auch das Lieferlog in Webhooks auf zurückgebliebene pending-Einträge.
Speichern Sie zuerst die Delivery-ID in derselben Transaktion wie Ihre Verarbeitung und antworten Sie danach schnell mit 2xx. Verlagern Sie langsame Verarbeitung in Ihre eigene Queue.