Webhooks
Webhooks melden Änderungen sofort an Ihr System - an Ihr ERP, Ihr CRM, einen eigenen Dienst oder direkt in Slack und Discord.
Einrichten
Webhooks gibt es ab dem Tarif Starter (siehe Preise). Sie legen sie in der App unter API & Webhooks → Webhook hinzufügen an:
- Ziel-URL: nur
https://und nur öffentlich erreichbare Adressen. Interne Adressen wielocalhostoder private Netze werden abgelehnt. - Ereignisse: eines oder mehrere aus der Liste unten.
- Format: JSON (signiert, für Ihre eigene Software), Slack oder Discord (fertige Nachricht für einen Kanal).
- Status: aktiv oder pausiert.
Mit Test senden schickt die App sofort ein Testereignis und zeigt die Antwort Ihres Servers. Unter Letzte Zustellungen sehen Sie die letzten 20 Zustellungen mit Status, HTTP-Code und Fehler.
Ereignisse
| Ereignis | Wann | data enthält |
|---|---|---|
location.created | Standort angelegt (in der App oder per API) oder aus dem Archiv geholt | id, name, street, zip, city, country, status, categoryId |
location.updated | Standort geändert | wie oben |
location.deleted | Standort archiviert | wie oben |
map.published | Karte veröffentlicht | id, name, token, url |
lead.created | neue Anfrage über das Kontaktformular einer Karte | id, name, email, phone, type, message, locationId, location (Name), mapId |
import.finished | CSV-Import abgeschlossen | count, ids (höchstens 500) |
Standorte aus einem CSV-Import lösen kein location.created pro Zeile aus, sondern einmal import.finished. Den kompletten Datensatz eines Standorts holen Sie bei Bedarf über die REST-API.
Was ankommt (Format JSON)
Jedes Ereignis kommt als POST mit Content-Type: application/json:
POST /ihr/webhook HTTP/1.1
Content-Type: application/json
User-Agent: MyStoreLocator-Webhooks/1.0 (+https://my-store-locator.com)
X-MSL-Event: location.created
X-MSL-Delivery: evt_1842
X-MSL-Signature: t=1792958400,sha256=5dccb3580b7f5727afacb98d93052372bbd60fccdb1166666b35cf3ac78e3c02
{"id":"evt_1842","event":"location.created","createdAt":"2026-10-25T19:20:00.000Z","data":{"id":1003,"name":"Filiale Köln","street":"Hohe Str. 1","zip":"50667","city":"Köln","country":"DE","status":"st_active_7","categoryId":12}}| Header | Bedeutung |
|---|---|
X-MSL-Event | Name des Ereignisses |
X-MSL-Delivery | ID der Zustellung, gleich dem id im Inhalt. Bei Wiederholungen bleibt sie gleich - nutzen Sie sie, um doppelte Zustellungen zu erkennen |
X-MSL-Signature | t=<Unix-Zeit>,sha256=<HMAC> zum Prüfen der Echtheit |
Das Testereignis aus der App hat event: "test" und data: { "test": true }.
Signatur prüfen
Den Schlüssel finden Sie in der App beim Webhook unter Signatur-Secret (HMAC-SHA256). Die Signatur ist ein HMAC-SHA256 über <t>.<Inhalt> - also den Zeitstempel aus dem Header, einen Punkt und den unveränderten Inhalt der Anfrage, als Hex-Zeichenkette. Prüfen Sie den Inhalt, bevor Sie ihn als JSON lesen, und lehnen Sie alte Zeitstempel ab, damit niemand eine mitgeschnittene Zustellung erneut abspielen kann.
Node.js (Express):
const crypto = require('crypto');
const express = require('express');
const app = express();
function verify(rawBody, header, secret) {
const m = /^t=(\d+),sha256=([a-f0-9]{64})$/.exec(header || '');
if (!m) return false;
if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false; // älter als 5 Minuten
const expected = crypto.createHmac('sha256', secret).update(m[1] + '.' + rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}
app.post('/msl-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const raw = req.body.toString('utf8');
if (!verify(raw, req.get('X-MSL-Signature'), process.env.MSL_WEBHOOK_SECRET)) return res.sendStatus(401);
const event = JSON.parse(raw);
res.sendStatus(204); // sofort bestätigen ...
handle(event); // ... und danach verarbeiten
});PHP:
$raw = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_MSL_SIGNATURE'] ?? '';
if (!preg_match('/^t=(\d+),sha256=([a-f0-9]{64})$/', $header, $m) || abs(time() - (int) $m[1]) > 300) {
http_response_code(400);
exit;
}
$expected = hash_hmac('sha256', $m[1] . '.' . $raw, getenv('MSL_WEBHOOK_SECRET'));
if (!hash_equals($expected, $m[2])) {
http_response_code(401);
exit;
}
$event = json_decode($raw, true);
http_response_code(204);Slack- und Discord-Nachrichten sind nicht signiert. Sie enthalten nur eine kurze Zusammenfassung für Menschen, nicht die Daten oben.
Zustellung und Wiederholungen
- Jede Antwort mit Status 2xx gilt als zugestellt. Antworten Sie schnell und verarbeiten Sie danach - nach 10 Sekunden ohne Antwort gilt die Zustellung als fehlgeschlagen.
- Weiterleitungen (3xx) folgen wir nicht. Tragen Sie die endgültige Adresse ein.
- Bei einem Fehler versuchen wir es nach 1, 5 und 30 Minuten erneut. Nach dem vierten erfolglosen Versuch gilt die Zustellung als fehlgeschlagen.
- Durch Wiederholungen kann sich die Reihenfolge verschieben. Ordnen Sie Ereignisse über
createdAt, nicht über die Ankunftszeit. - Pausierte oder gelöschte Webhooks bekommen keine offenen Zustellungen mehr.
- Die Liste der Zustellungen wird nach 30 Tagen gelöscht.
Webhooks per API anlegen
Webhooks lassen sich nicht nur in der App, sondern auch über die API anlegen und entfernen: POST /api/v1/ext/webhooks und DELETE /api/v1/ext/webhooks/{id} mit einem API-Key mit der Berechtigung webhooks:write. So verbinden sich Zapier, n8n und Make ohne Kopieren von Adressen. Die Felder stehen auf der Seite REST-API.
Probieren Sie es mit Ihren eigenen Standorten aus.
Konto anlegen, Standorte importieren, Karte einbinden. Der Free-Plan bleibt kostenlos - Pro können Sie 14 Tage testen.