Events & errors
Webhooks
Signed, retried and replayable. Add endpoints in Developers.
Webhooks are how your system finds out that an order was paid without polling for it. Bachs notifies Mercestack when a hosted checkout resolves; Mercestack verifies the provider signature, updates the transaction and ledger, then sends your app its own signed event. Add your endpoint in Commerce → Developers → Webhooks; your Mercestack signing secret is shown once, when you create it.
POST https://your-server.example.com/mercestack
Mercestack-Event-Id: 3f6c… deduplicate on this
Mercestack-Event-Type: order.paid
Mercestack-Signature: t=1774000000,v1=9a1f…
{
"id": "3f6c…",
"type": "order.paid",
"createdAt": "2026-09-18T13:04:00.000Z",
"livemode": true,
"data": { … }
}Verifying a delivery
With the Node SDK it's one call — mercestack.webhooks.constructEvent(rawBody, signature, secret) returns the event or throws. Without it:
The signature is an HMAC-SHA256 of the string "<timestamp>.<raw body>" using your endpoint secret. The timestamp is inside the signed material, so a captured delivery cannot be replayed against you tomorrow — reject anything older than a few minutes.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("=") as [string, string]),
);
const timestamp = Number(parts.t);
// Reject replays of a delivery captured earlier.
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}Delivery guarantees
- At least once. Deduplicate on
Mercestack-Event-Id; you may see the same event twice. - Retried after 30 seconds, 2 minutes, 10 minutes and 30 minutes.
- After that the delivery is marked dead and kept, so you can see what you missed and replay it once your receiver is fixed.
- An endpoint that fails 20 times in a row is switched off, visibly, rather than retried forever.
- Respond
2xxquickly and do your work afterwards. We time out at 10 seconds.
Events
product.created order.created
product.published order.paid
inventory.adjusted order.fulfilled
inventory.low order.cancelled
inventory.out_of_stock payment.failed
cart.created fulfillment.created
cart.updated fulfillment.shipped
cart.abandoned return.requested
checkout.started return.completed
giftcard.issued giftcard.redeemed
entitlement.granted customer.created
payment.transaction.succeeded payment_link.paid
payout.requested payout.paid
classroom.enrollment.confirmed classroom.enrollment.refunded
email.sent email.delivered email.delayed
email.bounced email.complained email.failed