Webhooks

Subscribe to events like balance changes, user connections, and usage completions. Quota delivers webhook payloads to your HTTPS endpoint and signs every request so you can verify authenticity.

Events

EventDescription
user.connectedA user linked their Quota account to your app via OAuth
user.disconnectedA user unlinked their account
balance.updatedA user's credit balance changed
balance.lowA user's balance dropped below the configured threshold
usage.completedAn API request completed and credits were deducted

Event Payloads

Every webhook delivery sends a JSON body with an id, type, created_at, and event-specific data. Below are examples for each event type.

balance.updated

Sent when a user's credit balance changes after an API request.

{
  "id": "evt_abc123",
  "type": "balance.updated",
  "created_at": "2026-01-15T12:00:00.000Z",
  "data": {
    "user_id": "usr_123",
    "new_balance": 450,
    "amount_spent": 50,
    "model": "gpt-4o",
    "endpoint": "/v1/chat/completions"
  }
}

balance.low

Sent when a user's balance drops below the configured low_balance_threshold.

{
  "id": "evt_def456",
  "type": "balance.low",
  "created_at": "2026-01-15T12:05:00.000Z",
  "data": {
    "user_id": "usr_123",
    "current_balance": 45,
    "threshold": 50
  }
}

usage.completed

Sent after each API request completes and credits are deducted.

{
  "id": "evt_ghi789",
  "type": "usage.completed",
  "created_at": "2026-01-15T12:00:01.000Z",
  "data": {
    "user_id": "usr_123",
    "model": "gpt-4o",
    "prompt_tokens": 150,
    "completion_tokens": 80,
    "total_tokens": 230,
    "credits_used": 50
  }
}

user.connected

Sent when a user links their Quota account to your app via OAuth.

{
  "id": "evt_jkl012",
  "type": "user.connected",
  "created_at": "2026-01-15T10:00:00.000Z",
  "data": {
    "user_id": "usr_123",
    "email": "user@example.com"
  }
}

user.disconnected

Sent when a user unlinks their account from your app.

{
  "id": "evt_mno345",
  "type": "user.disconnected",
  "created_at": "2026-01-15T14:00:00.000Z",
  "data": {
    "user_id": "usr_123",
    "email": "user@example.com"
  }
}

Signature Verification

Every delivery includes an X-Quota-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret.

import crypto from "crypto";

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

The Core SDK provides verifyWebhookSignature (using Web Crypto, works on edge runtimes), and the Next.js SDK adds createWebhookHandler for automatic route handling.

Headers

HeaderDescription
X-Quota-SignatureHMAC-SHA256 hex digest of the raw body
X-Quota-EventThe event type (e.g. balance.updated)
Content-Typeapplication/json
User-AgentQuota-Webhooks/1.0

Endpoints

POST /v1/webhooks

Create a new webhook subscription.

curl -X POST https://api.usequota.ai/v1/webhooks \
  -H "Authorization: Bearer sk-quota-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "your_client_id",
    "url": "https://yourapp.com/api/webhooks/quota",
    "events": ["balance.updated", "balance.low", "usage.completed"],
    "low_balance_threshold": 50
  }'

Response (201):

{
  "id": "wh_abc123",
  "url": "https://yourapp.com/api/webhooks/quota",
  "events": ["balance.updated", "balance.low", "usage.completed"],
  "secret": "whsec_abc123...",
  "low_balance_threshold": 50,
  "active": true,
  "created_at": "2026-01-15T12:00:00.000Z"
}

Important: The secret is only returned on creation. Store it securely for signature verification.

GET /v1/webhooks

List all webhooks for a client.

curl https://api.usequota.ai/v1/webhooks?client_id=your_client_id \
  -H "Authorization: Bearer sk-quota-your-api-key"

GET /v1/webhooks/:id

Get a single webhook's configuration.

PATCH /v1/webhooks/:id

Update a webhook's URL, events, threshold, or active status.

curl -X PATCH https://api.usequota.ai/v1/webhooks/wh_abc123 \
  -H "Authorization: Bearer sk-quota-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"active": false}'

DELETE /v1/webhooks/:id

Delete a webhook subscription.

GET /v1/webhooks/:id/deliveries

View recent delivery attempts for a webhook, including response status and body.

{
  "deliveries": [
    {
      "id": "del_xyz",
      "event_type": "balance.updated",
      "payload": { "..." : "..." },
      "response_status": 200,
      "response_body": "OK",
      "delivered_at": "2026-01-15T12:00:01.000Z",
      "created_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Retries

Failed deliveries (non-2xx responses or network errors) are retried up to 3 times within 24 hours of creation.

URL Requirements

  • Production webhooks must use https://
  • http:// is allowed for localhost during development