Integrazione
Webhooks
Have events about sessions, payments and devices sent to your system, with signature verification.
Questa pagina non è ancora disponibile nella tua lingua. Vedi la versione inglese.
Webhooks report events to an HTTPS URL of your choice, for example when charging starts or a session is settled. You don't have to poll the API.
Create an endpoint
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"] }'
The response contains the secret for signature verification. It is shown only in this response. Without events you receive all events (["*"]).
Events
| Type | When |
|---|---|
session.created | Session created |
session.started | Charging started |
session.stopped | Charging ended |
session.settled | Session settled, receipt created |
session.failed | Payment failed, expired or cancelled |
payment.authorized | Amount reserved or package paid |
payment.captured | Final amount captured |
payment.released | Reservation released |
payment.refunded | Refund executed |
device.online, device.offline, device.error | Charge point state changed |
terminal.online, terminal.offline | Terminal state changed |
integration.error | Connection to manufacturer or payment partner disrupted |
session.updated is only distributed live to the dashboard and not sent as a webhook, because it occurs very often during charging.
Structure
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 }
}
Verify the signature
The Ladehase-Signature header contains a timestamp t and the signature v1. v1 is an HMAC-SHA256 over t + . + the unmodified raw request body, keyed with the endpoint secret, hex encoded.
- Read the raw body before parsing it as JSON.
- Compute
HMAC_SHA256(secret, t + "." + rawBody). - Compare the result with
v1in constant time. - Reject requests whose
tdiffers from the current time by more than 5 minutes.
With the SDK it is one line:
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("Invalid signature", { status: 400 });
const event = JSON.parse(body);
// handle event …
return new Response(null, { status: 204 });
}
Without the 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);
}
Don't trust webhook content blindly. For important decisions, read the session again with GET /v1/sessions/{id}.
Response and retries
Respond within 10 seconds with a 2xx status. Otherwise Ladehase retries after 1 minute, 5 minutes, 30 minutes, 2, 6, 12, 24 and another 24 hours, about 3 days in total. Events may arrive twice, so check the id and process each event only once.
See the delivery log with GET /v1/webhook_endpoints/{id}/deliveries. Resend single events with POST /v1/events/{id}/resend.
Hai trovato un errore? Scrivi a developer@ladehase.com.