mayarin
Guides

Verify webhooks

Verify the raw body and timestamp before trusting a Mayarin event.

Every delivery carries three headers: webhook-id (the event id, your deduplication key), webhook-timestamp, and webhook-signature in the form t=<unix>,v1=<hex>.

Use the exact raw request body. Parsing and re-serializing JSON changes the signed bytes.

import { constructWebhook } from "@mayarin/sdk";

const event = await constructWebhook({
  payload: rawBody,
  signature: request.headers.get("webhook-signature") ?? "",
  secret: process.env.MAYARIN_WEBHOOK_SECRET ?? "",
});

The verifier checks an HMAC-SHA256 signature and rejects timestamps outside the default five-minute tolerance. Store event identifiers and process them idempotently.

Answer an unverified delivery with 401. A 2xx tells the dispatcher the event was accepted and stops the retries, which run on a backoff of roughly 1m, 5m, 30m, 2h, 12h before the delivery is marked dead.

A webhook is a notification, not settlement truth. Mayarin itself re-queries authoritative provider state before advancing a payment, and your handler should re-read the payment intent before acting on it — see webhook helpers for the full payload shape, rotation handling, and an end-to-end handler.