Zum Inhalt springen

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

TypWann
session.createdSitzung angelegt
session.startedLadung hat begonnen
session.stoppedLadung beendet
session.settledSitzung abgerechnet, Quittung erstellt
session.failedZahlung fehlgeschlagen, verfallen oder abgebrochen
payment.authorizedBetrag reserviert oder Paket bezahlt
payment.capturedEndbetrag belastet
payment.releasedReservation freigegeben
payment.refundedRückerstattung ausgeführt
device.online, device.offline, device.errorZustand eines Ladepunkts hat sich geändert
terminal.online, terminal.offlineZustand eines Terminals hat sich geändert
integration.errorVerbindung 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.

  1. Lies den Rohtext der Anfrage, bevor du ihn als JSON verarbeitest.
  2. Berechne HMAC_SHA256(secret, t + "." + rohtext).
  3. Vergleiche das Ergebnis zeitkonstant mit v1.
  4. Lehne Anfragen ab, deren t mehr 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.