Payloads and Signatures

Understand the delivered payload, verify its signature, and reason about retries.

Every HTTP delivery carries the full event in a signed JSON payload. Verifying the signature proves the delivery came from Vanta and was not tampered with, and understanding the retry policy keeps your endpoint resilient.

The delivery payload

The request body is JSON with the event under event and the project reference under project:

json
{
  "event": {
    "id": "e1f4c6d2b3a9...",
    "type": "payment_failed",
    "timestamp": "2026-08-24T10:00:00.000Z",
    "userId": "user_842",
    "groupId": "org_112",
    "data": {
      "amount": 49.99,
      "reason": "card_declined"
    },
    "context": { "deviceType": "desktop" },
    "tags": { "source": "billing-worker" }
  },
  "project": { "id": "<project_id>" }
}

The event object mirrors the event you tracked: its id, type, timestamp, user and group references, and any data, context, or tags.

Incident deliveries

Webhooks triggered by incident.started and incident.recovered deliver the monitor and incident context alongside the trigger:

json
{
  "event": {
    "type": "incident.started",
    "id": "inc_9f2c1e4a...",
    "at": "2026-08-24T13:30:00.000Z"
  },
  "project": {
    "id": "<project_id>",
    "name": "api-production"
  },
  "monitor": {
    "id": "mon_abc123",
    "name": "Production API",
    "slug": "api-production",
    "status": "down"
  },
  "incident": {
    "id": "inc_9f2c1e4a...",
    "status": "active",
    "startedAt": "2026-08-24T13:30:00.000Z",
    "recoveredAt": null,
    "durationMs": null
  }
}

The X-Vanta-Event-Id header carries the incident id, so you can correlate the incident.started and incident.recovered deliveries for the same outage. On recovery,incident.status becomes resolved and recoveredAt and durationMs are populated.

Delivery headers

HeaderPurpose
X-Vanta-SignatureHMAC-SHA256 over {t}.{rawBody}, verifying authenticity.
X-Vanta-Event-IdThe id of the event being delivered.
X-Vanta-Delivery-IdA unique id for this delivery attempt. Use it for idempotency.
User-AgentSet to Vanta-Webhooks/1.0.

Verifying the signature

The signature header looks like t=1756026000,v1=a3f0.... The t component is a Unix timestamp, and v1 is the HMAC-SHA256 digest of {t}.{rawBody} using your signing secret. Recompute the digest and compare it in constant time, and reject deliveries older than five minutes to prevent replay attacks:

typescript
import { createHmac, timingSafeEqual } from 'crypto'

function verifyVantaSignature(secret: string, rawBody: string, header: string) {
  const parts = Object.fromEntries(
    header.split(',').map((part) => part.split('=') as [string, string]),
  )
  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(parts.t))
  if (age > 300) return false

  const expected = createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex')
  return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1, 'hex'))
}

The signature covers the raw request body exactly as received, so capture the body as the raw bytes before any parsing. Verifying the signature first is mandatory for any endpoint that acts on the payload.

Retries and backoff

Vanta retries failed deliveries with exponential backoff. The policy applies to HTTP webhooks:

ResponseBehavior
2xxSuccess. No retry.
4xx (except 429)Permanent failure. No retry.
429 or 503Rate limited. Back off (honoring Retry-After), capped at 5 attempts.
5xx or network errorRetry with backoff, capped at 5 attempts.

Each request has a 10 second timeout. Backoff steps are roughly 30 seconds, 2 minutes, 10 minutes, and 30 minutes. A delivery that exhausts its 5 attempts is marked failed and you can retry it manually from the dashboard.

Delivery history

Every webhook keeps a full delivery log: when it fired, what triggered it (an event, an incident notification, a test, or a manual retry), the attempt number, HTTP status, duration, and the truncated response body. Use this history to debug failed deliveries and to confirm your endpoint is responding correctly.