Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Events and Webhooks

ScaiGrid emits events. You can subscribe to them via outbound webhooks — ScaiGrid posts to your HTTP endpoint when something interesting happens.

Event model#

Events have a type, a source module, a tenant/partner scope, and a payload. Example:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "event_type": "request.completed",
  "event_id": "evt_abc123",
  "source": "inference_service",
  "tenant_id": "tenant_acme",
  "partner_id": "partner_internal",
  "payload": {
    "model": "scailabs/poolnoodle-omni",
    "backend_id": "be_openai_gpt4o",
    "latency_ms": 842,
    "tokens": 156
  },
  "timestamp": "2026-04-22T14:30:00.000Z"
}

Events are delivered at-least-once. Your webhook handler should be idempotent — check the event_id before acting on an event you may have already processed.

Core event types#

Event type When emitted
request.completed Every successful inference call
request.failed Every failed inference call
budget.soft_limit_reached Spend crossed soft_limit_pct for a budget
budget.hard_limit_reached Spend crossed the hard limit, requests now blocked
scaikey.user.created New user provisioned via ScaiKey webhook
scaikey.user.updated User roles or profile changed

Module event types#

Modules emit their own events. Full list per module:

  • ScaiCorescaicore.activated, scaicore.passivated, scaicore.deleted, scaicore.checkpoint_pending, scaicore.checkpoint_resolved
  • ScaiQueuescaiqueue.message.published, scaiqueue.message.claimed, scaiqueue.message.completed, scaiqueue.message.dead_lettered
  • ScaiBunkerscaibunker.usage (per-60s tick), swp.bunker.* (conversation-linked bunker events)
  • ScaiBotscaibot.conversation.started, scaibot.escalation.triggered
  • ScaiMatrixscaimatrix.document.indexed, scaimatrix.crawl.completed

Each module's documentation lists its events.

Outbound webhooks#

Register a webhook to receive events:

bash
1
2
3
4
5
6
7
8
curl -X POST https://scaigrid.scailabs.ai/v1/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-service.example/scaigrid-webhooks",
    "events": ["request.completed", "request.failed", "budget.soft_limit_reached"],
    "secret": "whsec_random_string_for_signing"
  }'

ScaiGrid POSTs each matching event to your URL as JSON:

http
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST /scaigrid-webhooks HTTP/1.1
Host: your-service.example
Content-Type: application/json
X-ScaiGrid-Signature: sha256=...
X-ScaiGrid-Event: request.completed
X-ScaiGrid-Delivery: del_xyz789

{
  "event_type": "request.completed",
  "event_id": "evt_abc123",
  ...
}

Respond with 2xx within 10 seconds. Any other response (including timeouts) is a failed delivery.

Signature verification#

Each webhook delivery is signed with HMAC-SHA256 using your secret. Verify before trusting:

python
1
2
3
4
5
6
7
import hmac, hashlib

def verify_webhook(payload: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)
typescript
1
2
3
4
5
6
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyWebhook(payload: Buffer, signatureHeader: string, secret: string): boolean {
  const expected = "sha256=" + createHmac("sha256", secret).update(payload).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}

Always verify before parsing the body. An unverified webhook could be an attacker.

Retry behavior#

Failed deliveries retry with exponential backoff: 30 seconds, 2 minutes, 10 minutes, 30 minutes, 2 hours. After 5 consecutive failures on the same webhook, it's marked failing and stops receiving events until you re-enable it. After 50 consecutive failures across any events, the webhook is auto-disabled entirely.

Per-webhook delivery history:

bash
1
2
curl "https://scaigrid.scailabs.ai/v1/webhooks/{webhook_id}/deliveries" \
  -H "Authorization: Bearer $TOKEN"

Useful when a webhook is failing and you need to see why.

Inbound webhooks#

ScaiGrid also has an inbound webhook path at /v1/internal/scaikey/webhook for ScaiKey to push user/tenant lifecycle events. This is configured server-side during setup and isn't something you integrate with as an application developer.

Replay#

If your webhook endpoint was down and you missed events, replay via the admin UI or:

bash
1
2
curl -X POST "https://scaigrid.scailabs.ai/v1/webhooks/{webhook_id}/replay?since=2026-04-22T00:00:00Z" \
  -H "Authorization: Bearer $TOKEN"

Event bus internals#

Under the hood, events flow through Redis Streams. Modules publish events; core workers forward them to webhooks. The stream retains events for a configurable window (default 100K entries) so you can replay recent events without touching the database.

Advanced users can consume directly from Redis via gRPC — see gRPC API.

What's next#

Updated 2026-05-18 15:01:29 View source (.md) rev 17