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

# Signatures and retries

> Verify raw-body HMAC signatures and handle duplicate event delivery.

## Verify the signature

`X-Webhook-Signature` is a lowercase hexadecimal **HMAC-SHA256** of the exact JSON request body, using your webhook signing secret. It has no `sha256=` prefix.

Capture the raw bytes before JSON parsing. Re-serializing JSON changes whitespace or field order and can invalidate the signature.

```javascript Node.js verification helper theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyOutReignWebhook(rawBody, signature, secret) {
  if (typeof signature !== 'string' || !/^[a-f0-9]{64}$/.test(signature)) {
    return false;
  }
  const expected = createHmac('sha256', secret).update(rawBody).digest();
  const received = Buffer.from(signature, 'hex');
  return received.length === expected.length && timingSafeEqual(received, expected);
}
```

Pass your framework's raw-body `Buffer`, the header value and a secret from your secure environment. Reject missing or invalid signatures. Do not log the secret or private event data.

## Queued delivery retries

Normal queued deliveries have a 15-second request timeout and up to five attempts. Failed attempts become eligible for retry after 2, 4, 8 and 16 minutes respectively. Processing timing depends on the worker schedule; these are eligibility delays, not a delivery-time guarantee. After the fifth failed attempt, a queued delivery is marked `permanently_failed`.

The legacy direct-trigger path retries inline with shorter backoff and records failed attempts separately. Do not build a receiver that depends on one exact retry timetable. Use the delivery log as the source of truth for an individual attempt.

## Duplicates, replay and ordering

Retries can repeat a payload, and ordering is not guaranteed. Keep your business action idempotent and store a fingerprint of accepted events where practical. The envelope does not promise a globally unique event ID.

The signature authenticates the body, but it does not itself prevent replay. Acknowledge duplicates without repeating their side effects. Do not reject every old timestamp automatically: legitimate queued retries can arrive later than the original event.

## Test deliveries

Test requests can include `X-Webhook-Test: true`. Treat tests separately from live workflows, but still validate their signatures. Test payloads do not guarantee every real event's full `data` shape.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.