Billing Units
Last verified: 2026-05-03 (Task #334 — docs accuracy pass).
Every successful response includes a meta.billing_units value. That
number is what the calling key is charged against for the call. It is
recorded in api_usage_events.billing_units and never returned for
calls that 4xx/5xx out before they reach the handler.
| Endpoint | Billing units |
|---|---|
GET /v1/weather/health | 0 |
GET /v1/usage | 0 |
GET /v1/weather/current | 1 |
GET /v1/weather/forecast (daily) | 1 |
GET /v1/weather/forecast (hourly) | 2 |
POST /v1/weather/timeline | 2 × items_analyzed |
POST /v1/weather/route | 3 × segments_analyzed |
POST /v1/weather/watch (creation) | 1 |
POST /v1/weather/watch (daily accrual job) | 1 per active day per watch |
GET /v1/weather/watch/{id} | 1 |
DELETE /v1/weather/watch/{id} | 1 |
POST /v1/webhooks | 1 |
GET /v1/webhooks | 0 |
GET /v1/webhooks/{id} | 0 |
DELETE /v1/webhooks/{id} | 1 |
GET /v1/webhooks/{id}/attempts | 0 |
What counts toward requests
The requests quota dimension counts billable events only — that is,
api_usage_events rows where billing_units > 0. This matters in
two places:
GET /v1/usagelogsbilling_units = 0and doesn't move therequestscounter. You can poll your own usage as often as you want.- Pre-handler rate-limit rejections also log
billing_units = 0. We still record the attempt for forensics, but over-limit attempts don't double-charge you for the limit you already hit.
Provider failures
502 provider_unavailable and 504 weather_refresh_timeout responses
still bill the same units as a successful response would have — we
already paid the upstream cost (or the timeout cost) and the cache
layer counts a slot regardless. Validation failures (400) do not
bill.
Watches
Watch creation bills 1 unit. After that, a daily background job
accrues 1 unit per active watch per day as long as the watch's
status='active' and the current time is inside [starts_at, ends_at].
A watch that is paused, expired, failed, or cancelled does not accrue
new daily units.
How to see the cost of a call
Inspect meta.billing_units on the response, or query
api_usage_events for a window of recent calls:
SELECT
endpoint,
SUM(billing_units) AS units,
COUNT(*) AS calls
FROM api_usage_events
WHERE developer_account_id = $1
AND created_at >= date_trunc('month', now() at time zone 'utc')
GROUP BY endpoint
ORDER BY units DESC;