Loading...
Loading...
Implement usage-based billing with PayKit's check and report methods, gate features by entitlements, track and decrement usage, handle balance resets, and build metered billing flows. Use when users need to add usage limits, API rate limiting, or consumption-based billing with PayKit.
npx skill4agent add getpaykit/skills metered-usage-best-practicescheck()report()const result = await paykit.check({
customerId: "user_123",
featureId: "messages",
})
if (!result.allowed) {
throw new Error("Usage limit reached")
}| Parameter | Required | Description |
|---|---|---|
| Yes | Your app's user ID |
| Yes | Feature to check (type-safe) |
| No | Check if at least this many units remain |
interface CheckResult {
allowed: boolean
balance: {
limit: number
remaining: number
resetAt: Date | null
unlimited: boolean
} | null
}allowedtruefalsebalancenullallowedtrueremaining > 0remaining >= requiredbalancerequiredconst { allowed } = await paykit.check({
customerId: "user_123",
featureId: "api_calls",
required: 50,
})
if (!allowed) {
throw new Error("Not enough API calls remaining")
}const result = await paykit.report({
customerId: "user_123",
featureId: "messages",
amount: 1,
})
if (!result.success) {
// Usage limit exceeded
}| Parameter | Required | Description |
|---|---|---|
| Yes | Your app's user ID |
| Yes | Feature to decrement (type-safe) |
| No | Units consumed. Default: |
interface ReportResult {
success: boolean
balance: {
limit: number
remaining: number
resetAt: Date | null
unlimited: boolean
} | null
}successfalseconst { allowed } = await paykit.check({
customerId: userId,
featureId: "messages",
})
if (!allowed) {
return { error: "Message limit reached. Upgrade your plan." }
}
await sendMessage(content)
await paykit.report({
customerId: userId,
featureId: "messages",
})check()report()const { success, balance } = await paykit.report({
customerId: userId,
featureId: "api_calls",
})
if (!success) {
return Response.json(
{ error: "API call limit exceeded", resetAt: balance?.resetAt },
{ status: 429 },
)
}
// Process the API callconst { allowed } = await paykit.check({
customerId: userId,
featureId: "custom_branding",
})
if (!allowed) {
return { error: "Custom branding requires a Pro plan" }
}const { balance } = await paykit.check({
customerId: userId,
featureId: "messages",
})
// balance.remaining // units left
// balance.limit // total allowed
// balance.resetAt // when usage resets
// balance.unlimited // true if no limitcheck()report()| Reset Interval | Behavior |
|---|---|
| Resets every 24 hours from first usage |
| Resets every 7 days |
| Resets every calendar month |
| Resets every calendar year |
const customer = await paykit.getCustomer({ id: "user_123" })
for (const [featureId, entitlement] of Object.entries(customer.entitlements)) {
console.log(featureId) // "messages"
console.log(entitlement.balance) // current balance
console.log(entitlement.limit) // max allowed
console.log(entitlement.usage) // consumed
console.log(entitlement.unlimited) // boolean
console.log(entitlement.nextResetAt)
}// lib/paykit.ts
const messages = feature({ id: "messages", type: "metered" })
const proModels = feature({ id: "pro_models", type: "boolean" })
const free = plan({
id: "free",
group: "base",
default: true,
includes: [messages({ limit: 50, reset: "day" })],
})
const pro = plan({
id: "pro",
group: "base",
price: { amount: 20, interval: "month" },
includes: [messages({ limit: 2_000, reset: "day" }), proModels()],
})
// app/api/chat/route.ts
export async function POST(request: Request) {
const { userId, model, content } = await request.json()
// Check message quota
const { allowed, balance } = await paykit.check({
customerId: userId,
featureId: "messages",
})
if (!allowed) {
return Response.json({
error: "Daily message limit reached",
resetAt: balance?.resetAt,
}, { status: 429 })
}
// Check model access
if (model === "gpt-4") {
const { allowed } = await paykit.check({
customerId: userId,
featureId: "pro_models",
})
if (!allowed) {
return Response.json(
{ error: "Pro models require a Pro plan" },
{ status: 403 },
)
}
}
const response = await generateResponse(model, content)
// Decrement usage
await paykit.report({
customerId: userId,
featureId: "messages",
})
return Response.json({ response })
}