GET /v1/usage
Live composite of: current concurrent connections, period totals, overage accrual, and your plan limits. Same numbers the dashboard's Realtime Messaging → Usage page displays.
Endpoint
GET https://rms.metered.ca/v1/usage
Authorization: Bearer sk_live_xxx...
The endpoint is scoped to whichever app the sk_ belongs to — there's no :appId in the path.
Response — 200 OK
{
"appId": "app_abc",
"periodStartUnix": 1714435200,
"periodEndUnix": 1717027200,
"concurrentNow": 7,
"peakConcurrent": 132,
"messagesUsed": 47813,
"overageMessages": 0,
"overageConnections": 0,
"plan": {
"name": "SIGNALLING_BASIC",
"maxConcurrentConnections": 1000,
"maxMessagesPerPeriod": 5000000,
"overagesAllowed": true,
"overagesEnabled": true
}
}
| Field | Type | Notes |
|---|---|---|
appId | string | Your app's ID. |
periodStartUnix / periodEndUnix | int | null | Current billing-period boundary. null for brand-new customers who haven't had a period set yet. |
concurrentNow | int | Live count. Updated on connect/disconnect. |
peakConcurrent | int | Maximum simultaneous connections observed this period. Used for billing on the concurrent axis. |
messagesUsed | int | Cumulative messages attempted this period (publish + send). Includes soft-dropped over-quota attempts. |
overageMessages | int | Messages billed at overage rate so far this period. Lags real-time by ≤60s (one server flush interval). |
overageConnections | int | Concurrent-admit overages billed so far this period. Same ≤60s lag. |
plan.name | string | null | Plan tier identifier (e.g. SIGNALLING_FREE, SIGNALLING_BASIC, SIGNALLING_BUNDLED). |
plan.maxConcurrentConnections / plan.maxMessagesPerPeriod | int | Plan caps on each axis. |
plan.overagesAllowed | bool | Whether the plan permits overages at all (free tier: false). |
plan.overagesEnabled | bool | Customer toggle (defaults to true on tiers where overages are allowed). |
Errors
| HTTP | error | When |
|---|---|---|
| 401 | unauthorized | sk_ missing / invalid |
| 503 | internal_error | Plan lookup failed (auth-API blip). Retry after a short backoff — live signalling traffic is NOT affected by this error. |
Freshness
concurrentNowis live — the underlying counter is incremented/decremented per connect/disconnect.peakConcurrentis set-if-greater on every connect, so it's also effectively live for the live workload.messagesUsedis incremented per message, live.overageMessages/overageConnectionslag by ≤60s — they reflect what's been flushed and billed, not what's still in-flight on the signalling-server's pending counter. The dashboard shows the same lag.
Example — curl
curl https://rms.metered.ca/v1/usage \
-H "Authorization: Bearer sk_live_xxx..."
Example — building a customer-facing usage widget
usage-widget.tsx
async function fetchUsage() {
const resp = await fetch(
"https://rms.metered.ca/v1/usage",
{ headers: { Authorization: `Bearer ${SK}` } },
);
if (!resp.ok) throw new Error(`usage fetch failed: ${resp.status}`);
return resp.json();
}
// Render
const usage = await fetchUsage();
const concurrentPct = Math.round(100 * usage.peakConcurrent / usage.plan.maxConcurrentConnections);
const messagesPct = Math.round(100 * usage.messagesUsed / usage.plan.maxMessagesPerPeriod);
return (
<div>
<Bar label="Concurrent peak" value={concurrentPct} caption={`${usage.peakConcurrent} / ${usage.plan.maxConcurrentConnections}`} />
<Bar label="Messages used" value={messagesPct} caption={`${usage.messagesUsed} / ${usage.plan.maxMessagesPerPeriod}`} />
{usage.overageMessages > 0 && (
<p className="text-yellow-700">+ {usage.overageMessages} overage messages this period</p>
)}
</div>
);
Same shape as the Realtime Messaging → Usage dashboard page — feel free to point the widget directly at the dashboard URL instead of building your own.