Alerts

Alerts turn completed traces and spend controls into operational signals. In closed beta, Olyx supports two webhook alert paths: optimization grade alerts after trace completion and circuit breaker alerts when an API key crosses its hourly spend cap.

The practical rule is: use alert webhooks for immediate operational events; use insights for review and optimization workflows. Webhook alerts are asynchronous and best-effort. They are useful for notifying your systems, but they are not a replacement for your own incident management, retry queues, or provider-side budget controls.

What Alerts Detect

Olyx evaluates alerts from data it already records: completed trace summaries, API key spend counters, and project insights. The table below separates what can deliver a webhook today from what is currently exposed as an insight.

SignalDeliveryWhat it means
Optimization gradeWebhookA completed trace received a worse grade than the project’s configured threshold.
Circuit breaker trippedWebhookAn API key crossed its hourly spend cap and was paused.
Migration insightDashboard/APIA task pattern may be a candidate for a cheaper model. Validate with replays before changing routing.
Latency insightDashboard/APIA model or task pattern has high P99 latency over the lookback window.
Intent pattern insightDashboard/APIA task type is common enough that it may deserve its own routing rule.

During closed beta, avoid treating these signals as contractual quality benchmarks. They are operational cues for debugging, cost review, and safe rollout planning.

flowchart LR TRACE[COMPLETED TRACE] GRADE[GRADE CHECK] WEBHOOK[ALERT WEBHOOK] INSIGHTS[INSIGHTS ENGINE] REVIEW[ENGINEERING REVIEW] TRACE --> GRADE GRADE -->|below threshold| WEBHOOK TRACE --> INSIGHTS INSIGHTS --> REVIEW

Webhook Delivery

Alert webhooks are configured per project. You can add them from Settings -> Alert Webhooks or through the API. Each webhook has a URL and a secret. Olyx signs each payload with that secret so your endpoint can reject spoofed requests.

Webhook delivery happens in a background job. Olyx expects a 2xx response from your endpoint; network errors, timeouts, and non-2xx responses are retried by the job runner. The current beta job retries up to five attempts with backoff. Keep handlers fast and idempotent, because webhook delivery can be retried.

flowchart LR ALERT[ALERT EVENT] QUEUE[BACKGROUND JOB] SIGN[SIGN PAYLOAD] POST[POST TO ENDPOINT] OK{TWO XX} RETRY[RETRY LATER] LOG[STORE DELIVERY STATE] ALERT --> QUEUE QUEUE --> SIGN SIGN --> POST POST --> OK OK -->|yes| LOG OK -->|no| RETRY RETRY --> POST

Create a Webhook

Use a session-authenticated request from the dashboard or your internal admin tooling. The secret is returned on create; store it in your application secret manager because it is needed to verify X-Olyx-Signature.

POST /api/v1/projects/:project_id/alert_webhooks
Content-Type: application/json

{
  "alert_webhook": {
    "url": "https://yourapp.example.com/olyx/alerts",
    "secret": "your-signing-secret"
  }
}
import os
import httpx

session_token = os.environ["OLYX_SESSION_TOKEN"]
project_id = os.environ["OLYX_PROJECT_ID"]

response = httpx.post(
    f"https://api.olyx.ai/api/v1/projects/{project_id}/alert_webhooks",
    headers={"Authorization": f"Bearer {session_token}"},
    json={
        "alert_webhook": {
            "url": "https://yourapp.example.com/olyx/alerts",
            "secret": os.environ["OLYX_WEBHOOK_SECRET"],
        }
    },
)
response.raise_for_status()

webhook = response.json()
print(webhook["id"])
print(webhook["secret_last4"])

Payload Fields

Payloads vary by alert type, but these fields are stable enough to build handlers around in closed beta.

FieldTypeDescription
alert_typestringThe alert category, such as optimization_grade or circuit_breaker_tripped.
project_idstring/integerThe project that generated the alert.
triggered_atISO 8601 stringWhen Olyx detected the alert condition.
trace_idstringPresent for trace-grade alerts. Points to the completed trace.
gradestringPresent for optimization-grade alerts. The trace grade that crossed the threshold.
thresholdstringPresent for optimization-grade alerts. The configured minimum acceptable grade.
key_idstringPresent for circuit breaker alerts. The API key that was paused.
current_spendnumberPresent for circuit breaker alerts. The spend observed in the active hourly window.

Example Payloads

An optimization-grade alert is emitted after a trace completes and its grade is worse than the configured threshold.

{
  "alert_type": "optimization_grade",
  "project_id": 42,
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "grade": "D",
  "threshold": "B",
  "total_cost": 0.0182,
  "triggered_at": "2026-04-12T09:00:00Z"
}

A circuit-breaker alert is emitted when an API key crosses its hourly spend cap.

{
  "alert_type": "circuit_breaker_tripped",
  "key_id": "ak_abc123",
  "key_name": "Production",
  "project_id": 42,
  "hourly_limit": 5.0,
  "current_spend": 5.18,
  "status": "tripped",
  "triggered_at": "2026-04-12T09:00:00Z"
}

Signature Verification

Each configured webhook delivery includes X-Olyx-Signature. The value is an HMAC-SHA256 digest of the raw request body using the webhook secret.

Verify the raw body before parsing the payload. Do not recompute the signature from a decoded JSON object, because formatting differences change the digest.

import hashlib
import hmac
import json
import os

from fastapi import FastAPI, Header, HTTPException, Request

app = FastAPI()


def valid_signature(raw_body: bytes, signature: str | None) -> bool:
    secret = os.environ["OLYX_WEBHOOK_SECRET"].encode()
    expected = "sha256=" + hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature or "")


@app.post("/olyx/alerts")
async def receive_olyx_alert(
    request: Request,
    x_olyx_signature: str | None = Header(default=None),
):
    raw_body = await request.body()

    if not valid_signature(raw_body, x_olyx_signature):
        raise HTTPException(status_code=401, detail="Invalid signature")

    payload = json.loads(raw_body)

    if payload["alert_type"] == "circuit_breaker_tripped":
        notify_oncall(payload)
    elif payload["alert_type"] == "optimization_grade":
        open_cost_review(payload)

    return {"ok": True}

Circuit Breaker Alerts

Circuit breaker alerts are tied to API key hourly spend caps. When the cap is crossed, Olyx marks the key as tripped and rejects new requests made with that key until you reset the key or adjust the cap.

flowchart TD REQUEST[REQUEST WITH API KEY] SPEND[CHECK HOURLY SPEND] LIMIT{OVER LIMIT} ALLOW[ALLOW REQUEST] TRIP[MARK KEY TRIPPED] ALERT[ENQUEUE ALERT] REJECT[REJECT NEW REQUESTS] REQUEST --> SPEND SPEND --> LIMIT LIMIT -->|no| ALLOW LIMIT -->|yes| TRIP TRIP --> ALERT TRIP --> REJECT

Reset the key only after you understand the cause. If the spend counter is still above the limit, the key can trip again on the next request.

PATCH /api/v1/keys/:key_id
Content-Type: application/json

{
  "status": "active"
}
import os
import httpx

response = httpx.patch(
    "https://api.olyx.ai/api/v1/keys/ak_abc123",
    headers={"Authorization": f"Bearer {os.environ['OLYX_SESSION_TOKEN']}"},
    json={"status": "active"},
)
response.raise_for_status()

Thresholds & Configuration

Closed-beta alert configuration is intentionally small. Prefer simple thresholds that catch obvious waste or runaway traffic, then tune them after you have real trace volume.

Optimization Grade Threshold

The optimization-grade alert compares a completed trace grade to settings.alerts.min_optimization_grade. The default threshold is B.

PATCH /api/v1/projects/:project_id
Content-Type: application/json

{
  "project": {
    "settings": {
      "alerts": {
        "min_optimization_grade": "B"
      }
    }
  }
}

API Key Spend Caps

Set hourly_limit on an API key to pause that key when the rolling hourly spend counter crosses the cap.

PATCH /api/v1/keys/:key_id
Content-Type: application/json

{
  "hourly_limit": 10.0
}

Setting hourly_limit to null removes the per-key cap. Keep provider-side limits in place if you need hard budget enforcement outside Olyx.

Webhook Management

Webhook records are project scoped and require owner or admin access.

OperationEndpointNotes
List webhooksGET /api/v1/projects/:project_id/alert_webhooksReturns URL, active state, secret suffix, and delivery timestamps.
Create webhookPOST /api/v1/projects/:project_id/alert_webhooksAccepts url and optional secret. Generates a secret when omitted.
Delete webhookDELETE /api/v1/projects/:project_id/alert_webhooks/:idRemoves the destination. Delivery stops immediately.

Insights vs. Alerts

Insights are optimization recommendations, not webhook incidents. They are generated from trace history and exposed in the dashboard and API so you can review them before changing routing.

InsightTriggerRecommended action
migration_alertA task pattern may be cheaper on another registered model.Use Replays to validate the model before changing routing.
latency_alertP99 latency exceeds the beta threshold for a model or task pattern.Inspect slow traces and check prompt size, provider behavior, and tool latency.
intent_patternA recurring intent lacks a dedicated routing rule.Add or adjust a routing tier so that traffic lands on the intended model family.

You can refresh insights manually:

POST /api/v1/projects/:project_id/insights/refresh
import os
import httpx

project_id = os.environ["OLYX_PROJECT_ID"]

response = httpx.post(
    f"https://api.olyx.ai/api/v1/projects/{project_id}/insights/refresh",
    headers={"Authorization": f"Bearer {os.environ['OLYX_SESSION_TOKEN']}"},
)
response.raise_for_status()

Integration Targets

Olyx sends HTTP payloads. Your webhook endpoint decides where the signal goes next: Slack, PagerDuty, Linear, an internal queue, or a custom remediation workflow.

For production handlers, make the webhook endpoint boring:

  • verify X-Olyx-Signature
  • write the payload to your own queue or database
  • return 2xx quickly
  • process slow downstream work outside the request cycle
  • make every action idempotent because retries can happen
def route_alert(payload: dict) -> None:
    alert_type = payload["alert_type"]

    if alert_type == "circuit_breaker_tripped":
        page_oncall(
            title="Olyx API key paused",
            body=f"{payload['key_name']} crossed ${payload['hourly_limit']} hourly spend",
        )
        return

    if alert_type == "optimization_grade":
        create_review_ticket(
            title=f"Trace {payload['trace_id']} crossed grade threshold",
            metadata=payload,
        )
        return

    log_unknown_alert(payload)

Why This Matters

Alerts help you notice when AI traffic becomes expensive, slow, or blocked by a spend guard. They are intentionally small in closed beta: a few high-signal webhook events, signed delivery, and project insights that point you toward the next investigation.

Was this page helpful?