Getting Started

Event Delivery

How Avvyr delivers events to your endpoint — payload format, authentication, retries, and signature verification

Event Delivery

When a domain event matches one of your subscriptions, Avvyr sends an HTTP POST to your destination URL. This page covers the payload format, authentication, headers, retry behavior, and how to verify signatures.

Request format

POST https://your-system.com/webhooks/avvyr
Content-Type: application/json
X-Webhook-Event: orderCreated
X-Webhook-Delivery: 550e8400-e29b-41d4-a716-446655440000

{
  "_meta": {
    "eventType": "orderCreated",
    "entityType": "order",
    "tenantId": "676140c4...",
    "messageId": "abc123...",
    "timestamp": "2025-06-15T14:30:00.000Z"
  },
  "data": {
    // Full entity payload
  }
}

Headers

Every webhook request includes these headers:

HeaderDescription
Content-TypeAlways application/json
X-Webhook-EventThe event type (e.g. orderCreated)
X-Webhook-DeliveryUnique ID for this delivery attempt — use for deduplication

Plus any additionalHeaders you configured on the subscription.

Authentication

You can configure how Avvyr authenticates with your endpoint. Set authType when creating the subscription.

None (default)

No authentication header is sent. Use this only for endpoints behind a firewall or with their own access controls.

Basic

Authorization: Basic base64(username:password)

Set authUsername and authPassword on the subscription.

Bearer

Authorization: Bearer {token}

Set authToken on the subscription. Useful when your endpoint expects a static API key or JWT.

HMAC

X-Webhook-Signature: sha256={hex_digest}

Set hmacSecret on the subscription. Avvyr computes an HMAC-SHA256 of the request body using your secret and sends the result in the X-Webhook-Signature header.

Verifying the signature on your side:

const crypto = require("crypto");

function verifySignature(body, signature, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(body, "utf8").digest("hex");

  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

// In your webhook handler:
const isValid = verifySignature(rawBody, req.headers["x-webhook-signature"], "your-hmac-secret");
HMAC is recommended for production use. It lets you verify that the request genuinely came from Avvyr and wasn't tampered with.

Expected response

Avvyr only checks the HTTP status code to determine if the event was received. Return any 2xx status (e.g. 200 OK or 201 Created) — no response body is required.

HTTP 200 OK

That's it. We don't inspect the response body, headers, or anything else. A 2xx status means "received" and the event is marked as delivered.

Events are delivered asynchronously by design. Do not process the event synchronously inside your handler. Acknowledge receipt immediately by returning 200, then process the data in a background job. If your endpoint takes too long to respond, the delivery is treated as failed and will be retried — which can lead to duplicate processing.

Retry behavior

If your endpoint returns an error, Avvyr can retry the delivery. Enable retries by setting retryEnabled: true and retryCount on the subscription.

What gets retried

ResponseRetried?
2xx Success — no retry
4xx (except 408, 429) Client error — not retried
408 Request Timeout Retried
429 Too Many Requests Retried
5xx Retried
Network error / timeout Retried

Backoff

Retries use exponential backoff: min(1000ms × 2^attempt, 30 seconds).

AttemptDelay
1st retry~1 second
2nd retry~2 seconds
3rd retry~4 seconds
4th retry~8 seconds
5th+ retry30 seconds (cap)

Timeout

Each delivery attempt has a 30-second timeout. If your endpoint doesn't respond within 30 seconds, the attempt is treated as a failure and will be retried (if retries are enabled). This is why it's critical to return 200 immediately and handle processing asynchronously — a slow handler that does real work before responding will hit the timeout and trigger unnecessary retries.

Error notifications

Set errorEmail on your subscription to receive an email notification when a delivery fails after all retries are exhausted. This gives your team visibility without having to monitor webhook logs manually.

Best practices

  • Return 200 immediately — acknowledge receipt, then process asynchronously in a background job or queue. Never do heavy work inside the event handler.
  • Fetch fresh data — treat the event as a notification, then call the Management API to get the latest entity state before processing. See Always fetch fresh data.
  • Use HMAC — verify that events came from Avvyr, not a spoofed source
  • Deduplicate — use X-Webhook-Delivery to handle potential duplicate deliveries
  • Enable retries — transient failures happen; retryEnabled: true with retryCount: 3 is a good default
  • Test first — use the test endpoint to verify your setup before enabling the subscription
Copyright © 2026