usage.quota.warning

Your account has used 80% of a request quota for the current window — a heads-up, not a refusal.

When it fires

Fires once per account per window, the first time usage crosses 80% of the cap. Today it covers the daily request cap (`scope: "daily_requests"`), which is the circuit breaker that stops a runaway client loop from spending a month of quota in an afternoon. It will not fire again for the same window however many more requests you make, so treat it as a single alarm rather than a stream. `topOperation` names the operation responsible for most of the traffic so far — if one operation is a large share of the window, that is usually the loop.

Payload

Every delivery uses the same outer envelope (event, eventId, apiVersion, timestamp, data). Dedupe on eventId — it stays stable across retries and replays, while the X-Repull-Delivery-Id header changes on every attempt.

{
  "type": "usage.quota.warning",
  "eventId": "evt_01HX5XPQ2K",
  "apiVersion": "2026-04",
  "timestamp": "2026-05-01T18:04:11.000Z",
  "data": {
    "scope": "daily_requests",
    "windowKey": "2026-05-01",
    "tier": "starter",
    "used": 20000,
    "limit": 25000,
    "percentUsed": 80,
    "remaining": 5000,
    "resetsAt": "2026-05-02T00:00:00.000Z",
    "topOperation": {
      "operationId": "replay_webhook_delivery",
      "requestCount": 17000,
      "sharePercent": 85
    }
  }
}

Verifying signatures

Every delivery includes a timestamped X-Repull-Signature header of the form t=<unix_ts>,v1=<hex>, where v1 is HMAC-SHA256(signing_secret, `${t}.${raw_body}`). Verify it before processing — see Verify Signatures for full Node.js and Python examples.

Use the raw body

Sign the raw request body exactly as received, not a re-stringified JSON object. Re-serialisation can reorder keys or change whitespace and break the signature.

Example handler

// Page someone, and say which call site to look at.
app.post('/webhooks/repull', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verifyRepullSignature(req)) return res.sendStatus(401)
  const { type, data } = JSON.parse(req.body.toString())

  if (type === 'usage.quota.warning') {
    const top = data.topOperation
    alertOncall(
      `Repull: ${data.percentUsed}% of the ${data.scope} quota used ` +
      `(${data.used}/${data.limit}), resets ${data.resetsAt}.` +
      (top ? ` Biggest driver: ${top.operationId} at ${top.sharePercent}% of the window.` : '')
    )
    // If one operation dominates, that is almost always a loop with no exit
    // condition. Pause that worker before the cap stops it for you.
  }

  res.sendStatus(200)
})

Common patterns

  • Route it to whatever pages your on-call — this is the last warning before requests start being refused.
  • Compare `topOperation.sharePercent` against a normal day. A single operation above ~60% of a window is nearly always a runaway retry or poll loop.
  • Do not auto-raise limits in response to this. Find out what the traffic is first; `GET /v1/usage/summary?range=7d` shows whether today looks like the last week.
  • It fires once per window, so an alert built on it will not become noise — but it also will not repeat if you miss it. Store the event rather than relying on a transient notification.

Tip: Acknowledge with a 2xx status within 10 seconds. Failed deliveries are retried up to 5 times with exponential backoff.Webhook reliability →

AI