Raypx

@raypx/billing

Plan limits and billing logic for free and pro tiers.

@raypx/billing provides plan tier definitions and usage checking functions. It currently supports two tiers (free and pro) and exports utility functions for checking whether a user can perform AI operations or upload documents based on their current usage.

Plan Tiers

TierDescription
freeDefault tier with basic limits
proPaid tier with higher limits

Use resolvePlanTier() to convert a raw value to a PlanTier:

import { resolvePlanTier } from "@raypx/billing"

resolvePlanTier("pro")   // "pro"
resolvePlanTier("free")   // "free"
resolvePlanTier("other")  // "free"
resolvePlanTier(null)     // "free"
resolvePlanTier(undefined) // "free"

Plan Limits

LimitFreePro
Monthly AI tokens25,000250,000
Monthly AI requests1002,000
Max documents252,000
Max file size2 MB25 MB

Use getPlanLimits() to retrieve the limits for a tier:

import { getPlanLimits } from "@raypx/billing"

const limits = getPlanLimits("pro")
// { monthlyAiTokens: 250000, monthlyAiRequests: 2000, maxDocuments: 2000, maxFileSizeBytes: 26214400 }

Usage Check Functions

canUseAi

Check whether a user can make an AI request given their current usage:

import { canUseAi } from "@raypx/billing"

const result = canUseAi(
  { aiTokens: 24_000, aiRequests: 99, documents: 5 },
  "free",
  800, // requested tokens
)

if (result.allowed) {
  // Proceed with AI request
} else {
  // result.reason: "monthly_ai_tokens" or "monthly_ai_requests"
}

The function checks two conditions in order:

  1. Whether the next request would exceed monthlyAiRequests.
  2. Whether the requested tokens would push the total over monthlyAiTokens.

canUploadDocument

Check whether a user can upload a document:

import { canUploadDocument } from "@raypx/billing"

const result = canUploadDocument(
  { aiTokens: 100, aiRequests: 2, documents: 24 },
  "free",
  1_500_000, // file size in bytes
)

if (result.allowed) {
  // Proceed with upload
} else {
  // result.reason: "max_documents" or "max_file_size"
}

Checks two conditions:

  1. Whether adding one more document would exceed maxDocuments.
  2. Whether the file size exceeds maxFileSizeBytes.

Usage Snapshot

A UsageSnapshot represents the current usage counters for a billing period:

interface UsageSnapshot {
  aiTokens: number
  aiRequests: number
  documents: number
}

Use getDefaultUsageSnapshot() to get a zeroed snapshot:

import { getDefaultUsageSnapshot } from "@raypx/billing"

const snapshot = getDefaultUsageSnapshot()
// { aiTokens: 0, aiRequests: 0, documents: 0 }

Usage Allowance Result

Both check functions return a UsageAllowanceResult:

interface UsageAllowanceResult {
  allowed: boolean
  reason?: "monthly_ai_tokens" | "monthly_ai_requests" | "max_documents" | "max_file_size"
}

When allowed is false, the reason field indicates which limit was exceeded, allowing the frontend to display an appropriate message.

Future: Payment Provider Integration

The billing package currently handles plan limits only. Payment provider integration (subscription management, invoicing, webhooks) is planned for a future release. The existing PlanTier type and resolvePlanTier() function are designed to be extended with additional tiers as needed.

On this page