Help improve docs quality by sharing anonymous interaction telemetry (no PII or token data).

Next.js Quickstart

Complete the SDK-first MonetizeKit activation journey in a Next.js application.

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-id

Install commands

pnpm add @monetizekit/node

Happy 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.

Read the full guide

403 missing scope

Issue a key with customers:create, plans:read, subscriptions:write, entitlements:read, usage:write, usage:read, and cleanup permissions.

Read the full guide

Entitlement denied

Confirm MONETIZEKIT_PLAN_ID is the isolated plan that grants MONETIZEKIT_FEATURE_KEY and does not grant MONETIZEKIT_DENIED_FEATURE_KEY.

Read the full guide

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.

Read the full guide

Deploy + smoke test

Platform: Vercel.

  1. Set the seven quickstart environment variables in the Vercel project.

  2. Deploy the server-side integration, then run the smoke entry point from a trusted runner.

pnpm exec tsx examples/docs-quickstarts/nextjs/quickstart.ts --smoke

Expected: One JSON object with outcome "passed", allowed and denied entitlement decisions, and observed usage data, followed by successful subscription/customer cleanup.

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 30d
monetizekit customers list

Was this page helpful?