DEV Community

Emery Lin
Emery Lin

Posted on

I Read a 10-Million-Token Free Tier Like a Bank Statement

Most landing pages treat a free token pool as if it were unlimited chat minutes. I treated it that way too — until the balance hit zero and I still could not explain which habits spent it.

This post is not a feature roundup. It is a ledger. I logged real calls, split every request into debit line items, and mapped a 10 million token allowance onto a week of ordinary developer work. The useful part is not the headline number. It is learning which column on the receipt actually moves.

Disclosure: This article was prepared as part of MonkeyCode's product outreach. I ran the logging job on MonkeyCode's free server option with their free model access so the counter could keep ticking overnight.

The Wrong Unit of Measure

Developers budget in calls. Quotas are billed in tokens. Those two units only look related.

A classification that returns a three-word label can cost a few hundred tokens. A "quick look" at a CI dump can cost several thousand before the model writes a single sentence. Counting requests is like counting restaurant visits while ignoring whether you ordered espresso or a tasting menu.

I wanted a statement I could reconcile: for this kind of work, how many times can the account clear before it overdrafts?

Opening a Token Ledger

The logger is intentionally boring. One POST, one parse of the provider's usage object, one append-only table. No dashboard. No charts. Just deposits (the quota) and withdrawals (each call).

I stored medians of three runs per workload. Tokenizers jitter; medians ignore the dramatic outlier that would otherwise ruin a budget.

import csv, json, os, time, urllib.request
from pathlib import Path

LEDGER = Path("token_ledger.csv")

def debit(label: str, system: str, user: str) -> dict:
    body = json.dumps({
        "model": os.environ["MODEL_NAME"],
        "messages": [
            {"role": "system", "content": system},
            {"role": "user", "content": user},
        ],
    }).encode()
    req = urllib.request.Request(
        os.environ["MODEL_URL"],
        data=body,
        headers={
            "Authorization": f"Bearer {os.environ['MODEL_KEY']}",
            "Content-Type": "application/json",
        },
    )
    t0 = time.perf_counter()
    with urllib.request.urlopen(req, timeout=120) as resp:
        payload = json.load(resp)
    ms = int((time.perf_counter() - t0) * 1000)
    u = payload["usage"]
    new_file = not LEDGER.exists()
    with LEDGER.open("a", newline="") as fh:
        w = csv.writer(fh)
        if new_file:
            w.writerow(["label", "prompt_tokens", "completion_tokens", "latency_ms"])
        w.writerow([label, u["prompt_tokens"], u["completion_tokens"], ms])
    return u
Enter fullscreen mode Exit fullscreen mode

Swap the host, keep the habit. The ledger does not care whose API is on the other end.

Five Line Items From a Normal Week

These are not synthetic micro-benchmarks. They are the chores that actually show up on a Tuesday. Numbers are order-of-magnitude, not a contract — model, prompt padding, and how dense the source text is will move them.

1. Distill a meeting transcript

Deposit consumed: ~2,900 tokens.

A 2,000-word transcript lands around 2,700 prompt tokens. A six-bullet recap comes back near 150 completion tokens. Against 10 million: roughly 3,400 recaps.

That sounds generous until you paste the whole hour instead of the decisions.

2. Explain a red CI log

Deposit consumed: ~4,600 tokens.

A 5-file failure dump, ~300 lines, sits near 4,100 prompt tokens. A structured "what broke / why / where to look" reply is ~500 completion tokens. Against 10 million: roughly 2,100 explanations.

This is the expensive grocery run. Diffs and stack traces are dense.

3. Localize a single docs page

Deposit consumed: ~1,300 tokens.

One page of English (~700 prompt tokens) and a same-length target language page (~600 completion tokens). Against 10 million: roughly 7,600 pages.

Nearly even split between in and out — unusual, and useful to notice.

4. Stamp a support ticket

Deposit consumed: ~450 tokens.

A 300-word ticket (~420 prompt tokens) plus a JSON tag such as {"priority":"p2"} (~25 completion tokens). Against 10 million: roughly 22,000 stamps.

This is the espresso. Cheap per sip, lethal if you put it on a hot loop.

5. Scaffold tests from a signature

Deposit consumed: ~190 tokens.

A one-line ask (~25 prompt tokens) and a 20-line test file (~160 completion tokens). Against 10 million: roughly 52,000 scaffolds.

Here the output is the meal. Most other chores are the opposite.

The Receipt Always Has a Fat Left Column

Across the first four chores, prompt tokens ate about nine tenths of the bill. Completion was the tip, not the entrée.

That single observation changes how you thrift:

  • Cutting the reply style from "essay" to "bullets" saves pennies.
  • Cutting the pasted context — the unused files, the repeated system sermon, the full monorepo — saves dollars.

If you only remember one audit finding: the context window is the tax. Generation is the souvenir shop.

Three Ways the Account Empties Faster Than You Expect

Mix, don't average. A day of ticket stamps barely registers. Slip in a handful of CI dumps and the daily burn looks like a different product. The quota does not care about call count; it cares about the share of heavy line items.

Standing orders add up. A 400-token system preamble is a silent monthly fee. It is charged on every withdrawal. Trim it once, and every future debit shrinks.

Throughput is a different sport. 22,000 ticket stamps per month is comfortable for a human at a keyboard. It is 38 minutes of work at 10 requests per second. Free pools are for judgment, not for firehoses.

A One-Line Reconciliation

clears = quota / (prompt_per_job + completion_per_job)
Enter fullscreen mode Exit fullscreen mode

Plug in the CI-log row: 10_000_000 / (4100 + 500) ≈ 2,100.

Ten of those a day and the pool lasts months. A hundred a day and you are shopping for a paid tier in three weeks. Same quota. Same chore. Frequency is the multiplier people forget to write down.

Why Your Statement Will Not Match Mine

  • Tokenizers are not interchangeable. A thousand tokens here may be fifteen hundred on another model.
  • Code packs tighter than prose. A "page" of source is a heavier debit than a page of narrative.
  • Free-tier terms move. Re-read them before you treat any of these counts as a plan.
  • I measured median of three. Your long-tail prompt will not look like my median.

Treat the table as a ruler, not as a promise.

Who This Kind of Account Is For

A 10 million token pool is a checking account for a solo developer doing high-value, low-frequency work: a few log autopsies, a couple of recaps, the occasional localized page.

It is a bad fit if:

  • empty balance means a production incident,
  • you stream the whole repository into every prompt,
  • or the workload is a queue, not a person.

In those cases the problem is not the size of the gift. It is that you needed a credit line and picked a prepaid card.

Closing the Books

I stopped asking "how many million tokens is that?" and started asking "which column on the receipt did I just sign?" Once the left column (context) is visible, the remaining balance becomes a planning number instead of a surprise.

Build the logger. Run three of your chores. Divide. The marketing page will still say 10 million. Your CSV will say how many Tuesdays that actually is.

MonkeyCode's free model access plus the free server option is a convenient place to let that job sit — the server keeps writing rows while the laptop lid is closed. The same reconciliation works against any OpenAI-shaped endpoint. The ledger is the point, not the logo.

Top comments (0)