Server SDK
Import from wattfare/server. This runs on your backend, holds the secret key, and brokers everything that must never touch the browser — minting sessions and running inference.
new Wattfare(config)
The server entry point. Construct it once with your secret key and reuse it.
import { Wattfare } from "wattfare/server";
const wf = new Wattfare({
secretKey: process.env.WATTFARE_SECRET_KEY!, // required, starts with "sk_"
baseURL: "https://wattfare.com", // optional override
fetch: customFetch, // optional, for tests/runtimes
}); | Option | Type | Default | Notes |
|---|---|---|---|
| secretKey | string | — | Required. Must start with sk_ or the constructor throws WattfareAuthError. |
| baseURL | string | https://wattfare.com | Point at a different Wattfare service (self-host / staging). |
| fetch | typeof fetch | global fetch | Inject a custom fetch for tests or non-standard runtimes. |
Instance methods
| Method | Returns | Description |
|---|---|---|
| user(appUserId) | WattfareUser | Scope all operations to one of your user ids. |
| createSession(appUserId, request?) | Promise<CreatedSession> | Mint a short-lived JWT for the frontend. |
| sessionHandler(resolveUser, request?) | (req) => Promise<Response> | A drop-in route handler that mints sessions. |
| grant(grantToken) | WattfareGrant | Redeem a one-time access grant. Returns a handle whose model() spends against the grant. |
wf.user(appUserId)
Returns a WattfareUser bound to one of your users. Pass your own
user id — Wattfare keys all state by appId:appUserId, so there's nothing to map.
const ai = wf.user("user_123"); // your own user id
// 1) Inference — a standard AI SDK model, billed to this user.
import { generateText } from "ai";
const { text } = await generateText({
model: ai.model("anthropic/claude-sonnet-4"),
prompt: "Summarise this in one line.",
});
// 2) Status — connection + budget snapshot (never throws on first run).
const status = await ai.status();
if (!status.connected) {
// prompt the user to connect their budget
} | Method | Returns | Description |
|---|---|---|
| model(modelId) | LanguageModelV3 | An AI-SDK-compatible model. Requests proxy through Wattfare with the user header set. Accepts any OpenRouter model id. |
| status() | Promise<ConnectionStatus> | The user's connection + budget snapshot. Returns { connected: false } rather than throwing when they haven't connected. |
wf.grant(grantToken)
Redeems a one-time access grant token from the browser. Returns a WattfareGrant
handle whose model() works like WattfareUser.model() — no user id
needed. See One-time grants for the full guide.
wf.sessionHandler(resolveUser, request?)
Builds a Request → Response handler that mints session tokens. This is the
recommended way to expose your token route — it handles auth failures and error shaping for you.
// Next.js — app/api/wattfare-token/route.ts
export const POST = wf.sessionHandler(
async (req) => getUserId(req), // -> your user id, or null -> 401
{ requestLimit: { monthlyUsd: 20 } }, // optional cap the user approves
);
// The second arg can also be a function of the request, e.g. per-plan caps:
export const POST = wf.sessionHandler(
(req) => getUserId(req),
async (req) => ({ requestLimit: { monthlyUsd: await capFor(req) } }),
); | Parameter | Type | Description |
|---|---|---|
| resolveUser | (req) => string | null | Promise<…> | Resolve the signed-in user from the request. Return your user id, or null to answer 401. |
| request | SessionRequest | (req) => SessionRequest | Optional. The cap to request, or a function of the request for dynamic caps. |
On success it responds { token, expiresAt }. On a thrown WattfareError
it responds with that error's JSON and status; on anything else, a generic 500.
wf.createSession(appUserId, request?)
The lower-level primitive behind sessionHandler. Reach for it when you need to shape
the response yourself or aren't in a Request → Response runtime.
const { token, expiresAt } = await wf.createSession("user_123", {
requestLimit: { monthlyUsd: 20 }, // optional
});
// Hand 'token' to the frontend however you like (it's just a string).
return Response.json({ token, expiresAt }); | Field | Type | Description |
|---|---|---|
| token | string | The short-lived JWT. Pass it to the frontend client. |
| expiresAt | number | Unix epoch (seconds). Default TTL is 10 minutes. |
Types
Re-exported from wattfare/server for convenience.
interface ConnectionStatus {
connected: boolean;
limits: { monthlyUsd: number | null } | null;
usage: { monthlyUsd: number };
remainingUsd: number | null; // null = unlimited
} | Type | Shape |
|---|---|
| Limits | { monthlyUsd: number | null } |
| Usage | { monthlyUsd: number } |
| SessionRequest | { requestLimit?: { monthlyUsd?: number } } |
| CreatedSession | { token: string; expiresAt: number } |
| GrantResult | { grantToken: string; expiresAt: number; requests: number } |