# Webhooks

## Receiving events

Register a HTTPS endpoint in the dashboard. FinStack will POST JSON events to it:

{
  "id": "01927b3e-...",
  "type": "payment.captured",
  "tenant_id": "...",
  "created_at": "2026-06-01T00:00:00Z",
  "data": {
    "payment": { ... }
  }
}

## Verifying signatures

Every request carries an X-FinStack-Signature header. Verify it before processing:

import { createHmac, timingSafeEqual } from &#39;crypto&#39;;

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expected = createHmac(&#39;sha256&#39;, secret)
    .update(payload)
    .digest(&#39;hex&#39;);
  return timingSafeEqual(
    Buffer.from(signature, &#39;hex&#39;),
    Buffer.from(expected, &#39;hex&#39;),
  );
}

Always use a constant-time comparison — === is vulnerable to timing attacks.

## Retry policy

FinStack retries failed deliveries up to 3 times with exponential backoff: 1 min, 5 min, 30 min. An endpoint is considered failed if it returns a non-2xx status or times out after 30 seconds.

## Event types

Event
Trigger

payment.created
New payment

payment.captured
Payment captured

payment.cancelled
Payment cancelled

payment.refunded
Full or partial refund

customer.created
New customer

customer.updated
Customer profile updated