# CauseWise server SDK

`@razorsoft/causewise` is a server-side client for the CauseWise management and analytics API. It sends your workspace API key to CauseWise and returns the JSON the API already produces. It does not include the analytics engine, database, billing rules, or any other CauseWise service.

```bash
npm install @razorsoft/causewise
```

Do not import it from browser code. The package `browser` export throws.

## Requirements

Premium API access needs all of the following. CauseWise checks them on the server. The SDK cannot grant access.

1. A workspace API key (`cw_api_…`), created in CauseWise under Settings → API keys.
2. An active eligible subscription: Pro, Team, or Enterprise with status `active`, `trialing`, or unset. The free plan, and a paid plan that is `canceled`, `past_due`, or `unpaid`, receives `402 subscription_required`. There is no extra grace period.
3. The scopes the call needs.
4. A site that belongs to the key's workspace. Another workspace's site id returns `404`.

Tracking collection, the public tracking key, the dashboard, and the WordPress snippet do not use this SDK and stay available on the free plan.

## Scopes

| Call | Scope |
| --- | --- |
| `sites.list`, `sites.get` | `sites:read` |
| `analytics.summary`, `analytics.overview`, `analytics.trackingStatus`, `analytics.recentEvents` | `analytics:read` |
| `goals.list`, `goals.analytics` | `goals:read` |
| `funnels.list`, `funnels.analytics` | `funnels:read` |

Write scopes are not used by this SDK. A write scope does not include the matching read scope.

## Configuration

```ts
import { CauseWise } from "@razorsoft/causewise";

const causewise = new CauseWise({
  apiKey: process.env.CAUSEWISE_API_KEY!,
  // Optional. Defaults to https://causewise.io.
  baseUrl: process.env.CAUSEWISE_API_BASE_URL,
});
```

Read the key from the server environment or a secret store. Do not put it in `NEXT_PUBLIC_` variables, client components, or the browser bundle.

## Fetch analytics

```ts
const analytics = await causewise.analytics.summary({
  siteId: "site_123",
  range: "7d",
});

const overview = await causewise.analytics.overview({
  siteId: "site_123",
  range: "7d",
});

const goals = await causewise.goals.list("site_123");
const goal = await causewise.goals.analytics({
  siteId: "site_123",
  goalId: goals[0]?.id ?? "goal_123",
  range: "7d",
});

const funnels = await causewise.funnels.list("site_123");
const funnel = await causewise.funnels.analytics({
  siteId: "site_123",
  funnelId: funnels[0]?.id ?? "funnel_123",
  range: "7d",
});
```

`range` is `today`, `7d`, or `30d`. The API may shorten a range to the workspace retention window. `overview.trend` counts every event in each bucket. It is not a pageview series. `funnel.conversionWindow` is a number of seconds. Goal analytics `conversionRate` is the unique-visitor rate. The summary goal rate is the dashboard rollup.

Also available:

- `causewise.sites.list()` and `causewise.sites.get(siteId)`
- `causewise.analytics.overview({ siteId, range })` for the traffic trend. Each trend point counts every event in that bucket, not pageviews alone.
- `causewise.analytics.trackingStatus(siteId)`
- `causewise.analytics.recentEvents({ siteId, limit })`
- `causewise.goals.list(siteId)` and `causewise.goals.analytics({ siteId, goalId, range })`
- `causewise.funnels.list(siteId)` and `causewise.funnels.analytics({ siteId, funnelId, range })`

## Next.js server component

The server component calls CauseWise. The client component receives only the result.

```tsx
import { CauseWise } from "@razorsoft/causewise";
import { Stats } from "./stats";

export default async function Page() {
  const causewise = new CauseWise({ apiKey: process.env.CAUSEWISE_API_KEY! });
  const summary = await causewise.analytics.summary({
    siteId: process.env.CAUSEWISE_SITE_ID!,
    range: "7d",
  });
  return <Stats pageviews={summary.pageviews} sessions={summary.sessions} />;
}
```

```tsx
"use client";

export function Stats({ pageviews, sessions }: { pageviews: number; sessions: number }) {
  return (
    <p>
      {pageviews} pageviews, {sessions} sessions
    </p>
  );
}
```

## Secure route handler

Use this when the browser needs to refresh analytics. The handler must check the signed-in user before it calls CauseWise. Do not expose a public route that forwards the management key.

```ts
import { auth } from "@clerk/nextjs/server";
import { CauseWise, CauseWiseError } from "@razorsoft/causewise";
import { NextResponse } from "next/server";

export async function GET() {
  const { userId } = await auth();
  if (!userId) return NextResponse.json({ error: "Sign in required." }, { status: 401 });

  const causewise = new CauseWise({ apiKey: process.env.CAUSEWISE_API_KEY! });
  try {
    const summary = await causewise.analytics.summary({
      siteId: process.env.CAUSEWISE_SITE_ID!,
      range: "7d",
    });
    return NextResponse.json({ pageviews: summary.pageviews, sessions: summary.sessions });
  } catch (error) {
    if (error instanceof CauseWiseError) {
      return NextResponse.json({ error: error.message }, { status: error.status || 502 });
    }
    throw error;
  }
}
```

The browser calls `/api/analytics` on your application. It never sees `CAUSEWISE_API_KEY`.

## Errors

Failures throw `CauseWiseError` with `status`, `code`, `message`, and `retryAfterSeconds`.

| Code | Status | Meaning |
| --- | --- | --- |
| `unauthorized` | 401 | Missing, invalid, revoked, or expired key. |
| `forbidden` | 403 | The key is missing the required scope. |
| `subscription_required` | 402 | The workspace is not on an eligible paid subscription. |
| `rate_limited` | 429 | More than 120 requests in a minute. Wait `retryAfterSeconds`. |
| `not_found` | 404 | The site, goal, or funnel is not in this workspace. |
| `network_error` | 0 | CauseWise could not be reached. |

## Security

- Import the SDK from server code only. The package `browser` export throws, and constructing `CauseWise` throws when `window` exists.
- The SDK sends the key as `Authorization: Bearer` and does not write it to errors.
- Pass only the fields you want to render into client components.
- Your application decides which of its users may see a site. CauseWise only checks the workspace key, subscription, scopes, and site ownership.

## Component data

Future components should use the exported contracts (`CauseWiseDashboardData`, `CauseWiseTrafficChartData`, and the related types). `COMPONENT_DATA_GAPS` lists metrics the API does not provide. The traffic chart uses `analytics.overview().trend`. Each point counts every event in that bucket, not pageviews alone. The summary does not include a time series.

## License

The CauseWise Client License lets you install this package, use it in commercial applications, modify the client code, and redistribute it as part of a compiled application. It does not include the CauseWise service or analytics engine. See `LICENSE`.
