Skip to content

Azure Webhook setup guide

Azure Event Grid Webhook (CloudEvents) — Integration Guide

This guide explains how to configure your webhook endpoint so Azure Event Grid can deliver CloudEvents v1.0 to you. It includes the required validation handshake (HTTP OPTIONS) and the runtime delivery (POST) format, with example requests and responses.

Related Documentation: These webhooks publish our Event schema. For example, the Order Event will be the contents of our payload for Order Event subscriptions


Overview

  • Protocol & schema: HTTP, CloudEvents v1.0 (structured JSON mode).
  • Handshake: CloudEvents abuse-protection validation via HTTP OPTIONS; you must echo specific headers.
  • Delivery: HTTP POST with Content-Type application/cloudevents+json
  • Retries: Event Grid retries failed deliveries with configurable max attempts and TTL (defaults: 30 attempts or 1440 minutes).

Expose Your Endpoint

  • URL: https://<your-domain>/api/events
  • Methods: Must support OPTIONS (validation) and POST (event delivery).
  • TLS: HTTPS required.
  • Timeouts: Respond to deliveries quickly (aim < 30s) to avoid retries.

Implement the Validation Handshake (HTTP OPTIONS)

When you create/enable a subscription, Event Grid sends an HTTP OPTIONS request that includes:

  • WebHook-Request-Origin: <origin-host> (required)
  • Optionally: WebHook-Request-Rate: <requests-per-minute> and/or WebHook-Request-Callback: <url> (some services use these).

You must respond with:

  • WebHook-Allowed-Origin: <same value you received> or *
  • WebHook-Allowed-Rate: <integer or *> (required if WebHook-Request-Rate was sent; otherwise SHOULD be present)
  • Allow: POST, OPTIONS
  • HTTP 200 OK (empty body is fine)

Microsoft’s docs: “The WebHook-Request-Origin header MUST be included in the validation request… Reply including WebHook-Allowed-Origin (and WebHook-Allowed-Rate).”

Example: Validation Request → Response

Request (from Azure):

OPTIONS /api/events HTTP/1.1
Host: your-api.example.com
WebHook-Request-Origin: eventgrid.azure.com
WebHook-Request-Rate: 120

Response (your server):

HTTP/1.1 200 OK
WebHook-Allowed-Origin: eventgrid.azure.com
WebHook-Allowed-Rate: 120
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, WebHook-Request-Origin, WebHook-Request-Callback, WebHook-Request-Rate, Origin

Implementation Details

Accept Event Deliveries (HTTP POST)

Event Grid delivers CloudEvents using structured content mode:

  • Content-Type: application/cloudevents+json; charset=utf-8 (single event)

CloudEvent (single) — Example

Request:

POST /api/events HTTP/1.1
Content-Type: application/cloudevents+json; charset=utf-8

{
  "specversion": "1.0",
  "type": "Contoso.OrderCreated",
  "source": "/contoso/orders",
  "id": "a4f8f7e2-6e6f-4e3e-9f6b-80d3f0f0db31",
  "time": "2025-08-20T16:20:00Z",
  "datacontenttype": "application/json",
  "data": {
    "orderId": "12345",
    "status": "created"
  }
}

Your response:

HTTP/1.1 200 OK

Reliability & Retries

Event Grid retries on non-success responses or timeouts.

  • Defaults: up to 30 attempts or 1440 minutes TTL (whichever first).
  • You can configure both max attempts (1–30) and event TTL (1–1440 minutes) on the subscription.

Event Grid uses an exponential backoff (with some randomization) and may adjust schedule if your endpoint appears unhealthy.


Security Options

  • HTTPS only (recommended with modern TLS).
  • Idempotency: Use the CloudEvent id + source to deduplicate (at-least-once delivery).

CORS

If the webhook is called server-to-server (typical), CORS isn’t required. If you still need it for tooling, return:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, WebHook-Request-Origin, WebHook-Request-Callback, WebHook-Request-Rate, Origin

(These are not part of CloudEvents validation, just standard CORS.)


Reference Server Snippet (Python/Flask)

Your Flask OPTIONS handler should mirror Azure’s CloudEvents handshake:

# Handle OPTIONS requests for CloudEvent validation
@app.route("/api/events", methods=["OPTIONS"])
def handle_options():
    origin = request.headers.get("WebHook-Request-Origin")
    if not origin:
        app.logger.info("Missing WebHook-Request-Origin header")
        return "", 400

    response = make_response("")
    response.headers["WebHook-Allowed-Origin"] = origin
    response.headers["WebHook-Allowed-Rate"] = "120"  # requests per minute
    response.headers["Allow"] = "POST, OPTIONS"

    # Optional CORS (not required for CloudEvents itself)
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "POST, OPTIONS"
    response.headers["Access-Control-Allow-Headers"] = (
        "Content-Type, WebHook-Request-Origin, WebHook-Request-Callback, WebHook-Request-Rate, Origin"
    )

    app.logger.info(f"CloudEvent validation successful for origin: {origin}")
    return response, 200

Troubleshooting

  • 400 on validation: Ensure you received WebHook-Request-Origin and echoed WebHook-Allowed-Origin correctly.
  • Wrong header casing: Some hosting stacks normalize headers differently; be liberal in reading header case. Known issue noted by community.
  • Unsupported media type: For deliveries, accept application/cloudevents+json (and -batch+json) with UTF-8.
  • Repeated deliveries: Expect at-least-once; deduplicate by id/source.
  • Persistent failures: Check Event Grid subscription retry policy / TTL and dead-letter settings.
  • General validation issues: Microsoft’s “Endpoint validation with CloudEvents schema” and troubleshooting page.

Authoritative References

  • Microsoft: Endpoint validation with CloudEvents schema.
  • Microsoft: CloudEvents v1.0 schema with Azure Event Grid.
  • Microsoft: Delivery and retry (defaults & limits).
  • CloudEvents project (spec & concepts).
  • Content type requirements for CloudEvents HTTP deliveries.

Copy-paste checklist for your team

  • OPTIONS handler echoes WebHook-Allowed-Origin (from WebHook-Request-Origin).
  • Return WebHook-Allowed-Rate (match or *).
  • Allow: POST, OPTIONS.
  • POST handler accepts application/cloudevents+json and application/cloudevents-batch+json.
  • Idempotency by id + source.
  • HTTPS enforced; optional secret header check.
  • Monitoring and logs around non-2xx responses.
  • Set Event Grid subscription retry/TTL as needed.