@perkamo/nextjs
v0.9.0
Published
Next.js helpers for Perkamo server routes and browser SDK integrations.
Readme
@perkamo/nextjs
Next.js helpers for Perkamo server routes and browser SDK integrations.
Use this package with supported Next.js LTS releases. Per the Next.js support policy, this package supports Next.js 16 Active LTS and Next.js 15 Maintenance LTS. It requires Node.js 20.9 or newer.
Full SDK documentation: https://www.perkamo.com/docs/v1/sdk
npm install @perkamo/nextjs @perkamo/browser @perkamo/sdkApp Router token routes
Create short-lived client tokens from trusted server code. Never expose a Perkamo server API key or signing secret to Client Components or browser code.
Create a signing key in the Perkamo console (Settings → Security → Signing keys). It gives you a KID (shown in the creation dialog and then listed in the table) and a one-time secret (shown once, backend-only). The route below reads both from environment variables — the names are your own choice:
// app/api/perkamo/token/route.ts
import { createPerkamoClientTokenRoute } from "@perkamo/nextjs/server";
import { auth } from "@/auth";
export const POST = createPerkamoClientTokenRoute({
kid: process.env.PERKAMO_SIGNING_KID, // KID
signingSecret: process.env.PERKAMO_SIGNING_SECRET, // backend-only
getUserId: async () => (await auth())?.user?.id ?? null,
scope: ["customer:read", "events:write"],
});Each option means:
| Option | What it is |
| --------------- | -------------------------------------------------------------------------------------------------------------- |
| kid | KID of your signing key; goes in the token header. |
| signingSecret | The signing key's one-time secret. Sensitive — keep it backend-only. |
| getUserId | Resolves the authenticated user id from the request; return null to refuse with 401. |
| scope | Client permissions: customer:read, events:write, stream:read. Default: customer:read + events:write. |
| events | Optional allow-list of event names the token may emit. |
| ttlSeconds | Token lifetime in seconds. Default 600; Perkamo clamps to the key's maximum. |
For customer streams, expose a separate endpoint so regular bearer tokens are not placed in EventSource URLs:
// app/api/perkamo/stream-token/route.ts
import { createPerkamoClientTokenRoute } from "@perkamo/nextjs/server";
import { auth } from "@/auth";
export const POST = createPerkamoClientTokenRoute({
kid: process.env.PERKAMO_SIGNING_KID,
signingSecret: process.env.PERKAMO_SIGNING_SECRET,
getUserId: async () => (await auth())?.user?.id ?? null,
scope: ["stream:read"],
});kid and signingSecret also accept an async function returning the value, so
you can load them from a secret manager instead of environment variables.
Client Components
Use @perkamo/nextjs/client only from Client Components.
"use client";
import { PerkamoProvider, usePerkamoCustomerJson } from "@perkamo/nextjs/client";
export function LoyaltyPanel() {
return (
<PerkamoProvider>
<Points />
</PerkamoProvider>
);
}
function Points() {
const { customer, loading, error, refresh } = usePerkamoCustomerJson();
if (loading) return <p>Loading...</p>;
if (error) return <button onClick={refresh}>Retry</button>;
return <p>{customer?.wallets.points ?? 0} points</p>;
}PerkamoProvider defaults to these token endpoints:
POST /api/perkamo/tokenPOST /api/perkamo/stream-token
Override them when your Next.js app uses different route names.
Server Components and actions
Use the root export or /server only from trusted server code:
import { createPerkamoNextServerClient } from "@perkamo/nextjs/server";
const perkamo = createPerkamoNextServerClient({
apiKey: () => process.env.PERKAMO_SECRET_KEY,
});
export async function trackPurchase(userId: string, orderId: string) {
"use server";
await perkamo.emit(
userId,
"purchase.completed",
{ order_id: orderId },
{ txId: orderId },
);
}Security defaults
@perkamo/nextjs/serverrequires akidand signing secret from trusted server code.@perkamo/nextjs/clientnever accepts server API keys; it fetches short-lived client tokens from your own Next.js route handlers.- Token route helpers return
401whengetUserId()returnsnull,undefinedor an empty string. - Server helpers use Web
RequestandResponse, matching Next.js App Router route handlers and modern runtimes. - Helpers default to the hosted Perkamo API. Set
baseUrlonly for a custom, staging or private endpoint. - Perkamo API failures use
PerkamoApiErrorfrom@perkamo/sdk, includingrequestId,retryAfterandrateLimitmetadata when returned by the API or gateway.
