1. The headers
Successful live responses include these three headers:
X-RateLimit-Limit: 100 # your tier's included quota
X-RateLimit-Remaining: 73 # checks left this period
X-RateLimit-Reset: 1717196400 # unix timestamp when the period rollsTest keys don't include these — sandbox mode is free and uncounted.
2. Quota flow
For each live check, the server runs through:
1. Is the subscription past_due or unpaid?
→ 402 PAYMENT_REQUIRED (update payment in /app/billing)
2. Has billable_count reached the included quota?
2a. NO → billable_count += 1, run the check
2b. YES, paid tier → overage_count += 1, run the check
2c. YES, free tier → 402 QUOTA_EXCEEDED (upgrade to lift the cap)
3. Has total usage hit 1.5× the included quota?
→ 429 RATE_LIMITED, Retry-After at the next period boundary
(anti-runaway protection; enterprise tier has no soft throttle)
4. Has the per-key RPS limit been hit?
→ 429 RATE_LIMITED, Retry-After in seconds3. Overage billing
Overage usage is metered to Stripe hourly and settled monthly in arrears on the same invoice as your subscription. There's no "top-up" — the cron sets the cumulative overage count, so even a crash + retry won't double-bill (the report is idempotent on Stripe's side via the period-start timestamp).
# Example: Pro tier (£14/mo, 100 included, £0.25/overage), 137 checks this month
included = 100 -> £14.00 base
overage = 37 -> 37 × £0.25 = £9.25 metered
Total = £23.25 on the next monthly invoice4. Watching usage from your code
Read the headers after every successful check; emit a metric when X-RateLimit-Remaining falls below your alarm threshold.
const remaining = Number(res.headers.get('x-ratelimit-remaining') ?? '0');
const limit = Number(res.headers.get('x-ratelimit-limit') ?? '0');
if (limit > 0 && remaining / limit < 0.1) {
myMetrics.gauge('rtw.quota.remaining_pct', remaining / limit);
}5. The dashboard view
/app/usage shows your current period's billable, overage, and daily breakdown — the same numbers the headers expose, plotted over time.