Paymentsettled event delivered to your endpoint
Sent when a pay link settles. Verify the X-mag3nt-Signature header
(t=<unix>,v1=<hmac-sha256(secret, "${t}.${rawBody}")>) using your
webhook secret before trusting the payload. Respond 2xx to acknowledge;
non-2xx responses are retried with backoff. The X-mag3nt-Event-Id
header is stable across retries for idempotency.
Verify against the RAW request body (the exact bytes received), not a re-serialized object. Use a constant-time comparison and reject events whose timestamp is outside a tolerance window to block replays.
TypeScript / Node:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyReceipt(
secret: string,
rawBody: string,
signatureHeader: string,
toleranceSec = 300,
): boolean {
const parts = Object.fromEntries(
signatureHeader.split(",").map((kv) => {
const i = kv.indexOf("=");
return [kv.slice(0, i).trim(), kv.slice(i + 1).trim()];
}),
) as Record<string, string>;
const t = Number(parts.t);
const v1 = parts.v1;
if (!t || !v1) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(v1);
return a.length === b.length && timingSafeEqual(a, b);
}
Python:
import hmac, hashlib, time
def verify_receipt(
secret: str, raw_body: str, signature_header: str, tolerance_sec: int = 300
) -> bool:
try:
parts = dict(p.split("=", 1) for p in signature_header.split(","))
t = int(parts["t"])
v1 = parts["v1"]
except (KeyError, ValueError):
return False
if abs(int(time.time()) - t) > tolerance_sec:
return False
expected = hmac.new(
secret.encode(), f"{t}.{raw_body}".encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, v1)
Body
Body POSTed to a registered webhook when a pay link settles. Signed via the X-mag3nt-Signature header (t=,v1=<hex hmac-sha256 of ${t}.${rawBody}>). Verify with your webhook secret before acting.
Response
Acknowledged