useRevenue() — tenant revenue dashboards
useRevenue() reads pre-aggregated revenue buckets for the resolved tenant. It is the React-side consumer of the Phase 3 multi-source revenue capture pipeline (Stripe + Toss + Apple + Google → revenue_aggregates). Use it to render dashboards, MRR/ARR breakdowns, and refund summaries without hand-rolling a query layer.
The hook calls the merchant relay at
GET /api/paylera/revenue/aggregates, which proxies toGET /v1/me/revenue/aggregateson Paylera. Like every other@paylera/reacthook, it never talks toapi.paylera.devdirectly.
Install
useRevenue ships in @paylera/react@>=0.0.0 — no extra dependency.
Signature
import { useRevenue, type UseRevenueOptions } from "@paylera/react";
function useRevenue(opts: UseRevenueOptions): UseQueryResult<RevenueAggregateResponse>;Options
| Field | Type | Default | What it does |
|---|---|---|---|
from | Date | string | — | Window start. YYYY-MM-DD or a Date (coerced to UTC). Inclusive. |
to | Date | string | — | Window end. Same shape as from. Inclusive. |
grain | "day" | "month" | "day" | Bucket granularity. |
groupBy | "source" | "currency" | "product" | "source" | Faceting axis. Only the matching dimensional field appears on each bucket. |
source | "stripe" | "toss" | "apple_app_store" | "google_play" | — | Restrict to one upstream source. |
currency | ISO 4217 (e.g. "USD") | — | Restrict to one currency. |
enabled | boolean | true | Skip the network call when false. |
staleTime | number (ms) | 300000 (5 min) | Override the default cache window. |
The default 5-minute staleTime matches the upstream aggregator recompute cadence — refetching faster will return identical bucket rows.
Return shape
useRevenue returns the raw TanStack UseQueryResult. The data payload:
interface RevenueAggregateResponse { period: { from: string; to: string; grain: "day" | "month" }; currency: string; totals: { gross_amount_minor: number; refund_amount_minor: number; net_amount_minor: number; // gross - refund event_count: number; }; buckets: RevenueAggregateBucket[];}
interface RevenueAggregateBucket { period_start: string; // YYYY-MM-DD (or first-of-month) source_provider?: RevenueSource; // only on group_by="source" currency?: string; // only on group_by="currency" product_id?: string; // only on group_by="product" gross_amount_minor: number; refund_amount_minor: number; net_amount_minor: number; event_count: number; refund_count: number;}All amounts are in minor currency units (cents for USD, the smallest fractional unit per ISO 4217). Format with the merchant’s preferred locale + currency at render time.
Example — daily revenue, last 30 days, by source
import { useRevenue } from "@paylera/react";
function RevenueChart() { const today = new Date(); const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
const { data, isLoading, error } = useRevenue({ from: thirtyDaysAgo, to: today, grain: "day", groupBy: "source", });
if (isLoading) return <Spinner />; if (error) return <ErrorBanner error={error} />;
return ( <> <h2>Net revenue: {formatMoney(data!.totals.net_amount_minor, data!.currency)}</h2> <BucketTable rows={data!.buckets} /> </> );}Example — single source, single currency
const { data } = useRevenue({ from: "2026-01-01", to: "2026-01-31", grain: "day", source: "stripe", currency: "USD",});Example — monthly view
const { data } = useRevenue({ from: "2025-01-01", to: "2026-01-01", grain: "month", groupBy: "currency",});Caching + refetch behaviour
- The TanStack query key includes
{ from, to, grain, group_by, source, currency }. Changing any of these triggers a refetch automatically. - Within the 5-minute
staleTimewindow, identical option sets return from cache — multiple components mountinguseRevenue({ from, to })with the same arguments share one network round-trip. - The hook does not auto-refetch on focus (TanStack default behaviour can be overridden on the Provider’s
QueryClientif your dashboard wants live updates).
Relay forwarding
useRevenue calls GET /api/paylera/revenue/aggregates. The relay forwards the path to GET /v1/me/revenue/aggregates on Paylera.
@paylera/server-node (buildRelay) has an explicit allowlist of relay routes and ships proxy support for /revenue/aggregates alongside the React hook. Merchants on hand-written or Go relays should wire the same path-passthrough pattern.
Error handling
Errors are surfaced as PayleraRelayError — the same RFC-7807 shape every other hook returns:
const { error } = useRevenue({ from, to });if (error && "type" in error) { // error.type → "paylera.window_too_large", "paylera.window_invalid", …}