Primitive/billing3 min read

Introducing /billing: meter and monetize your own agent users

Define plans that map to an Account Kit, a Stripe price, and usage quotas — then reflect each customer's subscription and read their metered usage. The monetization layer for building a multi-tenant product on Naïve.

Primitive/billing
TL;DR
  • /billing the monetization layer for your own end-users, not your Naïve bill
  • Plans define a plan once: an Account Kit, a Stripe price, and per-primitive quotas
  • Subscriptions reflect a customer's Stripe subscription onto their user, auto-assigning the right kit
  • Usage read each tenant's metered usage against quotas for the current period
  • Account Kit-driven a plan's quotas enforce which primitives a customer's agent can use
  • Composes with the SDK's multi-tenant model one plan per tier, one subscription per user

Today we're launching /billing — the primitive that lets you monetize your users, not just pay your Naïve bill. Define plans that map to an Account Kit, a Stripe price, and usage quotas; reflect each customer's subscription onto their tenant user; and read their metered usage against quotas. It's the missing half of building a real multi-tenant product on Naïve: not just giving each customer capabilities, but charging for them.

The problem: capabilities without monetization is a demo

The Naïve SDK already lets you build multi-tenant — naive.users.create(...) gives every customer their own isolated tenant with their own cards, vault, connections, and apps. But a product isn't just capabilities. It's tiers, limits, and a way to charge. And historically that means bolting on a whole metering system:

  • A way to define plans and what each one unlocks.
  • A way to tie a plan to a Stripe price and keep subscriptions in sync.
  • A way to count usage per customer and enforce quotas.
  • A way to make entitlements actually enforced, not just displayed.

Build that yourself and you've written a billing platform before you've shipped your product. /billing makes it three calls, wired into the same multi-tenant model the rest of the SDK already uses.

How /billing works

There are two halves: defining plans (a control-plane operation on the root client), and applying them per customer (a data-plane operation scoped to a tenant user).

A plan ties together three things:

  1. An Account Kit — the policy template that gates which primitives a customer's agent can use, and at what limits.
  2. A Stripe price — the price id in your Stripe account that this plan corresponds to.
  3. Quotas — per-primitive usage caps for the billing period.
// Operator defines plans once (control plane)
await naive.plans.upsert({
  key: "pro",
  name: "Pro",
  stripePriceId: "price_1Pxyz...",
  accountKitId: "kit_pro",
  quotas: { "email.send": 1000, "search.web": 5000 },
  period: "month",
});

Reflect a subscription onto a customer

You own the Stripe relationship with your customers. When your Stripe webhook fires for a new or updated subscription, reflect it onto the tenant user. Setting the subscription also assigns the plan's Account Kit, so the customer's entitlements update atomically.

// In your Stripe webhook handler
await naive.forUser(userId).billing.setSubscription({
  planKey: "pro",
  status: "active",
  stripeCustomerId: "cus_...",
  stripeSubscriptionId: "sub_...",
  currentPeriodEnd: "2026-07-13T00:00:00Z",
  // assignKit defaults to true — the Pro kit is applied automatically
});

Read metered usage against quotas

Every metered primitive call by a tenant user is counted against that user. Read the current period's rollup to display consumption, gate features, or bill overages.

const { plan, status, period, quotas, usage } = await naive.forUser(userId).billing.usage();
 
// e.g. plan: "pro", quotas: { "email.send": 1000 }, usage: { "email.send": 342 }
const emailsLeft = quotas["email.send"] - (usage["email.send"] ?? 0);

Because the plan's Account Kit gates the primitives themselves, quotas aren't just a number on a dashboard — they're tied to what the customer's agent is actually allowed to do.

What you can build with /billing

Ship a multi-tenant agent SaaS end to end — Pair /billing with the SDK's multi-tenant model: a tenant user per customer, a plan per tier, and a subscription per account. Capabilities, limits, and charges all follow the plan.

Enforce tiers, not just advertise them — Because plans map to Account Kits, "Starter can't issue cards" or "Pro gets 10x search" is enforced at the runtime, not in your UI's if statements.

Meter and bill overages — Read per-period usage and charge for what exceeds the quota through your own Stripe account — usage-based billing on top of capabilities you didn't have to build.

Give each customer isolated economics — Combine /billing with per-tenant /cards and vaults so every customer's spend, credentials, and usage are tracked and contained separately.

Get started

Drop this starter prompt into any coding agent to wire up Naïve:

Read https://usenaive.ai/skill.md and use it to set up Naïve in my project.

Frequently Asked Questions
What is /billing?+
/billing is the primitive for monetizing your own end-users when you build a multi-tenant product on Naïve. You define plans (each mapping to an Account Kit, a Stripe price, and usage quotas), reflect each customer's subscription onto their tenant user, and read their metered usage. It's how you turn Naïve primitives into a product you charge for.
Is this the same as my own Naïve subscription?+
No. Your own plan and credit balance with Naïve are the operator's billing relationship. /billing is the other direction — defining the plans and metering for the customers of the product you build on top of Naïve. The two are independent.
How do plans and Account Kits relate?+
A plan maps to an Account Kit, which is the policy template that gates which primitives and connections an agent can use and at what limits. When you set a customer's subscription to a plan, /billing assigns that plan's Account Kit to the user automatically, so entitlements follow the plan.
How does Stripe fit in?+
You own the Stripe relationship with your customers. A plan references a Stripe price id; when your Stripe webhook fires for a new or changed subscription, you call setSubscription to reflect it onto the tenant user. Naïve doesn't charge your customers — it tracks the plan, kit, and usage so your product can.
Where does usage data come from?+
Every metered primitive call by a tenant user is counted against that user. naive.forUser(id).billing.usage() returns the current period's usage rollup and the plan's quotas, so you can show consumption, enforce limits, or bill overages.
How do I get started?+
Define plans with naive.plans.upsert(...), then reflect subscriptions with naive.forUser(id).billing.setSubscription(...) and read usage with naive.forUser(id).billing.usage(). The full guide is at usenaive.ai/docs/getting-started/customer-billing.
DZ
Dennis ZaxCTO

CTO of Naïve. Building the open-source agent runtime.

@denniszax