Integration
Webhooks
Ereignisse zu Sitzungen, Zahlungen und Geräten an dein System senden lassen, mit Signaturprüfung.
Webhooks melden Ereignisse an eine HTTPS-Adresse deiner Wahl, zum Beispiel wenn eine Ladung beginnt oder abgerechnet ist. So musst du die API nicht ständig abfragen.
Endpunkt anlegen
curl -X POST https://api.ladehase.com/v1/webhook_endpoints \
-H "Authorization: Bearer lh_test_…" \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.ch/webhooks/ladehase", "events": ["session.settled", "device.offline"] }'
Die Antwort enthält das Geheimnis secret für die Signaturprüfung. Es wird nur in dieser Antwort angezeigt. Ohne events erhältst du alle Ereignisse (["*"]).
Ereignisse
| Typ | Wann |
|---|---|
session.created | Sitzung angelegt |
session.started | Ladung hat begonnen |
session.stopped | Ladung beendet |
session.settled | Sitzung abgerechnet, Quittung erstellt |
session.failed | Zahlung fehlgeschlagen, verfallen oder abgebrochen |
payment.authorized | Betrag reserviert oder Paket bezahlt |
payment.captured | Endbetrag belastet |
payment.released | Reservation freigegeben |
payment.refunded | Rückerstattung ausgeführt |
device.online, device.offline, device.error | Zustand eines Ladepunkts hat sich geändert |
terminal.online, terminal.offline | Zustand eines Terminals hat sich geändert |
integration.error | Verbindung zu Hersteller oder Zahlungspartner gestört |
session.updated wird nur live an das Dashboard verteilt und nicht als Webhook versendet, weil es während einer Ladung sehr häufig vorkommt.
Aufbau
POST /webhooks/ladehase HTTP/1.1
Content-Type: application/json
User-Agent: Ladehase-Webhooks/1.0
Ladehase-Event: session.settled
Ladehase-Signature: t=1792958400,v1=5f2b9c…
{
"id": "evt_…",
"object": "event",
"type": "session.settled",
"livemode": true,
"created_at": "2026-10-25T08:30:00.000Z",
"data": { "id": "ses_…", "object": "session", "state": "settled", "captured_amount": 950 }
}
Signatur prüfen
Die Kopfzeile Ladehase-Signature enthält einen Zeitstempel t und die Signatur v1. v1 ist ein HMAC-SHA256 über t + . + den unveränderten Rohtext der Anfrage, mit dem Geheimnis des Endpunkts als Schlüssel, hexadezimal codiert.
- Lies den Rohtext der Anfrage, bevor du ihn als JSON verarbeitest.
- Berechne
HMAC_SHA256(secret, t + "." + rohtext). - Vergleiche das Ergebnis zeitkonstant mit
v1. - Lehne Anfragen ab, deren
tmehr als 5 Minuten von der aktuellen Zeit abweicht.
Mit dem SDK geht das in einer Zeile:
import { verifyWebhook } from "@ladehase/sdk";
export async function POST(request: Request) {
const body = await request.text();
const ok = await verifyWebhook(body, request.headers.get("ladehase-signature") ?? "", process.env.LADEHASE_WEBHOOK_SECRET!);
if (!ok) return new Response("Signatur ungültig", { status: 400 });
const event = JSON.parse(body);
// Ereignis verarbeiten …
return new Response(null, { status: 204 });
}
Ohne SDK, in Node.js:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(body: string, header: string, secret: string) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!parts.v1 || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest();
const given = Buffer.from(parts.v1, "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}
Vertrau dem Inhalt eines Webhooks nicht blind. Lies bei wichtigen Entscheiden die Sitzung mit GET /v1/sessions/{id} nach.
Antwort und Wiederholungen
Antworte innert 10 Sekunden mit einem Status 2xx. Andernfalls versucht Ladehase es erneut: nach 1 Minute, 5 Minuten, 30 Minuten, 2, 6, 12, 24 und nochmals 24 Stunden, insgesamt rund 3 Tage. Ereignisse können doppelt ankommen. Prüfe darum die id und verarbeite jedes Ereignis nur einmal.
Das Zustellprotokoll siehst du mit GET /v1/webhook_endpoints/{id}/deliveries. Einzelne Ereignisse sendest du mit POST /v1/events/{id}/resend erneut.
Fehler gefunden? Schreib an developer@ladehase.com.