SoxAIDocs
Guides

Webhooks

Receive real-time notifications for usage and billing events

Webhooks

Webhooks let you receive real-time HTTP notifications when specific events occur in your SoxAI account.

Configuring a Webhook

Console: Settings → Webhooks → Add Webhook

FieldDescription
URLHTTPS endpoint to receive events
EventsSelect which event types to subscribe to
SecretUsed to verify webhook signatures

Event Types

EventDescription
quota.thresholdA quota window has reached a configured percentage (e.g. 80%)
quota.exceededA quota window has been fully consumed
balance.lowAccount balance has dropped below a threshold
balance.depletedAccount balance has reached zero
request.completedA single API request completed (high-volume, use carefully)

Webhook Payload

All events follow this structure:

{
  "id": "evt_01jq4abc",
  "type": "quota.threshold",
  "created_at": "2026-03-31T12:00:00Z",
  "tenant_id": 1,
  "data": {
    "window": "1h",
    "dimension": "input_tokens",
    "used": 80000,
    "limit": 100000,
    "percentage": 80,
    "resets_at": "2026-03-31T12:47:00Z"
  }
}

Verifying Signatures

SoxAI signs every webhook with an HMAC-SHA256 signature using your webhook secret. Always verify this in production:

import hashlib
import hmac
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your-secret-here"

@app.route("/webhook", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-SoxAI-Signature")
    timestamp = request.headers.get("X-SoxAI-Timestamp")

    if not signature or not timestamp:
        abort(400)

    # Prevent replay attacks — reject events older than 5 minutes
    import time
    if abs(time.time() - int(timestamp)) > 300:
        abort(400)

    # Verify signature
    payload = f"{timestamp}.{request.get_data(as_text=True)}"
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(f"sha256={expected}", signature):
        abort(403)

    event = request.get_json()
    handle_event(event)
    return "", 200

def handle_event(event):
    if event["type"] == "quota.exceeded":
        send_alert_to_slack(event)
    elif event["type"] == "balance.low":
        trigger_auto_topup(event)

Node.js Verification

import crypto from "crypto";
import express from "express";

const app = express();
const WEBHOOK_SECRET = process.env.SOXAI_WEBHOOK_SECRET!;

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-soxai-signature"] as string;
  const timestamp = req.headers["x-soxai-timestamp"] as string;

  const payload = `${timestamp}.${req.body.toString()}`;
  const expected = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(payload)
    .digest("hex");

  if (`sha256=${expected}` !== signature) {
    return res.status(403).send("Invalid signature");
  }

  const event = JSON.parse(req.body.toString());
  console.log("Event:", event.type);
  res.sendStatus(200);
});

Retry Policy

If your endpoint returns a non-2xx response or times out (timeout: 30 seconds), SoxAI retries the delivery with exponential backoff:

AttemptDelay
1st retry5 minutes
2nd retry30 minutes
3rd retry2 hours
4th retry12 hours

After 4 failed retries, the event is marked as permanently failed. You can view failed deliveries and manually replay them in the Console under Settings → Webhooks → [Webhook] → Deliveries.

Testing Webhooks

Use the Send Test Event button in the Console to send a sample payload to your endpoint. This helps verify your signature verification code before going live.