Next.js uses the SDK-first path in TypeScript. Complete every step with an isolated non-production workspace before deploying.
Prerequisites
Node 22+
pnpm
A scoped non-production API key
Environment setup
MONETIZEKIT_BASE_URL=https://app.monetizekit.app/api/v1
MONETIZEKIT_API_KEY=${MONETIZEKIT_API_KEY}
MONETIZEKIT_PLAN_ID=${MONETIZEKIT_PLAN_ID}
MONETIZEKIT_FEATURE_KEY=${MONETIZEKIT_FEATURE_KEY}
MONETIZEKIT_DENIED_FEATURE_KEY=${MONETIZEKIT_DENIED_FEATURE_KEY}
MONETIZEKIT_METER_ID=${MONETIZEKIT_METER_ID}
MONETIZEKIT_RUN_ID=replace-with-a-unique-run-idInstall commands
pnpm add @monetizekit/nodeHappy path
1. Create a customer
Create a unique test customer. Raw HTTP variants send a deterministic idempotency key; the current Node SDK does not expose one for customer creation.
import {
MonetizeKit,
type Customer,
type Plan,
type Subscription,
} from "@monetizekit/node";
async function createCustomer(
client: MonetizeKit,
runId: string,
): Promise<Customer> {
return client.customers.create({
name: `Docs quickstart ${runId}`,
email: `docs-quickstart+${runId}@example.com`,
});
}Expected HTTP status: 201.
2. Select the isolated published plan
List published plans and select the exact MONETIZEKIT_PLAN_ID provisioned for this run.
async function selectPlan(client: MonetizeKit, planId: string): Promise<Plan> {
const plans = await client.plans.list();
const plan = plans.data.find((candidate) => candidate.id === planId);
if (!plan) {
throw new Error(`Isolated plan ${planId} is not published in this workspace`);
}
return plan;
}Expected HTTP status: 200.
3. Attach the plan
Create the customer's subscription. Raw HTTP variants reuse a deterministic idempotency key.
async function attachPlan(
client: MonetizeKit,
customerId: string,
planId: string,
): Promise<Subscription> {
return client.subscriptions.create({
customerId,
planId,
status: "active",
});
}Expected HTTP status: 201.
4. Check and enforce an entitlement
Request the feature decision and stop protected work unless `allowed` is true.
async function requireEntitlement(
client: MonetizeKit,
customerId: string,
featureKey: string,
): Promise<EntitlementDecision> {
const decision = (await client.entitlements.check(
customerId,
featureKey,
)) as unknown as EntitlementDecision;
if (!decision.allowed) {
throw new Error(
`Entitlement denied (${decision.reasonCode}): ${decision.reason}`,
);
}
return decision;
}Expected HTTP status: 200.
5. Submit usage
Record one metered event with a deterministic idempotency key that remains stable across retries.
async function submitUsage(
client: MonetizeKit,
customerId: string,
meterId: string,
idempotencyKey: string,
): Promise<unknown> {
return client.usage.submit({
customerId,
meterId,
value: 1,
idempotencyKey,
});
}Expected HTTP status: 201.
6. Verify the observed usage
Read the meter after submission and include the observed result in the smoke output.
async function validateUsage(
client: MonetizeKit,
customerId: string,
meterId: string,
): Promise<unknown> {
return client.usage.get(customerId, meterId);
}Expected HTTP status: 200.
Troubleshooting
401 missing_api_key / invalid_api_key
Confirm the API key is present, active, and uses the non-production prefix for the environment you intend to test.
403 missing scope
Issue a key with customers:create, plans:read, subscriptions:write, entitlements:read, usage:write, usage:read, and cleanup permissions.
Entitlement denied
Confirm MONETIZEKIT_PLAN_ID is the isolated plan that grants MONETIZEKIT_FEATURE_KEY and does not grant MONETIZEKIT_DENIED_FEATURE_KEY.
A retry records duplicate usage
Keep MONETIZEKIT_RUN_ID stable for retries of the same logical smoke run so the generated Idempotency-Key is reused.
Deploy + smoke test
Platform: Vercel.
Set the seven quickstart environment variables in the Vercel project.
Deploy the server-side integration, then run the smoke entry point from a trusted runner.
pnpm exec tsx examples/docs-quickstarts/nextjs/quickstart.ts --smokeExpected: One JSON object with outcome "passed", allowed and denied entitlement decisions, and observed usage data, followed by successful subscription/customer cleanup.
CLI links
Use the CLI to authenticate and inspect the same workspace after the smoke test.
monetizekit auth service-token create docs-quickstart --scopes customers:view --ttl 30dmonetizekit customers list