Skip to main content

Overview

This page is the authoritative reference for what every external paid API call in the codebase costs. It has three layers:
  1. The audit — every paid call site, its exact model id, and how it is invoked.
  2. The pricing — verified per-model rates, pulled from vendor pricing pages.
  3. The math — per-stage, per-pipeline, and corpus-scale cost projections.
Verified: August 14, 2026. Every model id below was read out of the code on that date; every price was read from the vendor’s own pricing page on that date. Where a number is an estimate rather than a measurement, it is labelled (est.).
The older Cost Tracking page covers the same ground as of July 3, 2026 and also documents fixed monthly subscriptions and Trigger.dev credit budgeting. Where the two disagree on a model or a price, this page is correct — see What changed.

Part 1 — The audit

Model registries

Four files decide which model runs. Change a model here and it changes everywhere.
packages/ai-prompts/src/models.ts carries a stale cost table of its own. Its costPerInputToken / costPerOutputToken fields are per 1K tokens and are not read by any live call path. Do not treat it as a pricing source — it is model metadata that happens to include numbers.

How calls reach a provider

Three distinct mechanisms are in use, and the distinction matters for cost:

Vercel AI Gateway

gateway("openai/gpt-5.6-luna") or getModelForFeature(). Zero markup — you pay provider list price. All Luna, and all Claude routed through the API app.

Direct provider SDK

anthropic.messages.create() and the GoogleGenAI client. Full list price, no gateway involved. Used by the strain pipeline’s Claude passes, all Gemini image generation, and Lyria.

Anthropic Batch API

anthropic.messages.batches.create(). 50% off input and output. Only reachable in the strain pipeline’s batch mode.
Reasoning effort is cost-critical. GPT-5.6 Luna bills reasoning tokens as output ($1.20/1M), and they are invisible in the response. Luna’s provider default is medium. Every call site below pins an explicit effort — the Effort column is the single biggest per-call cost lever in the codebase.

Strain research pipeline

All paths under packages/trigger/src/. Stage 05 runs direct by default: strain-research-pipeline.ts:62 sets useDirectMode to true, so the 50% Batch discount does not apply to a normal self-serve run.
The openai/ prefix on EXTRACTION_MODEL lives in a directory called lib/gemini/. Text extraction moved off Gemini Flash-Lite onto Luna on Aug 13 2026 but the directory was never renamed. lib/gemini/extraction.ts does not call Gemini — only image-generation.ts and clients.ts still do.

Other pipelines

Hono API features

No embeddings anywhere. A repo-wide sweep for embed(, .embeddings., and vector-model ids returns nothing in apps/api/src, packages/trigger/src, or apps/mobile/convex. Similarity and matching are done with SQL and string heuristics, not vectors — so there is $0 embedding spend to account for.
getReasoningOptions() returns { openai: { reasoningEffort } }. Non-OpenAI providers ignore the openai key, so it is harmless to spread into a Mistral or Claude call — the medium on the receipt parser has no effect and no cost.

Notebook section tiers

A full notebook is 23 sections: 2 computed (free) and 21 AI-billed, resolved through MODEL_TIERS in apps/api/src/config/ai.ts. Section definitions and their estimatedOutputTokens live in packages/ai-prompts/src/config/section-config.ts.

Things that look paid but are not

NOTEBOOK_ARTIFACT_MODEL_IDS in packages/report-contracts/src/artifact-plan.ts:88 still contains 'gpt-4o-mini-tts', and its own comment explains why: notebook narration is retired and no executor references the model. The value survives only because the enum is persisted to notebookArtifacts.executor.modelId and a Zod enum cannot be empty. There is no TTS call anywhere in the codebase — no audio/speech, no ElevenLabs, no .speech. call. This line costs $0.
MODELS in apps/api/src/config/ai.ts still lists gpt-5, gpt-5-mini, o3, and o4-mini. gpt-5 and gpt-5-mini are annotated in the file as delisted by OpenAI in June 2026. No FEATURE_MODELS entry points at any of them, so none can be reached.
Present in MODELS, referenced by no feature. Note also that magistral-medium-2506 no longer appears on Mistral’s pricing page at all — the medium tier is now Mistral Medium 3.5.
config/pipeline.config.ts declares maxUrls: 15, but tasks/stages/03-scrape.ts never reads it. Every filtered URL is scraped — which is why a ranked strain measures ~36 scrapes, not 15. Budget against the measured number, not the config.

Part 2 — Verified pricing

All rates in USD per 1M tokens unless stated otherwise. Read from vendor pricing pages on August 14, 2026.

Text and vision models

Claude Sonnet 5’s introductory pricing became permanent. Anthropic’s pricing page now states that the 2/2/10 launch rate “is now the standard price” and that the scheduled increase to 3/3/15 on September 1, 2026 will not occur.Our code has not caught up. packages/trigger/src/lib/anthropic/models.ts hardcodes SONNET_5_STANDARD_PRICING_START = Date.UTC(2026, 8, 1) (September 1 2026) and will begin reporting 1.50/1.50/7.50 batch instead of the correct 1.00/1.00/5.00 from that date. This is a cost-reporting bug only — Anthropic bills correctly regardless — but every batch-mode cost figure the pipeline logs after Sep 1 will be 50% too high.
Gemini Flash pricing doubles on January 1, 2027. The 0.75/0.75/3.75 rate is explicitly labelled “through December 31, 2026”, rising to 1.50/1.50 / 7.50 starting January 1, 2027. Context caching doubles on the same date. We route no production traffic to gemini-3.7-flash today, so the exposure is latent — but the label scanner’s documented fallback (FEATURE_MODELS.labelScanning reverting to gemini-3.7-flash) would land on the doubled rate if exercised after that date.
Claude 4.7-and-later models use a new tokenizer that produces ~30% more tokens for the same text. This affects claude-sonnet-5 (our copywriter and image-prompt passes) and claude-opus-4.8 (notebook creative sections). claude-sonnet-4.6 and claude-haiku-4.5 use the previous tokenizer. Sonnet 5’s headline rate is lower than Sonnet 4.6’s (2/2/10 vs 3/3/15) but ~30% more tokens claws back roughly a third of that saving. Every Sonnet 5 and Opus 4.8 figure on this page has the 30% uplift applied.

Image, audio, video

Search, scraping, compute

Checkpointed waits are free. Trigger.dev does not bill compute for any wait.for / wait.until longer than 5 seconds, which is why a 5-minute pipeline run bills for only ~5 minutes of active machine time.
One number we could not pin down: whether Exa bills contents on top of search. lib/exa.ts:363 calls exa.search() with a text: { maxCharacters: 5000 } contents option. Exa’s pricing page documents /contents at “1/1kpages,percontenttype"butdoesnotstatewhetherthatchargeappliestocontentsrequestedinlinewith/search.EveryExafigurebelowusestheconservativelowreading(search+extraresultsonly).Ifcontentsdobill,add1 / 1k pages, per content type" but **does not state whether that charge applies to contents requested inline with `/search`**. Every Exa figure below uses the **conservative-low** reading (search + extra-results only). If contents *do* bill, add **0.025/strain** unranked and $0.040/strain ranked — about +4% on a total run. Confirm against a live Exa invoice before relying on the lower figure.

Part 3 — Per-run cost math

Assumptions

  • Unranked strain: 25 results searched → 6–16 scraped → 6–16 extractions. 11 used as midpoint.
  • Ranked strain: 40 searched → ~36 scraped → ~34 extractions.
  • Extraction truncates article content at 50,000 chars ≈ 12,500 tokens per article (lib/gemini/extraction.ts:30).
  • Stage timings, typical unranked run (ms): search 3,200 · filter 1,300 · scrape 78,000 · extract 35,000 · process 150,000 · imaging 40,000 · save 1,100.
  • Ranked refresh with skipImaging+skipMusic (ms): search 4,630 · filter 2,055 · scrape 304,735 · extract 76,414 · process 86,625 · imaging 142 · save 1,897.
  • One paper summary measured at **1,345 in / 649 out = 0.00105whichreproducestothecentatLunas0.00105** — which reproduces to the cent at Luna's 0.20/$1.20, independently confirming the rate.
  • Machine presets read from code: orchestrator medium-1x; stages 03/04 medium-2x; stages 05/06 large-1x; stages 01/02/07 default small-1x.
  • Extraction: ~13,300 input tokens/article (12,500 content + ~800 prompt + schema); ~2,000 output tokens/article including low reasoning. (est.)
  • FactFinder: ~12,000 input/pass unranked, ~30,000 ranked; ~2,500 output/pass against a 4,096 cap. (est.)
  • Copywriter: ~15,000 input unranked / ~30,000 ranked; ~6,000 output against an 8,192 cap. (est.)
  • Image prompts: ~6,000 input; ~2,500 output against a 4,096 cap. (est.)
  • Notebook: ~4,000 input tokens per section (order context + strain data + prior sections). (est.)
  • A 30% token uplift is applied to all claude-sonnet-5 and claude-opus-4.8 figures for the new tokenizer.
  • Orchestrator billed at ~10s of active compute; the rest of its wall-clock is checkpointed and free. (est.)

(a) Typical unranked strain — direct mode

(b) Ranked strain — 40 results, direct mode

(c) Ranked refresh — skipImaging + skipMusic

Skipping imaging removes 0.204ofmodelspendand0.204 of model spend and 0.0136 of large-1x compute — a 26% cut on a ranked run. It is by far the cheapest optimization available, and the right default for any re-research pass where the existing hero and mascot images are still good.

Where the money goes

Luna is not the cost problem. Even on a ranked strain doing 34 extractions over ~450k input tokens, Luna accounts for 19% of the run. Two Gemini images cost more than every Luna token combined on an unranked strain. The optimization targets, in order, are: image resolution, the Sonnet 5 copywriter, and large-1x compute on stage 05.

Music pipeline

Auto-fires after research completes unless skipMusic is set.

Combined per strain


Extrapolations

All figures below are estimates, built on the token assumptions listed above. They are accurate to roughly ±20% on the model-spend lines and better than that on the fixed per-unit lines (images, songs, Exa, Firecrawl). The blended column assumes 30% of strains carry a popularity rank and therefore take the 40-result path — verify that ratio against strains_v2 before treating a blended total as a budget.

Cost to research N strains (research + music)

Cost to RE-research the full corpus

Re-research keeps existing images and audio, so skipImaging + skipMusic apply throughout.
A full corpus refresh at ~1,313costs401,313** costs 40% less than a fresh full research pass at ~2,174 — entirely because imaging and music are skipped. If a refresh does need new images, add 0.204×2,750=0.204 × 2,750 = **561.

Per-unit costs — other pipelines

Professor High is the only per-message cost on this page, and it is agentic. MAX_AGENT_STEPS = 8 (services/professor-high/agent.ts:56), and each step re-sends the full accumulated context to Sonnet 4.6. A single chat reply therefore ranges from 0.086to0.086 to 0.318 depending on how many tool calls it takes — and a chatty session multiplies that per message, not per session. It is the only feature here whose cost scales with user engagement rather than with content volume. Model spend on chat should be watched separately from pipeline spend.

Notebook breakdown

Seven Luna sections cost 2% of a notebook. Seven Opus sections cost 54%. Moving even two creative sections down to Sonnet 4.6 would cut a notebook by roughly 15% — the single highest-leverage model change on this page.

Could not be priced


What changed since the July page

The headline per-strain number moved less than the underlying changes suggest, because two large moves cancelled: extraction got much cheaper (Luna replaced Flash-Lite) while compute and Exa were both materially undercounted before.

How to update this page

Re-check this page whenever any of the following change. Pricing drift is silent — nothing in CI will catch it.
1

Re-read the model registries

These four files are the only places a model id is decided. If a model id changed, every number downstream is wrong.
2

Re-check every reasoningEffort call site

Reasoning tokens bill as output. A call site that loses its explicit effort silently falls back to Luna’s medium default and can multiply that call’s output cost.
Every hit should either be the definition in config/ai.ts or a call site with an explicit effort. A bare generateText against Luna with no providerOptions is a cost bug.
4

Watch these dated cliffs

  • Jan 1, 2027 — Gemini Flash input/output doubles (0.75/0.75/3.75 → 1.50/1.50/7.50). Context caching doubles too.
  • Sep 1, 2026 — no longer a real price change (Anthropic cancelled it), but getAnthropicBatchPricing() still thinks it is. Fix that function or every batch-mode cost log overstates by 50%.
  • Any OpenAI repricing of gpt-5.6-luna, which moved 80% within three weeks of launch and is the most volatile rate on this page.
5

Re-measure, don't re-estimate

The token counts in Part 3 are estimates. If a run’s real usage is available — Trigger.dev run metadata, an Anthropic usage block, or an AI Gateway spend report — prefer it and mark the row as measured. The paper-summarizer row is the model: a real 1,345/649 measurement that reproduced the vendor rate exactly.

Version history