> ## Documentation Index
> Fetch the complete documentation index at: https://docs.northfond.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Verify signed events and handle retries safely.

NorthFond signs `<unix_timestamp>.<raw_request_body>` with HMAC-SHA256 and sends `NorthFond-Signature: t=<timestamp>,v1=<hex_digest>`.

## Verify a signature

```javascript theme={null}
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyNorthFondWebhook(rawBody, signatureHeader, secret) {
  const fields = Object.fromEntries(
    signatureHeader.split(",").map((field) => field.split("=")),
  );
  const timestamp = fields.t;
  const received = Buffer.from(fields.v1, "hex");
  const expected = Buffer.from(
    createHmac("sha256", secret)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex"),
    "hex",
  );

  const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
  return fresh && received.length === expected.length && timingSafeEqual(received, expected);
}
```

<Steps>
  <Step title="Read the raw body">Do not parse and reserialize JSON before verification.</Step>
  <Step title="Check timestamp freshness">Reject events outside your replay window.</Step>
  <Step title="Compare signatures safely">Calculate HMAC-SHA256 with the endpoint secret and use a constant-time comparison.</Step>
  <Step title="Deduplicate the event ID">Persist processed event IDs before applying business side effects.</Step>
  <Step title="Return a 2xx response">Acknowledge promptly and process expensive work asynchronously.</Step>
</Steps>

NorthFond retries failed deliveries. Dashboard users can inspect attempts, rotate endpoint secrets, send tests, and replay deliveries.

## Delivery contract

* Event IDs remain stable across retries and manual replays.
* Delivery order is not guaranteed. Use the transaction's current state as the source of truth.
* Return a `2xx` response after durable receipt, then process the event asynchronously.
* Persist the event ID before applying side effects so a retry cannot duplicate work.
* Rotating an endpoint secret changes the credential used for subsequent deliveries.

<Warning>The signature must be calculated from the exact raw bytes received. Parsing and serializing the JSON first can change whitespace or field order and invalidate verification.</Warning>
