Eventium.aiDevelopers

WEBHOOKS

Receive account, quota and deployment signals.

A webhook endpoint is an HTTPS URL you own. When a subscribed event occurs, Eventium sends an HTTP POST with a JSON body and signature headers. Verify the signature, queue the work, and return 2xx quickly.

Open the webhook console

What you receive today

Four families of signal are delivered: billing plan changes, quota thresholds and request rejections, agent deployment updates, and webhook endpoint lifecycle changes. The authoritative list is served by the API rather than maintained here:

GET /api/webhooks/events

Event catalog

FamilyEvent types
Billingbilling.plan.changed
Quotaquota.threshold.reached, quota.request.rejected
Deploymentsagent.deployment.created, agent.deployment.updated, agent.deployment.deleted
Webhook lifecyclewebhook.endpoint.created, webhook.endpoint.updated, webhook.endpoint.deleted

Payload contract

Every delivery uses the same envelope. Only data varies by event type.

{
  "id": "0c3b1d5b-1d66-4a16-b2b5-7aa3c2c9b5ab",
  "type": "quota.threshold.reached",
  "created_at": "2026-05-26T09:14:02Z",
  "data": {
    "scope": "daily",
    "threshold": 80,
    "limit": 10000,
    "count": 8123,
    "plan": "builder"
  }
}

Three headers accompany the body: X-TitanVX-Signature, X-TitanVX-Event and X-TitanVX-Delivery. The X-TitanVX- prefix is retained for compatibility with endpoints written before the surface was renamed to Eventium; the header names are not changing underneath you.

Verify the signature

Deliveries are signed with HMAC SHA-256 over "{timestamp}.{raw_body}":

X-TitanVX-Signature: t=1764072842,v1=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Verify against the raw request body, before any JSON parsing or re-serialisation — re-encoding the body changes the bytes and the signature will not match.

import hashlib
import hmac

def verify_signature(secret: str, header: str, raw_body: bytes, tolerance: int = 300) -> bool:
    parts = dict(
        piece.split("=", 1) for piece in header.split(",") if "=" in piece
    )
    timestamp, received = parts.get("t", ""), parts.get("v1", "")
    if not timestamp or not received:
        return False

    expected = hmac.new(
        secret.encode("utf-8"),
        f"{timestamp}.{raw_body.decode('utf-8')}".encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()

    # compare_digest, never ==: an ordinary comparison leaks the signature
    # one byte at a time through its own timing.
    if not hmac.compare_digest(expected, received):
        return False

    # Reject replays of an old, genuinely signed delivery.
    import time
    return abs(time.time() - int(timestamp)) <= tolerance

A FastAPI handler that uses it:

from fastapi import FastAPI, HTTPException, Request

app = FastAPI()
ENDPOINT_SECRET = "YOUR_ENDPOINT_SECRET"

@app.post("/eventium/webhooks")
async def eventium_webhook(request: Request):
    raw_body = await request.body()
    signature = request.headers.get("X-TitanVX-Signature", "")

    if not verify_signature(ENDPOINT_SECRET, signature, raw_body):
        raise HTTPException(status_code=400, detail="Invalid signature")

    event = await request.json()
    # Queue by delivery id and return immediately -- see Retries below.
    enqueue(request.headers.get("X-TitanVX-Delivery"), event)
    return {"received": True}

Manage endpoints

POST   /api/webhooks/endpoints
GET    /api/webhooks/endpoints
PATCH  /api/webhooks/endpoints/{id}
DELETE /api/webhooks/endpoints/{id}

GET    /api/webhooks/deliveries
POST   /api/webhooks/test
GET    /api/webhooks/events

These require a signed-in session. Registering an endpoint with requests:

import requests

response = requests.post(
    "https://api.eventium.ai/api/webhooks/endpoints",
    json={
        "url": "https://example.com/eventium/webhooks",
        "events": ["quota.threshold.reached", "agent.deployment.updated"],
    },
    headers={"X-Api-Key": "YOUR_API_KEY"},
    timeout=30,
)
response.raise_for_status()
endpoint = response.json()
# The signing secret is returned once, at creation. Store it now.
print(endpoint["secret"])
The console is the shortest path.

The webhook console creates endpoints, shows recent deliveries with their status and last error, and sends a test event — without writing any of the calls above.

Retries and idempotency

Those figures are the deployed delivery worker's, not a target. The schedule, the attempt ceiling and the timeout are all configurable server-side, and this page is written from the running configuration rather than from intent.

Test your handler

Two ways, both real deliveries to your endpoint — there is no mock mode:

POST /api/webhooks/test
{
  "event_type": "webhook.test",
  "data": { "hello": "world" }
}

A test event is delivered and signed exactly like a production one, so a handler that accepts it will accept the real thing.

Client libraries

Eventium does not publish a client library for any language. The examples above use requests and the standard library only, and they are the supported way to integrate from Python.

If you followed an older version of this page.

A "Python SDK" example here was withdrawn on 2026-11-11 rather than restyled. It imported a client package that exists in no Eventium repository, in no branch history and on no package index, and the page never gave an install command — so it could not run for anyone who followed it. For the record, the withdrawn example imported titanvx_sdk and called client.webhooks.create_endpoint(...); if you copied it, replace it with the requests calls above. SDKs and libraries records what is actually available, and will list a real package name and version if one ships.