Right To Work Checker

← Back to docs

Quota and billing — what the headers tell you

How included quota, overage, and the 1.5× soft throttle interact, and how to read the response headers.

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 rolls

Test 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 seconds

3. 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 invoice

4. 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.