For the first few months after I shipped Claude API into my apps, I was checking the Anthropic billing page before my Stripe dashboard every morning. The moment you wire an LLM into your product, your wallet is directly connected to a metered system you don't fully control. If you've been used to the simple "revenue minus server cost equals profit" math that solo developers love, the variable nature of API spend feels disorienting.
This article is a working set of notes I've collected while integrating Claude API into wallpaper apps and wellness apps as a one-person developer. The goal is to spare you from the kind of mistake I made early on — wiring up Sonnet for a casual feature, only to find it had burned through 8,000 yen in a single day.
Why Solo Developer Budgets Crack
Most LLM cost articles are written for businesses, and reading them with a solo developer's wallet in mind feels off. The premises are different. Companies plan around per-request unit cost; indie devs reason from a hard ceiling like "I can spend 50,000 yen per month, no more." We want to protect the total, not optimize the unit.
In my experience, the budget breaks for one of three reasons.
The first is misjudging per-user volume. You assume "average users will hit this five times a day," but a handful of power users hit it 200 times. While you're celebrating positive App Store reviews, your API bill quietly inflates in the background.
The second is context bloat. The naive "send the entire conversation history every turn" pattern means your tenth turn consumes thirty times the tokens of your first. Most developers worry about output token pricing, but in practice it's the swelling input tokens that eat the invoice.
The third is the retry trap. Wrapping every call in "retry up to three times on any failure" sounds defensive, but during an Anthropic-side outage it triples your costs in minutes. I once let a process loop on 5xx responses for hours, ended up with a stack of error logs and a fully billed invoice for requests that returned nothing useful.
Backing Out a Budget From the Ceiling Down
Always start by deciding what you can actually afford. My personal rule is "API spend on any feature should never exceed 30% of the gross margin of the app it lives in." If projections show I'd cross that, I trim the feature, gate it behind a paid plan, or skip the integration altogether.
Once you have a monthly cap, work backward with this rough framework:
allowed monthly spend (USD) / per-request cost estimate (USD)
= max requests per month
max requests per month / 30 / expected DAU
= max requests per user per day
For example, if I cap a feature at 200 USD per month and Sonnet 4.6 costs me about 0.01 USD per request on average, I can afford 20,000 requests per month. With 100 daily active users, each can fire roughly 6.6 requests per day before I'm in the red.
The interesting moment is when you feel "6.6? That's barely anything." Most indie devs intuit "let's just give the AI feature to everyone for free." Run this calculation and you'll see why you almost certainly need to cap free users at three or fewer requests per day, reserving the rest of the budget for paying members.
Realistic Per-Model Pricing Intuition
The official price page is public, so I'll share the gut feel I've developed instead. As of May 2026, here are the numbers I keep in my head:
- Claude Haiku 4.5 — $0.25 input / $1.25 output per 1M tokens
- Claude Sonnet 4.6 — $3 input / $15 output per 1M tokens
- Claude Opus 4.6 — $5 input / $25 output per 1M tokens
The crucial fact is that Sonnet costs roughly twelve times what Haiku does. If you implement a Haiku-class job on Sonnet, your costs are 12x what they should be. I describe it internally as "putting a luxury sedan on a grocery run when a kei car would do."
Before I write a line of integration code, I always test whether Haiku can handle the task. In my apps, around 80% of user-facing replies and routine processing run on Haiku. Sonnet only comes out when the task genuinely needs reasoning — code review, complex summarization, anything where one degree of accuracy matters.
Logging Discipline: Measure Before You Optimize
When people hear "cost management" they jump to optimization tricks, but the highest-leverage move is building a measurement layer that tells you exactly what you're spending right now. Without it, every other tactic is a guess.
Whenever I integrate a new Claude-powered feature, the first thing I write is the logging wrapper. The Anthropic SDK returns a usage field on every response — make sure you persist it.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function callClaudeWithLogging(params: {
userId: string;
feature: string;
model: string;
messages: Anthropic.MessageParam[];
}) {
const startTime = Date.now();
const response = await client.messages.create({
model: params.model,
max_tokens: 1024,
messages: params.messages,
});
const elapsedMs = Date.now() - startTime;
// The most important line: persist the usage object on every call.
await db.apiUsageLog.create({
data: {
userId: params.userId,
feature: params.feature,
model: params.model,
inputTokens: response.usage.input_tokens,
outputTokens: response.usage.output_tokens,
cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,
cacheCreationTokens: response.usage.cache_creation_input_tokens ?? 0,
elapsedMs,
timestamp: new Date(),
},
});
return response;
}The detail people miss is the feature column. Without it, when next month's invoice doubles, you have no way to know which integration drove the spike. I tag mine with categories like "image-caption-generator," "conversation-mode," "translation," and so on.
I run a nightly batch that aggregates this log by feature and by user. The summary is posted to a Slack channel at 9 AM every morning, so any anomaly gets surfaced within hours instead of weeks.
Per-User Rate Limits You Have to Build Yourself
The provider's rate limits are about requests per minute and tokens per minute — useful for stability, useless for cost control. If you want to cap "what one user can spend in a day," you have to enforce it in your own application.
A clean pattern is to keep a daily counter per user in Redis or Cloudflare KV.
async function checkAndIncrementUsage(userId: string, estimatedCostUsd: number) {
const today = new Date().toISOString().slice(0, 10);
const key = `usage:${userId}:${today}`;
const dailyCapUsd = await getUserDailyCap(userId); // 0.05 free / 1.0 paid, etc.
const currentUsage = parseFloat(await kv.get(key) ?? "0");
if (currentUsage + estimatedCostUsd > dailyCapUsd) {
throw new Error("DAILY_LIMIT_EXCEEDED");
}
await kv.put(key, String(currentUsage + estimatedCostUsd), {
expirationTtl: 86400 * 2, // auto-expire after two days
});
}Capping each free user at five cents a day means even an abusive user or runaway bot can only do so much damage in 24 hours. In my apps, free users get $0.03 per day and Pro members get $0.50. Almost no real user ever hits the cap, so the limit is invisible to good actors but invaluable when something goes wrong.
Prompt Caching: Quiet Savings That Add Up
Anthropic's prompt caching can cut input token costs by up to 90% when you reuse a system prompt or long context. It's not flashy, but solo devs in particular leave money on the table by ignoring it.
In one of my wallpaper apps, Claude generates a one-line caption for every uploaded image. The system prompt that defines the persona and tone is fairly long, so caching it means the input cost is essentially free for any user who uploads several images in a row. Measured savings: about 4,000 yen per month.
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 200,
system: [
{
type: "text",
text: longSystemPrompt, // mark this block with cache_control
cache_control: { type: "ephemeral" },
},
],
messages: [{ role: "user", content: userImageUrl }],
});Marked blocks live in the cache for five minutes; subsequent calls within that window pay roughly one-tenth of the input cost. Just remember the cached block must be at least 1,024 tokens (or 2,048 for Haiku) to qualify.
Rethinking Retry Strategy
Unconditional retries are a ticking time bomb in your cost model. When Anthropic is degraded and returning 429 or 503, retrying aggressively means the moment service recovers, every queued attempt fires at once and your spend balloons.
I follow three rules in every integration:
First, cap retries at two attempts. Almost no production failure I've seen is rescued by a third try.
Second, always use exponential backoff. For 429 Too Many Requests, wait at least five seconds — preferably thirty — before the next attempt.
Third, implement a circuit breaker. If 10 consecutive 5xx responses arrive within a minute, stop calling the API for the next five minutes and switch the UI to a "service is busy" state. This is the pattern that has saved me the most money.
class CircuitBreaker {
private failures: number[] = [];
private openUntil: number = 0;
shouldAllow(): boolean {
if (Date.now() < this.openUntil) return false;
return true;
}
recordFailure() {
const now = Date.now();
this.failures = this.failures.filter(t => now - t < 60_000);
this.failures.push(now);
if (this.failures.length >= 10) {
this.openUntil = now + 5 * 60_000; // open for five minutes
this.failures = [];
}
}
recordSuccess() {
this.failures = [];
}
}The breaker doesn't only protect you against provider outages. It also catches the moment your own buggy code starts hammering the API, which is honestly the more common failure mode.
What My Monthly Operations Loop Looks Like
Putting all of this together, here's the rhythm I actually run.
Every Monday morning, a script posts last week's API usage summary into Slack. Anything more than 30% above the prior week triggers an investigation. Almost always it's either a feature launch or a single user behaving abnormally.
On the 25th of each month, I forecast the month-end total. If we're projected to exceed 80% of the cap, I prep a soft-throttle for the last five days. I'll post a Discord update saying "this month's usage came in higher than expected, so we're temporarily reducing the limits on a few features through the end of the month." Users take this well, and I've seen it nudge a few of them to upgrade.
Quarterly, I compute ROI per feature — revenue contribution divided by API cost. Anything clearly losing money gets either retired or moved behind the paywall. In one app, a free translation feature was wildly popular but ROI-negative. Moving it to Pro caused minimal churn and modestly improved conversion.
Closing Thought
Cost management isn't about discipline; it's about instrumentation and ceilings. If you do only one thing today, add the usage logging wrapper. That single change converts "I noticed too late" into "I see it before it grows." Everything else follows once you can read the numbers.
If you want to take the next step, the companion piece Designing a Revenue-Producing Claude API App — From Token Visibility to Billing Models walks through how to extend the same logging foundation into a real billing system.