SPICEPAY DEVELOPER DOCS
Webhook verification
The X-Webhook-Signature-512 header contains a hexadecimal HMAC-SHA512 digest of the exact request bytes.
How it works
The X-Webhook-Signature-512 header contains a hexadecimal HMAC-SHA512 digest of the exact request bytes. Use the shop's webhook signing secret to compute the expected digest.
Implementation
Read the raw body before any JSON middleware changes it. Reject a missing or malformed signature and compare equal-length byte buffers with a constant-time comparison. Parse the JSON only after verification succeeds. The API secret and webhook signing secret serve different purposes; do not substitute one for the other. Never log the secret or complete personal payment payloads.
HTTP example
const crypto = require("node:crypto");
const express = require("express");
const app = express();
// Register this raw-body route before express.json() middleware.
app.post("/webhooks/spicepay", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.get("x-webhook-signature-512") ?? "";
if (!/^[0-9a-f]{128}$/i.test(signature)) return res.sendStatus(401);
const expected = crypto
.createHmac("sha512", process.env.SPICEPAY_WEBHOOK_SECRET)
.update(req.body) // Buffer with the raw body
.digest();
const received = Buffer.from(signature, "hex");
if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
return res.status(401).send("Invalid signature");
}
let event;
try { event = JSON.parse(req.body.toString("utf8")); }
catch { return res.sendStatus(400); }
// Persist or queue event before acknowledging it.
// Deduplicate event_id and keep test events out of real fulfilment.
res.sendStatus(200);
});Related guides
Request examples
const crypto = require("node:crypto");
const express = require("express");
const app = express();
// Register this raw-body route before express.json() middleware.
app.post("/webhooks/spicepay", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.get("x-webhook-signature-512") ?? "";
if (!/^[0-9a-f]{128}$/i.test(signature)) return res.sendStatus(401);
const expected = crypto
.createHmac("sha512", process.env.SPICEPAY_WEBHOOK_SECRET)
.update(req.body) // Buffer with the raw body
.digest();
const received = Buffer.from(signature, "hex");
if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
return res.status(401).send("Invalid signature");
}
let event;
try { event = JSON.parse(req.body.toString("utf8")); }
catch { return res.sendStatus(400); }
// Persist or queue event before acknowledging it.
// Deduplicate event_id and keep test events out of real fulfilment.
res.sendStatus(200);
});Fragen zu deiner Integration? SpicePay kontaktieren ↗