order.paid could provision an entitlement that was never bought; a spoofed subscription.canceled could revoke access a customer is still paying for. Signature verification closes that gap: every payload Macropay sends is cryptographically signed with a secret only you and Macropay share, so your handler can prove an event is authentic before acting on it.
Macropay follows the Standard Webhooks specification, so any compliant library works out of the box and the scheme is identical across every event type — orders, subscriptions, refunds, payouts, and agent Signals API activity alike.
What gets signed
Every delivery carries three headers:
The signature is an HMAC-SHA256 over the concatenation:
- Use the raw body. Sign the exact bytes you received. Re-serializing parsed JSON reorders keys and breaks the digest.
- The ID and timestamp are part of the message. They aren’t decoration — they’re folded into what’s signed, which is what makes replay protection possible.
- Multiple signatures can appear. During secret rotation, Macropay sends signatures for both the old and new secret so you never miss a beat.
Get your signing secret
A unique secret is minted the moment you create an endpoint. Retrieve it from either place:- Dashboard — Settings → Webhooks, then open the endpoint.
- API — the response when creating a webhook endpoint.
whsec_ followed by a Base64-encoded key. Store it as a secret (environment variable, secrets manager) and never commit it.
Verify with a library (recommended)
Reach for an official Standard Webhooks library first. It handles Base64 decoding, the timestamp window, multi-signature comparison, and constant-time matching — all the places a hand-rolled check tends to go wrong.Verify manually
If you’d rather not add a dependency, reproduce the four steps yourself: enforce the timestamp window, rebuild the signed string, recompute the HMAC, and compare in constant time.Hardening checklist
Compare signatures with
timingSafeEqual (Node) or hmac.compare_digest (Python). Plain === leaks timing information that can be exploited to forge a match.Enforce the 5-minute timestamp window so a captured-but-valid payload can’t be replayed later.
Serve the endpoint over HTTPS only.
Acknowledge fast — return a
2xx within 30 seconds and offload heavy work to a queue.Make handlers idempotent. Macropay retries with exponential backoff, so key your processing on
webhook-id and ignore IDs you’ve already handled. See Webhook Delivery for the full retry schedule.Idempotency matters most for money-touching events. Because Macropay is your Merchant of Record — the seller of record that collects and remits sales tax and VAT on your behalf — events like
order.refunded and payout.paid are the source of truth for reconciliation. Process each one exactly once and your books stay clean.Skip it entirely with an adapter
Our framework adapters verify signatures for you, then hand you a typed, already-trusted event. Drop in the route and move straight to your business logic.Next.js
Route handler with verification baked in.
Express
Middleware for your webhook routes.
Fastify
Plugin that validates before your handler runs.
Hono
Edge-ready middleware for Hono.