Next.js SDK
Use @perkamo/nextjs when a Next.js app needs trusted Perkamo server calls plus browser-safe Client Component helpers.
The package supports the stable Next.js LTS lines: Next.js 16 Active LTS and Next.js 15 Maintenance LTS. It requires Node.js 20.9 or newer.
Install
bash
npm install @perkamo/nextjs @perkamo/browser @perkamo/sdkApp Router token routes
Create client tokens from trusted route handlers. The route verifies your app session, self-signs with a Perkamo signing key and returns only a short-lived client token to Client Components.
Create a signing key in the Perkamo console under 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). Read both from environment variables — the names are your own choice:
ts
// 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"],
});| Option | What it is |
|---|---|
kid | KID of your signing key; goes in the token header. Safe to expose. |
signingSecret | The signing key's one-time secret that signs the token. Backend-only. |
getUserId | Resolves the authenticated user id; return null to refuse with 401. |
scope | Client permissions: customer:read, events:write, stream:read. |
events | Optional allow-list of event names the token may emit. |
ttlSeconds | Token lifetime in seconds. Default 600; clamped to the key's maximum. |
Use a separate stream-token route when customer streams are enabled:
ts
// 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.
Server Components and actions
Use @perkamo/nextjs/server only from trusted server code.
ts
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 },
);
}The server client exposes the same trusted helpers as @perkamo/sdk, including program() and eventCatalog() for backend admin tooling:
ts
const events = await perkamo.eventCatalog();Client Components
Use @perkamo/nextjs/client only from Client Components.
tsx
"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:
POST /api/perkamo/tokenPOST /api/perkamo/stream-token
Override tokenEndpoint and streamTokenEndpoint when your app uses different route names.
Security boundary
- Server keys stay in route handlers, Server Components or server actions.
- Client Components receive only short-lived client tokens from your own Next.js
routes.
getUserId()should return your immutable application user id after verifying
the current session.
- Token helpers return
401when no user id is available. - Helpers default to the hosted Perkamo API. Set
baseUrlonly when Perkamo
support supplies a different API URL.
- Perkamo API failures use
PerkamoApiErrorfrom@perkamo/sdk, including
request id, retry-after and rate-limit metadata when available.