Realtime Usage Feed
A WebSocket push feed of in flight, provisional rated usage and credit burndown. Use it to show consumption, balances, and spend moving in near real time. The feed is read only and carries no derived totals: every value on the wire is read verbatim from the serving store, and any total is your own arithmetic over the delivered fields.
Endpoint
wss://metering.nue.io/wsPermission: metering read access (View Metering Usage, with credit frames gated on View Metering Credits).
1. Authenticate
Exchange your session for a short lived feed token, then present it on the WebSocket upgrade.
curl --request POST \
--url https://metering.nue.io/v1/metering/ws-token \
--header 'nue-api-key: <your-key>'{ "token": "<jwt>", "expiresIn": 120 }expiresIn is seconds. The token carries only the tenant and an expiry. Do not cache it; fetch a fresh one on every connect.
Present it on the upgrade: browser clients via Sec-WebSocket-Protocol: bearer, <token>; other clients via Authorization: Bearer <token>. The feed validates the token itself and derives the tenant from it. The tenant is never taken from the client.
2. Set scope
Scope is set at connect with query parameters. Filters are additive, and a connection that names none receives the whole tenant. To change scope, reconnect.
- ?customer=<customerId> — a single customer. This is the scope a self service portal uses, so each customer sees only their own usage and burndown across all of their subscriptions.
- ?subscription=<subscriptionNumber> — a single subscription.
3. Receive frames
Each frame carries a kind:
- snapshot — one per connect and reconnect: every in scope open window, plus live pools where available. windows is never null; an empty scope ships []. There is no replay of missed messages.
- update — one changed window in windows[]; no pools.
- credit — one changed pool in pools[].
Window entry: windowKey, subscriptionId, customerId, usageOrderProductId, windowStart / windowEndTime (epoch ms), windowSize, windowState, cumulativeQuantity, meteredQuantity, cumulativeQuantityTerm, ratedAmount (decimal strings), currencyIsoCode, ratingTransactionTime (epoch ms, the version fence).
Pool entry: poolKey, customerId, creditPoolId, liveConsumedCredits, liveOverageCredits, remaining (decimal strings), currencyIsoCode, asOf (epoch ms, the version fence).
{
"kind": "update",
"tenantId": "9a7f2e64-3d15-4b82-a6c9-1e5f8b0d47c3",
"subscriptionId": "SUB-000042",
"windows": [
{
"windowKey": "rtru:window:{tenant:9a7f2e64-…}:01M0V0GKD1…:SUB-000042:model.region\u001fclaude-opus.us-east-1:1789554180000",
"subscriptionId": "SUB-000042",
"customerId": "0015g00000ABCDE",
"windowStart": 1789554180000,
"windowEndTime": 1789554240000,
"windowSize": "Minute",
"windowState": "open",
"cumulativeQuantity": "18432",
"meteredQuantity": "18432",
"ratedAmount": "12.50",
"currencyIsoCode": "USD",
"ratingTransactionTime": 1789554204481
}
]
}Delivery semantics
Delivery is best effort and coalescing. A dropped provisional update self heals on the next tick, and a slow consumer receives the latest state of each scope rather than a backlog. Do not build an at least once assumption on this feed. The figures on the feed are live and provisional; the authoritative amounts are the ones that settle onto the invoice.
Reconnection
Key reconnect logic off the WebSocket close event, not an HTTP status.
- Close 1001 is a deliberate server goodbye (connection lifetime or drain). Mint a new token and reconnect.
- Close 1006 is abnormal, and is also what a browser sees on an authentication failure. Mint a new token and retry with backoff. Never hot loop. A readable HTTP 401 exists only for non browser clients.
Open windows update on the rating cadence, typically every few seconds while usage is arriving. A quiet scope produces no frames. Feed connections have a bounded lifetime and drain deliberately.