Metrics / routstr / provider_activity

provider_activity

Per-provider Routstr activity from the reconstructed ledger - reported revenue (msats), successful requests and tokens per provider, at grain=day one row per (bucket, provider), at grain=total one row per provider summed over the from/to window (omit both for all time). This is the data behind the Providers tab's 'Daily revenue by provider' chart, served for EVERY included provider rather than the chart's top-20 fold.

unit

msats+requests+tokens

grain

day | total (UTC)

series

sparse, full history

key

routstr.provider_activity@day

Parameters

paramaccepted values
grainday | total - default day (omit to get the default)
fromoptional inclusive ISO UTC calendar day (YYYY-MM-DD); omit for the series start
tooptional inclusive ISO UTC calendar day (YYYY-MM-DD); omit for today UTC (that day still in progress)
provider_pubkeyoptional 64-char lowercase hex Routstr provider key (npub must be decoded to hex first); narrows rows to that provider, and reaches an excluded provider that the unfiltered call leaves out
formatcsv | markdown

Columns per grain: day: utc_day, grain, provider_pubkey, provider_name, msats, requests, tokens, excluded - total: provider_pubkey, provider_name, msats, requests, tokens, daily_buckets, weekly_buckets, first_day, last_day, excluded.

Query it

MCP tool call against https://dev.nostrolo.gy/mcp (connect your agent):

{
  "name": "nostrology_query_metric",
  "arguments": {
    "metric": "provider_activity",
    "domain": "routstr",
    "grain": "day"
  }
}

Windowed (inclusive UTC days; both optional):

{
  "name": "nostrology_query_metric",
  "arguments": {
    "metric": "provider_activity",
    "domain": "routstr",
    "grain": "day",
    "from": "2026-07-01",
    "to": "2026-07-31"
  }
}

Response: a plain-text envelope (window, freshness, column contract, this page's caveats) followed by the data table (csv, or format: "markdown") at the grain you request.

Response columns

nametypedescription
utc_daydatebucket START day (UTC); a weekly bucket covers the 7 days from it
graintextd = daily bucket; w = weekly bucket (pre-daily era only)
provider_pubkeytextthe provider's Nostr key - provider identity (the announcement's provider_id is informational only)
provider_nametextannouncement content.name, clipped to 80 chars; the 12-hex pubkey prefix when never announced
msatsintegerrevenue reported, integer millisats - per bucket at grain=day, summed over the window at grain=total
requestsintegersuccessful requests reported - per bucket at grain=day, summed over the window at grain=total
tokensintegertokens billed - per bucket at grain=day, summed over the window at grain=total
excludedbooleantrue = the provider is outside the network aggregates (only reachable via the provider_pubkey filter)

What is counted

Without a provider_pubkey filter the rows cover INCLUDED providers only, so the per-day sums equal routstr.network_activity exactly; with a filter the named provider is returned whether or not it is excluded (the excluded column says which). Network aggregates cover INCLUDED providers only: test/staging-marked nodes and private-endpoint-only nodes are excluded (still listed, with the reason, by routstr.provider_leaderboard and the routstr.provider_profile record), and kind-38421 (routstr-provider-announcements) squatters are never providers.

Caveats

  • Every usage number is SELF-REPORTED by each provider's own node in kind-38422 (routstr-analytics-snapshots) events and is unverifiable by construction (RIP-01 payments travel as Cashu tokens in HTTP headers, invisible on Nostr): a node can overstate, understate or stay silent, so read these as what the network says about itself.
  • Daily figures come from a ledger reconstructed by merging the UTC-grid buckets of EVERY archived snapshot's trailing windows (full-coverage-only, newest-wins); observed history is a FLOOR - a day a node later omits is kept, a gap longer than the windows' reach stays a gap - and today is never a ledger day.
  • Grain 'w' rows are weekly buckets (Thursday-start, keyed by their start day) kept only for a provider's PRE-daily era, so the two grains never overlap and summing every row gives the all-time figure. A from/to window includes exactly the DAILY buckets STARTING inside it and no weekly bucket at all - the page's own windowed rule - so weekly_buckets is 0 whenever a window is given.
  • Revenue is integer MILLI-satoshis (divide by 1000 for sats; sum msats first, convert once).
  • Responses are capped at 2,000 rows with an explicit truncated: line (the whole ledger was ~1,100 rows on 2026-08-24, so an unfiltered call fits today); pass from/to or provider_pubkey to keep a response small. Series is sparse: a (bucket, provider) row exists only where the provider reported activity.

Freshness in every response is data-derived: the newest routstr refresh's generation instant (nightly 02:45 UTC; the newest ledger day is the previous UTC day).