CLAUDE LABJP
VERSION — v2.1.227 landed on August 10 with no new features, just fixes around plan detection and CI behaviorAUTO — Two days remain until August 14, when auto mode becomes the default in Claude Code for Pro, Max, and TeamCI — Bash commands no longer fail across the board under claude-code-action with allowed_non_write_users on GitHub-hosted runnersBILLING — Sessions started with an expired token could misread your plan and nudge Max users toward usage credits; that is now fixedSUNSET — The legacy Workbench and the experimental prompt tool APIs retire on August 17, five days outPRICE — Sonnet 5 promo pricing at $2/$10 per Mtok runs through August 31, moving to $3/$15 on September 1VERSION — v2.1.227 landed on August 10 with no new features, just fixes around plan detection and CI behaviorAUTO — Two days remain until August 14, when auto mode becomes the default in Claude Code for Pro, Max, and TeamCI — Bash commands no longer fail across the board under claude-code-action with allowed_non_write_users on GitHub-hosted runnersBILLING — Sessions started with an expired token could misread your plan and nudge Max users toward usage credits; that is now fixedSUNSET — The legacy Workbench and the experimental prompt tool APIs retire on August 17, five days outPRICE — Sonnet 5 promo pricing at $2/$10 per Mtok runs through August 31, moving to $3/$15 on September 1
Articles/API & SDK
API & SDK/2026-06-24Advanced

When Stripe's Bill and Your Own Ledger Drift Apart: Field Notes on Metered Billing for Claude API

Usage-based billing for Claude API looks clean until month-end, when Stripe's total and your own usage ledger quietly disagree. Here are the field-tested patterns for idempotent meter events, reconciliation jobs, and pricing-change-proof credits.

claude-api81stripe6metered-billingbilling-metersreconciliation

Premium Article

A Claude-API-backed service with usage-based billing looks healthy for the first few weeks. The trouble surfaces at month-end: the amount Stripe finalizes and the "usage this month" figure on your own dashboard disagree — slightly, but reliably. A few yen sometimes, a few hundred for heavy users.

This drift is less a bug than a structural fact: you are writing to two separate ledgers (Stripe's meter and your own usage counter) independently. Rather than trying to drive the difference to zero, these notes are about keeping it detectable and explainable. This isn't a setup walkthrough — it's what actually mattered after running billing in production for about a year.

First: stop using createUsageRecord

Until recently, Stripe metered billing meant sending subscriptionItems.createUsageRecord() against a Subscription Item. It still works during the migration window, but new builds should use Billing Meters. The difference looks small and matters a lot operationally: a meter event says "for this customer, increment this metric by this amount" without you having to resolve a Subscription Item ID at all.

// lib/claude-metering.ts
import Anthropic from "@anthropic-ai/sdk";
import Stripe from "stripe";
 
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
 
// Legacy: stripe.subscriptionItems.createUsageRecord(itemId, {...})  <- don't use for new work
// Modern: send an event to a meter, keyed by customer ID
async function sendMeterEvent(params: {
  stripeCustomerId: string;
  credits: number;
  identifier: string; // idempotency key (below)
}) {
  await stripe.billing.meterEvents.create({
    event_name: "claude_credits",
    identifier: params.identifier,
    payload: {
      stripe_customer_id: params.stripeCustomerId,
      value: String(params.credits),
    },
  });
}

event_name must match the meter you created in the Stripe dashboard. Configure the meter to sum value over the period, and each event accumulates straight into the month's usage.

Don't send tokens — send "credits"

This is the single biggest lever for keeping operations sane. Claude's per-token price differs between input and output, and between models. As of June 2026, the order of magnitude shifts across Sonnet, Opus 4.8, and the higher-tier Fable 5. If you send raw token counts to the meter, every price change rewrites the meaning of past events and your billing logic breaks.

So normalize tokens into your own credit unit before sending. Absorb per-model price differences into a conversion table, and hand Stripe nothing but a credit count. When a new model lands, you add one row to the table and move on.

// One place to hold per-model "round-to-credits" rates.
// Values are approximate as of June 2026; always confirm real prices on the official pricing page.
const MODEL_RATES: Record<string, { inPer1k: number; outPer1k: number }> = {
  "claude-sonnet-4-6": { inPer1k: 0.3, outPer1k: 1.5 },
  "claude-opus-4-8": { inPer1k: 1.5, outPer1k: 7.5 },
  "claude-fable-5": { inPer1k: 3.0, outPer1k: 15.0 },
};
 
// 1 credit = your smallest internal billing unit. Here we anchor it near "~0.1 yen" and integerize.
const YEN_PER_CREDIT = 0.1;
 
function tokensToCredits(model: string, inTok: number, outTok: number): number {
  const r = MODEL_RATES[model] ?? MODEL_RATES["claude-sonnet-4-6"];
  const yen = (inTok / 1000) * r.inPer1k + (outTok / 1000) * r.outPer1k;
  // Round up; we don't eat the remainder, and guarantee at least 1 credit per request.
  return Math.max(1, Math.ceil(yen / YEN_PER_CREDIT));
}

Why round to integers? Meter event values can be fractional, but floating-point rounding differences between Stripe and your own DB make reconciliation ambiguous — you can no longer tell a real discrepancy from a rounding artifact. Anchoring to integer credits means any drift shows up as a count mismatch, which is far easier to trace.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Idempotent Stripe Billing Meter events that prevent both double-counting and silent loss with one mechanism
A daily reconciliation job that catches drift between Stripe's aggregation and your own ledger before invoices finalize
A 'credits' abstraction that survives price changes like Opus 4.8 and Fable 5 without breaking billing logic
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API & SDK2026-05-04
Implementing Usage-Based Billing with Claude API + Stripe: A Minimal Setup for Indie Developers
Learn how to measure Claude API token consumption and implement usage-based billing with Stripe Meter Events. A minimal Node.js setup that indie developers can ship in a weekend, with real gotchas from production.
API & SDK2026-04-28
Building a Recurring Billing SaaS with Claude API and Stripe — From Architecture to Production
A complete architecture guide for building a SaaS product powered by Claude API with Stripe recurring billing. Covers usage metering, tiered pricing, webhook handling, and production deployment patterns.
API & SDK2026-07-13
Precision Lives in the Second Stage: Reranking a Personal Knowledge Search with Claude
Embedding search alone leaves 'semantically close but not the answer' passages at the top. This is a two-stage design that gathers candidates broadly, then lets Claude reorder them by answerability, with structured scoring, abstention, and a cost estimate.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →