Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ontora.com/llms.txt

Use this file to discover all available pages before exploring further.

Every webhook delivery is signed with HMAC-SHA256 using the secret you received when you created the endpoint. Always verify the signature before processing the payload. Without verification, anyone who knows your URL can impersonate Ontora.

How signing works

Ontora computes:
signature = HMAC-SHA256(secret, raw_request_body)
…and sends it in the X-Ontora-Signature header, prefixed with sha256=:
X-Ontora-Signature: sha256=8b1a9953c4611296a827abf8c47804d7
The body is JSON serialized with no whitespace between separators (, and :). Verify against the raw bytes of the request body — re-serializing the parsed JSON will produce a different hash and fail verification.

Verification examples

import hmac, hashlib
from fastapi import FastAPI, Request, HTTPException

WEBHOOK_SECRET = b"whsec_..."

app = FastAPI()

@app.post("/webhooks/ontora")
async def receive(request: Request):
    body = await request.body()
    sent = request.headers.get("X-Ontora-Signature", "")
    expected = "sha256=" + hmac.new(WEBHOOK_SECRET, body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sent, expected):
        raise HTTPException(status_code=401, detail="invalid signature")

    payload = await request.json()
    # ... handle payload
    return {"ok": True}

Checklist

  • ✅ Use a constant-time comparison (hmac.compare_digest, crypto.timingSafeEqual, hmac.Equal). Don’t compare with ==.
  • ✅ Verify against the raw request body, not a re-serialized parse.
  • ✅ Return 200 quickly and process asynchronously if your handler is slow.
  • ✅ Be idempotent — retries can deliver the same event twice. Use X-Ontora-Delivery-Id as a dedupe key.
  • ✅ Allow some clock skew when checking the timestamp in the payload.

Rotating the secret

To rotate, delete the old endpoint and register a new one with the same URL and events. There is currently no in-place rotation — this avoids the dual-secret window and keeps verification simple.