Quickstart
A key, a first call, and a gated feature.
By the end of this page your application will refuse work an account has not paid for, and record the work it does allow.
1. Get a secret key
From your application's directory:
npx @base316/cli login
npx @base316/cli initlogin opens the dashboard and asks you to approve a code; init creates a
project named after the directory (or uses the one you name with
--project) and writes its Sandbox keys to .env, adding .env to
.gitignore. Building with an AI agent? See Build with an agent.
Or by hand: in the dashboard, open your project and go to Developers → API
keys, copy the secret key for the Sandbox environment — it starts
b316_sk_sandbox_ — and export it:
export BASE316_SECRET_KEY=b316_sk_sandbox_...Secret keys are server-side only. The publishable key (b316_pk_) is the one
safe to ship to a browser, and it cannot read customers, subscriptions or
invoices.
2. Check the key works
npx @base316/cli whoamiEnvironment sandbox (env_…)
Project proj_…
Workspace org_…
API https://api.base316.comIf that fails, nothing below will work — fix it first.
3. Install the SDK
pnpm add @base316/sdkimport { Base316 } from "@base316/sdk";
// Reads BASE316_SECRET_KEY from the environment.
const base316 = new Base316();4. Define what you sell
In the dashboard's Catalog tab, create:
- A meter — the raw thing you count, for example
api_call. - A feature — what a customer buys, for example
api_calls, backed by that meter. - A plan — a price and what it entitles. Give it a limit on
api_calls.
Then create a customer and subscribe them to the plan.
Use the CLI to check your work without leaving the terminal: npx @base316/cli plans and npx @base316/cli features.
5. Gate the feature
This is the call you will make most often. Ask before doing the work:
const decision = await base316.access.check({
externalId: "acct_1234", // your own id for the account
feature: "api_calls",
requested: 1, // how much you are about to use
});
if (!decision.allowed) {
throw new Error(`Refused: ${decision.reason}`);
}
// ... do the work ...decision.usage carries used, limit, credits and remaining, so you can
show somebody how close they are before they hit the wall.
6. Record what you used
Metering is a separate call, made after the work succeeds. If the work fails, nothing should be billed.
await base316.events.record({
externalId: "acct_1234",
event: "api_call",
idempotencyKey: requestId, // required
payload: { tokens: 1_420 },
});idempotencyKey is required rather than optional. A retry after a network
timeout must not bill the same work twice, and you are the only one who knows
what "the same work" means — a request id is usually the right answer.
7. Watch it add up
npx @base316/cli check acct_1234 api_callsALLOWED
Limit 1000
Used 1
Remaining 999Your project's setup checklist
The project's Overview lists the first steps — a meter, a published plan, the first usage event, Stripe connected and able to charge, the first invoice, and a Production secret key that has made a call. Each step is read from what the environment actually has, links to the screen that does it, and the list disappears once everything is done. Hide it with the cross; that is remembered for you, not for your teammates.
Rather explore before building? On an empty Sandbox, the checklist offers
Load example data: three plans, four customers with subscriptions in
different states, and some usage — the same world POST /v1/seed builds. It
only ever adds to an empty catalog and is never offered in Production.
Where to go next
- How the model fits together — read this before designing a real catalog.
- Entitlements — exactly how
checkdecides. - Webhooks — react to invoices and subscription changes.

