Overview

Getting started

Install the packages, wire up AssetProvider with an access token, and render your first card.

Install

Install the styled package — it re-exports everything from the SDK.

npm install @get-asset/react

If you only need headless components and intend to bring your own styles, install @get-asset/sdk directly.

npm install @get-asset/sdk

Set up the provider

AssetProvider takes the businessIdyou're displaying data for and an accessToken — either a string or an async function that returns one. Pass baseUrl only if you need to point at a non-default API (it defaults to https://api.getasset.com).

import { AssetProvider } from "@get-asset/react";
import "@get-asset/react/theme.css";
import "@get-asset/react/styles.css";
export function Root({ children, businessId }) {
return (
<AssetProvider
businessId={businessId}
accessToken={() => fetchToken(businessId)}
>
{children}
</AssetProvider>
);
}

Token exchange

Never ship client_id/client_secret to the browser. Exchange them for a short-lived access token on your server and proxy that to the client.

The token must carry the OAuth scopes that every card on the page needs. Import the per-card constants from @get-asset/sdk/scopes— this subpath has no React imports, so it's safe to use from Route Handlers, Server Components, or edge runtimes. Union the sets and pass the result as the standardscope form field. Each card's page (e.g. RevenueCard) lists its required scopes under Required scopes. Requesting a superset of what the dashboard needs is fine; missing a scope means the affected card will surface an error state at fetch time.

// app/api/token/route.ts
//
// Import scope constants from "@get-asset/sdk/scopes" — this subpath has no
// React dependencies, so it's safe to use in Route Handlers, Server
// Components, or edge runtimes.
import {
revenueCardScopes,
expensesCardScopes,
snapshotCardScopes,
} from "@get-asset/sdk/scopes";
// Union the scopes required by every card you intend to render.
const SCOPES = [
...revenueCardScopes,
...expensesCardScopes,
...snapshotCardScopes,
];
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const businessId = searchParams.get("business_id");
const res = await fetch(`${process.env.ASSET_API_URL}/v0/auth/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: process.env.ASSET_CLIENT_ID!,
client_secret: process.env.ASSET_CLIENT_SECRET!,
business_id: businessId ?? "",
scope: [...new Set(SCOPES)].join(" "),
}),
});
return Response.json(await res.json());
}

Your first card

Every styled card is self-contained — drop it inside the provider and it'll fetch, show a skeleton while loading, surface an error state, and render the result.

import { AssetRevenueCard } from "@get-asset/react";
export function Dashboard() {
return <AssetRevenueCard />;
}

Shared reporting range

AssetProvider also stores one inclusive dateFrom/dateTo pair, and every date-driven component reports on it. Pass defaultDateFrom and defaultDateTo to seed it (both or neither); omit them and it starts on the current calendar year. Mount AssetDatePicker to let people move it — every card re-fetches automatically.

A card takes its own dateFrom/dateTo props to detach from the shared range entirely. Cards that compare against a previous period mirror whatever range they resolved: a month against the month before, a quarter against the quarter before, a year against the year before, and any other range against the same number of days immediately before it.

import { AssetProvider, AssetDatePicker, AssetRevenueCard, AssetSnapshotCard } from "@get-asset/react";
// Every card reports on April 2026, compared against March 2026.
<AssetProvider
businessId={businessId}
accessToken={() => fetchToken(businessId)}
defaultDateFrom="2026-04-01"
defaultDateTo="2026-04-30"
>
<AssetDatePicker /> {/* moves the range for every card below */}
<AssetRevenueCard />
<AssetSnapshotCard />
<AssetExpensesCard dateFrom="2026-01-01" dateTo="2026-12-31" />
{/* detached: all of 2026, and the picker no longer moves it */}
</AssetProvider>

To label or lay out around the range the cards are on, read it from useAsset():

import { useAsset } from "@get-asset/sdk";
function RangeCaption() {
const { dateFrom, dateTo } = useAsset();
return <p>Reporting on {dateFrom} to {dateTo}</p>;
}