Parksby sends booking and payment events to your system via signed webhooks. Add your endpoint during parking setup, store the secret key securely, and use this guide to verify and process events safely.
Four steps to a working receiver
event_id
Always compute HMAC over the raw request body. Parsed JSON will fail verification.
Parksby delivers booking and payment events to your webhook endpoint so your system stays in sync. You’ll add your endpoint when setting up a parking space, and you’ll receive a secret key for verification.
Event names are lowercase and case-sensitive.
payment.confirmed
booking.activated
booking.completed
booking.checked_in
booking.checked_out
You can add your webhook endpoint while setting up a parking space on Parksby. We’ll display a secret key at setup time — store it securely because it is used to verify webhook signatures.
You’ll see a sample payload during setup. Your webhook receives this JSON structure, with event-specific details
inside the data object.
{
"event_id": "uuid",
"event_type": "payment.confirmed",
"occurred_at": "2026-01-28T12:34:56Z",
"data": {
"booking_id": "uuid",
"parking_id": "uuid",
"tenant_id": "uuid",
"vehicle_plate": "KXX 123X",
"space_no": 5,
"status": "completed",
"payment_status": "paid",
"payment_reference": "PSP_REF",
"total_price": "1000.00",
"final_price": "1000.00",
"currency": "KES",
"entry_time": "2026-01-28T10:00:00Z",
"exit_time": "2026-01-28T11:00:00Z",
"entry_source": "user",
"exit_source": "hardware"
}
}
Every request is signed with HMAC-SHA256 using the secret key provided during setup, and includes a timestamp for replay protection.
X-Parksby-TimestampX-Parksby-SignatureX-Parksby-Event-IDevent_idimport crypto from "crypto";
const signature = req.headers["x-parksby-signature"];
const timestamp = Number(req.headers["x-parksby-timestamp"]);
const rawBody = req.rawBody; // Buffer or raw string
const tooOld = Math.abs(Date.now() / 1000 - timestamp) > 300;
if (tooOld) throw new Error("Stale webhook");
const expected = crypto
.createHmac("sha256", process.env.PARKSBY_WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
throw new Error("Invalid signature");
}
event_id
event_idpayment.confirmed