> ## Documentation Index
> Fetch the complete documentation index at: https://docs.highailabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AI & API Cost Reference

> Authoritative audit of every paid model and API call in the platform, with verified vendor pricing, per-stage cost math, per-pipeline unit costs, and corpus-scale extrapolations.

## 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.

<Info>
  **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.)**.
</Info>

<Note>
  The older [Cost Tracking](/planning/infrastructure/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](#what-changed-since-the-july-page).
</Note>

***

## Part 1 — The audit

### Model registries

Four files decide which model runs. Change a model here and it changes everywhere.

| File                                           | Controls                                                                                                                  |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `apps/api/src/config/ai.ts`                    | `MODELS`, `FEATURE_MODELS`, `MODEL_TIERS`, `GEMINI_IMAGE_MODELS`, `getReasoningOptions()` — everything the Hono API calls |
| `packages/trigger/src/lib/anthropic/models.ts` | `CLAUDE_PIPELINE_MODELS`, max-token budgets, and the hardcoded Anthropic **Batch** price table                            |
| `packages/trigger/src/lib/gemini/clients.ts`   | `EXTRACTION_MODEL`, `IMAGE_MODEL`, `IMAGE_MODEL_FAST`, `IMAGE_MODEL_PRO`, `VIDEO_MODEL_OMNI_FLASH`                        |
| `packages/ai-prompts/src/models.ts`            | Legacy metadata + its own cost table (advisory only; nothing routes through it)                                           |

<Warning>
  **`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.
</Warning>

### How calls reach a provider

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

<CardGroup cols={3}>
  <Card title="Vercel AI Gateway" icon="bolt">
    `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.
  </Card>

  <Card title="Direct provider SDK" icon="plug">
    `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.
  </Card>

  <Card title="Anthropic Batch API" icon="layer-group">
    `anthropic.messages.batches.create()`. **50% off input and output.** Only reachable in the strain pipeline's batch mode.
  </Card>
</CardGroup>

### Paid call sites

<Note>
  **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.
</Note>

#### Strain research pipeline

| File:line                         | Stage            | Service   | Model                                             | Mechanism           | Effort |
| --------------------------------- | ---------------- | --------- | ------------------------------------------------- | ------------------- | ------ |
| `lib/exa.ts:363`                  | 01 Search        | Exa       | `search`, `type: "auto"`, `livecrawl: "fallback"` | Direct SDK          | —      |
| `lib/firecrawl.ts`                | 03 Scrape        | Firecrawl | `asyncBatchScrapeUrls`                            | Direct SDK          | —      |
| `lib/gemini/extraction.ts:380`    | 04 Extract       | OpenAI    | `gpt-5.6-luna`                                    | **Gateway**         | `low`  |
| `lib/anthropic/processing.ts:210` | 05 FactFinder ×3 | Anthropic | `claude-haiku-4-5-20251001`                       | Direct SDK          | —      |
| `lib/anthropic/processing.ts:271` | 05 Copywriter    | Anthropic | `claude-sonnet-5`                                 | Direct SDK          | —      |
| `lib/anthropic/processing.ts:341` | 05 Image Prompts | Anthropic | `claude-sonnet-5`                                 | Direct SDK          | —      |
| `lib/anthropic-batch.ts:537-608`  | 05 (batch mode)  | Anthropic | same three models                                 | **Batch API, −50%** | —      |
| `lib/gemini/image-generation.ts`  | 06 Imaging       | Google    | `gemini-3.1-flash-image` @ 2K                     | Direct SDK          | —      |

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.

<Warning>
  **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.
</Warning>

#### Other pipelines

| File:line                                              | Pipeline           | Service   | Model                                    | Mechanism  | Effort                  |
| ------------------------------------------------------ | ------------------ | --------- | ---------------------------------------- | ---------- | ----------------------- |
| `lib/paper-summarizer.ts:361`                          | Paper summarize    | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `low`                   |
| `lib/paper-summarizer.ts:525`                          | Paper (2nd pass)   | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `none`                  |
| `lib/paper-quality.ts:654`                             | Paper quality gate | Anthropic | `claude-haiku-4-5-20251001`              | Direct SDK | —                       |
| `lib/paper-image-generator.ts:208`                     | Paper thumbnail    | Google    | `gemini-3.1-flash-image` @ 2K, 16:9      | Direct SDK | —                       |
| `tasks/strain-music/config/ai-prompt-builder.ts:197`   | Music prompt       | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `low`                   |
| `tasks/strain-music/03-generate.ts:134`                | Music generate     | Google    | `lyria-3-pro-preview`                    | Direct SDK | —                       |
| `tasks/strain-video/02-scene-director.ts:238`          | Video scenes       | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `low`                   |
| `tasks/strain-video/providers/gemini-omni-flash.ts:53` | Video clips        | Google    | `gemini-omni-flash-preview`              | Direct SDK | —                       |
| `tasks/social-content/02-generate-text.ts:159`         | Social text        | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `low`                   |
| `tasks/social-content/03-generate-images.ts`           | Social images      | Google    | `gemini-3.1-flash-image`                 | Direct SDK | —                       |
| `tasks/gmail/gmail-classify-task.ts:381`               | Gmail classify     | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `none`                  |
| `tasks/notebook-media/mindmap-first-party.ts:278`      | Notebook mindmap   | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `none` → `low` on retry |
| `tasks/feature-notebook-pipeline.ts:406`               | Feature notebook   | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `medium`                |
| `tasks/twitter/twitter-generate-tweet.ts:34`           | Tweet              | Anthropic | `claude-haiku-4-5-20251001`              | Direct SDK | —                       |
| `lib/side-effects-generator.ts:114`                    | Side effects       | OpenAI    | `gpt-5.6-luna`                           | Gateway    | `low`                   |
| `lib/shopping-recommendations.ts:132`                  | Shopping recs      | Anthropic | `claude-sonnet-4-6`                      | Direct SDK | —                       |
| `lib/firecrawl-agent.ts:620`                           | Menu scan          | Anthropic | `claude-sonnet-4-6`, `max_tokens: 16384` | Direct SDK | —                       |

#### Hono API features

| File:line                                                                                | Feature               | Model                                        | Mechanism                    | Effort                        |
| ---------------------------------------------------------------------------------------- | --------------------- | -------------------------------------------- | ---------------------------- | ----------------------------- |
| `services/ai-sdk/label-scanner.ts:343`                                                   | Label scan pass 1     | `gpt-5.6-luna` (vision)                      | Gateway                      | `medium`                      |
| `services/ai-sdk/label-scanner.ts:418`                                                   | Label scan pass 2     | `gpt-5.6-luna` (vision)                      | Gateway                      | `medium`                      |
| `services/ai-sdk/receipt-parser.ts:536`                                                  | Receipt parse         | `mistral-small-latest`                       | Gateway                      | `medium` (ignored by Mistral) |
| `services/ai-sdk/strain-matcher.ts:70`                                                   | Strain match          | `gpt-5.6-luna`                               | Gateway                      | `none`                        |
| `services/ai-sdk/section-streaming.ts:98`                                                | Notebook sections     | tier-resolved (below)                        | Gateway                      | —                             |
| `services/professor-high/agent.ts:105`                                                   | Professor High agent  | `claude-sonnet-4.6`                          | Gateway                      | —                             |
| `routes/chat/index.ts:544`                                                               | Chat (Professor High) | `claude-sonnet-4.6`                          | Gateway                      | —                             |
| `services/ai-sdk/deep-research.ts:479,702`                                               | Deep research         | `claude-sonnet-4.6`                          | Gateway                      | —                             |
| `services/ai-sdk/menu-notebook.ts:44`                                                    | Menu notebook         | `claude-sonnet-4.6`, `maxOutputTokens: 4000` | Gateway                      | —                             |
| `services/blog/`, `services/hero-images/`, `services/discover/`, `services/app-landing/` | Image generation      | `gemini-3.1-flash-image`                     | **Direct REST**, not gateway | —                             |

<Note>
  **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.
</Note>

<Note>
  `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.
</Note>

#### 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`.

| Tier       | Model               | Sections | Est. output tokens |
| ---------- | ------------------- | -------- | ------------------ |
| `creative` | `claude-opus-4.8`   | 7        | 4,300              |
| `analysis` | `claude-sonnet-4.6` | 7        | 11,500             |
| `simple`   | `gpt-5.6-luna`      | 7        | 5,900              |
| `computed` | none                | 2        | 0                  |

### Things that look paid but are not

<AccordionGroup>
  <Accordion title="gpt-4o-mini-tts — retired, not a live call site">
    `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.
  </Accordion>

  <Accordion title="Delisted OpenAI models still in the registry">
    `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.
  </Accordion>

  <Accordion title="Mistral Large / Magistral Medium">
    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.
  </Accordion>

  <Accordion title="SCRAPE_CONFIG.maxUrls is dead config">
    `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.
  </Accordion>
</AccordionGroup>

***

## 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

| Model                   | Input      | Cached in | Output      | Batch in/out   | Notes                             |
| ----------------------- | ---------- | --------- | ----------- | -------------- | --------------------------------- |
| `gpt-5.6-luna`          | **\$0.20** | \$0.02    | **\$1.20**  | —              | Cut 80% from $1/$6 on Jul 30 2026 |
| `gpt-5.6-terra`         | \$2.00     | \$0.20    | \$12.00     | —              | Cut 20% same day; unused          |
| `gpt-5.6-sol`           | \$5.00     | \$0.50    | \$30.00     | —              | Unchanged; unused                 |
| `gpt-5`                 | \$1.25     | \$0.125   | \$10.00     | —              | Delisted Jun 2026                 |
| `gpt-5-mini`            | \$0.25     | \$0.025   | \$2.00      | —              | Delisted Jun 2026                 |
| `gpt-5-nano`            | \$0.05     | \$0.005   | \$0.40      | —              | Unused                            |
| `o3`                    | \$2.00     | \$0.50    | \$8.00      | —              | Unused                            |
| `o4-mini`               | \$1.10     | \$0.275   | \$4.40      | —              | Unused                            |
| `claude-opus-4.8`       | \$5.00     | \$0.50    | \$25.00     | $2.50 / $12.50 |                                   |
| `claude-sonnet-5`       | **\$2.00** | \$0.20    | **\$10.00** | $1.00 / $5.00  | See warning below                 |
| `claude-sonnet-4.6`     | \$3.00     | \$0.30    | \$15.00     | $1.50 / $7.50  |                                   |
| `claude-haiku-4.5`      | \$1.00     | \$0.10    | \$5.00      | $0.50 / $2.50  |                                   |
| `gemini-3.7-flash`      | \$0.75     | —         | \$3.75      | —              | **Rises Jan 1 2027**              |
| `gemini-3.5-flash-lite` | \$0.30     | —         | \$2.50      | —              |                                   |
| `mistral-small-latest`  | \$0.15     | —         | \$0.60      | —              | Mistral Small 4                   |

<Warning>
  **Claude Sonnet 5's introductory pricing became permanent.** Anthropic's pricing page now states that the $2/$10 launch rate "is now the standard price" and that **the scheduled increase to $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/$7.50 batch instead of the correct $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**.
</Warning>

<Warning>
  **Gemini Flash pricing doubles on January 1, 2027.** The $0.75/$3.75 rate is explicitly labelled "through December 31, 2026", rising to **$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.
</Warning>

<Warning>
  **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/$10 vs $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.
</Warning>

### Image, audio, video

| Service | Model                         | Unit                            | Price                                          |
| ------- | ----------------------------- | ------------------------------- | ---------------------------------------------- |
| Google  | `gemini-3.1-flash-image`      | per image, 1K                   | \$0.067                                        |
| Google  | `gemini-3.1-flash-image`      | **per image, 2K (what we use)** | **\$0.101**                                    |
| Google  | `gemini-3.1-flash-image`      | per image, 4K                   | \$0.151                                        |
| Google  | `gemini-3.1-flash-image`      | text/image input                | \$0.50 / 1M                                    |
| Google  | `gemini-3.1-flash-lite-image` | per image, 1K only              | \$0.0336                                       |
| Google  | `gemini-3-pro-image`          | per image, 1K–2K                | \$0.134                                        |
| Google  | `lyria-3-pro-preview`         | **per full song**               | **\$0.08**                                     |
| Google  | Lyria 3 Clip                  | per 30s clip                    | \$0.04                                         |
| Google  | Veo 3.1                       | per second                      | $0.05 – $0.60                                  |
| OpenAI  | `gpt-4o-mini-tts`             | text in / audio out             | $0.60 / $12.00 per 1M — **retired, \$0 spend** |

### Search, scraping, compute

| Service           | Unit                                                | Price                                                |
| ----------------- | --------------------------------------------------- | ---------------------------------------------------- |
| Exa               | search request (covers first 10 results)            | \$7 / 1k                                             |
| Exa               | each result beyond 10                               | \$1 / 1k results                                     |
| Exa               | `/contents` per page, **per content type**          | \$1 / 1k pages                                       |
| Firecrawl         | scrape / crawl                                      | 1 credit per page                                    |
| Firecrawl         | browser `interact`                                  | 2 credits per browser-minute                         |
| Firecrawl         | Standard plan                                       | $83/mo yearly → 100k credits → **$0.00083/credit\*\* |
| Vercel AI Gateway | markup                                              | **\$0.00 — no markup, no platform fee**              |
| Trigger.dev       | run invocation                                      | \$0.000025                                           |
| Trigger.dev       | `small-1x` / `medium-1x` / `medium-2x` / `large-1x` | $0.0000338 / $0.000085 / $0.00017 / $0.00034 per sec |

<Note>
  **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.
</Note>

<Warning>
  **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 / 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.
</Warning>

***

## Part 3 — Per-run cost math

### Assumptions

<AccordionGroup>
  <Accordion title="Measured from production (not estimates)">
    * 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.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`.
  </Accordion>

  <Accordion title="Estimated (token counts we do not measure)">
    * 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.)**
  </Accordion>
</AccordionGroup>

### (a) Typical unranked strain — direct mode

| Stage             | Service / model              | Units                       | Cost        |
| ----------------- | ---------------------------- | --------------------------- | ----------- |
| 01 Search         | Exa, 25 results              | 1 search + 15 extra results | \$0.0220    |
| 02 Filter         | local                        | —                           | \$0.0000    |
| 03 Scrape         | Firecrawl                    | 11 credits                  | \$0.0091    |
| 04 Extract        | `gpt-5.6-luna`, effort `low` | 146k in + 22k out           | \$0.0557    |
| 05a FactFinder ×3 | `claude-haiku-4.5`           | 36k in + 7.5k out           | \$0.0735    |
| 05b Copywriter    | `claude-sonnet-5`            | 19.5k in + 7.8k out         | \$0.1170    |
| 05c Image Prompts | `claude-sonnet-5`            | 7.8k in + 3.3k out          | \$0.0481    |
| 06 Imaging        | `gemini-3.1-flash-image`     | 2 × 2K images               | \$0.2040    |
| 07 Save           | Supabase RPC                 | —                           | \$0.0000    |
| Compute           | Trigger.dev, 8 runs / \~309s | —                           | \$0.0850    |
| **Total**         |                              |                             | **\$0.614** |

### (b) Ranked strain — 40 results, direct mode

| Stage             | Service / model              | Units                       | Cost        |
| ----------------- | ---------------------------- | --------------------------- | ----------- |
| 01 Search         | Exa, 40 results              | 1 search + 30 extra results | \$0.0370    |
| 02 Filter         | local                        | —                           | \$0.0000    |
| 03 Scrape         | Firecrawl                    | 36 credits                  | \$0.0299    |
| 04 Extract        | `gpt-5.6-luna`, effort `low` | 452k in + 68k out           | \$0.1720    |
| 05a FactFinder ×3 | `claude-haiku-4.5`           | 90k in + 7.5k out           | \$0.1275    |
| 05b Copywriter    | `claude-sonnet-5`            | 39k in + 7.8k out           | \$0.1560    |
| 05c Image Prompts | `claude-sonnet-5`            | 7.8k in + 3.3k out          | \$0.0481    |
| 06 Imaging        | `gemini-3.1-flash-image`     | 2 × 2K images               | \$0.2040    |
| Compute           | Trigger.dev, 8 runs / \~540s | —                           | \$0.1307    |
| **Total**         |                              |                             | **\$0.905** |

### (c) Ranked refresh — `skipImaging` + `skipMusic`

| Stage                          | Cost                   |
| ------------------------------ | ---------------------- |
| 01 Search (Exa, 40)            | \$0.0370               |
| 03 Scrape (36 credits)         | \$0.0299               |
| 04 Extract (Luna)              | \$0.1720               |
| 05a FactFinder ×3 (Haiku 4.5)  | \$0.1275               |
| 05b Copywriter (Sonnet 5)      | \$0.1560               |
| 05c Image Prompts (Sonnet 5)   | \$0.0481               |
| 06 Imaging                     | **skipped — \$0.0000** |
| Compute (measured 476s active) | \$0.0956               |
| **Total**                      | **\$0.666**            |

<Note>
  Skipping imaging removes $0.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.
</Note>

### Where the money goes

| Provider               | Unranked | Share | Ranked  | Share |
| ---------------------- | -------- | ----- | ------- | ----- |
| Anthropic (Claude)     | \$0.239  | 39%   | \$0.332 | 37%   |
| Google (Gemini images) | \$0.204  | 33%   | \$0.204 | 23%   |
| Trigger.dev compute    | \$0.085  | 14%   | \$0.131 | 14%   |
| OpenAI (Luna)          | \$0.056  | 9%    | \$0.172 | 19%   |
| Exa                    | \$0.022  | 4%    | \$0.037 | 4%    |
| Firecrawl              | \$0.009  | 1%    | \$0.030 | 3%    |

<Tip>
  **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**.
</Tip>

### Music pipeline

Auto-fires after research completes unless `skipMusic` is set.

| Component                                     | Cost        |
| --------------------------------------------- | ----------- |
| Prompt builder (`gpt-5.6-luna`, effort `low`) | \$0.0028    |
| `lyria-3-pro-preview`, full song              | \$0.0800    |
| Trigger.dev compute (\~5 runs, \~80s)         | \$0.0060    |
| **Total**                                     | **\$0.089** |

### Combined per strain

| Profile                                      | Research | + Music | Combined    |
| -------------------------------------------- | -------- | ------- | ----------- |
| Unranked, direct                             | \$0.614  | \$0.089 | **\$0.703** |
| Ranked, direct                               | \$0.905  | \$0.089 | **\$0.994** |
| Ranked refresh (`skipImaging`+`skipMusic`)   | \$0.666  | —       | **\$0.666** |
| Unranked refresh (`skipImaging`+`skipMusic`) | \$0.397  | —       | **\$0.397** |

***

## Extrapolations

<Warning>
  **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.
</Warning>

### Cost to research N strains (research + music)

| Strains                 | All unranked   | All ranked     | Blended (30% ranked) |
| ----------------------- | -------------- | -------------- | -------------------- |
| 100                     | \$70.32        | \$99.40        | **\$79.04**          |
| 500                     | \$351.59       | \$497.01       | \$395.22             |
| 1,000                   | \$703.19       | \$994.02       | \$790.44             |
| **2,750 (full corpus)** | **\$1,933.77** | **\$2,733.55** | **\$2,173.71**       |

### Cost to RE-research the full corpus

Re-research keeps existing images and audio, so `skipImaging` + `skipMusic` apply throughout.

| Scope                    | Per strain  | 2,750 strains  |
| ------------------------ | ----------- | -------------- |
| All unranked-shaped      | \$0.397     | \$1,091.20     |
| All ranked-shaped        | \$0.666     | \$1,831.75     |
| **Blended (30% ranked)** | **\$0.478** | **\$1,313.37** |

<Tip>
  A full corpus refresh at **\~$1,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 = **$561**.
</Tip>

***

## Per-unit costs — other pipelines

| Unit                                        | Composition                                  | Cost        |
| ------------------------------------------- | -------------------------------------------- | ----------- |
| **Notebook** (full, 21 AI sections)         | Opus 4.8 ×7 + Sonnet 4.6 ×7 + Luna ×7        | **\$0.591** |
| **Professor High reply**, 8-step worst case | Sonnet 4.6, agentic tool loop                | \$0.318     |
| **Professor High reply**, typical 3 steps   | Sonnet 4.6, agentic tool loop                | \$0.086     |
| **Deep research run**                       | Sonnet 4.6, up to 5 tool calls               | \$0.255     |
| **Strain song**                             | Luna prompt + Lyria 3 Pro + compute          | \$0.089     |
| **Menu notebook**                           | Sonnet 4.6, 4k output cap                    | \$0.090     |
| **Menu scan**                               | Sonnet 4.6 (16k cap) + Firecrawl credits     | \$0.182     |
| **Research paper**                          | Luna summary + Haiku gate + 1 × 2K thumbnail | \$0.109     |
| **Shopping recommendations**                | Sonnet 4.6                                   | \$0.105     |
| **Social post**, 1 image                    | Luna text + 1 × 2K image                     | \$0.104     |
| **Social carousel**, 4 images               | Luna text + 4 × 2K images                    | \$0.407     |
| **Blog article image**                      | 1 × 2K Gemini image                          | \$0.101     |
| **Label scan**                              | Luna vision ×2 passes, effort `medium`       | \$0.0077    |
| **Tweet**                                   | Haiku 4.5                                    | \$0.0045    |
| **Side-effects backfill**                   | Luna, effort `low`                           | \$0.0022    |
| **Receipt parse**                           | Mistral Small 4                              | \$0.0012    |
| **Gmail classify**, 100-email batch         | Luna, effort `none`                          | \$0.0066    |
| **Gmail classify**, per email               | Luna, effort `none`                          | \$0.00007   |
| **Strain match**                            | Luna, effort `none`                          | \$0.0007    |

<Warning>
  **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.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.
</Warning>

### Notebook breakdown

| Tier       | Model               | Sections | Cost    | Share  |
| ---------- | ------------------- | -------- | ------- | ------ |
| `creative` | `claude-opus-4.8`   | 7        | \$0.322 | 54%    |
| `analysis` | `claude-sonnet-4.6` | 7        | \$0.257 | 43%    |
| `simple`   | `gpt-5.6-luna`      | 7        | \$0.013 | **2%** |
| `computed` | —                   | 2        | \$0.000 | 0%     |

<Tip>
  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.
</Tip>

### Could not be priced

| Item                                                    | Why                                                                                                                                                                                                                 |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Strain video pipeline** (`gemini-omni-flash-preview`) | Google publishes no per-second or per-video rate for `gemini-omni-flash-preview`. Veo 3.1 spans $0.05–$0.60/sec, a 12× range, so no defensible estimate is possible. **Measure a real run before budgeting video.** |
| **Exa inline contents**                                 | See the warning in Part 2 — vendor docs do not state whether search-inline `text` bills the `/contents` rate. Range given instead.                                                                                  |
| **Firecrawl `interact` per menu scan**                  | `lib/firecrawl-agent.ts:769` comments "7 credits/min"; Firecrawl's current page says **2 credits/browser-minute**. The code comment is stale, and session duration is not instrumented.                             |

***

## What changed since the July page

| Item                       | July 3, 2026 page       | Now (Aug 14, 2026)                                                                        |
| -------------------------- | ----------------------- | ----------------------------------------------------------------------------------------- |
| Extraction model           | `gemini-3.1-flash-lite` | **`gpt-5.6-luna`** via Gateway, effort `low`                                              |
| Copywriter / image prompts | `claude-sonnet-4-6`     | **`claude-sonnet-5`** (+30% tokenizer)                                                    |
| Stage 05 machine           | `medium-2x`             | **`large-1x`**                                                                            |
| Orchestrator machine       | `small-1x`              | **`medium-1x`**                                                                           |
| Exa cost/strain            | \$0.007                 | **$0.022 unranked / $0.037 ranked** — the old figure ignored per-result billing beyond 10 |
| Compute/strain             | \$0.021                 | **$0.085 unranked / $0.131 ranked** — stage 05 is `large-1x` and runs \~150s              |
| Ranked strains             | not modelled            | 40-result path, \~34 extractions                                                          |
| Per strain (research)      | \$0.571                 | **$0.614 unranked / $0.905 ranked**                                                       |
| Per strain (+ music)       | \$0.658                 | **$0.703 unranked / $0.994 ranked**                                                       |

<Note>
  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.
</Note>

***

## How to update this page

<Warning>
  **Re-check this page whenever any of the following change.** Pricing drift is silent — nothing in CI will catch it.
</Warning>

<Steps>
  <Step title="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.

    | File                                               | What to look for                                                                                                |
    | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
    | `apps/api/src/config/ai.ts`                        | `MODELS`, `FEATURE_MODELS`, `MODEL_TIERS`, `GEMINI_IMAGE_MODELS`                                                |
    | `packages/trigger/src/lib/anthropic/models.ts`     | `CLAUDE_PIPELINE_MODELS`, `CLAUDE_PIPELINE_MAX_TOKENS`, `ANTHROPIC_BATCH_PRICING`, `getAnthropicBatchPricing()` |
    | `packages/trigger/src/lib/gemini/clients.ts`       | `EXTRACTION_MODEL`, `IMAGE_MODEL*`, `VIDEO_MODEL_OMNI_FLASH`                                                    |
    | `packages/ai-prompts/src/config/section-config.ts` | Section count and `modelTier` / `estimatedOutputTokens` per section                                             |
  </Step>

  <Step title="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.

    ```bash theme={null}
    grep -rn "getReasoningOptions\|reasoningEffort" \
      apps/api/src packages/trigger/src apps/mobile/convex \
      | grep -v "\.test\."
    ```

    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.
  </Step>

  <Step title="Re-pull vendor pricing">
    | Vendor                | Page                                                                                                         |
    | --------------------- | ------------------------------------------------------------------------------------------------------------ |
    | OpenAI                | [developers.openai.com/api/docs/pricing](https://developers.openai.com/api/docs/pricing)                     |
    | Anthropic             | [platform.claude.com/docs/en/about-claude/pricing](https://platform.claude.com/docs/en/about-claude/pricing) |
    | Google Gemini + Lyria | [ai.google.dev/gemini-api/docs/pricing](https://ai.google.dev/gemini-api/docs/pricing)                       |
    | Mistral               | [mistral.ai/pricing/api](https://mistral.ai/pricing/api)                                                     |
    | Exa                   | [exa.ai/docs/reference/pricing](https://exa.ai/docs/reference/pricing)                                       |
    | Firecrawl             | [firecrawl.dev/pricing](https://www.firecrawl.dev/pricing)                                                   |
    | Trigger.dev           | [trigger.dev/pricing](https://trigger.dev/pricing)                                                           |
    | Vercel AI Gateway     | [vercel.com/docs/ai-gateway/pricing](https://vercel.com/docs/ai-gateway/pricing)                             |
  </Step>

  <Step title="Watch these dated cliffs">
    * **Jan 1, 2027** — Gemini Flash input/output doubles ($0.75/$3.75 → $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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

***

## Version history

| Date            | Change                                                                                                                                                                                                                         |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| August 14, 2026 | Initial publication. Full call-site audit; all pricing re-verified from vendor pages; Luna/Sonnet 5/`large-1x`/Exa-per-result corrections applied; ranked and refresh profiles added; `gpt-4o-mini-tts` identified as retired. |
