Skip to main content
If you are building your app in TypeScript using the Vercel AI SDK, you can automate usage tracking and cost calculation for DeepSeek models using the @ai-billing/deepseek package. This package provides an AI SDK middleware that automatically intercepts your DeepSeek usage, calculates the cost using the correct pricing (including cache hits and reasoning tokens), and sends the billing events to your preferred destination like Polar, Stripe, Lago, or your own custom backend.

Installation

First, ensure you have the necessary packages installed:
npm install @ai-sdk/deepseek @ai-billing/deepseek @ai-billing/core ai

Using generateText

Instead of a single large file, let’s break down how to set up the billing middleware and use it with the generateText function step-by-step.

1. The Setup & Configuration

Before making any AI calls, you need to set up the DeepSeek client and tell the billing system how much things cost.
import {
  UIMessage,
  convertToModelMessages,
  generateText,
  wrapLanguageModel,
} from 'ai';
import { createDeepSeek } from '@ai-sdk/deepseek';
import { createDeepSeekMiddleware } from '@ai-billing/deepseek';
import {
  consoleDestination,
  createObjectPriceResolver,
  ModelPricing,
} from '@ai-billing/core';

// 1. Initialize the DeepSeek client with your API key
const deepSeek = createDeepSeek({
  // eslint-disable-next-line turbo/no-undeclared-env-vars
  apiKey: process.env.DEEPSEEK_API_KEY,
});

// 2. Define the exact pricing for the model you are using
const customPricingMap: Record<string, ModelPricing> = {
  'deepseek-v4-pro': {
    promptTokens: 0.14 / 1_000_000,
    completionTokens: 0.28 / 1_000_000,
    inputCacheReadTokens: 0.028 / 1_000_000,
  },
};

const priceResolver = createObjectPriceResolver(customPricingMap);

// 3. Create the billing middleware
const billingMiddleware = createDeepSeekMiddleware({
  destinations: [consoleDestination()], // Where to send the bill (logging to console here)
  priceResolver: priceResolver,         // How to calculate the cost
});
  • The Pricing Map: AI models charge differently for reading your prompt vs. generating the answer. This map tells the system exactly how much deepseek-v4-pro costs per token.
  • The Middleware: This is the engine. It is configured to use your pricing map to calculate the cost, and right now it’s set to just log the final bill to your server console.

2. Preparing the Request

Inside your route handler (e.g., a POST function), prepare the actual question you want to ask the AI.
export async function POST() {
  try {
    const messages: UIMessage[] = [
      {
        id: 'test-gen-1',
        role: 'user',
        parts: [{ type: 'text', text: 'What is the capital of Sweden?' }],
      },
    ];

    const model = 'deepseek-v4-pro';

3. Wrapping the Model

This is the most important part. Instead of calling DeepSeek directly, wrap the standard DeepSeek model inside the billingMiddleware.
    const wrappedModel = wrapLanguageModel({
      model: deepSeek(model),
      middleware: billingMiddleware,
    });
Now, whenever this wrappedModel is used, the middleware will secretly watch the request, count the tokens that come back, do the math based on your pricing map, and log the cost.

4. Executing the Request

Finally, ask the AI the question using the wrapped model.
    const result = await generateText({
      model: wrappedModel,
      messages: await convertToModelMessages(messages),
    });

    return Response.json(result);
  } catch (error) {
    console.error('Generate Error:', error);
    return Response.json({ error: (error as Error).message }, { status: 500 });
  }
}

Using streamText

The middleware works seamlessly with streaming responses as well. The setup (steps 1 through 3) is exactly the same as above. The only difference is in Step 4: Executing the Request. Instead of generateText, you use streamText. The usage and cost will be calculated and dispatched automatically once the stream completes.
import { streamText } from 'ai';

// ... (Setup and wrappedModel from above) ...

export async function POST() {
  // ... (Prepare messages and wrappedModel) ...

  const result = streamText({
    model: wrappedModel,
    messages: await convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse();
}

Next Steps

To learn more about configuring the middleware and integrating with specific billing providers, check out the @ai-billing/deepseek reference.