Skip to main content

Installation

npm install crovver-node
# or
pnpm add crovver-node
# or
yarn add crovver-node
Requirements: Node.js 18+. TypeScript is optional but fully supported.

Initialize the Client

import { CrovverClient } from "crovver-node";

const crovver = new CrovverClient({
  apiKey: process.env.CROVVER_SECRET_KEY!,
});

Configuration Options

OptionTypeDefaultDescription
apiKeystringrequiredYour secret API key (sk_live_...)
timeoutnumber30000Request timeout in milliseconds
maxRetriesnumber3Retry attempts for server errors
debugbooleanfalseLog requests and responses
loggerfunctionundefinedCustom logger: (message, data?) => void

Tenant Management

// Create a tenant (B2B: workspace or user)
const tenant = await crovver.createTenant({
  externalTenantId: "workspace_abc123",
  name: "Acme Corp",
});

// Retrieve a tenant
const tenant = await crovver.getTenant("workspace_abc123");

Plans

const { plans } = await crovver.getPlans();

for (const plan of plans) {
  console.log(`${plan.name} - $${plan.priceAmount / 100}/mo`);
}

Subscriptions

const { subscriptions } = await crovver.getSubscriptions("workspace_abc123");

// status: active | trialing | canceled | past_due | ...
console.log(subscriptions[0].status);

// Cancel a subscription
await crovver.cancelSubscription(subscriptionId, "User requested cancellation");

Feature Entitlements

const canAccess = await crovver.canAccess("workspace_abc123", "advanced_analytics");

if (canAccess) {
  // serve the feature
}

Usage Tracking

// Record usage
await crovver.recordUsage("workspace_abc123", "api_calls", 1);

// Check against limit
const limit = await crovver.checkUsageLimit("workspace_abc123", "api_calls");
console.log(`${limit.used} / ${limit.limit}`);

Checkout

const session = await crovver.createCheckoutSession({
  externalTenantId: "workspace_abc123",
  planId: "plan_pro",
  successUrl: "https://yourapp.com/billing/success",
  cancelUrl: "https://yourapp.com/billing/cancel",
});

// Redirect user to session.checkoutUrl

Invoices

const { invoices } = await crovver.getInvoices("workspace_abc123");

Error Handling

import { CrovverClient, CrovverError } from "crovver-node";

try {
  const canAccess = await crovver.canAccess("workspace_abc123", "advanced_analytics");
} catch (error) {
  if (error instanceof CrovverError) {
    error.message;      // Human-readable message
    error.statusCode;   // HTTP status code
    error.code;         // API error code string
    error.isRetryable;  // Whether the SDK already retried
  }
}
5xx errors, 429, and 408 responses are retried automatically with exponential backoff. Checkout endpoints are never retried to prevent duplicate charges.