◉CLAUDE LABJP
●2.1.312 — Fixes Claude overwriting very large CLAUDE.md files and skills going missing after a Bash cd●API — The Messages API maximum request size grew from 32 MB to 128 MB (10/28)●SONNET 4.5 — Retires on the Claude API on 11/30, 28 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST — Opus 4.8 fast mode is deprecated and will be removed on 11/30. Migrate to Opus 5.5●NEW — I Put a Ten-Line Promise File at the To…●2.1.312 — Fixes Claude overwriting very large CLAUDE.md files and skills going missing after a Bash cd●API — The Messages API maximum request size grew from 32 MB to 128 MB (10/28)●SONNET 4.5 — Retires on the Claude API on 11/30, 28 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST — Opus 4.8 fast mode is deprecated and will be removed on 11/30. Migrate to Opus 5.5●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-11-02Intermediate

You Can't Put a Monthly Spend Limit on the Default Workspace — Splitting Workspaces to Cap a Solo Developer's API Bill

Monthly spend limits can't be set on the Default Workspace. Here is how I split workspaces by purpose, verify with a response header that requests land where I intend, and watch daily usage per workspace.

Claude API142Workspacespend limitcost controlindie development26

I once opened the Billing page to set a monthly cap, then ended up staring at the Workspaces list instead. The small backend behind my wallpaper app and my throwaway experiment scripts were all running on a single API key.

The thing I wanted to cap was the experiments. But the key I used most belonged to the Default Workspace, and that workspace doesn't accept a spend limit at all. I stopped there for a while.

Here is the point up front: limits belong to workspaces, not to keys. Below I'll walk through splitting workspaces by purpose to build a monthly ceiling, and a check that confirms traffic really lands where you think it does.

What the Default Workspace can and can't do

This is a summary of the official docs, limited to what matters for day-to-day operation.

ItemDefault WorkspaceWorkspaces you create
Rename, archive, deleteNot possiblePossible (archiving can't be undone)
Monthly spend limitCan't be setCan be set at or below the organization's limit
Per-workspace rate limits—Pick the workspace on the Rate limits page
Who can create one—Organization admins only

If everything stays on the Default Workspace, the only guardrail is the organization-wide limit. A runaway experiment can take your production app down with it.

Put the ceiling only around the things you can afford to stop. That single sentence is the whole reason to split.

A starting layout

For a solo developer, three workspaces have been enough for me. I name them so the purpose is obvious in the UI.

WorkspaceWhat runs thereHow I think about the limit
Prod - app backendUser-facing featuresHigh limit; alerts before hard stops
Batch - nightly jobsScheduled translation and cleanupA monthly amount I could tolerate losing to one bad run
Dev - experimentsLocal scripts and testingLow and fixed; stopping is fine

In the Console, open the Workspaces page, select the workspace, and use Spend limits in the panel that opens. You can set a monthly cap and alerts at chosen thresholds. A workspace limit can't exceed the organization's.

One thing to know before splitting: prompt caches are isolated per workspace. If you send the same long system prompt from three workspaces, they don't share a cache. I only split the pairs that weren't sharing a prefix anyway.

The quiet failure after you split

You can create a workspace and issue a key, yet an old key may still live in the Default Workspace. Anything sent with it piles up on the side with no cap — and the requests succeed, so nothing warns you.

So I check the anthropic-workspace-id response header once at startup. It carries the ID of the workspace the request's key resolved to.

# Verify at startup that this process lands in the intended workspace
import os
import sys
import anthropic
 
EXPECTED = os.environ["EXPECTED_WORKSPACE_ID"]  # an ID starting with wrkspc_
 
client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment
 
raw = client.messages.with_raw_response.create(
    model="claude-haiku-5-5",
    max_tokens=16,
    messages=[{"role": "user", "content": "ping"}],
)
actual = raw.headers.get("anthropic-workspace-id")
 
if actual != EXPECTED:
    print(f"Wrong workspace: expected={EXPECTED} actual={actual}")
    sys.exit(1)
 
print(f"OK: {actual}")

This guards against swapping a key and quietly billing the wrong place. Keep the expected ID in an environment variable and add this to your deploy checklist. If the header is missing, the call may have failed before authentication, or it may be a call such as the Admin API that doesn't resolve to a workspace.

You can find workspace IDs on the Console's Workspaces page, or by calling List Workspaces with an admin-capable key. Pass include_default=true if you want the Default Workspace included.

What it looks like when you hit the limit

When you reach a limit you set on a workspace, the API returns HTTP 400 with invalid_request_error. The message begins with "You have reached your specified workspace API usage limits" and states when access resumes.

Because it isn't a 429, retrying won't help. I wrote up the full triage in Hit the Limit but Got a 400? Telling Your Own Spend Limit, the Tier Cap, and Rate Limits Apart. For now, remember only this: workspace limits arrive as 400.

The Claude Code workspace is the exception. Its limits are checked separately and can come back as a 429 with a retry-after header, which is worth knowing if you run Claude Code in the same organization.

Watching daily usage per workspace

Once limits exist, make "how close am I" visible. The Usage and Cost Analytics API (beta) can group usage by workspace ID.

# Pull daily token usage per workspace
import os
import anthropic
 
# Needs an admin-capable key that isn't scoped to a workspace
client = anthropic.Anthropic(api_key=os.environ["ADMIN_API_KEY"])
 
rows = client.beta.organization.analytics.usage.list(
    starting_at="2026-11-01T00:00:00Z",
    ending_at="2026-11-08T00:00:00Z",
    time_bucket_width="1d",
    group_by=["workspace_id"],
)
 
for row in rows:
    print(f"{row.starting_at} {row.group.workspace_id}: {row.usage.total_tokens}")

Default Workspace usage is reported under its own ID. Right after a split, watch whether that number shrinks; a shrinking line means the migration is working, and a flat one means something is still pointed at the old key. These are token counts. For dollar amounts, check the cost-side report in the same family.

The steps, in order

  1. List your workloads and create workspaces, starting with the ones you can afford to stop (admin role required).
  2. Set Spend limits on each workspace.
  3. Issue workspace-bound keys and swap the environment variables.
  4. Verify anthropic-workspace-id at startup.
  5. A few days later, confirm in the Analytics API that Default Workspace usage is dropping.

Next step

Start by checking which workspace your busiest key belongs to. If it's the Default Workspace, carve out the most disposable workload first. For sizing the monthly amount itself, I've collected my approach in Designing a Claude API Monthly Budget That Doesn't Fall Apart.

My first split was the experiments. The uneasy feeling from that night — keeping something I couldn't afford to stop in a place I couldn't stop — hasn't come back so far.

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 →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⬡ API & SDK2026-10-22
You Hit Your Limit and Got a 400 — Telling Apart Your Own Spend Limit, the Tier Cap, and Rate Limits
Claude API limit errors come in three kinds, and they differ in status code and in whether waiting helps. A limit you set returns 400, the tier cap returns 429, and so do ordinary rate limits. Code and a decision table.
⬡ API & SDK2026-09-17
I Send Images Twenty at a Time — The Day the 21st Image Changed the Rules for the Other 61
Sending 62 images in one request failed with invalid_request_error. The cause was the image count, not the payload size. Here is how I recounted visual tokens as 28px patches and built batches that respect count, dimensions, and payload at once.
⬡ API & SDK2026-05-14
6 Traps I Hit Building In-App AI Chat with Claude API — A Record of Getting to Production
Six real design mistakes I encountered shipping Claude API in-app chat to production — covering context management, streaming error detection, guardrails, session persistence, model versioning, and cost monitoring. Includes working TypeScript code.