> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cursor Billing Model

> Deconstruct Cursor's model-weighted credit system and build the same hybrid subscription-plus-credits model using Dodo Payments.

## How Cursor Bills

Cursor combines a monthly subscription with a depleting pool of included usage. Users pay a predictable price, and Cursor covers the variable cost of different AI models from that pool.

**Pricing Tiers**: Cursor offers tiers from Hobby to Ultra. Cursor's plans include usage pools charged at each model's API price, not fixed request counts ([Cursor pricing docs](https://cursor.com/docs/account/pricing)). The request allowances in the table are illustrative values this deconstruction models.

| Plan | Price | Premium Requests | Slow Requests |
| :- | :- | :- | :- |
| Hobby | Free | 50/month | Unlimited |
| Pro | \$20/month | 500/month | Unlimited |
| Pro+ | \$60/month | Unlimited premium | - |
| Ultra | \$200/month | Unlimited premium | - |

**Model-Weighted Depletion**: Each request consumes credits based on the cost of the underlying model. One subscription covers several model providers, and expensive operations draw more from the pool. Cursor doesn't publish per-request credit costs, so the weights below are illustrative.

| Request Type | Model | Credit Cost |
| :- | :- | :- |
| Tab Completion | Default | 0 |
| Chat | GPT-4o Mini | 1 |
| Chat | Claude 3.5 Sonnet | 1 |
| Composer | GPT-4o | 5 |
| Agent | Claude 3.5 Sonnet | 10 |
| Agent | o1-preview | 25 |

**Credit Exhaustion and Overages**: When credits run out, users move to a "Slow" queue with cheaper models instead of being cut off. Users can also enable on-demand usage to keep premium access, billed at the end of the cycle.

```mermaid theme={null}
flowchart TD
    A[User Makes Request] --> B[Determine Model and Type]
    B --> C[Calculate Credit Cost]
    C --> D{Credits Remaining?}
    D -->|Yes| E[Deduct Credits]
    E --> F[Process with Premium Model]
    D -->|No| G{Overage Enabled?}
    G -->|Yes| H[Bill Overage at End of Cycle]
    H --> F
    G -->|No| I[Route to Slow Queue]
    I --> J[Process with Basic Model]
```

**Enterprise**: On the Enterprise plan, the whole organization shares one usage pool. Heavy users draw from the same pool as everyone else, so one person's limit doesn't block them while teammates have unused capacity. Cursor lists pooled usage as an Enterprise feature on [its pricing page](https://cursor.com/pricing).

## What Makes It Unique

Cursor's model balances user experience against infrastructure cost in four ways:

* **Provider Abstraction**: One subscription wraps several LLM providers, such as OpenAI and Anthropic. Cursor handles the provider pricing and API keys.
* **Weighted Depletion**: Powerful models cost more credits, so the price of a request tracks its cost.
* **Graceful Degradation**: The "Slow" queue replaces a hard cutoff. Users stay in the product, and the slower experience encourages an upgrade.
* **Pooled Credits**: An organization-level pool lets a team share capacity instead of managing individual limits.

## Build This with Dodo Payments

You can build this model with Dodo Payments credit entitlements and usage-based billing. The steps below create the credit, the plans, the meter, the slow-queue logic, and the checkout.

<Steps>
  <Step title="Create a Custom Unit Credit Entitlement">
    Go to **Products → Credits** and click **Create Credit**. This credit represents the "Premium Requests" that come with each subscription. Use these settings:

    * **Credit Type:** Custom Unit
    * **Unit Name:** "Premium Requests"
    * **Precision:** 0 (a request can't be split)
    * **Credit Expiry:** 30 days (credits reset each billing cycle)
    * **Rollover:** Disabled (unused requests don't carry over)
    * **Allow Overage:** Enabled
    * **Price Per Unit:** \$0.04 (the cost of each request after the included pool is used)
    * **Overage Behavior:** Bill overage at billing (the overage cost is added to the next invoice)

    Each user gets a fixed pool of requests per cycle and pays for extra requests at the per-unit price.
  </Step>

  <Step title="Create Subscription Products">
    Create one subscription product per tier. Attach the same credit entitlement to each product with a different **Credits issued per billing cycle** value. One credit system across all tiers keeps upgrades and downgrades simple.

    * **Hobby:** \$0/month, 50 credits/cycle
    * **Pro:** \$20/month, 500 credits/cycle
    * **Pro+:** \$60/month, 5000 credits/cycle (effectively unlimited for most users)
    * **Ultra:** \$200/month, 50000 credits/cycle (effectively unlimited)

    When a customer subscribes, Dodo Payments grants the product's credits for the billing cycle and grants them again at each renewal.
  </Step>

  <Step title="Create a Usage Meter Linked to Credits">
    Create a meter with the event name `ai.request`, **Sum** aggregation, and `credit_cost` as the **Over Property**. On your usage-based product, toggle **Bill usage in Credits**, select the credit entitlement, and set **Meter units per credit** to 1.

    Your application decides the credit cost of each request from the model and the action type, then sends it in the event:

    ```typescript theme={null}
    import DodoPayments from 'dodopayments';

    /**
     * Determines the credit cost for a given request type and model.
     * This logic lives in your application and can be updated without
     * changing your billing configuration.
     */
    function getCreditCost(requestType: string, model: string): number {
      const costs: Record<string, Record<string, number>> = {
        'tab_completion': { 'default': 0 },
        'chat': { 'gpt-4o-mini': 1, 'gpt-4o': 1, 'claude-sonnet': 1 },
        'composer': { 'gpt-4o-mini': 2, 'gpt-4o': 5, 'claude-sonnet': 5 },
        'agent': { 'gpt-4o': 10, 'claude-sonnet': 10, 'o1': 25 }
      };
      
      // Default to 1 credit if the combination isn't found
      return costs[requestType]?.[model] ?? 1;
    }

    /**
     * Ingests usage events into Dodo Payments.
     * The meter sums credit_cost, so one event carries the full weight of the request.
     */
    async function trackRequest(customerId: string, requestType: string, model: string) {
      const creditCost = getCreditCost(requestType, model);
      
      // Tab completions are free, so we don't need to track them for billing
      if (creditCost === 0) return;
      
      const client = new DodoPayments({
        bearerToken: process.env.DODO_PAYMENTS_API_KEY,
      });
      
      await client.usageEvents.ingest({
        events: [{
          event_id: `req_${Date.now()}_${Math.random().toString(36).slice(2)}`,
          customer_id: customerId,
          event_name: 'ai.request',
          timestamp: new Date().toISOString(),
          metadata: {
            request_type: requestType,
            model: model,
            credit_cost: creditCost
          }
        }]
      });
    }
    ```

    <Tip>
      A **Sum** meter over `credit_cost` lets a single event carry any weight. You send one event per request instead of one event per credit, which keeps high-volume ingestion small.
    </Tip>
  </Step>

  <Step title="Handle Credit Exhaustion (Slow Queue)">
    Subscribe to the `credit.balance_low` webhook. When a customer's balance falls below the **Low Balance Threshold** set on the product, move them to a slow queue in your application. This is the graceful degradation logic.

    ```typescript theme={null}
    import DodoPayments from 'dodopayments';
    import express from 'express';

    const app = express();
    app.use(express.raw({ type: 'application/json' }));

    const client = new DodoPayments({
      bearerToken: process.env.DODO_PAYMENTS_API_KEY,
      webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
    });

    // updateUserTier, getUserTier, and notifyUser are your application's own functions.
    app.post('/webhooks/dodo', async (req, res) => {
      try {
        const event = client.webhooks.unwrap(req.body.toString(), {
          headers: {
            'webhook-id': req.headers['webhook-id'] as string,
            'webhook-signature': req.headers['webhook-signature'] as string,
            'webhook-timestamp': req.headers['webhook-timestamp'] as string,
          },
        });
        
        if (event.type === 'credit.balance_low') {
          const customerId = event.data.customer_id;
          await updateUserTier(customerId, 'slow');
          await notifyUser(customerId, 'You have used most of your premium requests. Switching to standard models.');
        }
        
        res.json({ received: true });
      } catch (error) {
        res.status(401).json({ error: 'Invalid signature' });
      }
    });

    /**
     * Routes a request based on the user's current tier.
     * This function is called before every AI request to determine the model and queue.
     */
    async function routeRequest(customerId: string, requestType: string) {
      const tier = await getUserTier(customerId);
      
      if (tier === 'slow') {
        // Route to a cheaper model and a lower priority queue
        // This saves costs while keeping the user active in the product
        return { model: 'gpt-4o-mini', queue: 'standard' };
      }
      
      // Premium routing for users with remaining credits
      // This provides the best possible performance and model quality
      return { model: 'claude-sonnet', queue: 'priority' };
    }
    ```
  </Step>

  <Step title="Create Checkout">
    Create a checkout session when a user subscribes to a plan. Dodo Payments processes the payment, calculates tax, and grants the plan's credits.

    ```typescript theme={null}
    import DodoPayments from 'dodopayments';

    const client = new DodoPayments({
      bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    });

    /**
     * Creates a checkout session for a new subscription.
     * This is typically called when a user clicks an "Upgrade" button.
     */
    const session = await client.checkoutSessions.create({
      product_cart: [
        { product_id: 'pdt_cursor_pro', quantity: 1 }
      ],
      customer: { email: 'developer@example.com' },
      return_url: 'https://yourapp.com/dashboard'
    });
    ```
  </Step>
</Steps>

## Accelerate with the LLM Ingestion Blueprint

The credit-weighted events above drive billing. To also record raw token consumption per provider, run the [LLM Ingestion Blueprint](/developer-resources/ingestion-blueprints/llm) alongside your credit system.

```bash theme={null}
npm install @dodopayments/ingestion-blueprints
```

```typescript theme={null}
import { createLLMTracker } from '@dodopayments/ingestion-blueprints';
import OpenAI from 'openai';
import Anthropic from '@anthropic-ai/sdk';

// Track raw token usage for analytics alongside credit-weighted billing
const openaiTracker = createLLMTracker({
  apiKey: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'live_mode',
  eventName: 'analytics.openai_tokens',
});

const anthropicTracker = createLLMTracker({
  apiKey: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'live_mode',
  eventName: 'analytics.anthropic_tokens',
});

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

// Wrap each provider separately
const trackedOpenAI = openaiTracker.wrap({ client: openai, customerId: 'cus_abc123' });
const trackedAnthropic = anthropicTracker.wrap({ client: anthropic, customerId: 'cus_abc123' });

// Token tracking is automatic, credit deduction still uses your weighted system
const response = await trackedOpenAI.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Hello!' }],
});
```

Each tracked call sends `inputTokens`, `outputTokens`, `totalTokens`, and `model` in the event metadata. You get two layers of data: credit-weighted events for billing and raw token counts for cost and margin analysis.

<Tip>
  The LLM Blueprint supports OpenAI, Anthropic, Groq, Google Gemini, OpenRouter, and the Vercel AI SDK. See the [full blueprint documentation](/developer-resources/ingestion-blueprints/llm) for all supported providers.
</Tip>

## Pooled Team Credits (Enterprise)

Cursor's Enterprise plan pools usage across a team. To build this with Dodo Payments, create one subscription for the organization instead of one per user. The team's usage then accrues to a single billing entity, which larger customers expect.

### Implementation Strategy

1. **Organization-Level Customer:** Create one Dodo Payments customer for the whole organization. This customer holds the shared credit pool, and all invoices and credit grants belong to its `customer_id`.
2. **Seat-Based Billing:** Charge a per-user platform fee with a seat add-on, as described in [Seat-Based Billing](/features/seat-based-billing). When the team adds a member, change the add-on quantity. Revenue grows with the number of users, and the credit pool stays separate.
3. **Shared Usage Tracking:** Send every team member's requests with the organization's `customer_id`, so each request depletes the same pool. To report on individual users, add a `user_id` to the event metadata.

Each member pays a predictable platform fee, and the team shares one pool of credits for the expensive AI resources. Members don't manage their own limits.

## Comparison with Traditional SaaS Billing

Traditional SaaS billing uses flat-rate tiers, for example \$10/month for 100 units. A user who needs 101 units must often jump to a \$50/month tier. This "cliff" frustrates users and drives churn. Flat tiers also ignore the different costs of different kinds of usage, which matter for AI products.

A Cursor-style model built on Dodo Payments avoids these problems:

* **No "Cliff" Effects:** Users don't have to upgrade when they hit a limit. They can pay for overage or accept slower performance, so they keep working in the product.
* **Cost Alignment:** Revenue follows infrastructure cost. Users of expensive models pay more, through credits or overage, which protects your margins on high-cost features.
* **Better Retention:** Users who reach their limit can keep working instead of being cut off. Continued use builds loyalty and raises customer lifetime value.

## Handling Model Updates and Evolution

AI providers update and replace models often, and a new model can have a different cost. Because credit costs live in your application, you can price a new model without migrating billing data.

To add a more expensive model, give it a higher cost in `getCreditCost`. You don't change the credit entitlement, the meter, or existing subscriptions. Billing stays separate from application logic, so you can ship model changes without touching billing.

## User Notifications and Transparency

Show users how many credits they have used so they can manage cost and trust the bill. The `credit.balance_low` webhook fires when a balance drops below the product's **Low Balance Threshold**. For more checkpoints, such as 50% and 80% usage, compare the balance in `credit.deducted` events against the plan's allocation.

Send these alerts by email, in-app message, or Slack. A timely warning lets users reduce usage or upgrade before they reach the slow queue, which reduces support tickets.

## Security and Fraud Prevention

Credits have direct monetary value, so protect the system that spends them.

* **Idempotency:** Give every usage event a unique `event_id`. Dodo Payments uses `event_id` to detect duplicates, so a network retry with the same ID doesn't charge the user twice.
* **Rate Limiting:** Limit request rates in your application so one user can't exhaust their credits, or your provider budget, too quickly.
* **Monitoring:** Watch usage for anomalies such as account sharing or automated abuse. The meter dashboard's **Customers** view shows per-customer usage totals.

## Best Practices for Credit Systems

Keep these practices in mind when you design a credit system:

1. **Keep it Simple:** Users should understand what a request costs and how many credits they have left.
2. **Provide Value:** Price requests so users feel the credits are worth it. A cost that feels too high for a small action reads as nickel-and-diming.
3. **Be Transparent:** Show the current credit balance and usage history. Customers can also see both in the Customer Portal.
4. **Automate Everything:** Use Dodo Payments webhooks and APIs to automate billing tasks and remove manual work.

## Key Dodo Features Used

<CardGroup cols={2}>
  <Card title="Credit-Based Billing" icon="coins" href="/features/credit-based-billing">
    Manage depleting credit pools and overages with custom units.
  </Card>

  <Card title="Subscriptions" icon="calendar" href="/features/subscription">
    Set up recurring billing for different tiers with integrated credits.
  </Card>

  <Card title="Usage-Based Billing" icon="chart-line" href="/features/usage-based-billing/introduction">
    Track events and bill based on consumption.
  </Card>

  <Card title="Event Ingestion" icon="bolt" href="/features/usage-based-billing/event-ingestion">
    Send high-volume usage data to Dodo Payments.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/developer-resources/webhooks/intents/credit">
    React to credit balance changes and automate user tiering.
  </Card>

  <Card title="LLM Ingestion Blueprint" icon="brain-circuit" href="/developer-resources/ingestion-blueprints/llm">
    Automatic token tracking across multiple LLM providers.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.