Back to Blog
Getting StartedTutorial

Getting Started with Parmot

Learn how to set up your first usage plan with token limits and rate limiting in just a few minutes.

August 14, 2025
10 min read
By Parmot Team

Integrate usage tracking and plan enforcement for OpenAI, Anthropic, and more—with optional Stripe-driven plan changes.


1) Install

npm install parmot
# or
yarn add parmot

# Python
pip install parmot

2) Set API Keys

# .env
PARMOT_API_KEY="parmot_your_api_key_here"
OPENAI_API_KEY="your_openai_api_key_here"

3) Track Your First Call

TypeScript

import { TrackedOpenAI } from "parmot";

const client = new TrackedOpenAI({
apiKey: process.env.OPENAI_API_KEY!,
parmotApiKey: process.env.PARMOT_API_KEY!,
});

const res = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello, world!" }],
user_id: "user_123",
});

console.log(res.choices[0].message?.content);

Python

from parmot import TrackedOpenAI

client = TrackedOpenAI(
  api_key="your_openai_api_key",
  parmot_api_key="your_parmot_api_key"
)

res = client.chat.completions.create(
  model="gpt-4o-mini",
  messages=[{"role":"user","content":"Hello, world!"}],
  user_id="user_123"
)

print(res.choices[0].message.content)

Streaming responses are tracked automatically (both TS and Python).


4) Plans & Assignments (Programmatic)

TypeScript

import { ParmotClient } from "parmot";

const parmot = new ParmotClient();

const plan = await parmot.createEndUserPlan({
name: "Pro",
monthly_token_limit: 1_000_000,
monthly_cost_limit: 50.0,
description: "Pro tier with 1M tokens/month",
});

await parmot.assignEndUserToPlan("user_123", "Pro");

const assignment = await parmot.getEndUserPlanAssignment("user_123");
console.log(assignment?.name); // "Pro"

Python

from parmot import ParmotClient

parmot = ParmotClient()

plan = parmot.create_end_user_plan(
  name="Pro",
  monthly_token_limit=1_000_000,
  monthly_cost_limit=50.00,
  description="Pro tier with 1M tokens/month"
)

parmot.assign_end_user_to_plan("user_123", "Pro")
print(parmot.get_end_user_plan_assignment("user_123")?.name)

Usage summaries

// TS
const user = await parmot.getEndUserUsageSummary("user_123");
const all  = await parmot.getEndUserUsageSummary();
# Python
user = parmot.get_end_user_usage_summary("user_123")
all  = parmot.get_end_user_usage_summary()

5) Stripe Integration (Recommended)

Include end-user id in subscription metadata

import Stripe from "stripe";
const stripe = new Stripe("sk_your_stripe_key");

await stripe.subscriptions.create({
customer: "cus_customer_id",
items: [{ price: "price_your_stripe_price_id" }],
metadata: { end_user_id: "user_123" },
});

Webhook: move users between plans

import express from "express";
import Stripe from "stripe";
import { ParmotClient } from "parmot";

const app = express();
const stripe = new Stripe("sk_your_stripe_key");
const parmot = new ParmotClient();

app.post("/stripe/webhook", express.raw({ type: "application/json" }), async (req, res) => {
const sig = req.headers["stripe-signature"];
let event;
try {
  event = stripe.webhooks.constructEvent(req.body, sig!, "whsec_your_webhook_secret");
} catch (err:any) {
  return res.status(400).send(`Webhook Error: ${err.message}`);
}

switch (event.type) {
  case "invoice.payment_succeeded": {
    const subId = event.data.object.subscription as string;
    const sub = await stripe.subscriptions.retrieve(subId);
    const endUserId = sub.metadata?.end_user_id;
    if (endUserId) await parmot.assignEndUserToPlan(endUserId, "Pro");
    break;
  }
  case "invoice.payment_failed": {
    const subId = event.data.object.subscription as string;
    const sub = await stripe.subscriptions.retrieve(subId);
    const endUserId = sub.metadata?.end_user_id;
    if (endUserId) await parmot.assignEndUserToPlan(endUserId, "Free");
    break;
  }
}

res.json({ received: true });
});

Python Flask version available as well; mirror the same logic.
Configure invoice.payment_succeeded and invoice.payment_failed in your Stripe dashboard.


6) Error Handling

TypeScript

import {
TrackedOpenAI,
ParmotEndUserUsageLimitError,
ParmotEndUserRateLimitError,
} from "parmot";

const client = new TrackedOpenAI();

try {
await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "Hello!" }],
  user_id: "user_123",
});
} catch (err) {
if (err instanceof ParmotEndUserUsageLimitError) {
  // upgrade flow, show UI, etc.
} else if (err instanceof ParmotEndUserRateLimitError) {
  // respect err.retry_after
} else {
  // generic error path
}
}

Python

from parmot import (
  TrackedOpenAI,
  ParmotEndUserUsageLimitError,
  ParmotEndUserRateLimitError,
)

client = TrackedOpenAI()

try:
  client.chat.completions.create(
      model="gpt-4o-mini",
      messages=[{"role":"user","content":"Hello!"}],
      user_id="user_123"
  )
except ParmotEndUserUsageLimitError as e:
  pass  # upgrade flow
except ParmotEndUserRateLimitError as e:
  pass  # wait e.retry_after
except Exception:
  pass

7) Other Providers

Anthropic

import { TrackedAnthropic } from "parmot";

const client = new TrackedAnthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
parmotApiKey: process.env.PARMOT_API_KEY!,
});

const resp = await client.messages.create({
model: "claude-3-5-haiku-20241022",
messages: [{ role: "user", content: "Hello!" }],
max_tokens: 100,
user_id: "user_123",
});
console.log(resp.content[0].text);

Cohere

from parmot import TrackedCohere

client = TrackedCohere(
  api_key="your_cohere_api_key",
  parmot_api_key="your_parmot_api_key"
)

resp = client.chat(
  model="command-r-08-2024",
  messages=[{"role":"user","content":"Hello!"}],
  user_id="user_123"
)
print(resp.message.content[0].text)

Supported Providers (snapshot)

  • OpenAI — Supported (Chat Completions; Text, Vision)
  • Anthropic — Supported (Messages API; Text)
  • OpenRouter — Supported (Chat Completions; Text, Vision)
  • Cohere — Supported (Chat API; Python ready; TS not yet)
  • AWS Bedrock — Coming Soon
  • Databricks — Coming Soon

That’s it

Create plans in the dashboard or via API, assign users, and let Parmot enforce limits automatically. For keys and UI, head to /dashboard.