<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Owen</title>
    <description>The latest articles on DEV Community by Owen (@owen_fox).</description>
    <link>https://dev.to/owen_fox</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3893304%2Fb8cec06b-7789-423e-a8d0-386db7f00620.png</url>
      <title>DEV Community: Owen</title>
      <link>https://dev.to/owen_fox</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/owen_fox"/>
    <language>en</language>
    <item>
      <title>Best LLM API Providers 2026: 4 Types and What Each Costs</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Mon, 03 Aug 2026 04:36:02 +0000</pubDate>
      <link>https://dev.to/owen_fox/best-llm-api-providers-2026-4-types-and-what-each-costs-1m1g</link>
      <guid>https://dev.to/owen_fox/best-llm-api-providers-2026-4-types-and-what-each-costs-1m1g</guid>
      <description>&lt;h1&gt;
  
  
  Best LLM API Providers 2026: 4 Types and What Each Costs
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; There are four ways to buy LLM tokens in 2026 and they are not competing on the same axis. Native APIs sell the canonical price and day-zero features. Open-weight hosts sell cheap tokens, from $0.05/M on Together's gpt-oss-20B. Routers sell one key across many vendors, typically at list price with the cost moved into payment fees, 5.5% on card top-ups at OpenRouter. Cloud platforms sell procurement, and charge for it: partner-cloud regional endpoints run 10% over global, and Vertex's priority tier is 1.8x standard. The same Claude Opus 5 call costs $5/$25 per 1M tokens on three of the four. What actually differs is everything around the token.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: Which Type Should You Buy From?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Buy from&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You need a model the week it ships&lt;/td&gt;
&lt;td&gt;Native API&lt;/td&gt;
&lt;td&gt;Partner clouds and routers lag on new SKUs and on new features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your bill is dominated by one open-weight model&lt;/td&gt;
&lt;td&gt;Open-weight host&lt;/td&gt;
&lt;td&gt;Serverless per-token, then dedicated GPUs once you saturate them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You call four vendors and want one invoice&lt;/td&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;One key, one balance, one wire format if you want it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finance already approved a cloud commitment&lt;/td&gt;
&lt;td&gt;Cloud platform&lt;/td&gt;
&lt;td&gt;The spend lands on an invoice that exists, which is often the whole argument&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need sub-second first tokens on a small model&lt;/td&gt;
&lt;td&gt;Open-weight host&lt;/td&gt;
&lt;td&gt;Groq publishes 560 tok/s on its &lt;code&gt;llama-3.1-8b-instant&lt;/code&gt; and 1000 tok/s on its &lt;code&gt;openai/gpt-oss-20b&lt;/code&gt;, at its own prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a fallback route without a second contract&lt;/td&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;Failover is the product, not a feature you build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your data must stay in one legal region&lt;/td&gt;
&lt;td&gt;Cloud platform or native residency&lt;/td&gt;
&lt;td&gt;Both offer it, both charge about 10% for it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You are still deciding which model to use&lt;/td&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;Swapping a model ID is cheaper than swapping an integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two ways to stop reading here. If you spend under about $200 a month on tokens, buy directly from whichever lab makes the model you like and revisit this when the number gets interesting; every optimization below is worth less than the afternoon you would spend on it. If you already run production traffic across more than two vendors, skip to the hidden-cost table, because that is where your money is actually going.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Types, Side by Side
&lt;/h2&gt;

&lt;p&gt;The useful distinction is not brand. It is who runs the GPUs, who sets the price, and who sends the invoice.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Native API&lt;/th&gt;
&lt;th&gt;Open-weight host&lt;/th&gt;
&lt;th&gt;Router / aggregator&lt;/th&gt;
&lt;th&gt;Cloud platform&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Examples&lt;/td&gt;
&lt;td&gt;OpenAI, Anthropic, Google, DeepSeek&lt;/td&gt;
&lt;td&gt;Together, Fireworks, Groq&lt;/td&gt;
&lt;td&gt;OpenRouter, ofox&lt;/td&gt;
&lt;td&gt;Bedrock, Vertex AI, Microsoft Foundry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runs the inference&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, or resells the lab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model catalog&lt;/td&gt;
&lt;td&gt;One lab's models&lt;/td&gt;
&lt;td&gt;Open-weight only&lt;/td&gt;
&lt;td&gt;Many labs, 100+ IDs&lt;/td&gt;
&lt;td&gt;The cloud's partner list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sets the price&lt;/td&gt;
&lt;td&gt;Yes, this is list&lt;/td&gt;
&lt;td&gt;Yes, competitively&lt;/td&gt;
&lt;td&gt;Copies list, mostly&lt;/td&gt;
&lt;td&gt;List plus platform surcharges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New model on day one&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;For open weights, yes&lt;/td&gt;
&lt;td&gt;Usually within days&lt;/td&gt;
&lt;td&gt;Often weeks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Bearer token&lt;/td&gt;
&lt;td&gt;Bearer token&lt;/td&gt;
&lt;td&gt;Bearer token&lt;/td&gt;
&lt;td&gt;IAM roles, SigV4, service accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Billing&lt;/td&gt;
&lt;td&gt;Card or invoice, per lab&lt;/td&gt;
&lt;td&gt;Card, per host&lt;/td&gt;
&lt;td&gt;One prepaid balance&lt;/td&gt;
&lt;td&gt;Your existing cloud invoice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failover across vendors&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built in&lt;/td&gt;
&lt;td&gt;Within one cloud's catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best at&lt;/td&gt;
&lt;td&gt;Newest features, highest ceilings&lt;/td&gt;
&lt;td&gt;Cost per token&lt;/td&gt;
&lt;td&gt;Breadth and switching cost&lt;/td&gt;
&lt;td&gt;Procurement and compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything below is that table at length, with the numbers I could verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type 1: Native APIs
&lt;/h2&gt;

&lt;p&gt;Buying from the lab that trained the model is the default, and for most teams it stays the right answer longer than the internet suggests.&lt;/p&gt;

&lt;p&gt;You get three things nowhere else gives you reliably. New models on release day. Features that only exist first-party, like Anthropic's fast mode, which the pricing docs state is available on the Claude API only and not on partner-operated platforms. And the highest published rate-limit ceilings, since every other route is buying capacity from the same place you would be.&lt;/p&gt;

&lt;p&gt;Here is what the three big labs actually charge, per 1M tokens, checked 2026-08-02.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Cached input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Fable 5&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;$1&lt;/td&gt;
&lt;td&gt;$50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 5&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5&lt;/td&gt;
&lt;td&gt;$2 (through Aug 31, then $3)&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;td&gt;$10 (then $15)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5&lt;/td&gt;
&lt;td&gt;$1&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.6-sol&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.6-terra&lt;/td&gt;
&lt;td&gt;$2&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;td&gt;$12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.6-luna&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;td&gt;$1.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.5&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$7.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.5 Flash-Lite&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;td&gt;$0.03&lt;/td&gt;
&lt;td&gt;$2.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two caveats before you use those numbers. OpenAI publishes separate short-context and long-context columns, and the figures above are the short-context tier. Long context is not a uniform multiplier: &lt;code&gt;gpt-5.6-luna&lt;/code&gt; goes from $0.20/$1.20 to $0.40/$1.80, so input doubles while output rises by half. The Gemini figures are Vertex's Global tier, and several models in that line price non-global endpoints 10% higher, Gemini 3.5 Flash at $1.65/$9.90 against $1.50/$9.00.&lt;/p&gt;

&lt;p&gt;Two things in that table are worth more than the headline prices. Every one of these labs discounts batch work by 50% on both input and output, which is the single largest lever available if any part of your workload can wait. And cached input runs at a tenth of fresh input across all three, so an agent with a stable system prompt is paying a fraction of what the list price implies. We worked that math out in detail in &lt;a href="https://ofox.ai/blog/prompt-caching-cost-math-anthropic-vs-openai-2026/" rel="noopener noreferrer"&gt;Anthropic vs OpenAI prompt caching&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The cost of going native is administrative and it compounds quietly. Four labs means four keys, four dashboards, four billing relationships, and four different rate-limit rulebooks that share no vocabulary. We compared five of those rulebooks side by side in &lt;a href="https://ofox.ai/blog/llm-api-rate-limits-compared-2026/" rel="noopener noreferrer"&gt;LLM API rate limits compared&lt;/a&gt; and they disagree on almost everything, including what a "request" is.&lt;/p&gt;

&lt;p&gt;Go native if you are standardized on one lab, if you need release-day access, or if your volume is large enough that you want a direct commercial conversation with someone. It stops being comfortable at the point where you are still evaluating models, where you want somewhere to fail over to on the afternoon one lab has a bad day, or where you are holding four keys and a finance team has started asking about them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type 2: Open-Weight Inference Hosts
&lt;/h2&gt;

&lt;p&gt;This category exists because some model weights are public, which means the price is set by GPU economics rather than by whoever owns the model. Competition here is real, and the prices show it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Host&lt;/th&gt;
&lt;th&gt;Input /1M&lt;/th&gt;
&lt;th&gt;Output /1M&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-20B&lt;/td&gt;
&lt;td&gt;Together&lt;/td&gt;
&lt;td&gt;$0.05&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-20B&lt;/td&gt;
&lt;td&gt;Groq (&lt;code&gt;openai/gpt-oss-20b&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;$0.075&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LFM2.5-8B-A1B&lt;/td&gt;
&lt;td&gt;Together&lt;/td&gt;
&lt;td&gt;$0.03&lt;/td&gt;
&lt;td&gt;$0.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-120B&lt;/td&gt;
&lt;td&gt;Together&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-120B&lt;/td&gt;
&lt;td&gt;Groq (&lt;code&gt;openai/gpt-oss-120b&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.5-397B-A17B&lt;/td&gt;
&lt;td&gt;Together&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;td&gt;$3.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 3.3 70B&lt;/td&gt;
&lt;td&gt;Together&lt;/td&gt;
&lt;td&gt;$1.04&lt;/td&gt;
&lt;td&gt;$1.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 3.3 70B&lt;/td&gt;
&lt;td&gt;Groq (&lt;code&gt;llama-3.3-70b-versatile&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;$0.59&lt;/td&gt;
&lt;td&gt;$0.79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash&lt;/td&gt;
&lt;td&gt;DeepSeek (native)&lt;/td&gt;
&lt;td&gt;$0.14&lt;/td&gt;
&lt;td&gt;$0.28&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Prices as published on each vendor's pricing page, checked 2026-08-02.&lt;/p&gt;

&lt;p&gt;Read that table by row pairs, because the duplicated model names are the point. Same published weights, and what you pay depends on whose cluster they run on. Together is cheaper on gpt-oss-20B, $0.05/$0.20 against $0.075/$0.30. Groq is cheaper on Llama 3.3 70B, $0.59/$0.79 against a flat $1.04/$1.04. They tie on gpt-oss-120B. Nobody wins the category, which is what you get in a market where the product is commoditized and the differentiation is scheduling. It also means throughput and price do not travel together: Groq's 1000 tok/s belongs to Groq's gpt-oss-20B at Groq's price, not to Together's cheaper listing of the same weights.&lt;/p&gt;

&lt;p&gt;Two structural things separate this category from the rest.&lt;/p&gt;

&lt;p&gt;The first is that you can graduate off per-token pricing. Together publishes dedicated H100 instances at $5.49/hour on demand and GPU clusters at $3.99 per GPU-hour, dropping to $3.19 with a reservation. Fireworks lists on-demand GPUs at $7.00/hour for an H100 or H200, $10.00 for a B200 and $12.00 for a B300. That gives you a break-even you can compute: a single H100 at $5.49/hour is about $4,000 a month, so once your serverless bill on a 20B-class model passes that and your traffic is steady rather than spiky, dedicated starts to win. Spiky traffic keeps you on serverless longer than the arithmetic suggests, because you pay for the idle hours too.&lt;/p&gt;

&lt;p&gt;The second is a trap worth naming. Model availability on these hosts is not a promise. Groq's model docs split their catalog into production and preview, and the preview language is unusually direct: those models are "intended for evaluation purposes only and should not be used in production environments as they may be discontinued at short notice." At the 2026-08-02 check that list included &lt;code&gt;qwen/qwen3.6-27b&lt;/code&gt;. If you pin a preview model ID in production you have accepted a dependency that the vendor has told you in writing not to accept.&lt;/p&gt;

&lt;p&gt;This category earns its place on high volume against public weights, on latency-critical small-model work, and on anything you might eventually want to pull in-house and self-host with the same outputs. It is the wrong place to be if you need a frontier closed model, or if you need one specific model ID to still exist next quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type 3: Routers and Aggregators
&lt;/h2&gt;

&lt;p&gt;A router does not run inference. It terminates your request, decides which upstream gets it, forwards it, and hands you back a normalized response. What you are buying is the absence of integration work: one key, one balance, one wire format, and a fallback path you did not have to build.&lt;/p&gt;

&lt;p&gt;The pricing question people ask about this category is whether there is a markup, and the answer for the two biggest is more interesting than yes or no.&lt;/p&gt;

&lt;p&gt;OpenRouter states plainly that it does not mark up inference: "We pass through the pricing of the underlying providers; there is no markup on inference pricing (however we do charge a fee when purchasing credits)." The revenue moves to the payment layer instead. Its FAQ puts the card fee at "a 5.5% ($0.80 minimum) fee when you purchase credits," crypto at 5%, and bring-your-own-key routing at "5% of what the same model and provider would normally cost on OpenRouter" once you pass the first 1M BYOK requests in a month. On a $600 monthly token spend the card fee is about $33. At $10,000 it is $550. We itemized every charge in &lt;a href="https://ofox.ai/blog/openrouter-pricing-hidden-markup-breakdown-2026/" rel="noopener noreferrer"&gt;OpenRouter pricing: the hidden 5.5% fee&lt;/a&gt;, and looked at production reliability separately in &lt;a href="https://ofox.ai/blog/is-openrouter-reliable-honest-review-2026/" rel="noopener noreferrer"&gt;Is OpenRouter reliable?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since ofox is also in this category, the fair thing is to check our own price sheet the same way. Every model page I pulled on 2026-08-02, against the vendor's published list price:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model ID&lt;/th&gt;
&lt;th&gt;ofox listed&lt;/th&gt;
&lt;th&gt;Vendor list&lt;/th&gt;
&lt;th&gt;Match&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-opus-5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$5 / $25&lt;/td&gt;
&lt;td&gt;$5 / $25&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$2 / $10&lt;/td&gt;
&lt;td&gt;$2 / $10&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-5.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$5 / $30&lt;/td&gt;
&lt;td&gt;$5 / $30&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;google/gemini-3.6-flash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$1.50 / $7.50&lt;/td&gt;
&lt;td&gt;$1.50 / $7.50&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deepseek/deepseek-v4-flash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.14 / $0.28&lt;/td&gt;
&lt;td&gt;$0.14 / $0.28&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-5.6-luna&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$1 / $6&lt;/td&gt;
&lt;td&gt;$0.20 / $1.20&lt;/td&gt;
&lt;td&gt;No, 5x over&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Five out of six at list, one materially over it. The Luna row is not a rounding error: OpenAI cut that model's list price by 80% on 2026-07-30 and the listing still showed the pre-cut tier three days later. The lesson applies to every router including this one. A gateway price sheet is a snapshot, and vendor list prices move without warning, so check the model page for the exact model ID on the day you plan to call it rather than extrapolating from anyone's reputation for being cheap. Same finding we hit in &lt;a href="https://ofox.ai/blog/deepseek-v4-flash-vs-gemini-3-6-flash-2026/" rel="noopener noreferrer"&gt;DeepSeek V4 Flash vs Gemini 3.6 Flash&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The other thing to check before picking a router is which wire formats it speaks, because your tooling does not get a vote. Claude Code wants the Anthropic Messages shape. Codex CLI wants OpenAI's. A router exposing only one of them puts a translation layer in your path. ofox documents three base URLs, one per protocol: &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt; for OpenAI Chat Completions, &lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt; for Messages, &lt;code&gt;https://api.ofox.ai/gemini&lt;/code&gt; for Gemini. Its &lt;code&gt;/v1/models&lt;/code&gt; returned 122 model IDs across 12 provider prefixes when I called it on 2026-08-02.&lt;/p&gt;

&lt;p&gt;A router pays for itself while you are still choosing models, once you call more than two vendors, when you want failover you did not have to build, or when one prepaid balance is easier to defend than four card-on-file relationships. It is the wrong layer if you need a brand new SKU on day one, if you need a first-party-only feature, or if you have negotiated a volume discount directly with a lab. In that last case going through anyone else is strictly worse.&lt;/p&gt;

&lt;p&gt;There are more than two products in this category. We ranked seven of them, with migration notes, in &lt;a href="https://ofox.ai/blog/openrouter-alternatives-2026/" rel="noopener noreferrer"&gt;7 best OpenRouter alternatives&lt;/a&gt;, and the general selection framework is in &lt;a href="https://ofox.ai/blog/why-llm-api-gateway-how-to-choose-2026/" rel="noopener noreferrer"&gt;the LLM API gateway guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type 4: Cloud Platforms
&lt;/h2&gt;

&lt;p&gt;Amazon Bedrock, Google Vertex AI and Microsoft Foundry sell a different product from everyone above, and pretending otherwise is how teams end up disappointed by them. They sell procurement. The model is a line item on an invoice your company already pays, inside an account your security team already reviewed, billed against a commitment you may already have signed. For a large enough organization that is worth real money, and the token price is close to irrelevant.&lt;/p&gt;

&lt;p&gt;The surcharges are real and they are documented.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Surcharge&lt;/th&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Regional or multi-region endpoint&lt;/td&gt;
&lt;td&gt;Bedrock, Google Cloud&lt;/td&gt;
&lt;td&gt;10% over global endpoints. Anthropic's docs scope this to Claude Sonnet 4.5, Haiku 4.5, Opus 4.5 "and all future models", so Opus 5 and Sonnet 5 are included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Priority service tier&lt;/td&gt;
&lt;td&gt;Vertex AI&lt;/td&gt;
&lt;td&gt;1.8x standard. Google does not print the multiplier, but every Gemini row divides out to it: 3.6 Flash goes from $1.50/$7.50 to $2.70/$13.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US-only inference geography&lt;/td&gt;
&lt;td&gt;Claude API, Claude Platform on AWS, Foundry&lt;/td&gt;
&lt;td&gt;1.1x on all token categories, Claude 4.6 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provisioned throughput&lt;/td&gt;
&lt;td&gt;Bedrock&lt;/td&gt;
&lt;td&gt;Per model unit per hour, with no-commitment, 1-month and 6-month rates. In the Cohere section's Provisioned Throughput table, Cohere Command runs $49.50, $39.60 and $23.77 respectively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch / Flex tier&lt;/td&gt;
&lt;td&gt;Bedrock, Vertex AI&lt;/td&gt;
&lt;td&gt;Discount, not a surcharge: 50% off standard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Billing mechanics differ too, in ways that matter to whoever reconciles the invoice. Claude Platform on AWS and Claude in Microsoft Foundry both bill in Claude Consumption Units at a fixed $0.01 per CCU, metered hourly and invoiced monthly. Anthropic's docs describe that as "Arrears only (postpaid); no prepaid credits," and your cloud bill shows one CCU line item rather than a per-model breakdown. If your cost attribution depends on seeing which model spent what, that reconciliation happens in the vendor console, not in Cost Explorer.&lt;/p&gt;

&lt;p&gt;Bedrock also prices per region, with separate tables for US East, Frankfurt, Sydney and others, and it splits inference into Standard, Flex, Priority and Reserved tiers. Provisioned throughput is quoted per model unit per hour rather than per token, and for Anthropic models the page does not publish a rate at all: it tells you to reach out to your account team, which is a fair summary of the whole category. Vertex charges cached input at 10% of standard, the same ratio as first-party.&lt;/p&gt;

&lt;p&gt;Buy here when you have committed spend to burn down, when procurement treats a new vendor as a quarter-long project, or when compliance gets easier the moment traffic stays inside an account you already own. Buy elsewhere when you want the newest model, the lowest price, or an API key rather than an IAM role. Auth in this category is real work: SigV4 signing or service-account credentials instead of a bearer token, a day of engineering the first time and a little more every time a new service needs access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing Math: The Same Workload, Four Ways
&lt;/h2&gt;

&lt;p&gt;List prices do not answer the question people are actually asking, which is what the invoice says. Three workloads I see repeatedly, at the rates verified above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload A. Customer-facing assistant on a frontier model.&lt;/strong&gt; 20M input and 5M output tokens per month on Claude Opus 5.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Math&lt;/th&gt;
&lt;th&gt;Monthly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic direct, global endpoint&lt;/td&gt;
&lt;td&gt;20 × $5 + 5 × $25&lt;/td&gt;
&lt;td&gt;$225&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router at list price&lt;/td&gt;
&lt;td&gt;Same rates&lt;/td&gt;
&lt;td&gt;$225&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partner cloud, regional endpoint&lt;/td&gt;
&lt;td&gt;$225 × 1.10&lt;/td&gt;
&lt;td&gt;$247.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Batch API, if the work can wait&lt;/td&gt;
&lt;td&gt;20 × $2.50 + 5 × $12.50&lt;/td&gt;
&lt;td&gt;$112.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The type you buy from moves this bill by 10%. Whether the work can be batched moves it by 50%. That ordering holds for most teams, which is why "which provider is cheapest" is the wrong first question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload B. Agent backend at volume.&lt;/strong&gt; 200M input and 50M output tokens per month, cheap tier.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Math&lt;/th&gt;
&lt;th&gt;Monthly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash, native rates&lt;/td&gt;
&lt;td&gt;200 × $0.14 + 50 × $0.28&lt;/td&gt;
&lt;td&gt;$42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-120B on Together&lt;/td&gt;
&lt;td&gt;200 × $0.15 + 50 × $0.60&lt;/td&gt;
&lt;td&gt;$60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.6-luna, OpenAI list&lt;/td&gt;
&lt;td&gt;200 × $0.20 + 50 × $1.20&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.6-luna, via a listing still on the pre-cut tier&lt;/td&gt;
&lt;td&gt;200 × $1 + 50 × $6&lt;/td&gt;
&lt;td&gt;$500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;200 × $1.50 + 50 × $7.50&lt;/td&gt;
&lt;td&gt;$675&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The spread inside one quality tier is 16x, and one row of it is nothing but a stale price sheet. This is where checking the specific model page pays for itself in an afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload C. Offline classification.&lt;/strong&gt; 500M input and 20M output tokens per month on Claude Haiku 4.5.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Math&lt;/th&gt;
&lt;th&gt;Monthly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5, Batch API at 50% off&lt;/td&gt;
&lt;td&gt;500 × $0.50 + 20 × $2.50&lt;/td&gt;
&lt;td&gt;$300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5, standard rates&lt;/td&gt;
&lt;td&gt;500 × $1 + 20 × $5&lt;/td&gt;
&lt;td&gt;$600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash on Vertex, standard tier&lt;/td&gt;
&lt;td&gt;500 × $1.50 + 20 × $7.50&lt;/td&gt;
&lt;td&gt;$900&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash on Vertex, priority tier&lt;/td&gt;
&lt;td&gt;500 × $2.70 + 20 × $13.50&lt;/td&gt;
&lt;td&gt;$1,620&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first two rows are the same request to the same model, a factor of two apart, separated only by whether you were willing to wait. Add the model and tier choice and the spread across one unremarkable workload runs from $300 to $1,620. Almost nobody who could be running workload C in batch mode actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Costs That Don't Show Up on the Price Page
&lt;/h2&gt;

&lt;p&gt;Every category has one line item that is invisible until it arrives.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;The invisible cost&lt;/th&gt;
&lt;th&gt;What it looks like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Integration multiplied by vendor count&lt;/td&gt;
&lt;td&gt;Four SDKs, four retry policies, four rate-limit rulebooks with no shared vocabulary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Tokenizer changes&lt;/td&gt;
&lt;td&gt;Anthropic's docs note Claude 4.7 and later use a tokenizer producing about 30% more tokens for the same text, so a same-price model upgrade can still raise your bill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open-weight host&lt;/td&gt;
&lt;td&gt;Idle GPU hours&lt;/td&gt;
&lt;td&gt;Dedicated capacity bills the trough as well as the peak; spiky traffic burns the break-even&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open-weight host&lt;/td&gt;
&lt;td&gt;Catalog churn&lt;/td&gt;
&lt;td&gt;A preview model ID can be withdrawn at short notice, by the vendor's own warning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;Payment fees&lt;/td&gt;
&lt;td&gt;5.5% card top-up at OpenRouter, plus 5% for BYOK past 1M monthly requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router&lt;/td&gt;
&lt;td&gt;Price-sheet lag&lt;/td&gt;
&lt;td&gt;The Luna row above: 5x over list for three days after a vendor cut&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;td&gt;Auth engineering&lt;/td&gt;
&lt;td&gt;IAM roles and request signing instead of a bearer token, once per service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;td&gt;Surcharge stacking&lt;/td&gt;
&lt;td&gt;Regional 1.10 × priority 1.8 compound before you notice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All four&lt;/td&gt;
&lt;td&gt;Not batching&lt;/td&gt;
&lt;td&gt;50% left on the table on every workload that could have waited an hour&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tokenizer line is the one nobody plans for. A model upgrade at identical per-token pricing can still raise your invoice if the new tokenizer is denser, and no price-comparison table will show you that.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Need Two Types, and When One Is Enough
&lt;/h2&gt;

&lt;p&gt;One type is enough when your traffic runs on one or two models, an hour of downtime is an annoyance rather than an incident, and your monthly spend is small enough that a 10% difference is not worth an integration. That describes most teams for longer than they expect.&lt;/p&gt;

&lt;p&gt;You want a second type once one of three things is true. A model outage costs you more than the fallback would cost to build, in which case a router is the cheapest second route because failover is what it sells. Your finance process cannot absorb another vendor, in which case a cloud platform solves a problem no amount of price optimization will. Or your volume on one specific model is large enough that a dedicated deployment beats per-token pricing, which puts you on an open-weight host regardless of what else you run.&lt;/p&gt;

&lt;p&gt;The pairing that shows up most often is a native key plus a router. The native key carries primary traffic and gets you release-day models and the highest rate-limit ceiling. The router is the escape hatch, already integrated, holding a small balance, one model-ID string away from taking over.&lt;/p&gt;

&lt;p&gt;What you should not do is buy a second vendor of the same type and call it redundancy. Two routers pointed at the same upstream provider fail together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching Types Without Rewriting Your Client
&lt;/h2&gt;

&lt;p&gt;Type selection is reversible because three of the four categories speak the OpenAI Chat Completions shape. Native OpenAI, most open-weight hosts and most routers accept the same request body, so the base URL and the model string are the only things that change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;ROUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.openai.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.6-luna&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deepseek/deepseek-v4-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic/claude-opus-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ROUTES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize this in one line.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.openai.com/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.6-luna&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deepseek/deepseek-v4-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic/claude-opus-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Summarize this in one line.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that loop against your own prompts before committing to a type. Token counts vary more between models than prices do, and a model 3x cheaper per token that spends 4x the output tokens is not cheaper. The &lt;a href="https://ofox.ai/models" rel="noopener noreferrer"&gt;ofox model catalog&lt;/a&gt; has current per-model rates if you want today's numbers rather than this article's.&lt;/p&gt;

&lt;p&gt;Cloud platforms are the category that does not fit this pattern, which is the honest reason they are more work. Bedrock and Vertex want signed requests and platform SDKs, so moving onto or off them is a migration rather than two edited strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Refresh
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Anthropic model pricing, batch, caching, partner-cloud and CCU billing: &lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;platform.claude.com/docs/en/about-claude/pricing&lt;/a&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  OpenAI GPT-5.x list pricing and batch discount: &lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;developers.openai.com/api/docs/pricing&lt;/a&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  Vertex AI Gemini pricing, standard and priority tier tables, global vs non-global rates, batch discount: &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/pricing" rel="noopener noreferrer"&gt;cloud.google.com/vertex-ai/generative-ai/pricing&lt;/a&gt;, which now redirects to the Agent Platform pricing page (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  Amazon Bedrock pricing tiers, batch discount, provisioned throughput commitments, per-region tables: &lt;a href="https://aws.amazon.com/bedrock/pricing/" rel="noopener noreferrer"&gt;aws.amazon.com/bedrock/pricing&lt;/a&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  OpenRouter fee structure, all quotes: &lt;code&gt;openrouter.ai/docs/faq&lt;/code&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  Together serverless, dedicated and cluster pricing: &lt;code&gt;together.ai/pricing&lt;/code&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  Fireworks on-demand GPU pricing: &lt;code&gt;fireworks.ai/pricing&lt;/code&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  Groq production vs preview model policy, per-token prices and throughput figures: &lt;code&gt;console.groq.com/docs/models&lt;/code&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;li&gt;  ofox per-model pricing and catalog size: model pages under &lt;code&gt;ofox.ai/models/&lt;/code&gt;, plus a live &lt;code&gt;GET /v1/models&lt;/code&gt; call; protocol base URLs from &lt;code&gt;ofox.ai/llms-full.txt&lt;/code&gt; (checked 2026-08-02)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/best-llm-api-providers-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>comparison</category>
    </item>
    <item>
      <title>DeepSeek V4 Flash vs Gemini 3.6 Flash: Tied Score, 10x Price</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 02 Aug 2026 00:36:27 +0000</pubDate>
      <link>https://dev.to/owen_fox/deepseek-v4-flash-vs-gemini-36-flash-tied-score-10x-price-13h6</link>
      <guid>https://dev.to/owen_fox/deepseek-v4-flash-vs-gemini-36-flash-tied-score-10x-price-13h6</guid>
      <description>&lt;h1&gt;
  
  
  DeepSeek V4 Flash vs Gemini 3.6 Flash: Tied Score, 10x Price
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; DeepSeek V4 Flash 0731 and Gemini 3.6 Flash both land on 50 on the Artificial Analysis Intelligence Index v4.1, with GPT-5.6 Luna one point ahead at 51. Their list prices span more than an order of magnitude. The interesting part is what happens when you stop comparing price tags and start comparing invoices for the same evaluated workload. Artificial Analysis publishes what it paid to run each one: $72.02 for DeepSeek, $190.87 for Luna, $726.70 for Gemini. The sticker gap on output price is 27x. The gap on the actual bill is 10.1x, because DeepSeek burned 210M output tokens on that run to Gemini's 59M. Both numbers say buy DeepSeek if your workload is text; neither of them survives contact with a pipeline that sends images.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: Which One Should You Pick?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text-only, high volume, cost is the constraint&lt;/td&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;Cheapest per token by ~10x, and a 98% cache discount on top&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anything with images, audio, video or PDFs&lt;/td&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;DeepSeek 0731 is text only; there is no cheaper workaround&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive UX where latency is visible to a user&lt;/td&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;~220 output tokens/sec, and the lowest TTFT of the three on AA's runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long single generations (full files, long reports)&lt;/td&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;384K max output vs Gemini's 64K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want the top index score and vision on one model&lt;/td&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;51 on the index, vision, and an 80% price cut on 2026-07-30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bounded agent loops where you can cache aggressively&lt;/td&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;Cache reads at $0.0028/M, the lowest of the three by a wide margin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need reproducible third-party latency numbers today&lt;/td&gt;
&lt;td&gt;Gemini 3.6 Flash or GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;AA had no speed or TTFT data for the 0731 build at snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two ways to stop reading here. If your workload sends any non-text input, the second row settles it and the rest of this article is background. If your workload is text and runs under about 20M tokens a month, the annual difference between the cheapest and most expensive option above is smaller than a day of engineering time, so pick on latency and move on. Everything below is written for the case where the bill is large enough to argue about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changed on July 31
&lt;/h2&gt;

&lt;p&gt;DeepSeek shipped a new build of V4 Flash on 2026-07-31 and did not change the model. Same 284B total parameters, same 13B active, same 1M context, same $0.14 / $0.28 price. The API model name is unchanged too, &lt;code&gt;deepseek-v4-flash&lt;/code&gt;, with the build identified in DeepSeek's docs as model version &lt;code&gt;DeepSeek-V4-Flash-0731&lt;/code&gt;. What changed is post-training.&lt;/p&gt;

&lt;p&gt;The measured effect is larger than "post-training only" usually implies. On the Artificial Analysis Intelligence Index v4.1, the score went from 40 to 50. AA's agentic evaluation, GDPval-AA v2, moved from 1189 Elo to 1559. Terminal-Bench 2.1 gained 17 points to reach 79%. AA also places the 0731 build 6 points ahead of DeepSeek V4 Pro, DeepSeek's own flagship, which is an awkward result for anyone who wrote routing rules on the assumption that Pro handles the hard cases.&lt;/p&gt;

&lt;p&gt;We were among those people. Our DeepSeek V4 Pro vs Flash routing guide from May concluded that multi-file work and long agent loops belonged on Pro. For the 0731 build that conclusion no longer holds, and the honest version is that Flash is now the default and Pro is the exception you justify.&lt;/p&gt;

&lt;p&gt;The weights landed faster than anyone said they would. AA's launch coverage described full weights as expected "in the coming weeks", and most secondary coverage still repeats that. Checked on 2026-08-01, &lt;code&gt;deepseek-ai/DeepSeek-V4-Flash-0731&lt;/code&gt; on Hugging Face already carries the model as 48 safetensors shards under MIT, ungated. If you read somewhere that 0731 is API-only, that was true for about a day.&lt;/p&gt;

&lt;p&gt;One caveat worth stating before the numbers start. The Intelligence Index is a rolling leaderboard, and everything below is a 2026-08-01 snapshot. Treat the ordering as the durable fact and the absolute score as a reading taken on a particular day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Specs Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;DeepSeek V4 Flash 0731&lt;/th&gt;
&lt;th&gt;Gemini 3.6 Flash&lt;/th&gt;
&lt;th&gt;GPT-5.6 Luna&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ofox model ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deepseek/deepseek-v4-flash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;google/gemini-3.6-flash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-5.6-luna&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA Intelligence Index v4.1&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;51 🏆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Released&lt;/td&gt;
&lt;td&gt;2026-07-31 (0731 build)&lt;/td&gt;
&lt;td&gt;2026-07-21&lt;/td&gt;
&lt;td&gt;2026-07-09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input price (vendor list)&lt;/td&gt;
&lt;td&gt;$0.14/M 🏆&lt;/td&gt;
&lt;td&gt;$1.50/M&lt;/td&gt;
&lt;td&gt;$0.20/M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output price (vendor list)&lt;/td&gt;
&lt;td&gt;$0.28/M 🏆&lt;/td&gt;
&lt;td&gt;$7.50/M&lt;/td&gt;
&lt;td&gt;$1.20/M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cached input&lt;/td&gt;
&lt;td&gt;$0.0028/M 🏆&lt;/td&gt;
&lt;td&gt;$0.15/M&lt;/td&gt;
&lt;td&gt;$0.02/M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;td&gt;1M (1,048,576)&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max output&lt;/td&gt;
&lt;td&gt;384K 🏆&lt;/td&gt;
&lt;td&gt;64K (65,536)&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input modalities&lt;/td&gt;
&lt;td&gt;Text&lt;/td&gt;
&lt;td&gt;Text, image, video, audio, PDF 🏆&lt;/td&gt;
&lt;td&gt;Text, image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output speed (AA)&lt;/td&gt;
&lt;td&gt;not published at snapshot&lt;/td&gt;
&lt;td&gt;219.6 tok/s 🏆&lt;/td&gt;
&lt;td&gt;172.1 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to first token (AA)&lt;/td&gt;
&lt;td&gt;not published at snapshot&lt;/td&gt;
&lt;td&gt;15.11s 🏆&lt;/td&gt;
&lt;td&gt;121.89s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open weights&lt;/td&gt;
&lt;td&gt;Yes, MIT on Hugging Face 🏆&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wire protocols&lt;/td&gt;
&lt;td&gt;OpenAI, Anthropic, Responses&lt;/td&gt;
&lt;td&gt;OpenAI, Gemini&lt;/td&gt;
&lt;td&gt;OpenAI, Anthropic, Responses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two rows deserve a second look. Max output is a real separator: 384K against 64K is the difference between generating a long file in one call and building a continuation loop. And the empty latency cells are not a formatting accident. AA's provider page for the 0731 build listed no speed or time-to-first-token data at the 2026-08-01 snapshot, so anyone quoting you a tokens-per-second figure for this build is quoting something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benchmark Picture: One Point Separates Three Models
&lt;/h2&gt;

&lt;p&gt;Here is the AA sub-score detail for the 0731 build, with the delta against the April build where AA published one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Evaluation&lt;/th&gt;
&lt;th&gt;DeepSeek V4 Flash 0731&lt;/th&gt;
&lt;th&gt;Change vs April build&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Intelligence Index v4.1&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;+10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GDPval-AA v2 (Elo)&lt;/td&gt;
&lt;td&gt;1559&lt;/td&gt;
&lt;td&gt;+370&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-Bench 2.1&lt;/td&gt;
&lt;td&gt;79%&lt;/td&gt;
&lt;td&gt;+17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPQA Diamond&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-LCR&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;td&gt;+3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SciCode&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;+5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Humanity's Last Exam&lt;/td&gt;
&lt;td&gt;37%&lt;/td&gt;
&lt;td&gt;+5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;τ³-Bench Banking&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;td&gt;+8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CritPt&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;td&gt;+9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-Omniscience Index&lt;/td&gt;
&lt;td&gt;-16&lt;/td&gt;
&lt;td&gt;+7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Omniscience row is the one people skip. AA reports that the improvement came from fewer hallucinations rather than from knowing more, with accuracy flat. For a model you are about to point at production traffic, "wrong less often" is a more useful upgrade than "knows more", and it is the sort of thing a single composite score hides.&lt;/p&gt;

&lt;p&gt;Two sourcing notes, because this release has more than one set of numbers floating around.&lt;/p&gt;

&lt;p&gt;DeepSeek's own release materials report Terminal-Bench 2.1 at 82.7, DeepSWE at 54.4 and Cybergym at 76.7. Artificial Analysis reports Terminal-Bench 2.1 at 79%. Both can be correct; harnesses, scaffolds and effort settings differ, and there was no third-party reproduction of the DeepSWE and Cybergym figures at snapshot time. We are using AA's numbers throughout because they are the only ones measured the same way across all three models here. If you see 82.7 quoted somewhere, that is the vendor's harness, not a contradiction.&lt;/p&gt;

&lt;p&gt;The other one: the LMArena score attached to DeepSeek V4 Flash on most catalog pages, including ours, reads 1438 Overall with a rank in the seventies, updated 2026-07-12. That predates the 0731 build by nineteen days. It measures the April model. Arena scores for the new build will need new votes, and until then the number sitting next to "DeepSeek V4 Flash" on any comparison page is describing a model that scored 10 points lower on AA.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Verbosity Tax: Why the Sticker Gap Is Not the Bill Gap
&lt;/h2&gt;

&lt;p&gt;Every comparison of these two models leads with $0.14 against $1.50 and stops there. That ratio is real, and it is also the least reliable number in this article, because it prices a token rather than a job.&lt;/p&gt;

&lt;p&gt;Artificial Analysis publishes something better: what it actually paid to run each model through the same Intelligence Index suite, invoice included.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Output tokens for the index run&lt;/th&gt;
&lt;th&gt;AA's total cost for the run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;210M&lt;/td&gt;
&lt;td&gt;$72.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;130M&lt;/td&gt;
&lt;td&gt;$190.87&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;59M&lt;/td&gt;
&lt;td&gt;$726.70&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same evaluation, three real bills. Gemini costs 10.1x what DeepSeek costs, and Luna 2.7x. Against the sticker ratios of 27x and 4.3x on output price, that is roughly 60% of DeepSeek's paper advantage disappearing somewhere between the price card and the invoice.&lt;/p&gt;

&lt;p&gt;Where it goes is tokens. DeepSeek spent 210M output tokens on that suite against Gemini's 59M, which AA flags as very verbose against the field. Price the output leg alone at list rates and you get $58.80 for DeepSeek, $156.00 for Luna and $442.50 for Gemini, a 7.5x gap on that leg. The shape of the two bills differs accordingly: output is about 82% of what DeepSeek's run cost and about 61% of Gemini's. That is the signature of a model that writes three and a half times as much to reach the same score. AA does not publish input token counts per model, so the remainder is not decomposable any further from published figures.&lt;/p&gt;

&lt;p&gt;Which number you plan against depends on your traffic. A workload that is mostly prompt tracks the input ratio, 10.7x. A workload that is mostly generation gets compressed toward 7.5x by the verbosity. AA's end-to-end figure of 10.1x sits between them, on a suite that is itself a mix, which is why 10x is a better default than 27x for anything you have to defend in a budget review.&lt;/p&gt;

&lt;p&gt;Two caveats on the token counts. They come from AA's max-effort and high-effort configurations, which is the expensive end of each model's range rather than a typical production setting. And verbosity is workload dependent; a suite full of hard reasoning problems flatters models that reason briefly, and your extraction pipeline is not that suite.&lt;/p&gt;

&lt;p&gt;One footnote on the 210M, since two AA numbers circulate. The model page reports 210M output tokens for the index run; AA's launch article reports ~206M, alongside the more interesting fact that this is 12% &lt;em&gt;fewer&lt;/em&gt; output tokens than the previous V4 Flash build spent (~234M). So 0731 is both more verbose than its peers and less verbose than its own predecessor. We use 210M throughout because the model-page figure is the one published the same way for all three models here.&lt;/p&gt;

&lt;p&gt;The lever, though, is real and it is one flag. DeepSeek's docs list &lt;code&gt;deepseek-v4-flash&lt;/code&gt; as supporting both non-thinking and thinking modes, with thinking as the default, and reasoning tokens bill as output. For bounded work, turning thinking off is where the verbosity tax goes away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure it on your own traffic
&lt;/h3&gt;

&lt;p&gt;AA's ratio is a starting estimate, not your number. Getting your own takes one run over a sample of your real prompts, because every OpenAI-compatible response carries the token counts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_OFOX_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;costs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;# input, output, per 1M tokens
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deepseek/deepseek-v4-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.28&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google/gemini-3.6-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;7.50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-5.6-luna&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;totals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;load_your_real_prompts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;        &lt;span class="c1"&gt;# 50 is enough to see the shape
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;costs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;
        &lt;span class="n"&gt;totals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e6&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spend&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;spend&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; over the sample&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fifty representative prompts cost a few cents to run across all three and will tell you more than any leaderboard. Two things to watch for. Run it twice with thinking on and off for DeepSeek, since that flag moves the output column more than the model choice does. And sample from your actual traffic distribution rather than your hardest cases, because verbosity ratios measured on hard reasoning problems do not transfer to a queue full of two-line classifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing Math: Two Real Monthly Bills
&lt;/h2&gt;

&lt;p&gt;All prices below are vendor list, snapshot 2026-08-01, per 1M tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario A, an extraction pipeline.&lt;/strong&gt; 200M input tokens and 10M output tokens per month, no caching, short structured outputs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input cost&lt;/th&gt;
&lt;th&gt;Output cost&lt;/th&gt;
&lt;th&gt;Monthly total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;$28.00&lt;/td&gt;
&lt;td&gt;$2.80&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$30.80&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;$40.00&lt;/td&gt;
&lt;td&gt;$12.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$52.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;$300.00&lt;/td&gt;
&lt;td&gt;$75.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$375.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Input dominates, so this scenario tracks the input-price ratio closely: Gemini costs 12x DeepSeek, Luna 1.7x. Note how much the July 30 price cut changed Luna's position here. At the old $1 / $6 the same workload was $260 a month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario B, a coding agent loop.&lt;/strong&gt; 100M input tokens at a 70% cache hit rate and 40M output tokens per month.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Cached input&lt;/th&gt;
&lt;th&gt;Fresh input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Monthly total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;td&gt;$4.20&lt;/td&gt;
&lt;td&gt;$11.20&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$15.60&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;$1.40&lt;/td&gt;
&lt;td&gt;$6.00&lt;/td&gt;
&lt;td&gt;$48.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$55.40&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;$10.50&lt;/td&gt;
&lt;td&gt;$45.00&lt;/td&gt;
&lt;td&gt;$300.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$355.50&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That table holds tokens constant, which quietly assumes all three models write the same amount to do the same job. They do not. Holding the &lt;em&gt;work&lt;/em&gt; constant instead, and scaling output by the verbosity ratios from the index run, gives a fairer picture of the same agent loop:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Output tokens for equal work&lt;/th&gt;
&lt;th&gt;Monthly total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;142M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$44.16&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;88M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$113.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;40M (baseline)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$355.50&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;DeepSeek goes from 23x cheaper to 8x cheaper. The decision does not change. The number you put in a slide should.&lt;/p&gt;

&lt;p&gt;For the deeper version of this arithmetic on DeepSeek specifically, including what cache misses do to a real bill, see our V4 Pro cost breakdown and the DeepSeek V4 API pricing guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Pricing Details That Will Move Your Bill
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DeepSeek is about to introduce peak-hour pricing.&lt;/strong&gt; Its pricing docs carry a footnote: the API will adopt a peak/off-peak policy under which peak-hour prices are 2x regular prices, applicable to all billing items, with the effective date pending official announcement. The peak windows are 09:00 to 12:00 and 14:00 to 18:00 Beijing time, UTC+8.&lt;/p&gt;

&lt;p&gt;Translate that to your own clock before you assume it is harmless. Those windows land at 21:00 to 00:00 and 02:00 to 06:00 US Eastern, which is the middle of the night for a US-daytime workload, and at 03:00 to 06:00 and 08:00 to 12:00 Central European, which eats a European team's entire morning. If you run in Europe and DeepSeek turns this on, your $0.14 becomes $0.28 for the first half of the working day. That is still under Gemini, but it is not the number you budgeted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The route you buy through can differ from the vendor's list price.&lt;/strong&gt; OpenAI cut GPT-5.6 Luna by 80% on 2026-07-30, from $1 / $6 to $0.20 / $1.20. Listings that serve Luna through Azure had not moved at the 2026-08-01 snapshot, including ours, where &lt;code&gt;openai/gpt-5.6-luna&lt;/code&gt; is an Azure route showing $1 / $6 list. Same model ID, 5x apart, purely on which upstream you land on.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Route at snapshot&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Cached input&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;DeepSeek first-party&lt;/td&gt;
&lt;td&gt;$0.14&lt;/td&gt;
&lt;td&gt;$0.28&lt;/td&gt;
&lt;td&gt;$0.0028&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;Aliyun BaiLian&lt;/td&gt;
&lt;td&gt;$0.14&lt;/td&gt;
&lt;td&gt;$0.28&lt;/td&gt;
&lt;td&gt;$0.028&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Flash 0731&lt;/td&gt;
&lt;td&gt;Azure&lt;/td&gt;
&lt;td&gt;$0.19&lt;/td&gt;
&lt;td&gt;$0.51&lt;/td&gt;
&lt;td&gt;$0.19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;Google / Vertex&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;td&gt;$7.50&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.6 Flash&lt;/td&gt;
&lt;td&gt;Google batch or flex&lt;/td&gt;
&lt;td&gt;$0.75&lt;/td&gt;
&lt;td&gt;$3.75&lt;/td&gt;
&lt;td&gt;$0.075&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;OpenAI first-party&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;td&gt;$1.20&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;Azure&lt;/td&gt;
&lt;td&gt;$1.00&lt;/td&gt;
&lt;td&gt;$6.00&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two footnotes on that table. Our Luna listing was running a 20% promotion at snapshot, which takes the Azure route to an effective $0.80 / $4.80, still four times the OpenAI list price. And the cache-read column deserves its own look: on the Azure DeepSeek route, cache reads cost the same as fresh input, which deletes the single largest cost advantage this model has.&lt;/p&gt;

&lt;p&gt;The general rule the table teaches: check the route, not the model name. A price cut announced by a lab reaches that lab's own API immediately and everyone else on their own schedule. Two of the seven rows above are the same model at very different money.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Text-Only Actually Costs You
&lt;/h2&gt;

&lt;p&gt;The cheapest model in this comparison cannot see. DeepSeek V4 Flash 0731 accepts text, calls functions, returns JSON and speaks both the OpenAI and Anthropic wire formats, and that is the whole list. Gemini 3.6 Flash takes text, image, video, audio and PDF. GPT-5.6 Luna takes text and image.&lt;/p&gt;

&lt;p&gt;This is not a quality gap you can close with prompt engineering or a bigger budget. If your pipeline sends screenshots of a broken UI, scanned invoices, or frames from a video, the DeepSeek call does not fail gracefully at a higher price. It fails structurally. Every cost table above becomes irrelevant for that class of work, which is why the modality row sits near the top of the specs table rather than buried at the bottom.&lt;/p&gt;

&lt;p&gt;A common resolution is to split the traffic: multimodal requests to Gemini, everything else to DeepSeek, one router in front. That is more work than picking one model, and for a pipeline where 90% of requests are text it usually pays for itself in the first month.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Pick DeepSeek V4 Flash 0731
&lt;/h2&gt;

&lt;p&gt;Text-only workloads at volume, where the bill is a real line item. Anything with a high cache hit rate benefits disproportionately, because $0.0028/M cache reads are a 98% discount on fresh input, a 50x reduction. Long single generations favor it as well: 384K max output is six times Gemini's ceiling. It is also the only one of the three with published weights, MIT-licensed on Hugging Face, so if the plan is to prototype on an API and self-host later, this is the one with a path.&lt;/p&gt;

&lt;p&gt;Turn thinking off for bounded work. It is the difference between the $15.60 and the $44.16 rows above.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Pick Gemini 3.6 Flash
&lt;/h2&gt;

&lt;p&gt;Whenever a non-text modality is involved, which settles it before price enters the conversation. Also when latency is user-visible: 219.6 output tokens per second put it third of 185 models on AA's speed ranking at snapshot, and 15.11 seconds to first token is fast for a reasoning model. And when you want a third party to have measured the thing you are about to depend on, since AA has published speed and latency for Gemini and had not for the 0731 build.&lt;/p&gt;

&lt;p&gt;The batch tier is underrated. At $0.75 / $3.75 for work that tolerates delay, Gemini's effective distance from DeepSeek halves.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Pick GPT-5.6 Luna
&lt;/h2&gt;

&lt;p&gt;When you want the highest index score of the three and vision in the same model, and the 80% price cut has made that combination affordable in a way it was not three weeks ago. Luna at $0.20 / $1.20 is now closer to DeepSeek than to Gemini on price while scoring a point higher than both.&lt;/p&gt;

&lt;p&gt;Two things to check first. The 121.89 second time to first token that AA measured is the max-effort configuration, and max effort is not an interactive setting; if you use Luna in a UI, use a lower effort level. And confirm which route your gateway puts you on, because the pre-cut Azure tier is 5x the OpenAI list price. Our GPT-5.6 tier guide covers how Sol, Terra and Luna divide the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  When None of the Three Is the Right Answer
&lt;/h2&gt;

&lt;p&gt;If your workload is small, none of this matters. At a few million tokens a month the difference between the cheapest and most expensive option here is a rounding error against an hour of engineering time, and you should pick on capability and move on.&lt;/p&gt;

&lt;p&gt;If you are chasing zero, a hosted API is the wrong tool. The free and self-hosted paths for this model family are a separate exercise with real caps attached, covered in DeepSeek V4 Flash free: four zero-cost paths. Those paths were verified against the build that preceded 0731, so recheck the caps before relying on them. The self-host route has changed since: the 0731 weights are now on Hugging Face under MIT, so the license-free option applies to the current build rather than the April one.&lt;/p&gt;

&lt;p&gt;And if the job is deep multi-step agentic work with tool calls in the double digits, none of these three flash-tier models is an obvious fit. That is frontier-tier territory, and the honest answer is to benchmark on your own traces rather than on anyone's index. Our earlier Gemini Flash Lite vs DeepSeek V4 Flash agent-loop comparison walks through how tool-call reliability changes the math at depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try All Three via ofox: A/B in One Loop
&lt;/h2&gt;

&lt;p&gt;All three run on one OpenAI-compatible endpoint, so the comparison is a string swap rather than three integrations. The model IDs are &lt;code&gt;deepseek/deepseek-v4-flash&lt;/code&gt;, &lt;code&gt;google/gemini-3.6-flash&lt;/code&gt; and &lt;code&gt;openai/gpt-5.6-luna&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_OFOX_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;MODELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deepseek/deepseek-v4-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google/gemini-3.6-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-5.6-luna&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Refactor this function to remove the nested loop. Return only code.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; in=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt_tokens&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; out=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_tokens&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Log &lt;code&gt;completion_tokens&lt;/code&gt; and not just latency. That column is where the verbosity difference shows up on your own traffic, and it is the number the sticker price does not tell you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deepseek/deepseek-v4-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google/gemini-3.6-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai/gpt-5.6-luna&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Summarize this changelog in 3 bullets.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completion_tokens&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The call DeepSeek cannot run
&lt;/h3&gt;

&lt;p&gt;Same client, same endpoint, one content block that changes everything. Send this to &lt;code&gt;google/gemini-3.6-flash&lt;/code&gt; or &lt;code&gt;openai/gpt-5.6-luna&lt;/code&gt; and you get an answer. Send it to &lt;code&gt;deepseek/deepseek-v4-flash&lt;/code&gt; and there is no price at which it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;

&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;screenshot.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google/gemini-3.6-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Which element is misaligned?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data:image/png;base64,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;If none of the three fits, the neighbors worth checking are on the same endpoint. DeepSeek V4 Pro at $0.435 / $0.87 list, which the ofox listing rounds to $0.45 / $0.88, is now the more expensive and lower-scoring sibling on AA's index, though it remains the right call if you have workload-specific evidence that it wins on your traces. GPT-5.6 Terra sits above Luna when the flash tier is genuinely not enough. Outside the ofox catalog, the same models are available first-party from DeepSeek, Google AI Studio and the OpenAI API, which is the right choice if you only ever need one vendor and want the price cut the day it lands rather than whenever the route catches up.&lt;/p&gt;

&lt;p&gt;Model pages with live pricing: DeepSeek V4 Flash, Gemini 3.6 Flash, GPT-5.6 Luna.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/articles/deepseek-v4-flash-0731-scores-50-on-the-artificial-analysis-intelligence-index-10-points-above-previous-deepseek-v4-flash" rel="noopener noreferrer"&gt;https://artificialanalysis.ai/articles/deepseek-v4-flash-0731-scores-50-on-the-artificial-analysis-intelligence-index-10-points-above-previous-deepseek-v4-flash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/models/deepseek-v4-flash" rel="noopener noreferrer"&gt;https://artificialanalysis.ai/models/deepseek-v4-flash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/models/gemini-3-6-flash" rel="noopener noreferrer"&gt;https://artificialanalysis.ai/models/gemini-3-6-flash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/models/gpt-5-6-luna" rel="noopener noreferrer"&gt;https://artificialanalysis.ai/models/gpt-5-6-luna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://api-docs.deepseek.com/quick_start/pricing" rel="noopener noreferrer"&gt;https://api-docs.deepseek.com/quick_start/pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing?hl=en" rel="noopener noreferrer"&gt;https://ai.google.dev/gemini-api/docs/pricing?hl=en&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/3-6-flash" rel="noopener noreferrer"&gt;https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/3-6-flash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;https://developers.openai.com/api/docs/pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731" rel="noopener noreferrer"&gt;https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/deepseek-v4-flash-vs-gemini-3-6-flash-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>deepseek</category>
      <category>gemini</category>
      <category>benchmarks</category>
    </item>
    <item>
      <title>Codex CLI 401 Unauthorized: 9 Tested Causes and Lookalikes</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sat, 01 Aug 2026 11:37:09 +0000</pubDate>
      <link>https://dev.to/owen_fox/codex-cli-401-unauthorized-9-tested-causes-and-lookalikes-1m4c</link>
      <guid>https://dev.to/owen_fox/codex-cli-401-unauthorized-9-tested-causes-and-lookalikes-1m4c</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Codex CLI auth breaks in nine distinct ways, and only some of them arrive as a literal 401, which is exactly why the status code is the least useful part of the output. The message body is what identifies the cause. &lt;code&gt;Missing bearer or basic authentication in header&lt;/code&gt; means nothing was sent, and the surprise there is that exporting &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; does not help on the default provider. &lt;code&gt;Incorrect API key provided&lt;/code&gt; means your key arrived and was rejected. &lt;code&gt;You didn't provide an API key&lt;/code&gt; means the header was dropped in transit, almost always because the value ends with a newline. A local &lt;code&gt;Missing environment variable&lt;/code&gt; error is not a 401 at all, and neither is a 404 from a &lt;code&gt;base_url&lt;/code&gt; that lost its &lt;code&gt;/v1&lt;/code&gt;. Every case below was reproduced on Codex CLI 0.146.0 on 2026-07-30.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-Second Diagnosis
&lt;/h2&gt;

&lt;p&gt;Three checks, in this order. Most people skip the first one and spend twenty minutes re-issuing a key that was fine.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Did a request even happen?&lt;/td&gt;
&lt;td&gt;Look for &lt;code&gt;Missing environment variable&lt;/code&gt; in the output&lt;/td&gt;
&lt;td&gt;If present, Codex never made a network call. Your config points at a variable that is unset or empty.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. What does the 401 body say?&lt;/td&gt;
&lt;td&gt;Read the text after &lt;code&gt;401 Unauthorized:&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Three distinct messages, three distinct causes. See the table below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Does the key work at all?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;curl -s -o /dev/null -w "%{http_code}" -X POST https://api.ofox.ai/v1/responses -H "Authorization: Bearer $YOUR_KEY" -H "Content-Type: application/json" -d '{"model":"openai/gpt-5.5","input":"hi","max_output_tokens":16}'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200 means the key is good and the problem is in your Codex config. 401 means the key itself is the problem.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One trap in step 3 worth calling out early, because half the troubleshooting advice on the internet gets it wrong: &lt;strong&gt;do not use &lt;code&gt;/v1/models&lt;/code&gt; as a key check on an aggregator.&lt;/strong&gt; Tested on 2026-07-30, &lt;code&gt;https://api.ofox.ai/v1/models&lt;/code&gt; returns &lt;code&gt;200&lt;/code&gt; with the full catalog when sent with a bogus key, and also with no &lt;code&gt;Authorization&lt;/code&gt; header at all. The model catalog is public. OpenAI's own &lt;code&gt;api.openai.com/v1/models&lt;/code&gt; does return 401 without a key, which is where the habit comes from, but the habit does not transfer. Use an endpoint that actually runs inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Fix This, When to Switch, and When to Stop
&lt;/h2&gt;

&lt;p&gt;Auth failures are cheap to fix when you know which one you have, and expensive when you guess. Rough rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fix it&lt;/strong&gt; when the message names a specific cause: &lt;code&gt;Missing environment variable&lt;/code&gt;, &lt;code&gt;Incorrect API key provided&lt;/code&gt;, or anything mentioning a refresh token. These have deterministic one-step fixes and take under two minutes each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch the auth path&lt;/strong&gt; when you are three attempts deep on the ChatGPT login flow. The API key path has fewer moving parts (no refresh tokens, no browser round trip, no 8-day refresh window), and if you are automating anything, it is the only path that survives a container restart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop and check something else&lt;/strong&gt; if you get 404 instead of 401, or if the CLI refuses to start with a config error. Those are not auth problems and no amount of key rotation will move them. Same if the error mentions a usage limit rather than authorization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The one case where re-issuing a key is the right first move is &lt;code&gt;Incorrect API key provided&lt;/code&gt; with the masked suffix shown in the error matching the key you think you are using. If the suffix does not match, you have a config problem, not a key problem, and a new key will fail identically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the 401: Three Messages, Three Causes
&lt;/h2&gt;

&lt;p&gt;This is the core table. Every row was reproduced against a live endpoint.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Message body&lt;/th&gt;
&lt;th&gt;What actually happened&lt;/th&gt;
&lt;th&gt;Where it comes from&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Missing bearer or basic authentication in header&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No credential was attached to the request&lt;/td&gt;
&lt;td&gt;Default OpenAI provider with no login, or with only &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; exported&lt;/td&gt;
&lt;td&gt;`printenv OPENAI_API_KEY \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{% raw %}&lt;code&gt;Incorrect API key provided: sk-proj-****7890&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Header arrived, server rejected the value&lt;/td&gt;
&lt;td&gt;Wrong, revoked, or cross-account key in auth.json&lt;/td&gt;
&lt;td&gt;Re-issue the key, or log out and log in with the right one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Invalid or expired API key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same as above, gateway-side wording&lt;/td&gt;
&lt;td&gt;Custom provider whose &lt;code&gt;env_key&lt;/code&gt; value is wrong or quote-wrapped&lt;/td&gt;
&lt;td&gt;Check the variable's exact bytes, not just that it is set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Header was malformed and dropped&lt;/td&gt;
&lt;td&gt;Newline embedded in the key value&lt;/td&gt;
&lt;td&gt;Strip the trailing newline from the variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Your access token could not be refreshed...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ChatGPT OAuth refresh failed&lt;/td&gt;
&lt;td&gt;Expired, reused, or revoked refresh token&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;codex logout&lt;/code&gt; then sign in again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Missing environment variable: 'X'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not a 401. No request was made&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;env_key&lt;/code&gt; names a variable that is unset or empty&lt;/td&gt;
&lt;td&gt;Export the variable in the shell that launches Codex&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two details from the test runs that make the output easier to read. On the default OpenAI provider, Codex first tries a WebSocket transport against &lt;code&gt;wss://api.openai.com/v1/responses&lt;/code&gt;, retries five times, then falls back to HTTPS and retries five more, so a single auth failure produces roughly ten error lines before the real message. On a custom provider, WebSocket transport is off (&lt;code&gt;codex doctor&lt;/code&gt; reports &lt;code&gt;supports websockets: false&lt;/code&gt;), so you get one retry loop and a cleaner failure. If you are staring at a wall of &lt;code&gt;Reconnecting... 4/5&lt;/code&gt;, scroll to the bottom; the last line is the one that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: You Exported OPENAI_API_KEY and Assumed That Was Enough
&lt;/h2&gt;

&lt;p&gt;This is the single most common one, and it is counterintuitive enough that it deserves the top slot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-proj-..."&lt;/span&gt;
codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"say hi"&lt;/span&gt;
&lt;span class="c"&gt;# ERROR: unexpected status 401 Unauthorized: Missing bearer or basic&lt;/span&gt;
&lt;span class="c"&gt;# authentication in header, url: https://api.openai.com/v1/responses&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note what the server said: &lt;code&gt;Missing bearer&lt;/code&gt;. Not "your key is wrong". Nothing was sent. The default provider in Codex 0.146.0 reads credentials from &lt;code&gt;$CODEX_HOME/auth.json&lt;/code&gt;, not from the environment. Setting the variable changes nothing.&lt;/p&gt;

&lt;p&gt;The single-variable proof: take the exact same invalid key, write it into auth.json instead of the environment, and the message changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"sk-proj-invalidkeyfortesting1234567890"&lt;/span&gt; | codex login &lt;span class="nt"&gt;--with-api-key&lt;/span&gt;
codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"say hi"&lt;/span&gt;
&lt;span class="c"&gt;# ERROR: unexpected status 401 Unauthorized: Incorrect API key provided:&lt;/span&gt;
&lt;span class="c"&gt;# sk-proj-**************************7890 ... auth error code: invalid_api_key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same key, different message. The first run never sent it; the second did and got it rejected. That difference is the whole diagnostic.&lt;/p&gt;

&lt;p&gt;Write the key where Codex will actually look for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printenv &lt;/span&gt;OPENAI_API_KEY | codex login &lt;span class="nt"&gt;--with-api-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment variables do work, but only through a custom provider's &lt;code&gt;env_key&lt;/code&gt; field, which is a different mechanism covered further down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: You Used the Old --api-key Flag
&lt;/h2&gt;

&lt;p&gt;If you followed a tutorial written before mid-2026:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex login &lt;span class="nt"&gt;--api-key&lt;/span&gt; &lt;span class="s2"&gt;"sk-proj-..."&lt;/span&gt;
&lt;span class="c"&gt;# The --api-key flag is no longer supported. Pipe the key instead,&lt;/span&gt;
&lt;span class="c"&gt;# e.g. `printenv OPENAI_API_KEY | codex login --with-api-key`.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The message is clear, but it exits without writing anything, and in a setup script the output scrolls past. The next command then fails with &lt;code&gt;Missing bearer&lt;/code&gt; and the key gets blamed. Check that auth.json exists and contains what you expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/.codex/auth.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"auth_mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apikey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"OPENAI_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sk-proj-..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 3: env_key Points at a Variable That Is Not Set (Not a 401)
&lt;/h2&gt;

&lt;p&gt;With a custom provider block, Codex reads the key from the environment variable you name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"openai/gpt-5.5"&lt;/span&gt;
&lt;span class="py"&gt;model_provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ofox"&lt;/span&gt;

&lt;span class="nn"&gt;[model_providers.ofox]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ofox"&lt;/span&gt;
&lt;span class="py"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.ofox.ai/v1"&lt;/span&gt;
&lt;span class="py"&gt;env_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"OFOX_API_KEY"&lt;/span&gt;
&lt;span class="py"&gt;wire_api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"responses"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;OFOX_API_KEY&lt;/code&gt; is unset, you do not get a 401. You get a local error and no network call at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Missing environment variable: `OFOX_API_KEY`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An empty string produces the identical error, which matches the source: model-provider-info/src/lib.rs filters the variable with &lt;code&gt;!v.trim().is_empty()&lt;/code&gt; before using it. So &lt;code&gt;export OFOX_API_KEY=""&lt;/code&gt; and never exporting it are the same thing as far as Codex is concerned.&lt;/p&gt;

&lt;p&gt;This one bites hardest in launchd, systemd, and Docker, where the shell that starts Codex is not the shell where you exported the variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: A Newline in the Key Value
&lt;/h2&gt;

&lt;p&gt;This is the nastiest of the set, because the error accuses you of not providing a key that you can see with your own eyes in &lt;code&gt;printenv&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/keys/ofox.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;   &lt;span class="c"&gt;# file ends with a newline&lt;/span&gt;
codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"hi"&lt;/span&gt;
&lt;span class="c"&gt;# ERROR: unexpected status 401 Unauthorized: You didn't provide an API key.&lt;/span&gt;
&lt;span class="c"&gt;# You need to provide your API key in an Authorization header using Bearer&lt;/span&gt;
&lt;span class="c"&gt;# auth (i.e. Authorization: Bearer YOUR_KEY). [ofox.ai]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The header was built with a newline inside it and dropped on the floor. The server genuinely never saw a credential, so its message is accurate; it just sounds like you forgot to set anything.&lt;/p&gt;

&lt;p&gt;Worth knowing what is &lt;em&gt;not&lt;/em&gt; a cause here, because it is the obvious suspect and it is innocent: a trailing space is fine. Tested with &lt;code&gt;export OFOX_API_KEY="$REAL "&lt;/code&gt; and the request succeeded. Note that Codex is not cleaning it up for you: the &lt;code&gt;trim()&lt;/code&gt; in &lt;code&gt;api_key()&lt;/code&gt; is an emptiness check only, and the value it returns is the raw one, trailing space included. Something downstream tolerates it. A newline, by contrast, breaks the header outright. Either way, do not spend time hunting for stray spaces.&lt;/p&gt;

&lt;p&gt;A quoted value, on the other hand, does fail, with different wording:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'"sk-..."'&lt;/span&gt;   &lt;span class="c"&gt;# literal quote characters in the value&lt;/span&gt;
&lt;span class="c"&gt;# ERROR: unexpected status 401 Unauthorized: Invalid or expired API key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one is common when a &lt;code&gt;.env&lt;/code&gt; file is loaded with a naive &lt;code&gt;export $(cat .env | xargs)&lt;/code&gt; that keeps the quotes.&lt;/p&gt;

&lt;p&gt;Strip the offending bytes at export time and confirm the length:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'\n\r"'&lt;/span&gt; &amp;lt; ~/keys/ofox.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OFOX_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;   &lt;span class="c"&gt;# confirm the byte count matches the key length&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 5: The Provider Block Is Missing env_key Entirely
&lt;/h2&gt;

&lt;p&gt;The quietest failure of the nine. Delete one line from the config above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[model_providers.ofox]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ofox"&lt;/span&gt;
&lt;span class="py"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.ofox.ai/v1"&lt;/span&gt;
&lt;span class="py"&gt;wire_api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"responses"&lt;/span&gt;
&lt;span class="c"&gt;# env_key line deleted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codex does not complain. It falls back to the credential in auth.json, which for most people is an OpenAI key, and sends that to the gateway. The gateway rejects it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: unexpected status 401 Unauthorized: Invalid or expired API key,
url: https://api.ofox.ai/v1/responses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your environment variable is set correctly. Your key is valid. The error says the key is invalid, because a different key was sent. Tested both ways on the same shell: with &lt;code&gt;env_key&lt;/code&gt; present the request returns a normal completion, with the line deleted it 401s.&lt;/p&gt;

&lt;p&gt;The inverse is also worth knowing, and it is good news: when &lt;code&gt;env_key&lt;/code&gt; is present, it wins over auth.json. Tested with a deliberately bogus key stored in auth.json and a valid one in the environment variable, the request succeeded. You do not need to log out before configuring a custom provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 6: The ChatGPT Login Path Expired
&lt;/h2&gt;

&lt;p&gt;If you signed in with a ChatGPT subscription rather than an API key, the failure looks completely different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Your access token could not be refreshed. Please log out and sign in again.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the endpoint in the surrounding log lines: &lt;code&gt;wss://chatgpt.com/backend-api/codex/responses&lt;/code&gt;, not &lt;code&gt;api.openai.com&lt;/code&gt;. The two login modes talk to different backends, which is a fast way to tell which one you are actually on.&lt;/p&gt;

&lt;p&gt;Codex 0.146.0 prints one of five variants here, and they are not interchangeable. From login/src/auth/manager.rs at tag &lt;code&gt;rust-v0.146.0&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;What it means in practice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...because your refresh token has expired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Genuine expiry. Sign in again.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...because your refresh token was already used&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Two clients raced on the same auth.json. Copied config or a shared container image.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...because your refresh token was revoked&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Session killed server-side, often by a password change or a sign-out elsewhere.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;...could not be refreshed.&lt;/code&gt; (no reason)&lt;/td&gt;
&lt;td&gt;Refresh endpoint returned something unclassified. Sign in again.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...because you have since logged out or signed in to another account&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The stored account no longer matches the active one.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The "already used" variant is the one that surprises people. Refresh tokens are single-use, so baking an &lt;code&gt;auth.json&lt;/code&gt; into a Docker image or syncing &lt;code&gt;~/.codex&lt;/code&gt; across two laptops gives you an auth setup that works on whichever machine refreshes first and breaks on the other. The same source file sets &lt;code&gt;TOKEN_REFRESH_INTERVAL&lt;/code&gt; to 8 days, so a machine idle for more than a week will attempt a proactive refresh on its next run, which is usually when the conflict surfaces.&lt;/p&gt;

&lt;p&gt;There is one fix and it is the blunt one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex &lt;span class="nb"&gt;logout
&lt;/span&gt;codex login          &lt;span class="c"&gt;# browser flow&lt;/span&gt;
&lt;span class="c"&gt;# or, for anything automated:&lt;/span&gt;
&lt;span class="nb"&gt;printenv &lt;/span&gt;OPENAI_API_KEY | codex login &lt;span class="nt"&gt;--with-api-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For unattended environments, prefer the API key path. It has no refresh semantics to get out of sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 7: codex login status Told You Everything Was Fine
&lt;/h2&gt;

&lt;p&gt;It lies, in two different ways, and both were reproduced.&lt;/p&gt;

&lt;p&gt;With a hand-built &lt;code&gt;auth.json&lt;/code&gt; containing an expired ChatGPT token, every request failed with the refresh error above, while:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex login status
&lt;span class="c"&gt;# Logged in using ChatGPT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And under a custom provider, &lt;code&gt;status&lt;/code&gt; reports the key sitting in auth.json, which is not the key being used for requests at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex login status
&lt;span class="c"&gt;# Logged in using an API key - sk-proj-***n-999&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both outputs describe the contents of a file. Neither performs a network check. Use them to answer "is a credential stored", never "does my auth work". For the latter, run the curl from the 30-second diagnosis, or just run &lt;code&gt;codex exec "hi"&lt;/code&gt; and read the last line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;codex doctor&lt;/code&gt; is more useful here. Its Configuration section shows which config.toml was loaded and whether it parsed, the auth storage mode, and which auth environment variables it can see; its Connectivity section reports the active provider, wire API, whether WebSocket transport applies, and whether the endpoint is reachable. It still does not validate the credential, but it will tell you within a second if Codex is reading a different config file than the one you have been editing, which is a surprisingly frequent root cause when &lt;code&gt;CODEX_HOME&lt;/code&gt; is set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 8: auth.json Is Corrupt (Not a 401)
&lt;/h2&gt;

&lt;p&gt;Rarer, but it produces an error that looks nothing like an auth problem, which is exactly why it costs time. A truncated or hand-edited &lt;code&gt;auth.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"hi"&lt;/span&gt;
&lt;span class="c"&gt;# EOF while parsing a value at line 2 column 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No mention of authentication, no HTTP status, no file path. This happens after an interrupted &lt;code&gt;codex login&lt;/code&gt;, a partially synced file, or a hand edit that dropped a closing brace. The file is small enough to inspect directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool ~/.codex/auth.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"valid JSON"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it does not parse, delete it and log in again. There is nothing in it worth recovering; it is either an API key you can re-paste or OAuth tokens that will be reissued.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 9: Codex Is Reading a Different Config Than the One You Edited
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;CODEX_HOME&lt;/code&gt; relocates both &lt;code&gt;config.toml&lt;/code&gt; and &lt;code&gt;auth.json&lt;/code&gt;. If it is set in your shell profile, in a wrapper script, or by a tool that launched Codex for you, every edit you make to &lt;code&gt;~/.codex/config.toml&lt;/code&gt; is going into a file Codex never opens. The symptom is a 401 that survives changes that should have fixed it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;codex doctor&lt;/code&gt; answers this in one line, under its state section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CODEX_HOME  /private/tmp/codex401/home7 (dir)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and under Configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config.toml  /private/tmp/codex401/home7/config.toml
config.toml parse  ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that path is not the file you have been editing, stop debugging the key.&lt;/p&gt;

&lt;p&gt;The same command flags a second version of this problem. On a machine where Codex is installed both globally and locally, &lt;code&gt;doctor&lt;/code&gt; prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✗ install   npm install -g @openai/codex would update a different install
✗ updates   update would target a different npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read literally, that means the update command targets a different package root than the binary you are running, so an upgrade meant to pick up an auth fix can leave the running copy untouched. Worth resolving before you conclude that a version bump did not help.&lt;/p&gt;

&lt;h3&gt;
  
  
  One thing exit codes will not tell you
&lt;/h3&gt;

&lt;p&gt;Every failure mode in this article exits &lt;code&gt;1&lt;/code&gt;. No credential, missing environment variable, config parse error, corrupt auth.json, rejected key: all &lt;code&gt;1&lt;/code&gt;. If you are wrapping Codex in a script and branching on the exit status, you cannot distinguish "your key is wrong" from "your config file has a typo". Capture stderr and match on the message text instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"ping"&lt;/span&gt; 2&amp;gt;&amp;amp;1&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"Missing environment variable"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"config points at an unset variable"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"Missing bearer"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"no credential was sent"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"Incorrect API key"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"Invalid or expired API key"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"credential rejected"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"could not be refreshed"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ChatGPT session expired, log in again"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"other failure: &lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Two Things That Look Like 401 and Are Not
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;base_url&lt;/code&gt; missing its &lt;code&gt;/v1&lt;/code&gt; gives you a 404, not a 401:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: unexpected status 404 Not Found: 404 page not found,
url: https://api.ofox.ai/responses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;404 page not found&lt;/code&gt; with a URL that is missing a path segment you expected, fix the URL and stop looking at credentials.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wire_api = "chat"&lt;/code&gt; fails before any request, at config load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error loading config.toml: `wire_api = "chat"` is no longer supported.
How to fix: set `wire_api = "responses"` in your provider config.
More info: https://github.com/openai/codex/discussions/7782
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;chat&lt;/code&gt; value was removed; the enum has a single &lt;code&gt;Responses&lt;/code&gt; variant left. Any gateway you point Codex at has to expose a Responses-compatible endpoint. This trips people migrating from older configs, and because it kills the process at startup it sometimes gets filed as "auth broke after upgrade". It did not.&lt;/p&gt;

&lt;p&gt;A third near-miss: if you are behind a corporate proxy, the failure mode is usually a TLS or connect error rather than 401, and the fix is a different one entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixes by Auth Mode
&lt;/h2&gt;

&lt;p&gt;The same symptom needs a different fix depending on how you authenticate. This is the table to bookmark.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Auth mode&lt;/th&gt;
&lt;th&gt;Where the credential lives&lt;/th&gt;
&lt;th&gt;Most likely 401 cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT subscription&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;auth.json&lt;/code&gt; OAuth tokens&lt;/td&gt;
&lt;td&gt;Refresh token expired or reused across machines&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;codex logout&lt;/code&gt; then &lt;code&gt;codex login&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI API key&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;auth.json&lt;/code&gt; &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; field&lt;/td&gt;
&lt;td&gt;Key never written (old &lt;code&gt;--api-key&lt;/code&gt; flag, or only exported to the env)&lt;/td&gt;
&lt;td&gt;`printenv OPENAI_API_KEY \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom gateway provider&lt;/td&gt;
&lt;td&gt;Environment variable named by {% raw %}&lt;code&gt;env_key&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Variable unset in the launching shell, newline in the value, or &lt;code&gt;env_key&lt;/code&gt; line missing from the config&lt;/td&gt;
&lt;td&gt;Export in the right shell, strip newlines, confirm the line exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated or container&lt;/td&gt;
&lt;td&gt;Environment variable, injected at runtime&lt;/td&gt;
&lt;td&gt;Baked-in &lt;code&gt;auth.json&lt;/code&gt; with single-use refresh tokens&lt;/td&gt;
&lt;td&gt;Use the API key path, inject the key as an env var, never ship auth.json in an image&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For container and CI setups specifically: mount nothing from &lt;code&gt;~/.codex&lt;/code&gt;, set the variable in the container environment, and use a custom provider block with &lt;code&gt;env_key&lt;/code&gt;. That combination has no refresh state and no file to go stale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Failure Patterns, With What Each One Actually Prints
&lt;/h2&gt;

&lt;p&gt;Everything above, in one grid. Reproduced on Codex CLI 0.146.0 on 2026-07-30, macOS, against &lt;code&gt;api.openai.com&lt;/code&gt; for default-provider rows and &lt;code&gt;api.ofox.ai&lt;/code&gt; for custom-provider rows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;No credential anywhere&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Missing bearer or basic authentication in header&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;OPENAI_API_KEY&lt;/code&gt; exported, default provider&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Missing bearer or basic authentication in header&lt;/code&gt; (identical to #1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Invalid key written via &lt;code&gt;--with-api-key&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Incorrect API key provided: sk-proj-****7890&lt;/code&gt;, &lt;code&gt;auth error code: invalid_api_key&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;codex login --api-key&lt;/code&gt; (old flag)&lt;/td&gt;
&lt;td&gt;exits&lt;/td&gt;
&lt;td&gt;&lt;code&gt;The --api-key flag is no longer supported&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Custom provider, &lt;code&gt;env_key&lt;/code&gt; variable unset&lt;/td&gt;
&lt;td&gt;local error&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Missing environment variable: 'OFOX_API_KEY'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Custom provider, &lt;code&gt;env_key&lt;/code&gt; variable empty string&lt;/td&gt;
&lt;td&gt;local error&lt;/td&gt;
&lt;td&gt;identical to #5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Custom provider, invalid key&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Invalid or expired API key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Custom provider, key wrapped in literal quotes&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Invalid or expired API key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Custom provider, key with trailing space&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;request succeeds, the trailing space is tolerated downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Custom provider, key with trailing newline&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;&lt;code&gt;You didn't provide an API key...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Custom provider, &lt;code&gt;env_key&lt;/code&gt; line deleted from config&lt;/td&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Invalid or expired API key&lt;/code&gt; (auth.json key sent instead)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Bogus key in auth.json, valid key in &lt;code&gt;env_key&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;env_key&lt;/code&gt; takes precedence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;ChatGPT auth.json, stale refresh token&lt;/td&gt;
&lt;td&gt;refresh error&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Your access token could not be refreshed...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;base_url&lt;/code&gt; missing &lt;code&gt;/v1&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;404&lt;/td&gt;
&lt;td&gt;&lt;code&gt;404 page not found&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wire_api = "chat"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;config error&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wire_api = "chat" is no longer supported&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rows 9 and 12 are the two that save time by ruling things out. If you have been hunting for whitespace or assuming you need to log out before configuring a gateway, both of those are dead ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Cannot Fix the Credential: Alternatives That Work Now
&lt;/h2&gt;

&lt;p&gt;If the auth path itself is the obstacle rather than a typo, you have a few options.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;What it solves&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API key instead of ChatGPT login&lt;/td&gt;
&lt;td&gt;Removes refresh tokens, browser flows, and the 8-day refresh window&lt;/td&gt;
&lt;td&gt;Metered per token instead of covered by a subscription&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A gateway provider with &lt;code&gt;env_key&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;One key, one variable, works in containers and CI without a login step&lt;/td&gt;
&lt;td&gt;Requires a Responses-compatible endpoint, so per-model support varies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A second provider block as a manual fallback&lt;/td&gt;
&lt;td&gt;Lets you switch with &lt;code&gt;--config model_provider=...&lt;/code&gt; when one credential dies&lt;/td&gt;
&lt;td&gt;Manual, not automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A different agent&lt;/td&gt;
&lt;td&gt;OpenCode reads provider credentials straight from environment variables with no login step&lt;/td&gt;
&lt;td&gt;Different tool, different defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The gateway route is the one that removes the most moving parts for automated setups, because there is no login step to expire. Ofox works as one: it exposes &lt;code&gt;/v1/responses&lt;/code&gt;, so the &lt;code&gt;wire_api = "responses"&lt;/code&gt; requirement is satisfied, and a single &lt;code&gt;OFOX_API_KEY&lt;/code&gt; reaches models from several vendors, which means a credential problem with one upstream does not leave you with nothing to run. Support is per model rather than per gateway, so check the model you want before committing. The setup block is the one shown in Cause 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Keep This From Recurring
&lt;/h2&gt;

&lt;p&gt;A few habits that prevent most repeat incidents:&lt;/p&gt;

&lt;p&gt;Verify with a real request, not a catalog call. Put this in your setup script rather than a &lt;code&gt;/v1/models&lt;/code&gt; ping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.ofox.ai/v1/responses &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OFOX_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model":"openai/gpt-5.5","input":"ping","max_output_tokens":16}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"auth check failed: HTTP &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guard against the newline at the point of export, not after the fact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'\n\r'&lt;/span&gt; &amp;lt; ~/keys/ofox.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never ship &lt;code&gt;auth.json&lt;/code&gt; in an image or sync it between machines. Single-use refresh tokens make that a race by design. Inject a key through the environment instead.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;codex doctor&lt;/code&gt; after any config change. It catches the wrong-&lt;code&gt;CODEX_HOME&lt;/code&gt; and config-did-not-parse cases in about a second, which are the two failures most likely to make you doubt a perfectly good key.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/codex-cli-401-unauthorized-fix-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codexcli</category>
      <category>troubleshooting</category>
      <category>api</category>
    </item>
    <item>
      <title>OpenCode vs Codex CLI: Terminal AI Coding Agent Compared (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Fri, 31 Jul 2026 11:36:06 +0000</pubDate>
      <link>https://dev.to/owen_fox/opencode-vs-codex-cli-terminal-ai-coding-agent-compared-2026-5fm7</link>
      <guid>https://dev.to/owen_fox/opencode-vs-codex-cli-terminal-ai-coding-agent-compared-2026-5fm7</guid>
      <description>&lt;h1&gt;
  
  
  OpenCode vs Codex CLI: Terminal AI Coding Agent Compared (2026)
&lt;/h1&gt;

&lt;p&gt;OpenCode (190k stars, MIT, any model) vs Codex CLI (Rust, Apache-2.0, GPT-5-Codex). One is model-agnostic, one is OpenAI-native. Pick by your stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: Which One Should You Pick?
&lt;/h2&gt;

&lt;p&gt;Skip the essay if you already know your constraints. Here is the decision by scenario.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You run Claude, GPT, and open-weight models depending on the task&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Model-agnostic by design, swap without restarting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You are all-in on OpenAI and want GPT-5-Codex tuned in&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;First-party defaults, no gateway needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You auto-approve shell commands and need real isolation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OS-level sandbox is more hardened&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a desktop app and IDE extension, not just a TUI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ships TUI, desktop, and editor surfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want one API key for every model&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Codex needs the Responses API, which not every proxied model exposes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You care about avoiding single-vendor lock-in&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Community-governed, MIT, no default vendor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You migrate from Claude Code and want an import path&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in import of Claude Code and Cursor config&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both are free and open source. Both run in your terminal. The split is philosophy, not price.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Five-Minute Comparison
&lt;/h2&gt;

&lt;p&gt;The specs that change how each one feels day to day, verified against each project's repository and docs on 2026-07-29.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;OpenCode&lt;/th&gt;
&lt;th&gt;Codex CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Maintainer&lt;/td&gt;
&lt;td&gt;Anomaly (community, formerly sst)&lt;/td&gt;
&lt;td&gt;OpenAI (first-party)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;anomalyco/opencode&lt;/code&gt; (old &lt;code&gt;sst/opencode&lt;/code&gt; links 301 here)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openai/codex&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latest release&lt;/td&gt;
&lt;td&gt;v1.18.9 (2026-07-28)&lt;/td&gt;
&lt;td&gt;0.146.0 (2026-07-29)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub stars&lt;/td&gt;
&lt;td&gt;~190,800&lt;/td&gt;
&lt;td&gt;~102,400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm i -g opencode-ai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm i -g @openai/codex&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default model&lt;/td&gt;
&lt;td&gt;None, you choose&lt;/td&gt;
&lt;td&gt;OpenAI GPT-5-Codex family&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model support&lt;/td&gt;
&lt;td&gt;Any of 75+ providers via models.dev&lt;/td&gt;
&lt;td&gt;OpenAI, plus gateways that expose the Responses API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.config/opencode/opencode.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.codex/config.toml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project instructions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Surfaces&lt;/td&gt;
&lt;td&gt;TUI, desktop app, IDE extension&lt;/td&gt;
&lt;td&gt;TUI, non-interactive exec, mobile remote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandbox&lt;/td&gt;
&lt;td&gt;Permission prompts&lt;/td&gt;
&lt;td&gt;OS sandbox (seatbelt / Landlock) plus approvals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two lines in that table carry most of the weight. "Default model: none" is the whole OpenCode thesis. "Default model: GPT-5-Codex" is the whole Codex thesis. Everything else follows from those two facts.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenCode: The Model-Agnostic Harness
&lt;/h2&gt;

&lt;p&gt;OpenCode treats the model as a runtime argument, not a product decision. It ships with no default provider. On first run you connect one, and from there the model is a thing you pick per session, or per message, from a list of 75+ providers wired in through &lt;a href="https://models.dev" rel="noopener noreferrer"&gt;models.dev&lt;/a&gt;. Claude, GPT, Gemini, GLM, a local Ollama build, they are all just entries in &lt;code&gt;/models&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That design has a few real consequences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You are not tied to anyone's roadmap.&lt;/strong&gt; When a new model lands and shows up in the models.dev registry, it shows up in OpenCode without a client update. The harness does not care who made the model, which is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is a full agent, not a thin wrapper.&lt;/strong&gt; OpenCode runs a plan agent and a build agent, switchable with a keystroke. Plan mode is read-only and proposes an approach without touching files; build mode executes. It integrates Language Server Protocol servers, so for TypeScript, Python, Rust, Go, and a long tail of other languages, the model sees real type information and compiler diagnostics rather than guessing from raw text. It speaks MCP, supports custom tools, and runs multiple sessions in parallel on the same project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is not only a terminal tool.&lt;/strong&gt; Alongside the TUI there is a desktop app and an IDE extension. If you want the agent loop but not the terminal, OpenCode has a surface for you. Codex leans harder into the terminal and the exec pipeline.&lt;/p&gt;

&lt;p&gt;Where it bites: model-agnostic means you own the model decision, including the failure modes. Point OpenCode at a weak or misconfigured provider and you get weak or misconfigured output, and the harness will not save you from a bad routing choice. There is also a known rough edge in the provider registry. On a brand-new install, a freshly added provider can fail to appear on the very first invocation because the registry cache has not been written yet. Run the models command once to warm it, and it resolves. Worth knowing before you script a setup and assume the first call is authoritative.&lt;/p&gt;

&lt;p&gt;OpenCode treats the model as a runtime argument, not a product decision. That single choice is why it wins the multi-model case and loses the "just works out of the box" one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codex CLI: OpenAI's First-Party Agent
&lt;/h2&gt;

&lt;p&gt;Codex CLI comes from OpenAI, and it shows in every design decision. It is written in Rust, so it is a fast single binary rather than a Node process. It ships pointed at OpenAI's own endpoint and the Codex-tuned GPT-5 models, and for the default user that means zero configuration: install, authenticate with your ChatGPT account or an API key, and start coding.&lt;/p&gt;

&lt;p&gt;The strengths cluster around trust and safety.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The sandbox is the best in this comparison.&lt;/strong&gt; Codex isolates command execution with OS-level primitives, seatbelt on macOS, Landlock and seccomp on Linux, and puts approval modes on top. You choose how much rope the agent gets: suggest only, auto-edit within the workspace, or full auto inside the sandbox. An agent-run &lt;code&gt;rm&lt;/code&gt; is confined by construction, not by the model choosing to behave. If you auto-approve tasks or run anything you did not write, that isolation is the feature you are actually buying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is a first-party citizen of the OpenAI stack.&lt;/strong&gt; The &lt;code&gt;/review&lt;/code&gt; command does inline code review without touching your working tree. Subagents parallelize work. Codex Remote lets you drive a connected Mac or Windows host from the ChatGPT mobile app. The &lt;code&gt;/import&lt;/code&gt; command pulls Cursor and Claude Code settings, MCP servers, plugins, and commands into Codex, which makes migration a command rather than a weekend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is not locked to OpenAI, despite the defaults.&lt;/strong&gt; Add a &lt;code&gt;[model_providers.&amp;lt;id&amp;gt;]&lt;/code&gt; block to &lt;code&gt;~/.codex/config.toml&lt;/code&gt; pointing at a compatible gateway and Codex will call whatever that gateway serves. The door is there. You just have to open it by hand, which is the honest difference from OpenCode, where the door is open by default.&lt;/p&gt;

&lt;p&gt;The catch is which protocol counts as compatible, and the answer changed. Codex used to accept &lt;code&gt;wire_api = "chat"&lt;/code&gt;, meaning any Chat Completions endpoint. That value is gone. In the 0.146.0 source the &lt;code&gt;WireApi&lt;/code&gt; enum has exactly one variant left, &lt;code&gt;Responses&lt;/code&gt;, and passing &lt;code&gt;chat&lt;/code&gt; is not ignored, it is a hard startup error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;wire_api = "chat"&lt;/code&gt; is no longer supported. How to fix: set &lt;code&gt;wire_api = "responses"&lt;/code&gt; in your provider config.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That message links to &lt;a href="https://github.com/openai/codex/discussions/7782" rel="noopener noreferrer"&gt;discussion #7782&lt;/a&gt;, filed under the title "Deprecating &lt;code&gt;chat/completions&lt;/code&gt; support in Codex," which is about as unambiguous as deprecations get. Chat Completions is the near-universal dialect. The Responses API is not. Every tutorial written before that change now produces a config that will not load, and every gateway that only proxies Chat Completions is now out of reach.&lt;/p&gt;

&lt;p&gt;Where it bites: the OpenAI-first defaults are a comfort until you want to leave. Model freedom in Codex is a config task, not a menu, and the protocol boundary is real and has moved in OpenAI's favor. You cannot point &lt;code&gt;base_url&lt;/code&gt; at Anthropic's native API and expect it to work, because that is not the Responses API. You route non-OpenAI models through a Responses-capable gateway or you do not route them at all, and as the next section shows, "Responses-capable" turns out to be a per-model property rather than a per-gateway one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Head-to-Head: The Differences That Change Your Day
&lt;/h2&gt;

&lt;p&gt;Six dimensions, and who takes each. "Winner" here means "better for most people optimizing for that axis," not a universal verdict.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;OpenCode&lt;/th&gt;
&lt;th&gt;Codex CLI&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model freedom&lt;/td&gt;
&lt;td&gt;Any provider, swap live&lt;/td&gt;
&lt;td&gt;OpenAI default, others only if served over Responses&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandbox and safety&lt;/td&gt;
&lt;td&gt;Permission prompts&lt;/td&gt;
&lt;td&gt;OS-level sandbox plus approvals&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Out-of-box setup&lt;/td&gt;
&lt;td&gt;Choose a provider first&lt;/td&gt;
&lt;td&gt;Install and go on OpenAI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Surfaces&lt;/td&gt;
&lt;td&gt;TUI, desktop, IDE&lt;/td&gt;
&lt;td&gt;TUI, exec, mobile remote&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Governance and lock-in&lt;/td&gt;
&lt;td&gt;Community, MIT, no vendor&lt;/td&gt;
&lt;td&gt;First-party OpenAI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration from Claude Code&lt;/td&gt;
&lt;td&gt;Shared AGENTS.md convention&lt;/td&gt;
&lt;td&gt;Built-in import command&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you scan that column, the pattern is clear. OpenCode wins on freedom and independence. Codex wins on safety and on being turnkey inside one vendor. There is no dimension where one is strictly ahead on everything, which is exactly why the recommendation is conditional rather than a single name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and Daily Workflow, Measured
&lt;/h2&gt;

&lt;p&gt;Forget invented quality scores. The honest, checkable differences are in how many steps each tool needs to do the same job, and where the friction sits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting to a first response with a non-default model.&lt;/strong&gt; In OpenCode, you export the provider's key, open the TUI, run &lt;code&gt;/models&lt;/code&gt;, and pick. No file to edit. In Codex, a non-OpenAI model means writing a &lt;code&gt;model_providers&lt;/code&gt; block in &lt;code&gt;config.toml&lt;/code&gt; first, then checking that the model you want is actually served over the Responses API, then selecting it. OpenCode is fewer steps for the multi-model case by design; Codex is fewer steps if the model you want is OpenAI's, because then there are zero steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Switching models mid-task.&lt;/strong&gt; OpenCode swaps live through &lt;code&gt;/models&lt;/code&gt; inside a running session. Codex changes model with &lt;code&gt;--model&lt;/code&gt; per invocation, or by loading a named profile, which is closer to picking a lane than nudging the wheel. If your workflow is "reason with the expensive model, then let a cheap one grind the edits," OpenCode makes that a two-second toggle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running a shell command.&lt;/strong&gt; OpenCode asks for permission. Codex runs it inside the sandbox under whichever approval mode you set, so the isolation holds even when you say yes. Same prompt on the surface, very different blast radius underneath.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project instructions.&lt;/strong&gt; Both read &lt;code&gt;AGENTS.md&lt;/code&gt;, the same convention Cursor and others adopted, so a repo that already has one works in either agent with no changes. This is the quiet win of the last year: your project's agent instructions are now portable across tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Run, Side by Side
&lt;/h3&gt;

&lt;p&gt;The fastest way to feel the difference is to install both and reach a first response. OpenCode, with a model you supply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; opencode-ai
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-your-key      &lt;span class="c"&gt;# any OpenAI-compatible provider works&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
opencode                              &lt;span class="c"&gt;# /models to pick, Tab to toggle plan/build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codex, on OpenAI's defaults, which is the case it optimizes for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @openai/codex
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
codex                                 &lt;span class="c"&gt;# authenticates with ChatGPT or OPENAI_API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what each command assumes. OpenCode's happy path expects you to name a provider, and rewards you with a menu. Codex's happy path expects you to be an OpenAI user, and rewards you with zero setup. Neither is wrong. They are optimizing for different first users, and the install experience tells you which user each team pictured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extensibility: MCP, Skills, and Subagents
&lt;/h2&gt;

&lt;p&gt;Past the model question, both agents are extensible in similar shapes, with different maturity in each corner. This is where "first-party" starts to show as polish rather than philosophy.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;OpenCode&lt;/th&gt;
&lt;th&gt;Codex CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCP servers&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes, namespaced registration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reusable prompts&lt;/td&gt;
&lt;td&gt;Custom tools and agents&lt;/td&gt;
&lt;td&gt;Skills and slash commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subagents / parallelism&lt;/td&gt;
&lt;td&gt;Parallel sessions&lt;/td&gt;
&lt;td&gt;Subagents (multi-agent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read-only analysis&lt;/td&gt;
&lt;td&gt;Plan agent, Tab to switch&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/review&lt;/code&gt;, no working-tree edits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote / mobile&lt;/td&gt;
&lt;td&gt;Desktop app, IDE, &lt;code&gt;/share&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Codex Remote from the ChatGPT app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Theming&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both speak MCP, so the same context servers and tool integrations plug into either one. Codex leans into a structured extension model, skills, namespaced MCP, and slash commands that feel governed by a team that ships a product. OpenCode leans into surfaces, giving you the same agent in a terminal, a desktop window, and your editor, plus a &lt;code&gt;/share&lt;/code&gt; flow for handing a session to a teammate. The read-only story is a nice mirror of their philosophies: OpenCode gives you a dedicated plan agent you flip into, while Codex gives you a &lt;code&gt;/review&lt;/code&gt; command that critiques without touching your tree. Same goal, two idioms.&lt;/p&gt;

&lt;p&gt;One practical note on speed. Codex is a Rust binary, so it starts fast and stays light. OpenCode runs on Node, which is not slow in any way you will notice while a model is thinking, but it is a heavier process at rest. For most people the model's latency dwarfs the tool's, and this never matters. If you script a fleet of headless agents, it can.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Key, Two Very Different Model Menus
&lt;/h2&gt;

&lt;p&gt;Here is the part where the two philosophies stop being abstract, and where we stopped guessing and ran the thing. Both agents accept a gateway base URL, so one key can cover the billing for Claude, GPT, Gemini, and open-weight models. What one key does &lt;em&gt;not&lt;/em&gt; guarantee is that both agents can reach all of them. We set both up against &lt;a href="https://ofox.ai/models" rel="noopener noreferrer"&gt;ofox.ai&lt;/a&gt; on 2026-07-29 and the results were not symmetric.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenCode: one environment variable, zero config file.&lt;/strong&gt; Because ofox is a built-in provider in the models.dev registry, OpenCode discovers it the moment the key is present.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-your-key
opencode            &lt;span class="c"&gt;# /models now lists ofox/... entries, pick one&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole setup. No file, no provider block, and because OpenCode talks Chat Completions, everything the gateway serves is on the menu.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Codex CLI: one config block, and a shorter menu than you expect.&lt;/strong&gt; Codex needs the gateway declared once in &lt;code&gt;~/.codex/config.toml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"openai/gpt-5.5"&lt;/span&gt;
&lt;span class="py"&gt;model_provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ofox"&lt;/span&gt;

&lt;span class="nn"&gt;[model_providers.ofox]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ofox.ai"&lt;/span&gt;
&lt;span class="py"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.ofox.ai/v1"&lt;/span&gt;
&lt;span class="py"&gt;env_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"OFOX_API_KEY"&lt;/span&gt;
&lt;span class="py"&gt;wire_api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"responses"&lt;/span&gt;
&lt;span class="py"&gt;requires_openai_auth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;wire_api = "responses"&lt;/code&gt; is not a preference, it is the only value current Codex releases accept, so your gateway has to expose a Responses-compatible endpoint rather than just Chat Completions. &lt;code&gt;requires_openai_auth = false&lt;/code&gt; is the default and keeps Codex from showing the ChatGPT login flow, so it reads the key from &lt;code&gt;env_key&lt;/code&gt; instead. Full key list is in the &lt;a href="https://learn.chatgpt.com/docs/config-file/config-reference" rel="noopener noreferrer"&gt;Codex config reference&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What actually ran
&lt;/h3&gt;

&lt;p&gt;We pointed Codex 0.146.0 at that config and asked each model to reply with one word, using &lt;code&gt;codex exec --sandbox read-only&lt;/code&gt;. This is the result we did not expect going in.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Codex CLI via gateway&lt;/th&gt;
&lt;th&gt;What came back&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-5.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;td&gt;Normal completion, 12.7k tokens billed for the turn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools.0.custom.strict: Extra inputs are not permitted&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deepseek/deepseek-v4-pro&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Encrypted content is not supported with this model.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x-ai/grok-4.3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails&lt;/td&gt;
&lt;td&gt;Same encrypted-content error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;z-ai/glm-5.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails&lt;/td&gt;
&lt;td&gt;HTTP 503, &lt;code&gt;No providers support endpoint 'responses'&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note the asymmetry, because it is the most useful thing in this piece. GLM is the only one of the four the catalog flagged as unsupported ahead of time. Claude, DeepSeek, and Grok are all listed under &lt;code&gt;/v1/responses&lt;/code&gt; and failed anyway. The endpoint list is a pre-filter, not a guarantee.&lt;/p&gt;

&lt;p&gt;Three different failures, one theme. GLM never reaches the model at all because the gateway does not proxy it under &lt;code&gt;/v1/responses&lt;/code&gt;. DeepSeek and Grok are reachable but reject the &lt;code&gt;reasoning.encrypted_content&lt;/code&gt; field Codex attaches to every request, and that field is hard-coded in &lt;code&gt;client.rs&lt;/code&gt; rather than exposed as a setting, so there is no config escape hatch. Claude is reachable and accepts encrypted content, but chokes on the shape of Codex's freeform &lt;code&gt;apply_patch&lt;/code&gt; tool.&lt;/p&gt;

&lt;p&gt;We then ran the identical prompt through OpenCode 1.18.9 on the same key, same gateway, same machine. All four of the models Codex could not reach answered normally, and so did a plain &lt;code&gt;chat/completions&lt;/code&gt; call from the SDK. That is the tell: this is a protocol seam between Codex and the gateway layer, not a model problem and not a gateway being down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to check before you commit.&lt;/strong&gt; The gateway's model list reports which endpoints each model is served under, so you can screen ahead of time instead of debugging a config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.ofox.ai/v1/models &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OFOX_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
| jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.data[] | select(.supported_endpoints | index("/v1/responses")) | .id'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On 2026-07-29 that returned 67 model IDs. The catalog carries 123 entries, but 18 of those are image, video, embedding, and transcription models that expose neither text endpoint, so the denominator that matters is 105 text models: 102 served over chat completions, 67 over Responses. Those two sets overlap almost completely without nesting. 64 models offer both, and exactly three are Responses-only (&lt;code&gt;openai/gpt-5.2-codex&lt;/code&gt;, &lt;code&gt;openai/gpt-5.3-codex&lt;/code&gt;, &lt;code&gt;openai/gpt-5.4-pro&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Counted by family, the Claude, GPT, DeepSeek, Doubao, and Grok text models were covered end to end. Qwen (10 of 21), MiniMax (7 of 9), and Kimi (2 of 5) were covered in part, so per-model checking matters even inside a family you assume is supported. Gemini and GLM had no Responses entry at any version, and neither did Kimi K3. Treat that list as the outer bound of what Codex could reach and then test the specific model, because as the table above shows, being listed is necessary and not sufficient.&lt;/p&gt;

&lt;p&gt;None of this touches OpenCode, which is the practical argument for it if your model strategy is genuinely mixed. It is also worth saying plainly: this is a Codex-side protocol decision, it broke every Chat-Completions-only gateway at once, and it will presumably shake out as gateways build fuller Responses shims. It is a true thing about today, not a permanent verdict.&lt;/p&gt;

&lt;p&gt;The same key works from code too, which is how you A/B two models on the same task without either agent in the loop. Same base URL, swap one string, no protocol seam to worry about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python: run the same task on two models
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-your-ofox-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Refactor this function to remove the nested loop, keep behavior identical.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic/claude-sonnet-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;z-ai/glm-5.2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;=== &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Node: same shape
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk-your-ofox-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write a Postgres migration to add a nullable created_by column.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic/claude-sonnet-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai/gpt-5.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n=== &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ===`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model IDs are literal. They are what you paste into OpenCode, and what you paste into Codex for whichever subset it can currently reach. That is the honest version of the portability pitch: the agent is the harness and the model is a variable, but only one of these two agents lets you change that variable freely today.&lt;/p&gt;

&lt;h3&gt;
  
  
  What that costs
&lt;/h3&gt;

&lt;p&gt;Gateway pricing on the three models used above, read from the ofox model pages on 2026-07-29. These are per million tokens.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;ofox model ID&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$2 / M&lt;/td&gt;
&lt;td&gt;$10 / M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GLM-5.2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;z-ai/glm-5.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$1.4 / M&lt;/td&gt;
&lt;td&gt;$4.4 / M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-5.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$4 / M (list $5)&lt;/td&gt;
&lt;td&gt;$24 / M (list $30)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GPT-5.5 was carrying a 20% promotional discount on the day we checked, so the $4 and $24 figures are the ones you would actually be billed and the struck-through $5 and $30 are the list prices. Promos expire; read the model page rather than trusting this table in six months. The other two had no discount applied.&lt;/p&gt;

&lt;p&gt;The point of the table is not the absolute numbers, it is the spread. GLM-5.2 costs roughly a fifth of GPT-5.5 on output at promo pricing, so the "reason with the strong model, grind with the cheap one" workflow is a real bill difference, not a rounding error. OpenCode makes that toggle a keystroke. Codex, per the test above, could not reach two of these three models at all, which is the same finding arriving as a line on an invoice rather than an error string: the cost lever exists only for the agent that can pull it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Pick OpenCode
&lt;/h2&gt;

&lt;p&gt;Choose OpenCode if any of these describe you. You route work across multiple model vendors and want that to be a menu, not a migration. You are wary of tying your daily driver to a single company's pricing and roadmap. You want the agent outside the terminal too, in a desktop app or your editor. You value that the project is MIT-licensed and community-governed, with no default vendor collecting a toll. The model-agnostic design is the reason to be here, and if you would not use it, you are paying for flexibility you do not need.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Pick Codex CLI
&lt;/h2&gt;

&lt;p&gt;Choose Codex CLI if you are already inside the OpenAI world and want the defaults to just work, if you auto-approve or batch-run tasks and need the OS-level sandbox that Codex has hardened more than anyone else in this category, or if you are migrating off Claude Code and want the import command to do the boring part. The Rust binary is fast, the safety story is the strongest here, and the first-party integration with the ChatGPT app and Codex Remote has no equivalent on the OpenCode side. If you rarely reach past OpenAI's own models, the config work that unlocks other providers is work you will never do, and that is fine. If you do expect to reach past them, read the protocol section above before you build a plan on it, because today that door opens onto a smaller room than the docs imply.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Neither Is the Right Call (and What to Use Instead)
&lt;/h2&gt;

&lt;p&gt;If you barely leave your editor, a terminal agent is a tax on your workflow, and a Cursor or a Zed with an inline assistant will fit your hands better. If your job is a fixed pipeline, generate this, review that, ship on a schedule, you do not want an interactive agent at all, you want a script calling a model API directly, which is why the code examples above call the gateway without either CLI in the loop. And if you are comparing four agents rather than two, our &lt;a href="https://ofox.ai/blog/claude-code-vs-codex-cli-vs-cursor-vs-deepseek-tui-2026/" rel="noopener noreferrer"&gt;four-way terminal agent comparison&lt;/a&gt; covers Claude Code and DeepSeek TUI alongside Codex, with the price and daily-driver angles laid out.&lt;/p&gt;

&lt;p&gt;The terminal agent is a specific tool for a specific taste: you want the model in your shell, watching your files, running your commands. If that is not the taste, neither of these is your answer, and reaching for the wrong shape of tool is a more common mistake than picking the wrong one of the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/anomalyco/opencode" rel="noopener noreferrer"&gt;github.com/anomalyco/opencode&lt;/a&gt; (the former &lt;code&gt;sst/opencode&lt;/code&gt; path 301s here)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;github.com/openai/codex&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/openai/codex/blob/rust-v0.146.0/codex-rs/model-provider-info/src/lib.rs" rel="noopener noreferrer"&gt;codex-rs/model-provider-info/src/lib.rs at rust-v0.146.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/openai/codex/discussions/7782" rel="noopener noreferrer"&gt;openai/codex discussion #7782&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://opencode.ai/docs" rel="noopener noreferrer"&gt;opencode.ai/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://learn.chatgpt.com/docs/config-file/config-reference" rel="noopener noreferrer"&gt;Codex CLI config reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://models.dev" rel="noopener noreferrer"&gt;models.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models" rel="noopener noreferrer"&gt;ofox model pages&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Related reading: &lt;a href="https://ofox.ai/blog/opencode-api-configuration-guide-2026/" rel="noopener noreferrer"&gt;OpenCode setup guide&lt;/a&gt;, &lt;a href="https://ofox.ai/blog/codex-cli-custom-model-providers-byo-setup/" rel="noopener noreferrer"&gt;Codex CLI custom model providers&lt;/a&gt;, &lt;a href="https://ofox.ai/blog/codex-cli-config-toml-deep-dive/" rel="noopener noreferrer"&gt;Codex config.toml deep dive&lt;/a&gt;, and &lt;a href="https://ofox.ai/blog/migrate-claude-code-to-codex-2026/" rel="noopener noreferrer"&gt;migrating from Claude Code to Codex&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/opencode-vs-codex-cli-terminal-coding-agent-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opencode</category>
      <category>codexcli</category>
      <category>cli</category>
    </item>
    <item>
      <title>fal vs WaveSpeed vs AtlasCloud: Video Generation API Compared (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Wed, 29 Jul 2026 11:36:20 +0000</pubDate>
      <link>https://dev.to/owen_fox/fal-vs-wavespeed-vs-atlascloud-video-generation-api-compared-2026-3644</link>
      <guid>https://dev.to/owen_fox/fal-vs-wavespeed-vs-atlascloud-video-generation-api-compared-2026-3644</guid>
      <description>&lt;p&gt;fal, WaveSpeed and AtlasCloud run per-second video APIs but price differently: floors from $0.01/s, $0.045/s and $0.05/s. Match the model, then compare.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which One Should You Pick?
&lt;/h2&gt;

&lt;p&gt;There is no single winner here, and any comparison that crowns one is selling you something. fal, WaveSpeed, and AtlasCloud are all serverless generative-media APIs that bill per output. They differ on three axes that actually decide the call: how wide the model catalog is, how fast and reliable the inference is, and how the per-second price lands for the exact model you ship.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your priority&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Widest catalog + production track record&lt;/td&gt;
&lt;td&gt;fal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lowest latency, cheap fast variants, easiest free start&lt;/td&gt;
&lt;td&gt;WaveSpeed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lowest per-second video + one bill across LLM/image/video + compliance&lt;/td&gt;
&lt;td&gt;AtlasCloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same models on one key without three separate accounts&lt;/td&gt;
&lt;td&gt;An aggregator (see the last section)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you already know your model and resolution, skip to the pricing section. If you are choosing a platform for a pipeline you have not built yet, read the positioning and billing sections first, because the billing model will surprise you more than the sticker price.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Each One Actually Is
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;fal&lt;/strong&gt; calls itself a generative-media platform for developers: one API in front of 1,000+ image, video, audio, and 3D models, plus serverless GPU deployment and dedicated compute for teams running their own weights. Its differentiator is not only breadth. fal leans on a proprietary inference stack it says is up to 10x faster on diffusion models, and it has the commercial track record to back a production bet: a $140M Series D led by Sequoia at a $4.5B valuation in December 2025, 1.5M+ developers, and named customers including Canva, Perplexity, and Poe (which fal says it powers for 40% of its image and video bots). It is SOC 2 compliant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WaveSpeed&lt;/strong&gt; is built around one word: speed. It bills itself as the fastest AI inference platform for images and video, and the headline product claims are sub-1-second average inference, zero cold starts, and a 99.99% uptime SLA. The company is younger and smaller, founded in 2024, based in Singapore, and angel-funded, with a founding team that comes out of open-source inference-optimization work. The catalog spans image, video, audio, 3D, and LLMs, though the exact model count is quoted inconsistently across its own pages (anywhere from 600+ to 1,000+), so treat any single figure loosely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AtlasCloud&lt;/strong&gt; is the broadest of the three by product surface. It is a multimodal aggregator, chat, image, video, audio, and 3D behind one API, and it also rents raw GPUs by the second (H100 at $2.95/GPU-hr, H200 at $3.50/GPU-hr). It advertises 400+ models and competes on price, with marketing that repeatedly claims industry-low rates. It is the only one of the three that lists both SOC 2 and HIPAA compliance, which matters if your video pipeline touches regulated data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Head-to-Head Specs
&lt;/h2&gt;

&lt;p&gt;Read this as positioning, not a benchmark. The counts and claims below come from each provider's own pages; the "Best for" column is a use-case tag, not a scored winner.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;fal&lt;/th&gt;
&lt;th&gt;WaveSpeed&lt;/th&gt;
&lt;th&gt;AtlasCloud&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Positioning&lt;/td&gt;
&lt;td&gt;Dev media platform&lt;/td&gt;
&lt;td&gt;Fastest inference&lt;/td&gt;
&lt;td&gt;Low-price multimodal + GPU&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catalog size (self-reported)&lt;/td&gt;
&lt;td&gt;1,000+&lt;/td&gt;
&lt;td&gt;600+ to 1,000+&lt;/td&gt;
&lt;td&gt;400+&lt;/td&gt;
&lt;td&gt;fal / breadth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video billing unit&lt;/td&gt;
&lt;td&gt;Per second or per video&lt;/td&gt;
&lt;td&gt;Per image / second / token&lt;/td&gt;
&lt;td&gt;Per second (video)&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Also offers&lt;/td&gt;
&lt;td&gt;GPU compute (hourly)&lt;/td&gt;
&lt;td&gt;Serverless GPU&lt;/td&gt;
&lt;td&gt;GPU rental (H100 $2.95/hr)&lt;/td&gt;
&lt;td&gt;AtlasCloud / range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed claim (vendor)&lt;/td&gt;
&lt;td&gt;Engine up to 10x faster&lt;/td&gt;
&lt;td&gt;Sub-1s avg, zero cold start&lt;/td&gt;
&lt;td&gt;0 to 800 GPUs, 90% cold-start cut&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free to start&lt;/td&gt;
&lt;td&gt;Prepaid credits&lt;/td&gt;
&lt;td&gt;$1 credit, no card&lt;/td&gt;
&lt;td&gt;Trial credits&lt;/td&gt;
&lt;td&gt;WaveSpeed / entry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimum top-up&lt;/td&gt;
&lt;td&gt;Pay-as-you-go&lt;/td&gt;
&lt;td&gt;Any amount&lt;/td&gt;
&lt;td&gt;$25&lt;/td&gt;
&lt;td&gt;fal / WaveSpeed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance&lt;/td&gt;
&lt;td&gt;SOC 2&lt;/td&gt;
&lt;td&gt;99.99% uptime SLA&lt;/td&gt;
&lt;td&gt;SOC 2 + HIPAA&lt;/td&gt;
&lt;td&gt;AtlasCloud / regulated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale signal&lt;/td&gt;
&lt;td&gt;Series D, 1.5M+ devs&lt;/td&gt;
&lt;td&gt;Founded 2024, angel&lt;/td&gt;
&lt;td&gt;Founded 2024&lt;/td&gt;
&lt;td&gt;fal / maturity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How Each One Bills
&lt;/h2&gt;

&lt;p&gt;The sticker price is the part people read. The billing unit is the part that changes the invoice. All three charge per output rather than per token-of-compute for their curated media models, but the unit shifts by modality and sometimes by model, and two of the three also expose raw GPU rental on a completely different meter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three video-API billing models compared
&lt;/h3&gt;

&lt;p&gt;Same output, three billing mental models. Units change per model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;fal&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per output, or hourly GPU&lt;/li&gt;
&lt;li&gt;Per second of video, or a flat rate per video&lt;/li&gt;
&lt;li&gt;Wan 2.5: $0.05/s (480p)&lt;/li&gt;
&lt;li&gt;Veo 3: $0.20/s (no audio), $0.40/s (audio)&lt;/li&gt;
&lt;li&gt;Or rent compute: H100 $3.99/hr list&lt;/li&gt;
&lt;li&gt;Not charged for 500 errors or queue wait&lt;/li&gt;
&lt;li&gt;Read the model page for the unit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WaveSpeed&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per successful generation&lt;/li&gt;
&lt;li&gt;Per image, per second, or per million tokens&lt;/li&gt;
&lt;li&gt;Wan 2.2 Ultra Fast: $0.01/s&lt;/li&gt;
&lt;li&gt;Veo 3.1 Fast: $0.15/s&lt;/li&gt;
&lt;li&gt;$1 free credit on signup, no card&lt;/li&gt;
&lt;li&gt;No subscription, no stated minimum&lt;/li&gt;
&lt;li&gt;Tiers scale with cumulative top-up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AtlasCloud&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per modality + GPU rental&lt;/li&gt;
&lt;li&gt;Video per second, LLM per million tokens&lt;/li&gt;
&lt;li&gt;Seedance 2.0 Mini: $0.045/s&lt;/li&gt;
&lt;li&gt;HappyHorse-1.1: $0.14/s&lt;/li&gt;
&lt;li&gt;Rent GPUs: H100 $2.95/hr, H200 $3.50/hr&lt;/li&gt;
&lt;li&gt;$25 minimum top-up, credits expire 365 days&lt;/li&gt;
&lt;li&gt;One bill across LLM, image, video&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;fal states its dual model plainly: choose per-output pricing for serverless model calls, or hourly GPU pricing if you deploy your own model on Compute. WaveSpeed bills per successful generation and does not charge for failures. AtlasCloud splits by modality, per-second for video, per-million-tokens for LLMs, per-image for stills, and layers GPU rental on top for teams that want to run their own stack. The practical takeaway: two providers can quote the "same" model and still bill it in different units, so a headline rate is only comparable once you know what a unit buys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video Pricing: You Have to Match the Model
&lt;/h2&gt;

&lt;p&gt;Here is the honest part most comparison posts skip. You cannot line up a single dollar-per-second number across these three and declare a winner, because the cheapest listing on each platform is a different model at a different fidelity, and sometimes a different mode (text-to-video versus image-to-video, standard versus a "fast" variant). The only fair comparison fixes the model, the resolution, and the mode first. Our deeper breakdown of that trap lives in the &lt;a href="https://ofox.ai/blog/fal-vs-replicate-vs-ofox-video-api-pricing-2026/" rel="noopener noreferrer"&gt;fal vs Replicate vs Ofox video pricing&lt;/a&gt; piece; the short version is below.&lt;/p&gt;

&lt;p&gt;Start with each provider's cheapest verified per-second video floor. These are not the same model, which is the point.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Cheapest verified per-second video&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;What you are actually buying&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WaveSpeed&lt;/td&gt;
&lt;td&gt;$0.01/s&lt;/td&gt;
&lt;td&gt;Wan 2.2 Ultra Fast&lt;/td&gt;
&lt;td&gt;A speed-optimized, lower-fidelity variant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AtlasCloud&lt;/td&gt;
&lt;td&gt;$0.045/s&lt;/td&gt;
&lt;td&gt;Seedance 2.0 Mini&lt;/td&gt;
&lt;td&gt;Recently a 20% promo off $0.056&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fal&lt;/td&gt;
&lt;td&gt;$0.05/s&lt;/td&gt;
&lt;td&gt;Wan 2.5 (480p)&lt;/td&gt;
&lt;td&gt;Steps to $0.10/s (720p), $0.15/s (1080p)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now a near-match, so you see how the gap moves when the model holds roughly still. On Wan 2.5, fal charges $0.05/s at 480p, $0.10/s at 720p, and $0.15/s at 1080p for text-to-video. WaveSpeed's Wan 2.5 image-to-video Fast variant is $0.068/s at 720p and $0.102/s at 1080p, lower than fal at those resolutions, but it is a different mode, so treat it as adjacent, not identical. AtlasCloud does not publish a Wan 2.5 per-second rate on its rate page as of this writing, so verify it on the model page before you budget around it.&lt;/p&gt;

&lt;p&gt;At the premium end the ranking shifts again. fal cut its Veo 3 pricing to $0.20/s without audio and $0.40/s with audio (down from $0.50/$0.75 earlier in 2025), while WaveSpeed lists Veo 3.1 Fast at $0.15/s. Different Veo generations, so again, not a clean race, but it shows why "who is cheapest" has no stable answer across a whole catalog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why we do not crown a price winner
&lt;/h3&gt;

&lt;p&gt;Because a second of a 480p fast variant is not a second of a 1080p flagship, and an image-to-video call is not a text-to-video call. On a single provider the same model steps up cleanly with resolution. Across providers you are comparing different models wearing the same family name. Fix the model, resolution, and mode, convert each to cost per identical clip, then compare. Anyone who hands you a single "$/s cheapest" verdict skipped that step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monthly Bill: What "Cheapest" Costs in Practice
&lt;/h2&gt;

&lt;p&gt;Say you ship 2,000 clips a month at 5 seconds each. That is 10,000 output-seconds. At each provider's cheapest verified per-second video rate, the monthly bill looks like this, and the labels matter more than the bars.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monthly bill: 10,000 output-seconds&lt;/strong&gt; — 2,000 clips at 5s each, at each provider's cheapest verified rate&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$100 — WaveSpeed Wan 2.2 Ultra Fast, $0.01/s&lt;/li&gt;
&lt;li&gt;$450 — AtlasCloud Seedance 2.0 Mini, $0.045/s&lt;/li&gt;
&lt;li&gt;$500 — fal Wan 2.5 480p, $0.05/s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different models at different fidelities. Read the labels, not just the bars.&lt;/p&gt;

&lt;p&gt;The $100 bar is real, and it is also a trap if you read it as "WaveSpeed is 5x cheaper." Wan 2.2 Ultra Fast is a speed variant, not a flagship, so you are buying lower fidelity for that rate. Move everyone up to a 720p working tier and the picture flattens: fal's Wan 2.5 at 720p is $1,000/month for the same 10,000 seconds, WaveSpeed's Wan 2.5 Fast at 720p is about $680, and AtlasCloud's HappyHorse-1.1 lip-sync model at $0.14/s would run $1,400. The cheapest floor and the cheapest thing-you-actually-ship are rarely the same line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image and LLM Pricing
&lt;/h2&gt;

&lt;p&gt;Video is the headline, but all three also generate images, and AtlasCloud reaches further into language models, so if your pipeline mixes modalities the non-video rates matter too. The same rule applies: these are list rates pulled from each provider's pricing pages in July 2026, and the cheapest listing is usually a lower-fidelity variant. Confirm on the model page before you budget.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Image example (list)&lt;/th&gt;
&lt;th&gt;Also meters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;fal&lt;/td&gt;
&lt;td&gt;Flux dev $0.025/img, Seedream V4 $0.03/img&lt;/td&gt;
&lt;td&gt;Per megapixel on some models (Qwen $0.02/MP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WaveSpeed&lt;/td&gt;
&lt;td&gt;Flux 2 Klein $0.008/img, Nano Banana 2 $0.07/img&lt;/td&gt;
&lt;td&gt;Per second (video), per million tokens (LLM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AtlasCloud&lt;/td&gt;
&lt;td&gt;Flux Schnell from $0.003/img&lt;/td&gt;
&lt;td&gt;LLM tokens: Grok 4.5 $2/$6, Kimi K3 $3/$15 per 1M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The structural difference worth calling out: AtlasCloud is the only one of the three that also meters LLM tokens the way an OpenAI-style API does, which is why it pitches a single bill across chat, image, and video rather than a media-only shop. fal and WaveSpeed keep their center of gravity on generative media. If your product needs both a language model and a video model behind one invoice, that narrows the field before you even look at video rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Renting Raw GPUs
&lt;/h2&gt;

&lt;p&gt;Two of the three will also rent you the metal. This matters if you plan to deploy your own weights or run a model that is not in the catalog, and it is a different meter from the per-output pricing above: you pay for GPU time whether a job renders in one second or ten.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;fal (list / as low as)&lt;/th&gt;
&lt;th&gt;AtlasCloud&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;H100 (80GB)&lt;/td&gt;
&lt;td&gt;$3.99/hr / $1.89/hr&lt;/td&gt;
&lt;td&gt;$2.95/GPU-hr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H200 (141GB)&lt;/td&gt;
&lt;td&gt;$4.50/hr / $2.10/hr&lt;/td&gt;
&lt;td&gt;$3.50/GPU-hr&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;fal's Compute product bills per second with a list-versus-committed spread, so the effective rate depends on how much you commit up front. AtlasCloud's on-demand rate is flat per GPU-hour with per-second billing and no minimum, and it advertises scaling from zero to hundreds of GPUs for burst work. WaveSpeed also offers serverless GPU billed per compute-second, though it does not publish a clean rate card, so price it in the dashboard rather than trusting a summary. If you never plan to leave the curated model APIs, skip this section; it only matters once you outgrow the catalog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed and Reliability
&lt;/h2&gt;

&lt;p&gt;Two of these three sell speed as the headline, so weigh the claims for what they are: vendor numbers, not independent benchmarks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;fal&lt;/strong&gt; points to its Inference Engine, which it measures as up to 10x faster on diffusion models, and to production scale: 100M+ daily inference calls, billions of requests a day, 99.99%+ uptime by its own reporting. The scale is the more useful signal, because it is a track record rather than a lab number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WaveSpeed&lt;/strong&gt; advertises sub-1-second average inference and zero cold starts, plus a 99.99% uptime SLA. A press claim of "up to 6x faster" exists, but it comes from a B200-versus-H100 framing in a funding announcement, not a product-page benchmark.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AtlasCloud&lt;/strong&gt; talks scale-out rather than raw latency: scaling from 0 to 800 GPUs in seconds and a 90% cold-start reduction on its serverless tier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these is third-party verified. If latency is your deciding factor, run your own model in your own region against each and measure the p50 and p95 yourself. A homepage number tells you what a provider optimized for, not what your workload will see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accounts, Credits, and the Fine Print
&lt;/h2&gt;

&lt;p&gt;The onboarding terms decide how painful a proof-of-concept is, and they vary more than the prices.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;fal&lt;/th&gt;
&lt;th&gt;WaveSpeed&lt;/th&gt;
&lt;th&gt;AtlasCloud&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sign-in&lt;/td&gt;
&lt;td&gt;GitHub, Google, SSO&lt;/td&gt;
&lt;td&gt;Google, GitHub&lt;/td&gt;
&lt;td&gt;Email / account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free to start&lt;/td&gt;
&lt;td&gt;Prepaid credits (promo terms unconfirmed)&lt;/td&gt;
&lt;td&gt;$1 credit, no card required&lt;/td&gt;
&lt;td&gt;Trial credits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimum top-up&lt;/td&gt;
&lt;td&gt;Pay-as-you-go&lt;/td&gt;
&lt;td&gt;Any amount (moves you off Bronze)&lt;/td&gt;
&lt;td&gt;$25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credit expiry&lt;/td&gt;
&lt;td&gt;Not stated&lt;/td&gt;
&lt;td&gt;Not stated&lt;/td&gt;
&lt;td&gt;365 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Account model&lt;/td&gt;
&lt;td&gt;Personal, Team, Org&lt;/td&gt;
&lt;td&gt;Bronze to Ultra by top-up&lt;/td&gt;
&lt;td&gt;Pay-as-you-go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not charged for&lt;/td&gt;
&lt;td&gt;500 errors, queue wait&lt;/td&gt;
&lt;td&gt;Failed generations&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance&lt;/td&gt;
&lt;td&gt;SOC 2&lt;/td&gt;
&lt;td&gt;99.99% uptime SLA&lt;/td&gt;
&lt;td&gt;SOC 2 + HIPAA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;WaveSpeed is the lowest-friction start: sign in with Google, take the $1 credit, no card. One catch worth knowing is that a key created before your first top-up will not activate, so add any amount before you expect calls to work. AtlasCloud asks for a $25 minimum and expires credits after a year, but gives you compliance certs and GPU rental in the same account. fal is pay-as-you-go on prepaid credits, and its concurrency limit scales with how much you have purchased, which is worth knowing if you plan to burst.&lt;/p&gt;

&lt;p&gt;Each of these is a separate account, a separate API key, and a separate prepaid balance with its own request schema. That is fine for one provider. It gets tedious the moment you want to A/B the same model across two of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a Multi-Model Aggregator Fits
&lt;/h2&gt;

&lt;p&gt;If you find yourself running the same underlying models (Seedance, Wan) across more than one of these providers, you are also maintaining more than one integration, one per vendor schema, one per prepaid balance. An aggregator collapses that. &lt;a href="https://ofox.ai/?utm_source=blog&amp;amp;utm_medium=inline&amp;amp;utm_campaign=fal-wavespeed-atlascloud-video" rel="noopener noreferrer"&gt;Ofox&lt;/a&gt;, for instance, fronts the same models behind one OpenAI-style endpoint, so &lt;code&gt;bytedance/seedance-2.0&lt;/code&gt; and &lt;code&gt;alibaba/wan-2.7&lt;/code&gt; are a one-string swap on a single key, billed per output second by resolution (Seedance 2.0 at $0.07/s for 480p up to $0.34/s at 1080p, Wan 2.7 at $0.10/s for 720p). It is not a replacement for going direct when you have settled on one model and one provider, but it removes the three-accounts tax while you are still comparing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# One key, one endpoint, swap the model string to A/B the same clip
&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1/videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer $OFOX_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytedance/seedance-2.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# or "alibaba/wan-2.7"
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a paper boat drifting down a rain gutter, cinematic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resolution&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1080p&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# 202 + polling_url; poll GET /v1/videos/{id} until completed
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Pick Each
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When to Pick fal
&lt;/h3&gt;

&lt;p&gt;Pick fal when you want the widest catalog, a proprietary speed engine, and a provider with a production track record you can point a stakeholder at. The Series D scale, the 1.5M+ developers, and customers like Canva and Perplexity are the reason fal is the low-risk default for a pipeline you are betting a product on. You pay for that maturity in per-second rates that are rarely the cheapest.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Pick WaveSpeed
&lt;/h3&gt;

&lt;p&gt;Pick WaveSpeed when latency is the product and you want the cheapest possible start. The $1 free credit with no card is the easiest proof-of-concept of the three, the fast model variants are genuinely low-cost, and the whole platform is tuned for speed. Weigh the vendor speed claims against your own measurement, and accept that a younger, angel-funded company is a slightly higher operational bet than fal.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Pick AtlasCloud
&lt;/h3&gt;

&lt;p&gt;Pick AtlasCloud when you want the lowest per-second video and a single bill across LLMs, images, and video, ideally with compliance attached. The SOC 2 plus HIPAA posture and the built-in GPU rental make it the pick for a team that wants media generation and model hosting under one roof. The $25 minimum and 365-day credit expiry are the trade for that breadth.&lt;/p&gt;

&lt;h3&gt;
  
  
  When None of the Three Fits
&lt;/h3&gt;

&lt;p&gt;If you have settled on exactly one model at scale, price it directly against the model maker's own API and whichever host is cheapest for that specific model, resolution, and mode, and ignore the catalog breadth you will not use. And if the friction you actually feel is maintaining several accounts to compare the same models, that is the aggregator case above, not a fourth provider to sign up for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Refresh
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;WaveSpeed pricing page: &lt;code&gt;https://wavespeed.ai/pricing&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;WaveSpeed Wan 2.5 image-to-video Fast model page: &lt;code&gt;https://wavespeed.ai/models/alibaba/wan-2.5/image-to-video-fast&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;WaveSpeed platform overview: &lt;code&gt;https://wavespeed.ai/landing/introduce&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AtlasCloud video model pricing: &lt;code&gt;https://www.atlascloud.ai/pricing/models&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AtlasCloud GPU pricing: &lt;code&gt;https://www.atlascloud.ai/pricing/gpu&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AtlasCloud LLM pricing: &lt;code&gt;https://www.atlascloud.ai/models/llm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AtlasCloud about / compliance: &lt;code&gt;https://www.atlascloud.ai/about&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;fal pricing page: &lt;code&gt;https://fal.ai/pricing&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;fal Wan 2.5 model page: &lt;code&gt;https://fal.ai/models/fal-ai/wan-25-preview/text-to-video&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;fal Veo 3 model page: &lt;code&gt;https://fal.ai/models/fal-ai/veo3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;fal model-API pricing docs: &lt;code&gt;https://fal.ai/docs/documentation/model-apis/pricing&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcrunch.com/2025/12/09/fal-nabs-140m-in-fresh-funding-led-by-sequoia-tripling-valuation-to-4-5b/" rel="noopener noreferrer"&gt;TechCrunch: fal's $140M Series D at a $4.5B valuation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://seed.bytedance.com/en/seedance" rel="noopener noreferrer"&gt;ByteDance Seed: the Seedance model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wan.video/" rel="noopener noreferrer"&gt;Wan project site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/models/bytedance/seedance-2.0" rel="noopener noreferrer"&gt;Ofox Seedance 2.0 model page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/models/alibaba/wan-2.7" rel="noopener noreferrer"&gt;Ofox Wan 2.7 model page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/video" rel="noopener noreferrer"&gt;Ofox video models and pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/blog/fal-vs-replicate-vs-ofox-video-api-pricing-2026/" rel="noopener noreferrer"&gt;fal vs Replicate vs Ofox: Video API Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/blog/fal-ai-alternatives-video-generation-api-2026/" rel="noopener noreferrer"&gt;fal.ai alternatives for video generation APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/blog/seedance-2-0-vs-wan-video-api-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 vs Wan: video API compared&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/blog/seedance-2-0-fast-mini-tier-comparison-2026/" rel="noopener noreferrer"&gt;Seedance 2.0, Fast, and Mini: tier comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/blog/seedance-2-0-video-api-access-2026/" rel="noopener noreferrer"&gt;How to access the Seedance 2.0 video API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/fal-vs-wavespeed-vs-atlascloud-video-api-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>videogeneration</category>
      <category>compare</category>
    </item>
    <item>
      <title>How to Choose a Video Generation API by Use Case (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Wed, 29 Jul 2026 04:33:41 +0000</pubDate>
      <link>https://dev.to/owen_fox/how-to-choose-a-video-generation-api-by-use-case-2026-8m3</link>
      <guid>https://dev.to/owen_fox/how-to-choose-a-video-generation-api-by-use-case-2026-8m3</guid>
      <description>&lt;p&gt;The hard part of video generation is not the API call, it is picking the model. "Best" depends entirely on the job. A character who has to stay recognizable across three cuts, a spokesperson who lip-syncs to a voiceover, and a throwaway draft you will regenerate ten times each point to a different model. ofox puts three model families behind one &lt;code&gt;POST /v1/videos&lt;/code&gt; endpoint and one key: Seedance 2.0, Wan, and HappyHorse. Because they share the endpoint, choosing between them is a &lt;code&gt;model&lt;/code&gt; string change, not a new integration. This guide maps the common use cases to the right model, with the real per-second pricing for each.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Price per output second&lt;/th&gt;
&lt;th&gt;Max res&lt;/th&gt;
&lt;th&gt;Clip length&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bytedance/seedance-2.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multi-shot consistency, cinematic, up to 4K&lt;/td&gt;
&lt;td&gt;$0.07 (480p) to $0.34 (1080p) to $1.37 (4K)&lt;/td&gt;
&lt;td&gt;4K&lt;/td&gt;
&lt;td&gt;4 to 15s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cheap drafts at volume, capped at 720p&lt;/td&gt;
&lt;td&gt;$0.04 (480p) / $0.08 (720p)&lt;/td&gt;
&lt;td&gt;720p&lt;/td&gt;
&lt;td&gt;4 to 15s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alibaba/wan-2.7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Budget quality, short loops, open-weights lineage&lt;/td&gt;
&lt;td&gt;$0.10 (720p) / $0.15 (1080p)&lt;/td&gt;
&lt;td&gt;1080p&lt;/td&gt;
&lt;td&gt;2 to 15s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alibaba/happyhorse-1.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Audio-driven avatars and lip-sync&lt;/td&gt;
&lt;td&gt;$0.13 (720p) / $0.17 (1080p)&lt;/td&gt;
&lt;td&gt;1080p&lt;/td&gt;
&lt;td&gt;3 to 15s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pick by use case, not by a leaderboard.&lt;/strong&gt; Consistent characters across cuts point to Seedance 2.0. A talking head that lip-syncs to your audio points to HappyHorse. A 2-second loop or the lowest 1080p bill points to Wan. Cheap throwaway drafts point to Seedance Mini. All four are one &lt;code&gt;model&lt;/code&gt; string on the same &lt;code&gt;/v1/videos&lt;/code&gt; key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Consistent characters and multi-shot scenes: Seedance 2.0
&lt;/h2&gt;

&lt;p&gt;Seedance 2.0's signature is native multi-shot generation with subject consistency. The same character, product, or set holds its look across separate cuts inside one job, which is exactly the thing that breaks when you stitch clips from a model that redraws the subject every render. It reaches 4K, runs 4 to 15 seconds, and does text-to-video, image-to-video, and video-to-video.&lt;/p&gt;

&lt;p&gt;Cost scales with resolution: $0.07/s at 480p, $0.16/s at 720p, $0.34/s at 1080p, and $1.37/s at 4K for text-to-video. Video-to-video is a higher tier on the same model ($0.09/s at 480p, $0.20/s at 720p, $0.45/s at 1080p, $1.70/s at 4K), so budget for the mode you actually run, not just the resolution. If your deliverable is a short branded sequence where one hero has to survive several shots, this is the model to reach for. If you are only choosing between its own Mini, Fast, and flagship tiers, the &lt;a href="https://ofox.ai/blog/seedance-2-0-fast-mini-tier-comparison-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 tier comparison&lt;/a&gt; covers that split in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Talking heads and avatars: HappyHorse 1.1
&lt;/h2&gt;

&lt;p&gt;When the deliverable is a person speaking, an avatar, a spokesperson, or a lip-synced explainer, HappyHorse is the model built for it. It is the audio-driven avatar and lip-sync specialist: give it a reference image and an audio track and it returns a clip whose mouth matches the sound. It also handles multi-image reference, runs 3 to 15 seconds, and reaches 1080p.&lt;/p&gt;

&lt;p&gt;Pricing is $0.13/s at 720p and $0.17/s at 1080p. Seedance and Wan both generate audio, so they are fine for scenes where sound is ambient, but neither is a lip-sync engine. If a face has to say specific words on cue, HappyHorse is the one that is designed for it rather than approximating it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Budget, short loops, and open-weights lineage: Wan 2.7
&lt;/h2&gt;

&lt;p&gt;Wan is the value pick. It is $0.10/s at 720p and $0.15/s at 1080p, flat by resolution with no premium tiers to reason about, and it supports text-to-video, image-to-video, and video-to-video up to 1080p. Two things it wins outright among the three families. First, it accepts a 2-second minimum clip where every Seedance tier floors at 4 seconds, so 2 to 3 second loops and stingers are only possible here. Second, its open-weights lineage makes it the natural choice if you want the option of parity between a hosted API and a model you can inspect. The &lt;a href="https://ofox.ai/blog/seedance-2-0-vs-wan-video-api-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 vs Wan comparison&lt;/a&gt; walks the full head-to-head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheap drafts at volume: Seedance Mini
&lt;/h2&gt;

&lt;p&gt;When you will regenerate a shot ten times before you like it, do not pay flagship rates to iterate. Render drafts on &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt; at $0.04/s for 480p and $0.08/s for 720p, the lowest 720p rate on the platform, then promote the winning prompt to the flagship for the final master. Because the tiers share the endpoint and differ only by the &lt;code&gt;model&lt;/code&gt; string, the promotion is a one-line change, not a rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pricing reality: per second, by resolution
&lt;/h2&gt;

&lt;p&gt;Every model here bills per output second, and the rate rises with the resolution you request. The "from" figure next to each model in the catalog is the resolution floor, not a flat rate, which is the single most common budgeting mistake. Match the model to the job first, then match the resolution to where the clip actually lands.&lt;/p&gt;

&lt;p&gt;Here is the same 8-second clip across the three families at 1080p:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;1080p rate&lt;/th&gt;
&lt;th&gt;8-second clip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alibaba/wan-2.7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.15/s&lt;/td&gt;
&lt;td&gt;$1.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alibaba/happyhorse-1.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.17/s&lt;/td&gt;
&lt;td&gt;$1.36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bytedance/seedance-2.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.34/s&lt;/td&gt;
&lt;td&gt;$2.72&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those rates are text-to-video. Seedance also runs video-to-video at a higher tier, where 1080p is $0.45/s and the same 8-second clip is $3.60 rather than $2.72, so price the mode, not just the resolution. Seedance costs more per second at 1080p because it is the only one of the three that also reaches 4K, and its multi-shot consistency is doing more work per frame. For a feed that downscales to 720p anyway, the gap narrows, and Seedance Mini at $0.08/s undercuts everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Sora, Veo, Kling, and Hailuo fit
&lt;/h2&gt;

&lt;p&gt;Plenty of strong video models sit outside these three families. Sora, Veo, Kling, and Hailuo are all capable, and for some shots they are the right answer. On ofox they are listed as coming next rather than live, so for now each still runs on its own native API with its own SDK, auth, and billing. The point of a single endpoint is what happens when they land: adding one becomes a one-line &lt;code&gt;model&lt;/code&gt; string on the same &lt;code&gt;/v1/videos&lt;/code&gt; key, not a fresh integration to build and maintain. If your pipeline needs one of them today, the &lt;a href="https://ofox.ai/blog/ai-video-generation-apis-sora-veo-kling-compared-2026/" rel="noopener noreferrer"&gt;Sora vs Veo vs Kling comparison&lt;/a&gt; covers running them as separate integrations in the meantime. This guide is about the three families you can drive through a single ofox key right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  One key, every model
&lt;/h2&gt;

&lt;p&gt;The reason choosing is cheap is that switching is cheap. Every model here uses the same request: &lt;code&gt;POST /v1/videos&lt;/code&gt; with a model ID and a prompt, poll the job, then read the clip from &lt;code&gt;unsigned_urls[0]&lt;/code&gt;. The &lt;a href="https://ofox.ai/blog/seedance-2-0-video-api-access-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 API access guide&lt;/a&gt; walks that full request and response cycle, and it is identical across all three families.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Try all three on the key you already have.&lt;/strong&gt; &lt;a href="https://ofox.ai/video?utm_source=blog&amp;amp;utm_medium=post&amp;amp;utm_campaign=video-model-by-use-case" rel="noopener noreferrer"&gt;Start on the ofox video API&lt;/a&gt;: one key, USD billing, pay only for the seconds you render, and swap Seedance, Wan, or HappyHorse with a single string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which video model should I use for a talking-head avatar?&lt;/strong&gt; HappyHorse 1.1. It is the audio-driven avatar and lip-sync specialist: feed it an image and an audio track for a synced talking clip, up to 1080p, at $0.13/s (720p) or $0.17/s (1080p).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the cheapest way to generate video on ofox?&lt;/strong&gt; &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt; at $0.04/s (480p) and $0.08/s (720p). Use it for drafts, then re-render the winner on the flagship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which model can make a 2-second clip?&lt;/strong&gt; Wan, which accepts a 2-second minimum. Seedance tiers floor at 4 seconds; HappyHorse starts at 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do these models all cost the same?&lt;/strong&gt; No. Per output second by resolution: Wan $0.10 to $0.15, HappyHorse $0.13 to $0.17, Seedance $0.07 to $1.37 across 480p to 4K.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use one API key for all of them?&lt;/strong&gt; Yes. All three sit behind &lt;code&gt;POST /v1/videos&lt;/code&gt; on one ofox Bearer key. Switching is a &lt;code&gt;model&lt;/code&gt; string change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Guide
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/video" rel="noopener noreferrer"&gt;ofox video model catalog and per-second floor pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models/bytedance/seedance-2.0" rel="noopener noreferrer"&gt;ofox Seedance 2.0 model detail, 480p to 4K per-resolution pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models/alibaba/wan-2.7" rel="noopener noreferrer"&gt;ofox Wan 2.7 model detail, 720p and 1080p pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models/alibaba/happyhorse-1.1" rel="noopener noreferrer"&gt;ofox HappyHorse 1.1 model detail, 720p and 1080p pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/blog/seedance-2-0-fast-mini-tier-comparison-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 tier comparison: Mini, Fast, and flagship&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/blog/seedance-2-0-vs-wan-video-api-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 vs Wan video API comparison&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/blog/seedance-2-0-video-api-access-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 API access quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/how-to-choose-a-video-generation-api-by-use-case/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>videogeneration</category>
      <category>api</category>
      <category>modelcomparison</category>
    </item>
    <item>
      <title>How to Access the Seedance 2.0 Video Generation API (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Wed, 29 Jul 2026 00:33:25 +0000</pubDate>
      <link>https://dev.to/owen_fox/how-to-access-the-seedance-20-video-generation-api-2026-2f9b</link>
      <guid>https://dev.to/owen_fox/how-to-access-the-seedance-20-video-generation-api-2026-2f9b</guid>
      <description>&lt;h1&gt;
  
  
  How to Access the Seedance 2.0 Video Generation API (2026)
&lt;/h1&gt;

&lt;p&gt;Seedance 2.0 is ByteDance's text-to-video and image-to-video model, and the fastest way to call it is through ofox: one API key, USD billing, and a single async REST endpoint. You &lt;code&gt;POST https://api.ofox.ai/v1/videos&lt;/code&gt; with a model ID and a prompt, get back a &lt;code&gt;polling_url&lt;/code&gt;, poll until the status is &lt;code&gt;completed&lt;/code&gt;, then read the clip from &lt;code&gt;unsigned_urls[0]&lt;/code&gt;. No per-vendor account, no separate SDK. The rest of this guide is the working quickstart: auth, a text-to-video call in Python and Node, the async lifecycle, image and reference inputs, and what a clip actually costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST https://api.ofox.ai/v1/videos&lt;/code&gt; (async)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;one ofox Bearer key&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model IDs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bytedance/seedance-2.0&lt;/code&gt;, &lt;code&gt;-fast&lt;/code&gt;, &lt;code&gt;-mini&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time to first clip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;about 5 minutes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get the result&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;poll &lt;code&gt;GET /v1/videos/{id}&lt;/code&gt;, read &lt;code&gt;unsigned_urls[0]&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Need
&lt;/h2&gt;

&lt;p&gt;Three things, and you already have two of them if you use ofox for chat or image calls.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;An ofox API key.&lt;/strong&gt; The base URL is &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt; and auth is a standard &lt;code&gt;Authorization: Bearer&lt;/code&gt; header. The same key you use for OpenAI-compatible chat and image requests also submits video jobs, so there is no separate account or vendor SDK to set up.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The endpoint.&lt;/strong&gt; Everything runs through &lt;code&gt;POST /v1/videos&lt;/code&gt; and &lt;code&gt;GET /v1/videos/{id}&lt;/code&gt;. That is the whole surface.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;A model ID.&lt;/strong&gt; &lt;code&gt;bytedance/seedance-2.0&lt;/code&gt; is the flagship: text-to-video, image-to-video, video-to-video, synced audio, clips from 4 to 15 seconds, up to 4K. &lt;code&gt;bytedance/seedance-2.0-fast&lt;/code&gt; and &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt; are the cheaper tiers and both cap at 720p.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Set the key once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Your First Request: Text-to-Video
&lt;/h2&gt;

&lt;p&gt;Video generation is not a blocking call the way a chat completion is. The clip takes render time, so &lt;code&gt;POST /v1/videos&lt;/code&gt; returns &lt;code&gt;202 Accepted&lt;/code&gt; right away with a &lt;code&gt;polling_url&lt;/code&gt;, and you poll that URL until the job reaches a terminal state. The mode is inferred from the fields you send: no image field means text-to-video.&lt;/p&gt;

&lt;p&gt;Here is a complete round trip in Python. It submits the job, polls at a sane cadence, and pulls the clip from &lt;code&gt;unsigned_urls[0]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HEAD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;TERMINAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cancelled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expired&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytedance/seedance-2.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A red kayak cuts through morning fog on a still lake, slow dolly forward.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resolution&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1080p&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aspect_ratio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16:9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                     &lt;span class="c1"&gt;# 202 Accepted
&lt;/span&gt;&lt;span class="n"&gt;task_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;polling_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;TERMINAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="c1"&gt;# break on ALL four terminal states
&lt;/span&gt;        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                          &lt;span class="c1"&gt;# poll every 1-2s, not in a tight loop
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clip:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unsigned_urls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# there is no output_url field
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billed:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_cost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job ended as:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same shape in Node with &lt;code&gt;fetch&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HEAD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TERMINAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cancelled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expired&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/videos`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bytedance/seedance-2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A red kayak cuts through morning fog on a still lake, slow dolly forward.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1080p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16:9&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;polling_url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// 202 Accepted&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// poll every 1-2s&lt;/span&gt;
  &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;polling_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HEAD&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;TERMINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unsigned_urls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;     &lt;span class="c1"&gt;// not output_url&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;billed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video_cost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things trip up first-time callers. The first is reaching for &lt;code&gt;resp["output_url"]&lt;/code&gt;, which does not exist and returns &lt;code&gt;None&lt;/code&gt; in Python or &lt;code&gt;undefined&lt;/code&gt; in Node. The clip lives in &lt;code&gt;unsigned_urls[0]&lt;/code&gt;. The second is a poll loop that only checks for &lt;code&gt;completed&lt;/code&gt;. A job that ends in &lt;code&gt;failed&lt;/code&gt; or &lt;code&gt;expired&lt;/code&gt; never sets &lt;code&gt;completed&lt;/code&gt;, so a loop that ignores the other terminal states spins forever. Break on all four.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the Async Lifecycle
&lt;/h2&gt;

&lt;p&gt;A Seedance job moves through a fixed set of states. Three are transient and four are terminal. There is no &lt;code&gt;processing&lt;/code&gt; state, so do not check for one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;What to do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accepted, not yet queued&lt;/td&gt;
&lt;td&gt;Keep polling every 1-2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;queued&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Queued for render&lt;/td&gt;
&lt;td&gt;Keep polling every 1-2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;in_progress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rendering&lt;/td&gt;
&lt;td&gt;Keep polling every 1-2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;completed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Done, URLs attached&lt;/td&gt;
&lt;td&gt;Download from &lt;code&gt;unsigned_urls[0]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;failed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generation error&lt;/td&gt;
&lt;td&gt;Read the error, retry or fall back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cancelled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;You cancelled it&lt;/td&gt;
&lt;td&gt;Stop polling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;expired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Task aged out&lt;/td&gt;
&lt;td&gt;Resubmit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Poll cadence matters. &lt;code&gt;GET /v1/videos/{id}&lt;/code&gt; no faster than once per second; roughly every one to two seconds is the sweet spot. Hammering it in a tight loop wastes quota and gets you nothing sooner, since the clip is rendering upstream regardless.&lt;/p&gt;

&lt;p&gt;The result URLs have a shelf life, so treat &lt;code&gt;completed&lt;/code&gt; as your cue to download. &lt;code&gt;unsigned_urls&lt;/code&gt; expire about 24 hours after the job finishes. &lt;code&gt;mirror_urls&lt;/code&gt; are persistent, but each signed link still carries its own TTL. In practice: when the status flips to &lt;code&gt;completed&lt;/code&gt;, pull &lt;code&gt;unsigned_urls[0]&lt;/code&gt; into your own bucket (S3, R2, GCS) immediately rather than storing the API URL and serving it to clients later.&lt;/p&gt;

&lt;p&gt;For production you usually want a webhook instead of a polling thread. Pass a &lt;code&gt;callback_url&lt;/code&gt; at creation and ofox posts an HMAC-signed payload when the job reaches a terminal state. The address must be public HTTPS; a private, loopback, or otherwise unreachable host is rejected at submit time with a &lt;code&gt;400 invalid_callback_url&lt;/code&gt;. Polling and webhooks are not mutually exclusive, so a common pattern is a webhook for the happy path plus a slow poll as a backstop.&lt;/p&gt;

&lt;p&gt;Need to stop a job early? &lt;code&gt;DELETE /v1/videos/{id}&lt;/code&gt; cancels it, and the task settles into &lt;code&gt;cancelled&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image-to-Video and Reference Images
&lt;/h2&gt;

&lt;p&gt;You do not switch endpoints to animate a still or steer generation with reference frames. Same &lt;code&gt;POST /v1/videos&lt;/code&gt;, same polling. The request mode is inferred from which fields you include.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;No image field&lt;/strong&gt; gives text-to-video, the call above.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;frame_images&lt;/code&gt;&lt;/strong&gt; gives image-to-video. Pass one URL for a single starting frame, or a first and last frame for interpolation between them.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;input_references&lt;/code&gt;&lt;/strong&gt; gives reference-guided generation, where you supply images that anchor identity, style, or a product's look.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Image-to-video from a starting frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytedance/seedance-2.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The logo tilts up and catches a rim light, subtle rotation.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;frame_images&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://your-cdn.com/first-frame.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resolution&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1080p&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aspect_ratio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16:9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything downstream is identical: &lt;code&gt;202&lt;/code&gt;, a &lt;code&gt;polling_url&lt;/code&gt;, the same status set, and the clip in &lt;code&gt;unsigned_urls[0]&lt;/code&gt;. Audio is generated across all three tiers, so name the sound you want in the prompt or you inherit whatever the model infers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing: Per Resolution, Not Flat
&lt;/h2&gt;

&lt;p&gt;This is the number people get wrong. The &lt;code&gt;from $0.07/s&lt;/code&gt; next to Seedance 2.0 on the catalog is a 480p floor, not a flat rate. Price scales with the resolution you request, so the real cost of a clip is the per-second rate at your resolution times the clip length. Here is the flagship text-to-video rate card:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;bytedance/seedance-2.0&lt;/code&gt; (text-to-video)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;480p&lt;/td&gt;
&lt;td&gt;$0.07/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;720p&lt;/td&gt;
&lt;td&gt;$0.16/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1080p&lt;/td&gt;
&lt;td&gt;$0.34/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4K&lt;/td&gt;
&lt;td&gt;$1.37/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Billing is per output second, and the completed response tells you the exact charge in &lt;code&gt;usage.video_cost&lt;/code&gt;. So an 8-second 1080p clip is &lt;code&gt;8 x $0.34 = $2.72&lt;/code&gt;, and the same clip at 4K is &lt;code&gt;8 x $1.37 = $10.96&lt;/code&gt;. Video-to-video runs a little higher per second than text-to-video at each resolution, which the model page spells out in full.&lt;/p&gt;

&lt;p&gt;The cheaper tiers trade resolution for cost and both cap at 720p: &lt;code&gt;bytedance/seedance-2.0-fast&lt;/code&gt; is $0.06/s at 480p and $0.13/s at 720p, while &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt; is $0.04/s at 480p and $0.08/s at 720p. If most of your output lands on a feed that downscales to 720p anyway, Mini at $0.08/s is the lowest 720p rate of the three.&lt;/p&gt;

&lt;p&gt;Because all three tiers share the same endpoint and differ only by the &lt;code&gt;model&lt;/code&gt; string, you can route drafts to Mini and reserve the flagship for masters. For the full head-to-head, including when Fast is worth its premium over Mini, read the &lt;a href="https://ofox.ai/blog/seedance-2-0-fast-mini-tier-comparison-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 tier comparison&lt;/a&gt; and the &lt;a href="https://ofox.ai/models/bytedance/seedance-2.0" rel="noopener noreferrer"&gt;Seedance 2.0 model page&lt;/a&gt; for the complete per-resolution matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Key, Every Video Model
&lt;/h2&gt;

&lt;p&gt;The reason this quickstart is short is that ofox collapses the whole video stack into one auth and one schema. You already have the pattern: submit to &lt;code&gt;/v1/videos&lt;/code&gt;, poll, download. Swapping models is a string change.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Generate on Seedance 2.0 with the key you already have.&lt;/strong&gt; &lt;a href="https://ofox.ai/video?utm_source=blog&amp;amp;utm_medium=post&amp;amp;utm_campaign=seedance-api-access" rel="noopener noreferrer"&gt;Start on the ofox video API&lt;/a&gt;: one key, USD billing, pay only for the seconds you render, no per-vendor signup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If Seedance is not the right fit for a given clip, the same endpoint reaches the rest of the catalog. Alibaba's Wan starts at a 2-second minimum where Seedance floors at 4 seconds; the &lt;a href="https://ofox.ai/blog/seedance-2-0-vs-wan-video-api-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 vs Wan comparison&lt;/a&gt; covers that trade. The exact request and response fields, including every optional parameter, live in the &lt;a href="https://ofox.ai/docs/api/videos" rel="noopener noreferrer"&gt;ofox video API reference&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How do I call the Seedance 2.0 API?&lt;/strong&gt; Send &lt;code&gt;POST https://api.ofox.ai/v1/videos&lt;/code&gt; with a Bearer ofox key and a JSON body of &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;prompt&lt;/code&gt;, &lt;code&gt;duration&lt;/code&gt;, &lt;code&gt;resolution&lt;/code&gt;, and &lt;code&gt;aspect_ratio&lt;/code&gt;. It returns &lt;code&gt;202&lt;/code&gt; with a &lt;code&gt;polling_url&lt;/code&gt;. Poll &lt;code&gt;GET /v1/videos/{id}&lt;/code&gt; every 1-2 seconds until &lt;code&gt;status&lt;/code&gt; is &lt;code&gt;completed&lt;/code&gt;, then read the clip from &lt;code&gt;unsigned_urls[0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is the video URL empty when I read output_url?&lt;/strong&gt; There is no &lt;code&gt;output_url&lt;/code&gt; field. The clip is in &lt;code&gt;unsigned_urls&lt;/code&gt; (an array, so use &lt;code&gt;unsigned_urls[0]&lt;/code&gt;) or in &lt;code&gt;mirror_urls&lt;/code&gt;. Reading &lt;code&gt;resp["output_url"]&lt;/code&gt; returns &lt;code&gt;None&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long do Seedance 2.0 result URLs stay valid?&lt;/strong&gt; &lt;code&gt;unsigned_urls&lt;/code&gt; expire about 24 hours after completion. &lt;code&gt;mirror_urls&lt;/code&gt; are persistent, but each signed link carries its own TTL. Download the file as soon as the status is &lt;code&gt;completed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does the Seedance 2.0 API cost?&lt;/strong&gt; Per output second by resolution, not a flat rate. Flagship text-to-video is $0.07/s at 480p, $0.16/s at 720p, $0.34/s at 1080p, and $1.37/s at 4K. An 8-second 1080p clip is $2.72.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can Seedance 2.0 generate video from an image?&lt;/strong&gt; Yes. Pass &lt;code&gt;frame_images&lt;/code&gt; for image-to-video or &lt;code&gt;input_references&lt;/code&gt; for reference-guided generation. The mode is inferred from the fields; no image means text-to-video.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the cheapest Seedance 2.0 model?&lt;/strong&gt; &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt;, at $0.04/s for 480p and $0.08/s for 720p. It caps at 720p, as does &lt;code&gt;-fast&lt;/code&gt;. Only the flagship reaches 1080p and 4K.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Refresh
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/video" rel="noopener noreferrer"&gt;ofox video model catalog and per-second floor pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models/bytedance/seedance-2.0" rel="noopener noreferrer"&gt;ofox Seedance 2.0 model detail, 480p to 4K per-resolution pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/docs/api/videos" rel="noopener noreferrer"&gt;ofox video API reference: endpoint, polling, status enum, callback_url&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://seed.bytedance.com/en/seedance" rel="noopener noreferrer"&gt;ByteDance Seed, Seedance model overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/blog/seedance-2-0-fast-mini-tier-comparison-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 tier comparison: Mini, Fast, and flagship&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/blog/seedance-2-0-vs-wan-video-api-2026/" rel="noopener noreferrer"&gt;Seedance 2.0 vs Wan video API comparison&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/seedance-2-0-video-api-access-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>videogeneration</category>
      <category>seedance</category>
    </item>
    <item>
      <title>GLM-5.2 in Cline: Setup, Thinking, Cost vs Sonnet 5 (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Tue, 28 Jul 2026 14:39:38 +0000</pubDate>
      <link>https://dev.to/owen_fox/glm-52-in-cline-setup-thinking-cost-vs-sonnet-5-2026-1iln</link>
      <guid>https://dev.to/owen_fox/glm-52-in-cline-setup-thinking-cost-vs-sonnet-5-2026-1iln</guid>
      <description>&lt;p&gt;Cline bills by the token, and it is not shy about spending them. Every turn it resends your file tree, the open buffers, and the running task log, so the model you pick shows up on the invoice within a day. GLM-5.2 is the model a lot of teams reach for to make that loop cheaper without dropping to something that can’t hold a refactor together. This guide wires it into Cline in about five minutes.&lt;/p&gt;

&lt;p&gt;Two things trip people up, and neither is the part people worry about. The first is that GLM-5.2 is not a Claude model, so it does not go in the slot most Cline guides point you at. The second is the thinking toggle, which does not behave the way the Sonnet 5 one does. Both are below, along with the cost comparison that decides whether GLM-5.2 is actually the right call over Claude Sonnet 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Do After This Setup (And What You Can’t)
&lt;/h2&gt;

&lt;p&gt;After this you will have GLM-5.2 driving Cline as an agent: reading files, proposing diffs, running commands, across a full 1M-token context. Here is the honest scope before you spend the five minutes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Can GLM-5.2 act as a full Cline agent?&lt;/td&gt;
&lt;td&gt;Yes, through the OpenAI Compatible provider it gets tool use.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does it use the Anthropic provider slot?&lt;/td&gt;
&lt;td&gt;No. That slot is for Claude. GLM goes through OpenAI Compatible.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can I control reasoning depth?&lt;/td&gt;
&lt;td&gt;Partly. Cline sends a reasoning-effort hint; you can’t turn GLM’s thinking off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the full 1M context work?&lt;/td&gt;
&lt;td&gt;Yes, if you set the context window to 1000000 in Cline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is it cheaper than Claude Sonnet 5?&lt;/td&gt;
&lt;td&gt;On raw rates yes, about 1.6-1.9x. Caching narrows it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Will tool use be as clean as Claude’s?&lt;/td&gt;
&lt;td&gt;Not always. GLM has documented tool-call parsing quirks in Cline.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Decision Frame: When to Run GLM-5.2 in Cline (and When Not)
&lt;/h2&gt;

&lt;p&gt;GLM-5.2 is a genuine value play for coding, not a downgrade. But it is not the automatic pick, and choosing it in the wrong situation costs you either money or a morning of debugging tool calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use GLM-5.2
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Your Cline sessions are long and file-heavy, so token volume, not peak reasoning, sets the bill, and a lower output rate compounds fast.&lt;/li&gt;
&lt;li&gt;You want a coding-first model with a real 1M window for large-repo work.&lt;/li&gt;
&lt;li&gt;You already route mixed models through one OpenAI-compatible endpoint and want to add a cheap default without a second integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When NOT to use it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are a Claude shop and value native tool use, cache controls, and the effort dial. Sonnet 5 on Cline’s Anthropic provider keeps all three, and the ~1.6x price gap may not pay for the rougher integration.&lt;/li&gt;
&lt;li&gt;The task is a gnarly cross-file refactor or a subtle concurrency bug where a stronger model finishes in one pass instead of three. Save the escalation for those and let GLM handle the other 80%.&lt;/li&gt;
&lt;li&gt;You need a hard off-switch for reasoning on trivial turns. GLM keeps thinking on by default from Cline, which you cannot change from the UI (covered below).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The stop rule
&lt;/h3&gt;

&lt;p&gt;If your goal is just to point Cline at a cheap coding model, do Steps 1 through 5, set the context window, and stop. The thinking and cost sections are for people tuning spend against quality, not for the basic connect.&lt;/p&gt;

&lt;h2&gt;
  
  
  System Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VS Code with the &lt;a href="https://github.com/cline/cline" rel="noopener noreferrer"&gt;Cline extension&lt;/a&gt;&lt;/strong&gt; installed from the marketplace, on a current release. GLM tool-call handling has improved across recent versions, so an old build is a common source of trouble.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An API key&lt;/strong&gt; for a backend that serves GLM-5.2. This guide uses ofox, an OpenAI-compatible gateway, so one key also reaches Claude, GPT, and the rest when you want to escalate a hard turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network reach&lt;/strong&gt; to your endpoint. Behind a corporate TLS proxy, fix the certificate first; the same Node rules from our &lt;a href="https://ofox.ai/blog/claude-code-ssl-certificate-error-2026/" rel="noopener noreferrer"&gt;Claude Code SSL certificate error guide&lt;/a&gt; apply to Cline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step-by-Step: GLM-5.2 in Cline
&lt;/h2&gt;

&lt;p&gt;The whole setup is five fields and a test message. The one decision that matters is Step 1, and it is the opposite of the Claude answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Pick the provider slot (not the Claude one)
&lt;/h3&gt;

&lt;p&gt;Cline offers two ways in. Most guides tell you to use the Anthropic provider, because most guides are about Claude. GLM-5.2 is not Claude, so that slot is wrong here.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider slot&lt;/th&gt;
&lt;th&gt;Base URL&lt;/th&gt;
&lt;th&gt;Use it for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI Compatible&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GLM-5.2 and any non-Claude model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Claude models only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pick &lt;strong&gt;OpenAI Compatible&lt;/strong&gt;. The gateway does expose GLM-5.2 over an Anthropic-protocol endpoint too, which matters if you drive it from Claude Code, but inside Cline the OpenAI Compatible slot is the path that behaves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Open Cline settings and select the provider
&lt;/h3&gt;

&lt;p&gt;Click the Cline icon in the VS Code Activity Bar, then the gear icon at the top of the panel. Under &lt;strong&gt;API Provider&lt;/strong&gt;, select &lt;strong&gt;OpenAI Compatible&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Set the base URL and key
&lt;/h3&gt;

&lt;p&gt;Paste the base URL and your API key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Base URL: https://api.ofox.ai/v1
API Key:  sk-ofox-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result: the fields save and Cline stops warning about a missing key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Set the Model ID
&lt;/h3&gt;

&lt;p&gt;Set the Model ID to the namespaced id, prefix included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;z-ai/glm-5.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bare &lt;code&gt;glm-5.2&lt;/code&gt; fails on a gateway, because the catalog is namespaced by provider. If you have seen &lt;code&gt;glm-5.2[1m]&lt;/code&gt; elsewhere, that alias is a Claude Code convention on Z.ai’s own coding endpoint for switching on the 1M window; it is not what Cline’s OpenAI Compatible field wants. Here the model ID and the context setting do that job separately. The full set of access paths and where each ID applies is in our &lt;a href="https://ofox.ai/blog/glm-5-2-access-guide-2026/" rel="noopener noreferrer"&gt;GLM-5.2 access guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Set the context window and test
&lt;/h3&gt;

&lt;p&gt;In the OpenAI Compatible model settings, set the context window to &lt;code&gt;1000000&lt;/code&gt;. GLM-5.2 ships a 1M-token window; leave Cline on a smaller default and it will quietly drop earlier tool-call steps on a long task, which reads as the model “losing the plot” mid-refactor.&lt;/p&gt;

&lt;p&gt;Then send a short message in the Cline chat, such as “list the files in this project.” If Cline reads the tree and replies, the wire is connected. Point it at something small next, like “add input validation to the &lt;code&gt;parseConfig&lt;/code&gt; function and a test for it,” and watch that it reads files on its own, proposes a diff you approve, and runs the test. If it reads but never writes, that is a known GLM behavior, not your config; the errors section covers it.&lt;/p&gt;

&lt;p&gt;You can confirm GLM-5.2’s live model ID and per-token rates on its &lt;a href="https://ofox.ai/models/z-ai/glm-5.2" rel="noopener noreferrer"&gt;ofox model page&lt;/a&gt; before you commit a project to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Thinking Toggle: What Cline Actually Sends GLM-5.2
&lt;/h2&gt;

&lt;p&gt;This is the section that surprises people coming from a Claude setup, so it is worth being precise.&lt;/p&gt;

&lt;p&gt;GLM-5.2 is a reasoning model with thinking &lt;strong&gt;on by default&lt;/strong&gt;. Z.ai’s docs are explicit that thinking is “activated by default in GLM-5.2 … series” (the same line covers GLM-5.1, GLM-5, and GLM-4.7). The documented way to change that is a &lt;code&gt;thinking&lt;/code&gt; object on the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"thinking": { "type": "disabled" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the catch. Cline’s OpenAI Compatible provider does not send that object. Its Model Configuration has a Reasoning Effort selector that defaults to &lt;code&gt;none&lt;/code&gt;; set it to low, medium, or high and Cline sends a &lt;code&gt;reasoning&lt;/code&gt; object (&lt;code&gt;{enabled: true, effort}&lt;/code&gt;) instead. Those are two different controls, and GLM’s on/off switch is the one Cline never touches.&lt;/p&gt;

&lt;p&gt;What this means in practice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;Cline OpenAI Compatible&lt;/th&gt;
&lt;th&gt;GLM-5.2 native&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Turn thinking on/off&lt;/td&gt;
&lt;td&gt;Not exposed&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;thinking: {type: enabled/disabled}&lt;/code&gt;, default on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tune reasoning depth&lt;/td&gt;
&lt;td&gt;Reasoning Effort selector, &lt;code&gt;none&lt;/code&gt; default (low/medium/high)&lt;/td&gt;
&lt;td&gt;Gateway-dependent mapping (unverified per gateway)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning output&lt;/td&gt;
&lt;td&gt;Returned as &lt;code&gt;reasoning_content&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Returned as &lt;code&gt;reasoning_content&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Send any reasoning hint&lt;/td&gt;
&lt;td&gt;Move the selector off its &lt;code&gt;none&lt;/code&gt; default&lt;/td&gt;
&lt;td&gt;On by default&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two consequences worth internalizing. First, if you want any reasoning hint to reach the model, you have to move the Reasoning Effort selector off its &lt;code&gt;none&lt;/code&gt; default; left at &lt;code&gt;none&lt;/code&gt;, Cline sends no reasoning parameter at all. Second, whether that &lt;code&gt;reasoning&lt;/code&gt; object actually changes GLM’s behavior depends on the gateway translating it into GLM’s own &lt;code&gt;thinking&lt;/code&gt; control, and it will not disable thinking regardless. GLM thinks; you pay for those tokens as output. Plan for it rather than trying to switch it off.&lt;/p&gt;

&lt;h2&gt;
  
  
  GLM-5.2 vs Claude Sonnet 5: The Cost Math
&lt;/h2&gt;

&lt;p&gt;This is the comparison that decides the setup. Both models are coding-capable, both carry a 1M context, and on ofox both sit behind the same key, so the choice is real rather than a migration.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Cache read&lt;/th&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;th&gt;Model ID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GLM-5.2&lt;/td&gt;
&lt;td&gt;\$1.4/M&lt;/td&gt;
&lt;td&gt;\$4.4/M&lt;/td&gt;
&lt;td&gt;\$0.26/M&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;td&gt;&lt;code&gt;z-ai/glm-5.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5&lt;/td&gt;
&lt;td&gt;\$2/M&lt;/td&gt;
&lt;td&gt;\$10/M&lt;/td&gt;
&lt;td&gt;\$0.20/M&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Sonnet 5 rates above are Anthropic’s introductory pricing, in effect through August 31, 2026 per Anthropic’s pricing docs; the standard rate afterward is \$3/M input and \$15/M output, which widens GLM’s lead. The current per-token numbers match the ofox model pages.&lt;/p&gt;

&lt;p&gt;Blend those at a 2:1 input-to-output ratio, which is typical for coding turns: GLM-5.2 lands near \$2.40 per million tokens, Sonnet 5 near \$4.67. That is roughly a 1.9x gap on raw rates, and it holds around 1.6x once you account for Sonnet 5’s cheaper cache reads. Note the one place Sonnet wins: its cache read at \$0.20/M actually undercuts GLM’s \$0.26/M, so for the resent context Cline leans on every turn, Sonnet’s caching is slightly more efficient per cached token.&lt;/p&gt;

&lt;p&gt;Put real numbers on a session. Say a working session moves roughly 2M input and 200K output across many turns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;GLM-5.2&lt;/th&gt;
&lt;th&gt;Claude Sonnet 5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Session, no caching&lt;/td&gt;
&lt;td&gt;~\$3.68&lt;/td&gt;
&lt;td&gt;~\$6.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session, ~70% context cached&lt;/td&gt;
&lt;td&gt;~\$2.08&lt;/td&gt;
&lt;td&gt;~\$3.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team month (5 devs x 20 days, cached)&lt;/td&gt;
&lt;td&gt;~\$208&lt;/td&gt;
&lt;td&gt;~\$348&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So GLM-5.2 is meaningfully cheaper, on the order of 1.6x for realistic cached workloads, not the 5x you see when comparing a value model against a flagship. That gap is real money at team scale, and it is the whole case for GLM as the default driver. It is also small enough that if you are already a Claude shop getting native tool use and cache controls out of Cline’s Anthropic provider, staying on Sonnet 5 is a defensible call. For the deeper per-token breakdown against the other frontier models, see our &lt;a href="https://ofox.ai/blog/glm-5-2-vs-gpt-5-5-cost-2026/" rel="noopener noreferrer"&gt;GLM-5.2 vs GPT-5.5 cost analysis&lt;/a&gt;, and for the Claude side of this exact setup, the &lt;a href="https://ofox.ai/blog/claude-sonnet-5-cline-setup-2026/" rel="noopener noreferrer"&gt;Claude Sonnet 5 in Cline guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Errors During Setup (and Fixes)
&lt;/h2&gt;

&lt;p&gt;GLM’s open-weight lineage means its Cline integration is rougher than Claude’s, and most of the friction is well-documented rather than mysterious.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model not found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bare ID, or the &lt;code&gt;glm-5.2[1m]&lt;/code&gt; alias on the wrong endpoint&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;z-ai/glm-5.2&lt;/code&gt; on the OpenAI Compatible slot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reads files, never edits&lt;/td&gt;
&lt;td&gt;GLM re-parses the file without emitting an edit call (Cline &lt;a href="https://github.com/cline/cline/issues/7486" rel="noopener noreferrer"&gt;#7486&lt;/a&gt;, GLM-4.6/MiniMax-M2, closed)&lt;/td&gt;
&lt;td&gt;Keep tasks small and context at 1M; escalate stubborn turns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool tags shown as plain text, then stalls&lt;/td&gt;
&lt;td&gt;Thinking tokens leak into &lt;code&gt;content&lt;/code&gt;, Cline treats it all as reasoning (Cline &lt;a href="https://github.com/cline/cline/issues/5843" rel="noopener noreferrer"&gt;#5843&lt;/a&gt;, GLM-4.5, closed)&lt;/td&gt;
&lt;td&gt;Update Cline to a build that parses GLM’s &lt;code&gt;reasoning_content&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning hint has no effect&lt;/td&gt;
&lt;td&gt;Reasoning Effort left at its &lt;code&gt;none&lt;/code&gt; default sends no reasoning params (Cline &lt;a href="https://github.com/cline/cline/issues/6581" rel="noopener noreferrer"&gt;#6581&lt;/a&gt;, gpt-5, closed)&lt;/td&gt;
&lt;td&gt;Set Reasoning Effort to low/medium/high in the model options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model forgets earlier steps mid-task&lt;/td&gt;
&lt;td&gt;Context window left at Cline’s default&lt;/td&gt;
&lt;td&gt;Set the context window to &lt;code&gt;1000000&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;401 Unauthorized&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Key is for a different gateway, or blank&lt;/td&gt;
&lt;td&gt;Paste the key that matches your base URL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a model ID resolves but responses feel truncated, check that Cline’s max-output setting is not clipping the answer before the reasoning pass and the actual reply both fit. GLM-5.2 supports up to 128K output tokens, but Cline’s default cap is much lower.&lt;/p&gt;

&lt;h2&gt;
  
  
  Team / Multi-Developer Configuration
&lt;/h2&gt;

&lt;p&gt;For a team the win is one endpoint and one model policy instead of everyone wiring their own keys against their own GLM subscription. Register a single gateway, hand each developer a key through your secret manager, and standardize the Cline provider settings so everyone routes &lt;code&gt;z-ai/glm-5.2&lt;/code&gt; through the same base URL. Billing lands in one place, and switching the whole team’s default is a one-line change to the shared Model ID rather than a fleet of individual reconfigurations.&lt;/p&gt;

&lt;p&gt;The habit that pairs with this is model tiering: run GLM-5.2 as the cheap default for the bulk of turns and escalate only the genuinely hard ones to a stronger model. Because ofox exposes GLM, Claude, and the rest on the same key, escalation is a single Model ID swap, not a new integration. The routing logic is the same one in our &lt;a href="https://ofox.ai/blog/30-dollar-ai-coding-stack-setup-guide-2026/" rel="noopener noreferrer"&gt;\$30 AI coding stack guide&lt;/a&gt;, and the general endpoint mechanics are in the &lt;a href="https://ofox.ai/blog/cline-vscode-ai-api-configuration-guide-2026/" rel="noopener noreferrer"&gt;Cline API configuration guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives: Other Ways to Run GLM-5.2
&lt;/h2&gt;

&lt;p&gt;Cline through ofox is the setup this guide recommends, because one key covers GLM plus every model you would escalate to. It is not the only path.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ofox (OpenAI Compatible), recommended.&lt;/strong&gt; &lt;code&gt;z-ai/glm-5.2&lt;/code&gt; at &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;, pay-as-you-go, and the same key reaches Claude and GPT for the hard turns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Z.ai directly.&lt;/strong&gt; Z.ai’s own API and Coding Plan serve GLM-5.2 natively, including the &lt;code&gt;glm-5.2[1m]&lt;/code&gt; alias for the 1M window on the coding endpoint. Cheapest if you only ever use GLM and want the native &lt;code&gt;thinking&lt;/code&gt; controls. The &lt;a href="https://ofox.ai/blog/glm-5-2-access-guide-2026/" rel="noopener noreferrer"&gt;GLM-5.2 access guide&lt;/a&gt; walks through it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenRouter.&lt;/strong&gt; Also exposes &lt;code&gt;z-ai/glm-5.2&lt;/code&gt; behind an OpenAI-compatible slot, useful if you already route everything through it. See &lt;a href="https://openrouter.ai/z-ai/glm-5.2" rel="noopener noreferrer"&gt;openrouter.ai/z-ai/glm-5.2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosting the open weights.&lt;/strong&gt; GLM-5.2’s weights make a local vLLM deployment possible if your workload justifies the hardware. We costed that out in &lt;a href="https://ofox.ai/blog/glm-5-2-self-host-vllm-hardware-cost-2026/" rel="noopener noreferrer"&gt;self-hosting GLM-5.2 on vLLM&lt;/a&gt;, and the free-tier paths are in &lt;a href="https://ofox.ai/blog/glm-5-2-free-zero-cost-paths-2026/" rel="noopener noreferrer"&gt;GLM-5.2 free: the \$0 routes&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How do I run GLM-5.2 in Cline?&lt;/strong&gt; Open Cline settings, pick the OpenAI Compatible provider, set the Base URL to &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;, paste your key, set the Model ID to &lt;code&gt;z-ai/glm-5.2&lt;/code&gt;, and set the context window to &lt;code&gt;1000000&lt;/code&gt;. Send a test message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What model ID does Cline use for GLM-5.2?&lt;/strong&gt; &lt;code&gt;z-ai/glm-5.2&lt;/code&gt; through the gateway, prefix included. A bare &lt;code&gt;glm-5.2&lt;/code&gt; fails, and the &lt;code&gt;glm-5.2[1m]&lt;/code&gt; alias belongs to Z.ai’s coding endpoint, not Cline’s OpenAI Compatible field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does GLM-5.2 work with Cline’s agent mode?&lt;/strong&gt; Yes, through OpenAI Compatible it reads files, writes diffs, and runs commands. Tool use runs through a translation layer and GLM has documented parsing quirks, so keep command approval on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I turn off GLM-5.2’s thinking in Cline?&lt;/strong&gt; You can’t from the UI. Thinking is on by default and the off switch is the &lt;code&gt;thinking: {type: disabled}&lt;/code&gt; parameter, which Cline’s OpenAI Compatible path does not send. The Reasoning Effort selector (default &lt;code&gt;none&lt;/code&gt;) tunes depth, not on/off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is GLM-5.2 cheaper than Claude Sonnet 5?&lt;/strong&gt; On raw rates yes, about 1.6-1.9x (\$1.4/\$4.4 vs \$2/\$10 on ofox). Sonnet 5’s cheaper cache reads and native Cline integration narrow the practical gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does GLM read files but never edit them?&lt;/strong&gt; The same behavior was tracked for earlier GLM builds (GLM-4.6) in Cline issue #7486, now closed; it can still surface with 5.2 on the compatible path. Keep tasks small and context at 1M; escalate the turn if it persists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do I see &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; tags or raw reasoning in the output?&lt;/strong&gt; GLM’s &lt;code&gt;reasoning_content&lt;/code&gt; is leaking into the main stream and Cline stalls on tool use. Update Cline to a build that parses the reasoning field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What context window should I set?&lt;/strong&gt; &lt;code&gt;1000000&lt;/code&gt;. GLM-5.2 has a 1M window and up to 128K output; a smaller setting drops earlier steps on long tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Refresh
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.z.ai/guides/capabilities/thinking-mode" rel="noopener noreferrer"&gt;Z.ai thinking-mode documentation&lt;/a&gt;. Confirms thinking is on by default for GLM-5.2, the &lt;code&gt;thinking: {type}&lt;/code&gt; parameter, and &lt;code&gt;clear_thinking&lt;/code&gt; (verified 2026-07-28).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.z.ai/guides/llm/glm-5.2" rel="noopener noreferrer"&gt;Z.ai GLM-5.2 model reference&lt;/a&gt;. Source for the 1M context, up to 128K output, and the &lt;code&gt;reasoning_content&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cline/cline" rel="noopener noreferrer"&gt;Cline repository&lt;/a&gt; and issues &lt;a href="https://github.com/cline/cline/issues/5843" rel="noopener noreferrer"&gt;#5843&lt;/a&gt; (GLM-4.5), &lt;a href="https://github.com/cline/cline/issues/6581" rel="noopener noreferrer"&gt;#6581&lt;/a&gt; (gpt-5), &lt;a href="https://github.com/cline/cline/issues/7486" rel="noopener noreferrer"&gt;#7486&lt;/a&gt; (GLM-4.6/MiniMax-M2), all closed. Reasoning-effort handling and GLM tool-call behavior on the compatible path.&lt;/li&gt;
&lt;li&gt;ofox model pages for &lt;a href="https://ofox.ai/models/z-ai/glm-5.2" rel="noopener noreferrer"&gt;z-ai/glm-5.2&lt;/a&gt; and &lt;a href="https://ofox.ai/models/anthropic/claude-sonnet-5" rel="noopener noreferrer"&gt;anthropic/claude-sonnet-5&lt;/a&gt;. Per-token rates \$1.4/\$4.4 and \$2/\$10, cache reads \$0.26/M and \$0.20/M (verified 2026-07-28).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic pricing documentation&lt;/a&gt;. Source for the Sonnet 5 introductory window through August 31, 2026 and the standard \$3/\$15 rate afterward.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/glm-5-2-in-cline-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cline</category>
      <category>glm</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Claude Opus 5 vs GPT-5.6 Sol (2026): Benchmarks + Real Bill</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Mon, 27 Jul 2026 04:36:11 +0000</pubDate>
      <link>https://dev.to/owen_fox/claude-opus-5-vs-gpt-56-sol-2026-benchmarks-real-bill-1hce</link>
      <guid>https://dev.to/owen_fox/claude-opus-5-vs-gpt-56-sol-2026-benchmarks-real-bill-1hce</guid>
      <description>&lt;h1&gt;
  
  
  Claude Opus 5 vs GPT-5.6 Sol (2026): Benchmarks + Real Bill
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; Claude Opus 5 and GPT-5.6 Sol are two frontier models priced within a rounding error of each other, and the "cheaper" one depends on where you buy. On &lt;strong&gt;vendor list price&lt;/strong&gt; they match on input ($5/M) and cache ($0.50/M), and differ only on output: &lt;strong&gt;$25/M on Opus 5 versus $30/M on Sol&lt;/strong&gt;, so on list Opus 5 is ~17% cheaper. On &lt;strong&gt;ofox as of July 27, 2026&lt;/strong&gt;, Sol is on a &lt;strong&gt;-20% promo&lt;/strong&gt; ($4/$24/$0.40) while Opus 5 sits at list, which flips it: on ofox, Sol is currently cheaper on every line. On the one third-party benchmark that scores both on the same harness, the &lt;a href="https://artificialanalysis.ai/models/comparisons/claude-opus-5-vs-gpt-5-6-sol" rel="noopener noreferrer"&gt;Artificial Analysis Intelligence Index v4.1&lt;/a&gt;, Opus 5 leads by two points (&lt;strong&gt;61 vs 59&lt;/strong&gt; at max effort). Every other launch number is vendor-reported on a different harness and cannot be lined up. Sol streams tokens ~1.4x faster (75.9 vs 52.8 tok/s); Opus 5 reaches first token ~1.9x faster (69.7s vs 129.5s). Both live on one &lt;a href="https://ofox.ai/en" rel="noopener noreferrer"&gt;ofox&lt;/a&gt; key, so the honest way to decide is a one-line A/B on your own tasks. This post gives you the numbers that are real, flags the ones that aren't, and hands you the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: Which One Should You Pick?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your job&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cheapest on ofox right now&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ofox runs Sol at -20% ($4/$24/$0.40); cheaper on every line while the promo holds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cheapest on vendor list price&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Opus 5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Output $25/M vs $30/M; input and cache identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Highest score on a neutral composite&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Opus 5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AA Intelligence Index 61 vs 59 at max effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency-sensitive interactive turns&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Opus 5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~69.7s to first token vs ~129.5s on the same test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Streaming a long answer as fast as possible&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~75.9 output tok/s vs ~52.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You already run the OpenAI Responses API and want Pro/Ultra&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Heavy-compute modes are Sol-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Computer use and desktop automation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Opus 5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anthropic's OSWorld/AutomationBench framing (vendor, unverified)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One sentence: Opus 5 wins the one comparable benchmark and starts faster; Sol streams faster, owns the heavy-compute ceiling, and is the cheaper model on ofox while its promo lasts. These two are close enough that the tie-breaker is your own workload, so keep both on one key and A/B them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Specs Comparison
&lt;/h2&gt;

&lt;p&gt;Both models are current flagships, both went live within three weeks of each other (&lt;a href="https://simonwillison.net/2026/Jul/9/gpt-5-6/" rel="noopener noreferrer"&gt;Sol at GA on July 9&lt;/a&gt;, &lt;a href="https://www.anthropic.com/news/claude-opus-5" rel="noopener noreferrer"&gt;Opus 5 on July 24&lt;/a&gt;). The table below lists vendor &lt;strong&gt;list&lt;/strong&gt; price and the &lt;strong&gt;ofox&lt;/strong&gt; price separately, because they differ: ofox is running Sol on a 20% promo. All figures verified against each model's ofox page on July 27, 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Claude Opus 5&lt;/th&gt;
&lt;th&gt;GPT-5.6 Sol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ofox model ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-opus-5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-5.6-sol&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input (list)&lt;/td&gt;
&lt;td&gt;$5.00 / M&lt;/td&gt;
&lt;td&gt;$5.00 / M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output (list)&lt;/td&gt;
&lt;td&gt;$25.00 / M&lt;/td&gt;
&lt;td&gt;$30.00 / M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cached input (list)&lt;/td&gt;
&lt;td&gt;$0.50 / M&lt;/td&gt;
&lt;td&gt;$0.50 / M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ofox price (Jul 27)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$5 / $25 / $0.50&lt;/strong&gt; (list, no promo)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$4 / $24 / $0.40&lt;/strong&gt; (-20% promo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;1,000,000 tokens&lt;/td&gt;
&lt;td&gt;1,000,000 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max output&lt;/td&gt;
&lt;td&gt;128,000 tokens&lt;/td&gt;
&lt;td&gt;128,000 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning control&lt;/td&gt;
&lt;td&gt;Adaptive thinking + effort &lt;code&gt;low&lt;/code&gt;–&lt;code&gt;max&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;reasoning_effort&lt;/code&gt; &lt;code&gt;none&lt;/code&gt;–&lt;code&gt;xhigh&lt;/code&gt; (chat); Responses API for &lt;code&gt;max&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy-compute mode&lt;/td&gt;
&lt;td&gt;Fast Mode (speed), no parallel-subagent tier&lt;/td&gt;
&lt;td&gt;Pro / Ultra (Sol only, Responses API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native API&lt;/td&gt;
&lt;td&gt;Anthropic Messages&lt;/td&gt;
&lt;td&gt;OpenAI Responses / chat&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On paper the two nearly match: same context, same output cap, and the same $5 list input. The two spots that actually separate them are price (identical on list except output, but currently reshuffled by ofox's Sol promo) and which native API you reach for reasoning control. The pricing section below works both prices through a real bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The One Number You Can Actually Compare
&lt;/h2&gt;

&lt;p&gt;Here is the trap in every GPT-5.6-vs-Opus-5 post you will read this week: they build a big table with Terminal-Bench in one row and CursorBench in the next and a SWE-Bench number below that, as if those figures came off the same ruler. They did not. Anthropic ran Opus 5 on Anthropic's harness. OpenAI ran Sol on OpenAI's. A benchmark name is not a shared measurement.&lt;/p&gt;

&lt;p&gt;The one place both models are scored by the same third party, on the same tasks, with the same grader, is the &lt;a href="https://artificialanalysis.ai/models/comparisons/claude-opus-5-vs-gpt-5-6-sol" rel="noopener noreferrer"&gt;Artificial Analysis Intelligence Index v4.1&lt;/a&gt;. That index is a weighted composite of nine evaluations, including GDPval-AA v2, Terminal-Bench v2.1, SciCode, Humanity's Last Exam, GPQA Diamond, and AA-LCR, weighted roughly 34% toward agents, 24% coding, 24% scientific reasoning, and 18% general intelligence. Because Artificial Analysis runs both models itself, on its own harness, its composite is the closest thing to an apples-to-apples read that exists right now, and the eval mix leans toward exactly the agentic and coding work most people are choosing between these two for.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Artificial Analysis Intelligence Index v4.1&lt;/th&gt;
&lt;th&gt;Claude Opus 5&lt;/th&gt;
&lt;th&gt;GPT-5.6 Sol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Intelligence Index, max effort&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;61&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://artificialanalysis.ai/models/comparisons/claude-opus-5-vs-gpt-5-6-sol" rel="noopener noreferrer"&gt;Artificial Analysis comparison page&lt;/a&gt;, read July 27, 2026. Opus 5 is scored in Adaptive Reasoning at max effort; Sol at max. AA is a rolling benchmark, so the exact figures can shift, re-read the page on publish day.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Opus 5 leads by two points at max effort. That is a real, reproducible, same-harness result, and it is the strongest single fact in this comparison. It is also small. For context, the same index puts &lt;a href="https://ofox.ai/models/anthropic/claude-fable-5" rel="noopener noreferrer"&gt;Claude Fable 5&lt;/a&gt; at 60 (max), which means AA's composite rates Opus 5 a hair above Anthropic's own larger flagship, and rates Sol a hair below it. Read that carefully before you over-invest in it. A two-point gap on a nine-eval composite is not a knockout. It tells you Opus 5 is at least Sol's equal on a broad neutral test, and probably a shade better, but it does not tell you which one is better at &lt;em&gt;your&lt;/em&gt; refactor, &lt;em&gt;your&lt;/em&gt; migration, or &lt;em&gt;your&lt;/em&gt; agent loop. That is what the A/B at the end is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Launch Benchmarks Don't Line Up
&lt;/h2&gt;

&lt;p&gt;Both vendors published launch numbers. They are worth reading, as long as you read them as two separate marketing decks and never as a shared table. Split by source:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anthropic's Opus 5 figures&lt;/strong&gt; (Anthropic internal, unverified, from the &lt;a href="https://www.anthropic.com/news/claude-opus-5" rel="noopener noreferrer"&gt;Opus 5 announcement&lt;/a&gt;):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Anthropic's claim&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontier-Bench v0.1&lt;/td&gt;
&lt;td&gt;Surpasses all other models; more than doubles Opus 4.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CursorBench 3.2&lt;/td&gt;
&lt;td&gt;Within 0.5% of Fable 5's peak, at half the cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARC-AGI-3&lt;/td&gt;
&lt;td&gt;Roughly 3x the next-best model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OSWorld 2.0 (computer use)&lt;/td&gt;
&lt;td&gt;Beats Fable 5 at one-third the cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GDPval-AA (economic work)&lt;/td&gt;
&lt;td&gt;State of the art&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;OpenAI's GPT-5.6 Sol figures&lt;/strong&gt; (OpenAI's own harness, from the &lt;a href="https://platform.openai.com/docs/models/gpt-5-6-sol" rel="noopener noreferrer"&gt;GA launch&lt;/a&gt;):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;OpenAI's claim&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-Bench 2.1&lt;/td&gt;
&lt;td&gt;88.8% base, 91.9% in Ultra mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agents' Last Exam&lt;/td&gt;
&lt;td&gt;53.6 (medium beats Fable 5 by 11.4 pts at ~1/4 cost)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SWE-Bench Pro&lt;/td&gt;
&lt;td&gt;64.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You cannot subtract one table from the other. Notice what happens if you try: OpenAI's own SWE-Bench Pro line has Sol at 64.6%, while Anthropic reports Fable 5 at 80% on the same-named benchmark, which would suggest the Claude family is well ahead on that one. But those two figures also come from different harness runs, so even that comparison is soft. The honest position is that the launch decks establish each model is frontier-class in its vendor's own tests, and nothing more. Two more points worth keeping straight, because loose paraphrases are already circulating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;91.9% is Ultra, not base.&lt;/strong&gt; The Terminal-Bench headline that gets quoted as "GPT-5.6 hits 91.9%" is Sol running the heavy-compute Ultra mode, a parallel-subagent architecture that is not the default and costs a lot more per task. Base Sol is 88.8%. The 3.1-point Ultra gain rarely pays for itself outside the hardest agent problems.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The "half the price of Fable 5" line is Anthropic's, and it is about Opus 5, not Sol.&lt;/strong&gt; Opus 5's pitch is near-Fable-5 intelligence at half the Fable price. Do not attach it to GPT-5.6.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a fuller walkthrough of how the Claude flagship tier actually lands on coding tasks, the &lt;a href="https://ofox.ai/blog/claude-fable-5-vs-opus-4-8-vs-gpt-5-5-swe-bench-2026/" rel="noopener noreferrer"&gt;Fable 5 vs Opus 4.8 vs GPT-5.5 SWE-Bench breakdown&lt;/a&gt; splits the harnesses the same way this post does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing Math: List Price Says Opus 5, ofox Currently Flips It
&lt;/h2&gt;

&lt;p&gt;There are two prices here and they disagree, so keep them apart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vendor list price.&lt;/strong&gt; Anthropic lists Opus 5 at $5 input / $25 output / $0.50 cached per million tokens. OpenAI lists Sol at $5 / $30 / $0.50. Input and cache match exactly, so on list pricing the only line that differs is output, and the whole dollar gap is your output volume at a flat $5/M. On list, Opus 5 is the cheaper model, by 17% on output and nothing else. Artificial Analysis, blending at its own cache/input/output profile, agrees: about &lt;strong&gt;$3.85 per 1M for Opus 5 versus $4.35 for Sol&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ofox price today.&lt;/strong&gt; This is where it flips. As of July 27, 2026, ofox runs GPT-5.6 Sol at a 20% discount, &lt;strong&gt;$4 input / $24 output / $0.40 cached&lt;/strong&gt;, against its $5/$30/$0.50 list. Opus 5 sits at list, $5/$25/$0.50, no promo. So on ofox right now, Sol is the cheaper model on every single line: input $4 &amp;lt; $5, output $24 &amp;lt; $25, cache $0.40 &amp;lt; $0.50. The list-price verdict inverts. Promos move, so re-check both model pages the day you commit a route.&lt;/p&gt;

&lt;p&gt;Put real ofox numbers on it. A coding-agent fleet at 100,000 requests a day, 4K input and 2K output per request:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Line item&lt;/th&gt;
&lt;th&gt;Opus 5 ($5/$25)&lt;/th&gt;
&lt;th&gt;Sol -20% ($4/$24)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input: 4K × 100K/day&lt;/td&gt;
&lt;td&gt;$2,000/day&lt;/td&gt;
&lt;td&gt;$1,600/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output: 2K × 100K/day&lt;/td&gt;
&lt;td&gt;$5,000/day&lt;/td&gt;
&lt;td&gt;$4,800/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Daily total (no cache)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$7,000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$6,400&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monthly (×30)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$210,000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$192,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Difference&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-$18,000/mo on Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Turn on a realistic 70% input cache hit rate and the ordering holds, just tighter. Opus 5's effective input rate drops to about $1.85/M and Sol's to about $1.48/M, landing Opus 5 near &lt;strong&gt;$172,000/month&lt;/strong&gt; and Sol near &lt;strong&gt;$162,000&lt;/strong&gt;, roughly $10K/month apart. The gap narrows under caching because Sol's cheaper input matters less once most input is already cached, but on ofox Sol stays ahead as long as the promo is live.&lt;/p&gt;

&lt;p&gt;So the cost answer has a shelf life. On vendor list price Opus 5 wins; on ofox as of late July, Sol's promo makes it cheaper outright. If you buy through ofox, treat price as a point for Sol until the discount ends, and let the AA index lead, the latency split, and the API shape be what actually separate the two.&lt;/p&gt;

&lt;p&gt;Two adders the base rate hides, and they do not cancel evenly. A web-search tool call is billed per request, and it is not equal: on ofox, Sol charges &lt;strong&gt;$0.035 per search versus $0.015 for Opus 5&lt;/strong&gt;, so search-heavy agents tilt back toward Opus 5. And the speed premiums are separate line items: Opus 5's Fast Mode runs the same model at up to 2.5x output speed for double the base rate, and Sol's Pro and Ultra modes cost more tokens per task. Model those into your own numbers rather than the base table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed and Latency: They Win Different Races
&lt;/h2&gt;

&lt;p&gt;Cost is a near-tie that depends on where you buy. Speed is a genuine split, and which model is "faster" depends entirely on what you are measuring. Artificial Analysis benchmarked both under load (read July 27, 2026; these are rolling figures):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric (AA, max effort)&lt;/th&gt;
&lt;th&gt;Claude Opus 5&lt;/th&gt;
&lt;th&gt;GPT-5.6 Sol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Output speed&lt;/td&gt;
&lt;td&gt;52.8 tok/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;75.9 tok/s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to first token&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;69.7 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;129.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sol streams about 1.4x faster once it is producing tokens, so for a long generated answer where the user watches it stream, Sol finishes sooner. Opus 5 reaches the first token roughly 1.9x faster, so for short interactive turns, tool-calling loops, and anything where perceived responsiveness matters, Opus 5 feels quicker. (Both time-to-first-token numbers are large because these are reasoning models under a heavy-effort test; the ordering, not the absolute seconds, is the point.) If you run an interactive coding assistant, low first-token latency usually beats raw throughput, which tilts toward Opus 5. If you run batch generation of long documents, throughput wins, which tilts toward Sol.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API Reality: What Actually Breaks When You Switch
&lt;/h2&gt;

&lt;p&gt;The benchmarks are a near-tie; the API shapes are not. This is where the two models feel genuinely different, and it is the part most comparison posts skip. If you are migrating a real codebase, these are the things that will actually cost you an afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasoning control lives in different places.&lt;/strong&gt; Opus 5 uses Anthropic's model: adaptive thinking is on by default, and you steer depth with an &lt;code&gt;effort&lt;/code&gt; ladder from &lt;code&gt;low&lt;/code&gt; to &lt;code&gt;max&lt;/code&gt; (defaulting to &lt;code&gt;high&lt;/code&gt;). Sol uses OpenAI's &lt;code&gt;reasoning_effort&lt;/code&gt; parameter, which accepts &lt;code&gt;none&lt;/code&gt; through &lt;code&gt;xhigh&lt;/code&gt; on &lt;code&gt;/v1/chat/completions&lt;/code&gt;; OpenAI routes the Pro and Ultra modes, and recommends &lt;code&gt;max&lt;/code&gt; effort, through the Responses API. So dialing Opus 5 to maximum reasoning is a one-word change, while Sol's heaviest modes generally mean moving to a second endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opus 5 turns thinking on by default; that can truncate you.&lt;/strong&gt; On Opus 4.8 a request with no &lt;code&gt;thinking&lt;/code&gt; field ran without thinking. On Opus 5 the same request reasons, and because &lt;code&gt;max_tokens&lt;/code&gt; caps thinking plus visible output together, a workload tuned for silent 4.8 can truncate. Set &lt;code&gt;thinking: {"type": "disabled"}&lt;/code&gt; to restore the old behavior, or raise &lt;code&gt;max_tokens&lt;/code&gt;. One catch that surprises people: on the Anthropic API, disabling thinking is only allowed at effort &lt;code&gt;high&lt;/code&gt; or below, so &lt;code&gt;disabled&lt;/code&gt; plus &lt;code&gt;xhigh&lt;/code&gt;/&lt;code&gt;max&lt;/code&gt; returns a 400.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sol 404s on the bare ID.&lt;/strong&gt; On ofox, &lt;code&gt;openai/gpt-5.6&lt;/code&gt; does not resolve; you must pass &lt;code&gt;openai/gpt-5.6-sol&lt;/code&gt; (or &lt;code&gt;-terra&lt;/code&gt;/&lt;code&gt;-luna&lt;/code&gt;). If you A/B by string-swapping the model field, use the explicit tier or you will spend ten minutes debugging a not-found error. Our &lt;a href="https://ofox.ai/blog/gpt-5-6-sol-terra-luna-which-tier-2026/" rel="noopener noreferrer"&gt;GPT-5.6 tier guide&lt;/a&gt; covers the full Sol/Terra/Luna split if you want the cheaper tiers in the same routing table.&lt;/p&gt;

&lt;p&gt;For the complete Opus 5 migration checklist, including the cache-minimum drop to 512 tokens and the sampling-param rejections that carry over from 4.8, the &lt;a href="https://ofox.ai/blog/claude-opus-5-api-guide-2026/" rel="noopener noreferrer"&gt;Opus 5 API guide&lt;/a&gt; walks through every change.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Pick Claude Opus 5
&lt;/h2&gt;

&lt;p&gt;Reach for Opus 5 when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;You buy at vendor list price and output dominates your bill.&lt;/strong&gt; Agentic coding, long code generation, verbose tool-use loops. On list, the 17% output discount is real money at scale and predictable to model. (On ofox, note Sol's promo currently undercuts this; see the pricing section.)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;You want the highest neutral score.&lt;/strong&gt; Opus 5 leads the AA Intelligence Index 61 vs 59 at max effort. It is a two-point lead, but it is the only same-harness lead anyone has.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;First-token latency matters.&lt;/strong&gt; Interactive assistants and tool-calling agents feel snappier at ~69.7s TTFT versus ~129.5s.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;You are on Claude Code or the Anthropic protocol already.&lt;/strong&gt; Opus 5 is a drop-in model-string change from 4.8, same $5/$25 list pricing, and it slots into &lt;code&gt;anthropic/claude-opus-5&lt;/code&gt; on ofox with no new SDK.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Computer use and desktop automation are in scope.&lt;/strong&gt; Anthropic's OSWorld 2.0 and AutomationBench framing is the strongest part of its deck (still vendor-reported, so verify).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Pick GPT-5.6 Sol
&lt;/h2&gt;

&lt;p&gt;Reach for Sol when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;You buy on ofox and want the lowest bill right now.&lt;/strong&gt; While ofox's -20% promo holds, Sol is cheaper than Opus 5 on every price line ($4/$24/$0.40). Re-check before you commit, since promos expire.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;You stream long answers and throughput is the bottleneck.&lt;/strong&gt; 75.9 tok/s versus 52.8 is a 1.4x edge on sustained generation.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;You need Pro or Ultra heavy-compute.&lt;/strong&gt; The parallel-subagent Ultra mode that posted 91.9% on Terminal-Bench has no Opus 5 equivalent. If your hardest agent tasks genuinely benefit from that mode, it lives only on Sol.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Your stack is already OpenAI-native.&lt;/strong&gt; If you are deep in the Responses API, tool schemas, and OpenAI's ecosystem, Sol is the zero-friction upgrade and the &lt;code&gt;max&lt;/code&gt; effort path is already wired.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;You want tier flexibility on one family.&lt;/strong&gt; Sol, Terra, and Luna share a generation, so you can drop to &lt;a href="https://ofox.ai/blog/gpt-5-6-terra-vs-gpt-5-5-coding-cost-2026/" rel="noopener noreferrer"&gt;Terra at half the price&lt;/a&gt; for bulk traffic and keep Sol for the hard tail, all on the same key.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When NOT to Pick Either
&lt;/h2&gt;

&lt;p&gt;Some workloads should not be paying flagship rates at all. If your task is high-volume classification, routing, short chat glue, or anything where a bounded, well-specified prompt gets a short answer, both of these models are overkill and overpriced. Send that traffic to a cost tier: on ofox, &lt;a href="https://ofox.ai/blog/gpt-5-6-sol-terra-luna-which-tier-2026/" rel="noopener noreferrer"&gt;GPT-5.6 Luna&lt;/a&gt; runs about $0.80/$4.80 per M and &lt;a href="https://ofox.ai/models/anthropic/claude-sonnet-5" rel="noopener noreferrer"&gt;Claude Sonnet 5&lt;/a&gt; about $2/$10, and keep Opus 5 or Sol for the reasoning-heavy tail. The most expensive mistake in production LLM routing is running every request through a flagship because one hard case needed it. Route by difficulty, not by default. If you want a structured way to decide, &lt;a href="https://ofox.ai/blog/best-ai-model-for-coding-2026/" rel="noopener noreferrer"&gt;Best AI Model for Coding 2026&lt;/a&gt; and &lt;a href="https://ofox.ai/blog/best-ai-model-for-agents-2026/" rel="noopener noreferrer"&gt;Best AI Model for Agents 2026&lt;/a&gt; lay out the full tiering.&lt;/p&gt;

&lt;p&gt;Here is the same decision as a routing table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If the request is…&lt;/th&gt;
&lt;th&gt;Route to&lt;/th&gt;
&lt;th&gt;Because&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bounded, short, high-volume (classification, routing)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Luna&lt;/strong&gt; or &lt;strong&gt;Sonnet 5&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Flagship rates are wasted on short bounded answers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning-heavy, and the lowest ofox bill matters now&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The -20% promo makes it cheaper on every line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning-heavy, buying at vendor list price&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Opus 5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17% cheaper output; leads the AA index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive, first-token latency matters&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Opus 5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~1.9x faster to first token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long streamed output, throughput matters&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~1.4x higher tokens/sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs Pro or Ultra heavy-compute&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No Opus 5 equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try Both via ofox: A/B in 10 Lines of Code
&lt;/h2&gt;

&lt;p&gt;The only comparison that settles this is the one you run on your own tasks, and the friction of running it is usually what stops people. On &lt;a href="https://ofox.ai/en" rel="noopener noreferrer"&gt;ofox&lt;/a&gt; both models sit on the same OpenAI-compatible endpoint under one key, so an A/B is a loop over two model strings. Same SDK, same billing line, no second account. The two IDs are &lt;code&gt;anthropic/claude-opus-5&lt;/code&gt; and &lt;code&gt;openai/gpt-5.6-sol&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python — A/B both models in one loop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-ofox-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;MODELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic/claude-opus-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-5.6-sol&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Refactor this module for testability and explain the two riskiest changes:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;paste your real code&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;=== &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[in=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; out=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_tokens&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it across 20-30 of your real tasks, not one toy prompt, and log &lt;code&gt;completion_tokens&lt;/code&gt; per model. Multiply that count by each model's output rate (whichever price you actually pay, list or the current ofox promo) and you are measuring quality and cost in the same loop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node — same shape
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-ofox-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic/claude-opus-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai/gpt-5.6-sol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Find the race condition in this service and propose a fix:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;paste your real code&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n=== &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ===`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[in=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt_tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; out=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completion_tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To exercise Opus 5's adaptive thinking or Sol's &lt;code&gt;reasoning_effort&lt;/code&gt;, point the Anthropic-native calls at &lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt; with model &lt;code&gt;claude-opus-5&lt;/code&gt;, and the Sol &lt;code&gt;max&lt;/code&gt;-effort calls at the OpenAI Responses API. For a plain quality-and-cost A/B, the chat/completions loop above is enough, and it is the fastest way to replace a launch-day benchmark argument with a number from your own workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Verdict
&lt;/h2&gt;

&lt;p&gt;Strip away the launch-week noise and the picture is narrow. On the one benchmark that measures both models the same way, Opus 5 is two points ahead at max effort (61 vs 59). On price the answer depends on where you buy: at vendor list price Opus 5 is ~17% cheaper on output, but on ofox right now Sol's -20% promo makes it cheaper on every line. On latency Opus 5 starts faster (~1.9x to first token); on throughput Sol streams faster (~1.4x). Everything else, the CursorBench numbers, the Terminal-Bench 91.9%, the "beats Fable 5" claims, is vendor-reported on a private harness and should move your decision by roughly nothing until you reproduce it.&lt;/p&gt;

&lt;p&gt;That makes this a genuinely close call, not a blowout. Opus 5 has the durable edges: the neutral-composite lead, the lower first-token latency, and the drop-in path from Claude Code and Opus 4.8. Sol counters with faster streaming, the Pro and Ultra heavy-compute modes that have no Claude equivalent, and, while the promo lasts, the cheaper ofox bill. Neither should be handling your bulk classification or routing traffic; that belongs on a cost tier.&lt;/p&gt;

&lt;p&gt;The two-point index gap is not a reason to migrate a production route on its own, and neither is a promo that can expire next week. Both are reasons to run the A/B, because the case for either model is built from small, real edges, and the only thing that turns that into a decision is your own eval. Both models are one string apart on the same key. Spend the afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://artificialanalysis.ai/models/comparisons/claude-opus-5-vs-gpt-5-6-sol" rel="noopener noreferrer"&gt;Artificial Analysis: Claude Opus 5 vs GPT-5.6 Sol comparison&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://artificialanalysis.ai/articles/gpt-5-6-has-landed" rel="noopener noreferrer"&gt;Artificial Analysis: GPT-5.6 has landed&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.anthropic.com/news/claude-opus-5" rel="noopener noreferrer"&gt;Anthropic: Claude Opus 5 announcement&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://platform.openai.com/docs/models/gpt-5-6-sol" rel="noopener noreferrer"&gt;OpenAI: GPT-5.6 Sol model documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://simonwillison.net/2026/Jul/9/gpt-5-6/" rel="noopener noreferrer"&gt;Simon Willison: GPT-5.6 (July 9, 2026 GA notes)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models/anthropic/claude-opus-5" rel="noopener noreferrer"&gt;ofox model page: Claude Opus 5&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/models/openai/gpt-5.6-sol" rel="noopener noreferrer"&gt;ofox model page: GPT-5.6 Sol&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Related: &lt;a href="https://ofox.ai/blog/claude-opus-5-api-guide-2026/" rel="noopener noreferrer"&gt;Claude Opus 5 API guide&lt;/a&gt; — pricing, the 4.8→5 changes, and how to call it. &lt;a href="https://ofox.ai/blog/gpt-5-6-sol-terra-luna-which-tier-2026/" rel="noopener noreferrer"&gt;GPT-5.6 tiers: Sol, Terra, Luna&lt;/a&gt; — which tier for which job. &lt;a href="https://ofox.ai/blog/gpt-5-6-terra-vs-gpt-5-5-coding-cost-2026/" rel="noopener noreferrer"&gt;GPT-5.6 Terra vs GPT-5.5&lt;/a&gt; — the half-price mid tier. &lt;a href="https://ofox.ai/blog/claude-fable-5-vs-opus-4-8-vs-gpt-5-5-swe-bench-2026/" rel="noopener noreferrer"&gt;Fable 5 vs Opus 4.8 vs GPT-5.5 on SWE-Bench&lt;/a&gt; — the Claude flagship tier on coding.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/claude-opus-5-vs-gpt-5-6-sol-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>benchmarks</category>
      <category>pricing</category>
    </item>
    <item>
      <title>Claude Opus 5 API: Fable 5-Class at Half Price, Complete Guide</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 26 Jul 2026 04:33:50 +0000</pubDate>
      <link>https://dev.to/owen_fox/claude-opus-5-api-fable-5-class-at-half-price-complete-guide-15lp</link>
      <guid>https://dev.to/owen_fox/claude-opus-5-api-fable-5-class-at-half-price-complete-guide-15lp</guid>
      <description>&lt;p&gt;Claude Opus 5 (claude-opus-5) shipped July 24, 2026 at $5/$25 — half Fable 5's price. Benchmarks, the Opus 4.8 to 5 API changes, and how to call it via ofox.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Anthropic Shipped
&lt;/h2&gt;

&lt;p&gt;Claude Opus 5 is Anthropic's new recommended default for complex agentic coding and enterprise work. The model ID is &lt;code&gt;claude-opus-5&lt;/code&gt; with a fixed, dateless snapshot and no version suffix. It carries a full 1M-token context window, 128K maximum output tokens (expandable to 300K through Message Batches API with beta header), and May 2026 knowledge cutoff.&lt;/p&gt;

&lt;p&gt;The pricing represents a significant capability-to-cost ratio: "a thoughtful and proactive model that comes close to the frontier intelligence of Claude Fable 5 at half the price." Fable 5 costs $10/$50 per million tokens; Opus 5 lists at $5 input/$25 output—matching Opus 4.8's rate since May and undercutting Fable 5 by fifty percent. Fast Mode runs the same model at up to 2.5x output speed for double the base cost.&lt;/p&gt;

&lt;p&gt;Fable 5 remains Anthropic's most capable model. Opus 5 targets users seeking most of that capability without the Fable premium.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks: Anthropic's Own Numbers
&lt;/h2&gt;

&lt;p&gt;All figures presented are Anthropic internal and unverified vendor launch numbers, not third-party results. Treat them as best-case scenarios and run independent evaluations before commitment.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Anthropic internal figure (unverified)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontier-Bench v0.1&lt;/td&gt;
&lt;td&gt;Surpasses all other models; more than doubles Opus 4.8's score&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CursorBench 3.2&lt;/td&gt;
&lt;td&gt;Within 0.5% of Fable 5's peak, at half the cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARC-AGI 3&lt;/td&gt;
&lt;td&gt;Roughly 3x the next-best model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OSWorld 2.0 (computer use)&lt;/td&gt;
&lt;td&gt;Beats Fable 5's result at one-third the cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zapier AutomationBench&lt;/td&gt;
&lt;td&gt;Pass rate ~1.5x the next-best model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GDPval-AA (real economic work)&lt;/td&gt;
&lt;td&gt;State of the art&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The consistent theme spans agentic and computer-use work—long-horizon coding, desktop control, real-task automation—where Opus 5 either matches Fable 5 for substantially less money or outperforms competing models. Anthropic acknowledges one honest limitation: Opus 5 stays behind Mythos 5 on cybersecurity-exploitation and biology-research tasks, handled by a separate model line for defensive use. Non-applicable workloads face no gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed from Opus 4.8 (the part that breaks code)
&lt;/h2&gt;

&lt;p&gt;Opus 5 maintains the same request surface as 4.8 in most respects, but three changes will surprise users swapping the model string without additional modifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Adaptive thinking is on by default
&lt;/h3&gt;

&lt;p&gt;On Opus 4.8, a request without a &lt;code&gt;thinking&lt;/code&gt; field ran without thinking. On Opus 5, the identical request now runs with adaptive thinking. Since &lt;code&gt;max_tokens&lt;/code&gt; is a hard cap on total output—thinking plus visible response—workloads tuned for no-thinking 4.8 can truncate. Revisit &lt;code&gt;max_tokens&lt;/code&gt;, or pass &lt;code&gt;thinking: {"type": "disabled"}&lt;/code&gt; to retain the old behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Disabling thinking is capped at &lt;code&gt;high&lt;/code&gt; effort
&lt;/h3&gt;

&lt;p&gt;This is the new 400 error users don't expect. You can disable thinking, but only at effort &lt;code&gt;high&lt;/code&gt; or below. Combining &lt;code&gt;thinking: {"type": "disabled"}&lt;/code&gt; with effort &lt;code&gt;xhigh&lt;/code&gt; or &lt;code&gt;max&lt;/code&gt; triggers rejection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Rejected on Opus 5 — 400 error
&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-opus-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thinking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;output_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;effort&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xhigh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;   &lt;span class="c1"&gt;# xhigh/max + disabled = 400
&lt;/span&gt;    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fix: either re-enable thinking at high effort...
&lt;/span&gt;&lt;span class="n"&gt;output_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;effort&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xhigh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;         &lt;span class="c1"&gt;# thinking on by default
# ...or keep it off and drop to high or below
&lt;/span&gt;&lt;span class="n"&gt;thinking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;output_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;effort&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. The cache minimum drops to 512 tokens
&lt;/h3&gt;

&lt;p&gt;Cache thresholds decreased from 1,024 on 4.8. Short system prompts previously too small to cache now create cache entries without code modification—a small, free win on prompt-caching expenses.&lt;/p&gt;

&lt;p&gt;Two additional considerations: mid-conversation tool changes are now possible without invalidating the prompt cache (beta header &lt;code&gt;mid-conversation-tool-changes-2026-07-01&lt;/code&gt;), and Opus 5 ships cybersecurity safety classifiers, requiring handling of &lt;code&gt;stop_reason: "refusal"&lt;/code&gt; with optional automatic model fallbacks (&lt;code&gt;fallbacks: "default"&lt;/code&gt;, beta header &lt;code&gt;server-side-fallback-2026-07-01&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Unchanged elements: pricing, the 1M context window, 128K output, and hard rejections from 4.8—non-default &lt;code&gt;temperature&lt;/code&gt;/&lt;code&gt;top_p&lt;/code&gt;/&lt;code&gt;top_k&lt;/code&gt;, manual &lt;code&gt;budget_tokens&lt;/code&gt;, and assistant prefill all return 400. Priority Tier remains unsupported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Effort and Prompting Notes
&lt;/h2&gt;

&lt;p&gt;Opus 5 supports the complete effort ladder—&lt;code&gt;low&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;xhigh&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;—defaulting to &lt;code&gt;high&lt;/code&gt; on Claude API and Claude Code. Anthropic recommends running a fresh effort sweep rather than carrying over 4.8 settings, and testing &lt;code&gt;max&lt;/code&gt; for capability-critical work (allocate large &lt;code&gt;max_tokens&lt;/code&gt;, starting around 64K, for &lt;code&gt;xhigh&lt;/code&gt; or &lt;code&gt;max&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Two behavioral shifts warrant prompt review. Opus 5 verifies its own work without explicit instruction, so explicit "double-check your output" directives now cause over-verification—remove them. Default responses run longer than 4.8's; lowering effort trims thinking but not visible length, so prompt for conciseness or target length directly for shorter output.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Call Opus 5 Through ofox
&lt;/h2&gt;

&lt;p&gt;The model ID on ofox.ai is &lt;code&gt;anthropic/claude-opus-5&lt;/code&gt;, on the same OpenAI-compatible endpoint as every other model—no separate Anthropic account or billing. Point your existing OpenAI SDK at the ofox base URL and change two strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-ofox-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic/claude-opus-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Refactor this module for testability...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use adaptive thinking and the &lt;code&gt;effort&lt;/code&gt; parameter, call the Anthropic-native endpoint instead—the model ID drops the provider prefix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/anthropic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-ofox-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-opus-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thinking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adaptive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;output_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;effort&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;   &lt;span class="c1"&gt;# low | medium | high | xhigh | max
&lt;/span&gt;    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Audit this service for race conditions...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running through one gateway makes the migration question empirical: put identical prompts through Opus 5, Opus 4.8, and Fable 5 on one key and compare quality and token counts on your workload before switching production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opus 5 vs Fable 5 vs Sonnet 5: Which to Pick
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Opus 5&lt;/strong&gt; ($5/$25)—the new default for agentic coding, computer use, and long-horizon enterprise tasks. Best capability-per-dollar in the lineup right now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Fable 5&lt;/strong&gt; ($10/$50)—the ceiling. Reach for it only when a task genuinely needs the most capable model and cost is secondary; on many agentic benchmarks Opus 5 is within a rounding error at half the price.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Sonnet 5&lt;/strong&gt; ($3/$15)—the speed-and-cost tier. Near-Opus quality on coding for high-volume or latency-sensitive work where you don't need Opus-level reasoning depth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Opus 4.8 users, this is a clean migration: same price, higher scores, one model-string change plus the three gotchas above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;Opus 5 is another Opus upgrade with no asterisk on price—same $5/$25, materially higher scores across coding and computer-use, and Anthropic's claim of near-Fable-5 capability at half the cost holds up across a broad benchmark set. The caveats are narrow and honest: benchmark numbers are Anthropic internal and unverified (run your own evals), disabling thinking now conflicts with high effort levels, and default output runs longer so watch your &lt;code&gt;max_tokens&lt;/code&gt; and latency budgets.&lt;/p&gt;

&lt;p&gt;For new projects, start on Opus 5. For anything in production on 4.8, change the model string, revisit &lt;code&gt;max_tokens&lt;/code&gt;, audit any request that disables thinking, and ship.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/claude-opus-5-api-guide-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>anthropic</category>
      <category>benchmarks</category>
      <category>modelcomparison</category>
    </item>
    <item>
      <title>Qwen Image 3.0 Pro Free API (2026): Setup, Caps, and 429s</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sat, 25 Jul 2026 04:35:18 +0000</pubDate>
      <link>https://dev.to/owen_fox/qwen-image-30-pro-free-api-2026-setup-caps-and-429s-19nn</link>
      <guid>https://dev.to/owen_fox/qwen-image-30-pro-free-api-2026-setup-caps-and-429s-19nn</guid>
      <description>&lt;p&gt;Alibaba released Qwen Image 3.0 Pro on 2026-07-21, and it went up on ofox at $0. Not $0 tokens with a per-image charge hiding underneath, which is how most image models on this gateway are priced. Nothing per image either. It is a real zero, not a trial credit that quietly drains.&lt;/p&gt;

&lt;p&gt;It is also not the kind of free you should build a product on this week, and the reason is written on the model card in Chinese where most English coverage has skipped past it: "本版本为限时免费体验版，目前为限量体验阶段" (Limited-time free trial version, currently in a limited-quota phase). Two separate constraints, and the second one is the one that will actually interrupt your afternoon.&lt;/p&gt;

&lt;p&gt;Here is what the free tier gives you, what it takes away, and the three integration details that will break code you copied from a gpt-image-2 tutorial. Every image in this post is raw output from the model, generated on 2026-07-23.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Do After This Setup (And What You Can't)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What you can do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Generate images at $0, tokens and per-image both, through an OpenAI-compatible endpoint, text-to-image, at arbitrary sizes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Time required
&lt;/h3&gt;

&lt;p&gt;About 3 minutes if you already have an ofox key&lt;/p&gt;

&lt;h3&gt;
  
  
  What you need
&lt;/h3&gt;

&lt;p&gt;An ofox API key, Python 3.8+ or Node 18+, and the &lt;code&gt;openai&lt;/code&gt; SDK you probably already have installed&lt;/p&gt;

&lt;h3&gt;
  
  
  What you can't do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run a batch. Plan around a published quota. Assume the price holds next month. Get base64 back. Use reference images (see below)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decision Frame: When to Use This (and When NOT)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use it when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are evaluating image models and want to test Qwen 3.0 Pro's text rendering against your own prompts before committing budget anywhere.&lt;/li&gt;
&lt;li&gt;You generate images occasionally and interactively, a few per hour, where a 429 costs you a retry rather than a failed job.&lt;/li&gt;
&lt;li&gt;You need Chinese text inside images and your current model mangles it. This is the capability where Qwen is genuinely differentiated, and it costs nothing to verify.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Don't use it when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are generating in bulk. The quota phase makes throughput unpredictable, and unpredictable throughput in a batch job is worse than a known price.&lt;/li&gt;
&lt;li&gt;You have a latency SLA. Backoff on a 429 is measured in tens of seconds here, not hundreds of milliseconds.&lt;/li&gt;
&lt;li&gt;You are writing something that must still work in three months without anyone looking at it. The free listing is explicitly time-boxed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Stop rule
&lt;/h3&gt;

&lt;p&gt;If all you wanted was to know whether the text rendering claim is real, read the four test images below and skip the rest of this guide. The short version is that it holds for words and fails for sequences, and you do not need to integrate anything to benefit from knowing that.&lt;/p&gt;

&lt;h2&gt;
  
  
  System Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An ofox API key from the &lt;a href="https://ofox.ai/" rel="noopener noreferrer"&gt;ofox dashboard&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Python 3.8 or later with &lt;code&gt;openai&amp;gt;=1.0&lt;/code&gt;, or Node 18+ with the &lt;code&gt;openai&lt;/code&gt; package. No Alibaba account, no DashScope key, no separate region config.&lt;/li&gt;
&lt;li&gt;Somewhere to write files. The endpoint hands you a URL, not bytes, and that URL does not live forever.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step-by-Step Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Point the SDK at ofox
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_OFOX_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result: no output. If the import fails, upgrade with &lt;code&gt;pip install -U openai&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Call the model
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bailian/qwen-image-3.0-pro:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A ceramic mug on a linen cloth, morning light, shallow depth of field&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1024x1024&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result: an &lt;code&gt;https://dashscope-*.oss-accelerate.aliyuncs.com/...&lt;/code&gt; URL printed to stdout.&lt;/p&gt;

&lt;p&gt;Node, if that is your stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bailian/qwen-image-3.0-pro:free&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A ceramic mug on a linen cloth, morning light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1024x1024&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Download the bytes before they expire
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt;

&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlretrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result: &lt;code&gt;out.png&lt;/code&gt; on disk, typically 1 to 1.5 MB at 1024x1024.&lt;/p&gt;

&lt;p&gt;This step is not optional housekeeping. Read the next section before you write the URL into a database.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Integration Details That Break Copied Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  It returns a URL, not base64
&lt;/h3&gt;

&lt;p&gt;Most image-generation tutorials in circulation are written against &lt;code&gt;gpt-image-2&lt;/code&gt;, which returns &lt;code&gt;b64_json&lt;/code&gt;. Qwen 3.0 Pro on this endpoint returns &lt;code&gt;url&lt;/code&gt; and leaves &lt;code&gt;b64_json&lt;/code&gt; empty. Code that does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;b64_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# TypeError on Qwen
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;fails on a &lt;code&gt;None&lt;/code&gt;. Handle both shapes if you route across models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64_json&lt;/span&gt;
       &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The URL points at Alibaba's OSS and carries a signed expiry. Persist the bytes. A URL stored in your database is a broken image later.&lt;/p&gt;

&lt;h3&gt;
  
  
  The free quota is per-moment, not per-day
&lt;/h3&gt;

&lt;p&gt;There is no published requests-per-minute number, so we measured what we could observe. Firing requests back to back returned &lt;code&gt;429 Requests rate limit exceeded&lt;/code&gt; on the second call. Running two generation processes concurrently caused both to 429 and neither to progress until one was killed. A single sequential worker with escalating backoff starting at 45 seconds completed every request it attempted.&lt;/p&gt;

&lt;p&gt;That shape, immediate 429 under any concurrency, generous success when strictly serial, is what a limited-quota trial phase looks like from the outside. It is not an outage and retrying harder makes it worse.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Call pattern&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Two requests back to back&lt;/td&gt;
&lt;td&gt;Second returns 429 immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two processes in parallel, same key&lt;/td&gt;
&lt;td&gt;Both 429, neither completes until one is killed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One worker, 45s backoff, 20s gap between jobs&lt;/td&gt;
&lt;td&gt;Every request completed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same pattern, four jobs in a row&lt;/td&gt;
&lt;td&gt;All four completed, no 429 after the first clear&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical reading: the limiter cares about concurrency and burst far more than about total volume. A single-threaded loop with a pause is not a workaround, it is the intended usage shape.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1024x1024&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bailian/qwen-image-3.0-pro:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RateLimitError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quota never cleared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Through the OpenAI SDK a 429 arrives as openai.RateLimitError.
# You only catch urllib's HTTPError(429) if you call the HTTP endpoint directly.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Does the Text Rendering Claim Hold Up?
&lt;/h2&gt;

&lt;p&gt;Alibaba's pitch for this generation is typography: small text staying legible, long prompts staying coherent, multiple scripts in one frame. Those are checkable, so we checked them. Every image below is raw model output at the size given, no retouching and no cherry-picking across attempts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 1: small print in a spec table
&lt;/h3&gt;

&lt;p&gt;The prompt asked for four labelled rows with exact values and a fine-print serial line at the bottom.&lt;/p&gt;

&lt;p&gt;Every value landed: &lt;code&gt;Pressure 9 bar&lt;/code&gt;, &lt;code&gt;Boiler 1.6 L&lt;/code&gt;, &lt;code&gt;Weight 12.4 kg&lt;/code&gt;, &lt;code&gt;Warranty 24 months&lt;/code&gt;. The bottom line reads &lt;code&gt;Serial AT-2026-0731 / Made in Suzhou&lt;/code&gt;, correct down to the slash and the hyphenated serial. At 1024x1536 that fine print is roughly 8pt equivalent. No dropped glyphs, no invented characters, no melted letterforms in the small sizes, which is where image models usually give themselves away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 2: two scripts in one frame
&lt;/h3&gt;

&lt;p&gt;Mixed English and Chinese on a single sign, each with its own line and a shared numeric field.&lt;/p&gt;

&lt;p&gt;Both scripts are correct. &lt;code&gt;开发者专场&lt;/code&gt; and &lt;code&gt;注册签到&lt;/code&gt; are properly formed characters, not the character-shaped noise that most image models produce for CJK. The Latin and Chinese lines share a consistent weight and the &lt;code&gt;09:00&lt;/code&gt; matches on both rows.&lt;/p&gt;

&lt;p&gt;For anyone who has tried to get a usable Chinese-language poster out of a Western image model, this is the interesting result in the whole post, and it is the one you can verify yourself for nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 3: a technical diagram with many labelled parts
&lt;/h3&gt;

&lt;p&gt;This is the case that usually collapses. The prompt named five strings that had to appear (&lt;code&gt;CLIENT&lt;/code&gt;, &lt;code&gt;GATEWAY&lt;/code&gt;, &lt;code&gt;MODEL&lt;/code&gt;, &lt;code&gt;RESPONSE&lt;/code&gt;, and a legend of &lt;code&gt;auth&lt;/code&gt; / &lt;code&gt;route&lt;/code&gt; / &lt;code&gt;inference&lt;/code&gt;) and left the captions under each block unspecified.&lt;/p&gt;

&lt;p&gt;All five specified strings rendered correctly and in the right positions. What the model did unprompted is the part worth noting: it added a title, numbered the arrows &lt;code&gt;1. Request&lt;/code&gt; / &lt;code&gt;2. Forward&lt;/code&gt; / &lt;code&gt;3. Output&lt;/code&gt;, and wrote its own captions that are technically coherent rather than lorem-ipsum shaped ("Validates authentication / Routes to endpoint" under the gateway). The spelling holds throughout.&lt;/p&gt;

&lt;p&gt;That makes it plausible for first-draft documentation diagrams. It does not make it reliable, because the captions it invents are its own guesses about your architecture and it will state them just as confidently when they are wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 4: where it actually breaks
&lt;/h3&gt;

&lt;p&gt;We asked for a code editor screenshot with a file tree, syntax-highlighted Python, and visible line numbers 1 through 14.&lt;/p&gt;

&lt;p&gt;The chrome is close to perfect. Filenames are correct and correctly icon-matched, the status bar reads &lt;code&gt;UTF-8 CRLF Python 3.12 Ln 8, Col 22 Spaces: 4&lt;/code&gt; exactly as prompted, the menu bar is coherent, and the syntax highlighting assigns plausible colours to keywords, strings and function names.&lt;/p&gt;

&lt;p&gt;Now read the gutter. The line numbers run &lt;code&gt;1, 3, 3, 4, 6, 7, 9, 8, 0, 8, 11, 11, 12, 13, 14&lt;/code&gt;. There is no 2, no 5, no 10, several duplicates, and a stray &lt;code&gt;0&lt;/code&gt;. Then look at the last line of code: &lt;code&gt;if __name__ = "__main__":&lt;/code&gt;, with a single equals sign where Python needs two.&lt;/p&gt;

&lt;p&gt;This is the honest boundary of the model. Words and labels, including small ones and Chinese ones, come out right. &lt;strong&gt;Sequences and code operators do not.&lt;/strong&gt; A line-number gutter is the purest test of monotonic counting there is, and the model produced something that looks like counting from a distance and falls apart on inspection. The same weakness shows up as the &lt;code&gt;=&lt;/code&gt; where &lt;code&gt;==&lt;/code&gt; belongs.&lt;/p&gt;

&lt;p&gt;Practical rule: use it for anything where a human reads the text as language. Do not use it for screenshots that a reader will treat as literally correct code, or for charts where the axis labels have to be a real sequence. That is not a prompt engineering problem you can fix with a better prompt, it is what the model is currently bad at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sizes: There Is No Aspect Ratio Enum
&lt;/h2&gt;

&lt;p&gt;Several image endpoints accept a fixed list of sizes and reject anything else, which is why so much generation code carries a lookup table mapping "widescreen" to whatever string that particular vendor blessed. This one does not appear to work that way.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size passed&lt;/th&gt;
&lt;th&gt;Returned&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1024x1024&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;As requested&lt;/td&gt;
&lt;td&gt;Default square&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1024x1536&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;As requested&lt;/td&gt;
&lt;td&gt;Portrait, posters and spec cards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1664x928&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;As requested&lt;/td&gt;
&lt;td&gt;Widescreen, close to 16:9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every value we passed came back at exactly that resolution. If you are generating blog heroes or social cards at a fixed aspect ratio, you can ask for the final dimensions directly instead of generating square and cropping, which is one fewer place for a composition to get its head cut off.&lt;/p&gt;

&lt;p&gt;The caveat is that this is observed behaviour rather than a documented contract. Validate the dimensions of what comes back rather than assuming, especially if you are feeding the output into a layout that breaks on the wrong ratio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference Images: We Could Not Get Them to Work
&lt;/h2&gt;

&lt;p&gt;The model card lists reference-image input alongside text-to-image. We could not make it work through this endpoint, and the way it fails is worth documenting because it fails quietly.&lt;/p&gt;

&lt;p&gt;Three shapes tried, all against the same source image (the espresso poster from Test 1) with a prompt asking for an ink-sketch restyle that preserved the layout and spec values:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attempt&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;images.generate(..., image="data:image/png;base64,...")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP 200, image returned, reference ignored entirely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;images.generate(..., image_url="data:image/png;base64,...")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP 200, image returned, reference not reproduced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST /images/edits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP 400 &lt;code&gt;You must provide a model parameter&lt;/code&gt;, with &lt;code&gt;model&lt;/code&gt; present in the body&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first attempt is the clearest. Given a photograph-style poster of an espresso machine, it returned a botanical serum advertisement. Correct style, entirely unrelated subject. Nothing from the reference survived.&lt;/p&gt;

&lt;p&gt;The second attempt looked closer at a glance and is more instructive on inspection. That is on-topic, but only because the prompt named the subject in words. Compare the numbers against Test 1. The source poster says boiler 1.6 L and weight 12.4 kg; this one says 2.0 L and 28 kg. The four-row table became an eight-cell grid, the product shot became a cutaway with callouts, and the warranty row vanished. The one value that matches, 9 bar, is the standard pressure for every espresso machine ever built, so it is not evidence of anything.&lt;/p&gt;

&lt;p&gt;In other words the model generated a fresh image from the prompt text and did not use the reference. The third attempt is worse than either, because a 400 complaining about a missing &lt;code&gt;model&lt;/code&gt; parameter that is demonstrably present will send you debugging your own serialization for twenty minutes.&lt;/p&gt;

&lt;p&gt;What we can say precisely: reference-image input is documented for this model, and we did not find a parameter shape that delivers it through ofox's OpenAI-compatible image endpoint. It may work through Alibaba's native DashScope API, or the correct parameter name may be something we did not try. What it does not do is fail loudly, so if you build on it, verify that the output actually reflects your input rather than assuming a 200 means it worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Errors During Setup
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;429 Requests rate limit exceeded&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Free-tier quota, not an outage&lt;/td&gt;
&lt;td&gt;Serialize requests, back off 45s and up. Do not parallelize&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;TypeError: expected str, got None&lt;/code&gt; on &lt;code&gt;b64_json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;You copied gpt-image-2 code&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;data[0].url&lt;/code&gt; and fetch it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image URL 403s later&lt;/td&gt;
&lt;td&gt;OSS signed URL expired&lt;/td&gt;
&lt;td&gt;Download at generation time, store the bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model_not_found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Missing the &lt;code&gt;:free&lt;/code&gt; suffix&lt;/td&gt;
&lt;td&gt;The ID is &lt;code&gt;bailian/qwen-image-3.0-pro:free&lt;/code&gt;, colon included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Empty &lt;code&gt;data&lt;/code&gt; array&lt;/td&gt;
&lt;td&gt;Prompt hit a content filter&lt;/td&gt;
&lt;td&gt;Rephrase. The endpoint does not always return an explicit refusal reason&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Team / Multi-Developer Configuration
&lt;/h2&gt;

&lt;p&gt;The quota behaviour has a consequence that matters more for teams than for individuals: your developers throttle each other. Two people iterating on prompts against the same free model at the same time is the concurrency case that reliably 429s.&lt;/p&gt;

&lt;p&gt;Three ways to handle it, in increasing order of effort:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One key, one queue.&lt;/strong&gt; Put generation behind a single-worker job queue rather than letting each developer's laptop call the endpoint directly. This is the change that actually fixes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split by model, not by key.&lt;/strong&gt; Qwen is the only free image model on ofox, so this means moving bulk work onto a paid model and keeping Qwen for the typography cases where it wins. Seedream 5.0 Lite at $0.035/image is the cheapest place to put that bulk work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fall back automatically.&lt;/strong&gt; Catch the 429 and retry against a paid model with real throughput. At $0.035 to $0.05 per image, a handful of unblocked images costs less than an engineer waiting.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because everything sits behind one base URL and one key, option 3 is a model string change rather than a second integration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CHAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bailian/qwen-image-3.0-pro:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# $0, quota-capped
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;volcengine/doubao-seedream-5.0-lite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# $0.035/image
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-image-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                &lt;span class="c1"&gt;# $4/M in, $24/M out
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_with_failover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1024x1024&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;CHAIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;429&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all providers throttled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Return the model name alongside the image. When you later wonder why one batch looks different from another, knowing which model actually served each request saves an hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planning for the Day the Free Window Closes
&lt;/h2&gt;

&lt;p&gt;"Limited-time" with no published end date is a scheduling problem disguised as a pricing note. The failure mode is not that you get a bill. It is that one morning the model ID stops resolving, or starts resolving to a paid variant, and whatever you wired it into stops working for reasons nobody on your team remembers.&lt;/p&gt;

&lt;p&gt;Three cheap precautions, none of which take longer than the setup itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep the model ID in config.&lt;/strong&gt; One string in an environment variable, not scattered through six call sites. This is the whole mitigation for most teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log which model served each image.&lt;/strong&gt; If output quality shifts, you want to know whether the model changed under you before you start blaming your prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know your fallback's price before you need it.&lt;/strong&gt; The alternatives table below exists so that the decision is already made when the 429s turn permanent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are archiving generated images, this matters more than it sounds. The signed OSS URLs expire on their own schedule, so an image you generated for free and linked rather than downloaded is a broken asset waiting to happen regardless of what the pricing does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives When Qwen Throttles You
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;ofox price&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bailian/qwen-image-3.0-pro:free&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0, nothing per image&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The only genuinely free one. Quota-capped, time-boxed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volcengine/doubao-seedream-5.0-lite&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.035/image&lt;/td&gt;
&lt;td&gt;Cheapest per-image option. Bills per image, not per token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volcengine/doubao-seedream-4.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.04/image&lt;/td&gt;
&lt;td&gt;Previous generation of the same family&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volcengine/doubao-seedream-5.0-pro&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.05/image&lt;/td&gt;
&lt;td&gt;Top Seedream tier. Natural first failover if you want a Chinese lab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;google/gemini-3.1-flash-lite-image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.25/M in, $1.50/M out&lt;/td&gt;
&lt;td&gt;Token-billed. Predictable throughput&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;google/gemini-3.1-flash-image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.50/M in, $3.00/M out&lt;/td&gt;
&lt;td&gt;Token-billed, larger tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-image-2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$4/M in, $24/M out (cache $1/M)&lt;/td&gt;
&lt;td&gt;Most predictable. See our GPT-Image-2 release guide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read that table carefully, because the pricing pages are easy to misread and we misread them ourselves on the first pass. &lt;strong&gt;Image models do not all bill the same way.&lt;/strong&gt; The Seedream entries show &lt;code&gt;$0/M&lt;/code&gt; on both token rows, which looks free and is not: they bill per generated image, and the Per Image line is the one that reaches your invoice. A &lt;code&gt;$0/$0&lt;/code&gt; token row on an image model tells you nothing.&lt;/p&gt;

&lt;p&gt;That leaves Qwen Image 3.0 Pro as the only image model on ofox that currently costs nothing at all, per token or per image. Which cuts against the comfortable version of this story: there is no free failover. When the quota throttles you, the alternative costs money, somewhere between $0.035 and $0.05 an image on the cheap end. That is not much, but it is not zero, and a pipeline you designed around "free" needs to know which one it is.&lt;/p&gt;

&lt;p&gt;The Seedream models are still the natural first hop. Same base URL, same key, one string to change. But they are a different family and we have not run the same four typography tests against them, so treating them as a drop-in for Qwen's text rendering would be an assumption, not a finding.&lt;/p&gt;

&lt;p&gt;Prices verified by fetching the ofox model pages on 2026-07-23. One thing we hit while checking: for &lt;code&gt;gpt-image-2&lt;/code&gt; the &lt;code&gt;/v1/models&lt;/code&gt; API returned $5/M and $30/M against our key, which is the struck-through list price the model page shows next to ofox's discounted $4/M and $24/M. We have only tested this on one key, so treat it as a reason to read the page rather than a documented rule.&lt;/p&gt;

&lt;p&gt;The paid options earn their price in exactly one dimension that matters here, which is that you can predict them. A pipeline that must finish in a known window wants a rate limit it can read in documentation, not one it has to infer from 429s.&lt;/p&gt;

&lt;p&gt;If you want the paid-tier comparison in depth, we have written up Seedream 4.5 and Flux 2 Max separately, and the GPT-Image-2 failure modes post covers what slow generations and 504s usually mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Could Not Verify
&lt;/h2&gt;

&lt;p&gt;Being straight about the gaps, since a lot of the coverage of this release is not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No benchmarks.&lt;/strong&gt; Alibaba shipped this generation without a technical report or published eval numbers. Any ranking you see for Qwen Image 3.0 Pro is somebody's vibe check, including ours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No open weights.&lt;/strong&gt; Earlier Qwen-Image generations had downloadable weights. This one does not, so self-hosting is not an escape hatch from the quota.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No published rate limit.&lt;/strong&gt; The numbers above are observed behaviour from one key on one afternoon, not documented limits. Yours may differ and Alibaba can change them without telling anyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No end date on the free pricing.&lt;/strong&gt; "Limited-time" with no date is the entire disclosure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The long-prompt claim is untested here.&lt;/strong&gt; Alibaba advertises prompt handling in the thousands of tokens. Our test prompts ran to a few dozen words each, which tells you nothing about whether a 4,000-token scene description stays coherent. The quota made a proper stress test impractical in one sitting, so we are not going to pretend we ran one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample size is four.&lt;/strong&gt; Four prompts, one attempt each, no retries and no cherry-picking. That is enough to demonstrate that small-text rendering works and that number sequences break. It is not enough to put a percentage on either.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason to spell this out: most of the coverage of this release repeats Alibaba's capability list as though it were measured. A capability list is a claim. The four images above are four data points, which is more than a claim and much less than a benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Refresh
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://qwen.ai/blog?id=qwen-image-3.0" rel="noopener noreferrer"&gt;Qwen Image 3.0 announcement, qwen.ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/models/bailian/qwen-image-3.0-pro%3Afree" rel="noopener noreferrer"&gt;Qwen-Image 3.0 Pro (Free) model page, ofox.ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/models/volcengine/doubao-seedream-5.0-pro" rel="noopener noreferrer"&gt;Doubao Seedream 5.0 Pro model page, ofox.ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.aliyun.com/zh/model-studio/error-code" rel="noopener noreferrer"&gt;Alibaba Model Studio error codes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.ofox.ai/api" rel="noopener noreferrer"&gt;ofox API reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/qwen-image-3-0-pro-free-api-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>qwen</category>
      <category>imagegeneration</category>
      <category>api</category>
    </item>
    <item>
      <title>LLM API Rate Limits Compared (2026): 5 Vendors, 5 Rulebooks</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sat, 25 Jul 2026 00:36:19 +0000</pubDate>
      <link>https://dev.to/owen_fox/llm-api-rate-limits-compared-2026-5-vendors-5-rulebooks-377</link>
      <guid>https://dev.to/owen_fox/llm-api-rate-limits-compared-2026-5-vendors-5-rulebooks-377</guid>
      <description>&lt;h1&gt;
  
  
  LLM API Rate Limits Compared (2026): 5 Vendors, 5 Rulebooks
&lt;/h1&gt;

&lt;p&gt;Five LLM APIs, five rate-limit rules: Anthropic caps tokens/min (10M, cache free), DeepSeek caps concurrency (500), OpenAI/Google went dashboard-only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; There is no single table that ranks LLM API rate limits, because the five biggest vendors do not measure the same thing. Anthropic caps requests, input tokens, and output tokens per minute, and cache reads do not count against you. Moonshot and OpenAI raise your ceiling as you spend more. DeepSeek ignores per-minute rate entirely and caps how many requests you can have running at once. Google and OpenAI have both pulled their per-model numbers off the public docs and into a dashboard. The useful question is not "who has the highest RPM." It is which limit design matches the way your app actually calls the API, and how you route around whichever one hits first.&lt;/p&gt;

&lt;p&gt;A rate limit is not one number you can rank. Anthropic counts tokens per minute, DeepSeek counts requests in flight, OpenAI counts how much you have paid. Lining them up in one column is a category error.&lt;/p&gt;

&lt;p&gt;Here is which limit tends to bite which kind of workload, so you can jump to the vendor design that fits.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your workload&lt;/th&gt;
&lt;th&gt;The limit that bites first&lt;/th&gt;
&lt;th&gt;Design that fits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Many small, fast calls (chat UI, autocomplete)&lt;/td&gt;
&lt;td&gt;RPM (requests/min)&lt;/td&gt;
&lt;td&gt;Anthropic Scale, OpenAI Tier 4-5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A few huge-context calls (RAG, long docs)&lt;/td&gt;
&lt;td&gt;Input tokens/min (ITPM / TPM)&lt;/td&gt;
&lt;td&gt;Anthropic (cache reads free of ITPM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bursty parallel agents&lt;/td&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;DeepSeek (caps in-flight directly, 2,500 on Flash)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Steady production at real scale&lt;/td&gt;
&lt;td&gt;Monthly spend cap&lt;/td&gt;
&lt;td&gt;Anthropic Scale or OpenAI Tier 5 ($200k)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Just starting, tight budget&lt;/td&gt;
&lt;td&gt;Entry-tier ceiling&lt;/td&gt;
&lt;td&gt;Moonshot T0-T1, Gemini Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The One Table Everyone Wants (and Why It Won't Line Up)
&lt;/h2&gt;

&lt;p&gt;Every "rate limits compared" post promises a grid where you scan a column and pick the winner. The grid falls apart on contact, because the vendors disagree about what a limit even is. Here is the honest version: the same five columns, filled with the fact that the columns don't match.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vendor&lt;/th&gt;
&lt;th&gt;Tier is set by&lt;/th&gt;
&lt;th&gt;What it actually caps&lt;/th&gt;
&lt;th&gt;429 signal&lt;/th&gt;
&lt;th&gt;Per-model numbers public?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Anthropic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usage history (Start / Build / Scale / Custom)&lt;/td&gt;
&lt;td&gt;RPM + input tokens/min + output tokens/min, per model class&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;429&lt;/code&gt; + &lt;code&gt;retry-after&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes, full table per tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Moonshot / Kimi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cumulative top-up ($1 to $3,000)&lt;/td&gt;
&lt;td&gt;Concurrency + RPM + TPM + tokens/day&lt;/td&gt;
&lt;td&gt;&lt;code&gt;429&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes, full T0-T5 table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeepSeek&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flat (account level)&lt;/td&gt;
&lt;td&gt;Concurrency only (in-flight requests)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;429&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes, per model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cumulative paid ($5 to $1,000)&lt;/td&gt;
&lt;td&gt;RPM + RPD + TPM + TPD + images/min&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;429&lt;/code&gt; + &lt;code&gt;x-ratelimit-*&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;No, moved to dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Google Gemini&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Billing + spend + time&lt;/td&gt;
&lt;td&gt;RPM + TPM + RPD, plus a 10-min spend gate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;429 RESOURCE_EXHAUSTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No, in AI Studio panel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read across any row and the shape changes. Three vendors will show you exact per-model numbers; two will not. Two gate on tokens, one gates on requests in flight, two gate mostly on how much money you have moved through the account. That mismatch is the real finding, and the rest of this post is what each cell means when you are the one getting the 429.&lt;/p&gt;

&lt;p&gt;All numbers below were pulled from each vendor's official rate-limit documentation on 2026-07-22. Where a vendor no longer publishes per-model figures, this post says so rather than guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anthropic: Three Axes, and Cache Reads Are Free
&lt;/h2&gt;

&lt;p&gt;Anthropic is the most transparent of the five and also the most multi-dimensional. Every model class is limited on three axes at once: requests per minute (RPM), input tokens per minute (ITPM), and output tokens per minute (OTPM). Exceed any one and you get a &lt;code&gt;429&lt;/code&gt; with a &lt;code&gt;retry-after&lt;/code&gt; header telling you exactly how long to wait. The bucket refills continuously (token bucket), so you are not waiting for a fixed reset.&lt;/p&gt;

&lt;p&gt;Tiers are Start, Build, Scale, and Custom. You do not buy your way onto a tier directly; organizations move up automatically based on usage history and account standing. Each tier carries a monthly spend cap:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Monthly spend cap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Start&lt;/td&gt;
&lt;td&gt;$500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build&lt;/td&gt;
&lt;td&gt;$1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;$200,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;None (arranged with account team)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The per-model numbers are where Anthropic actually publishes detail. For Claude Opus 4.x, which shares one combined bucket across Opus 4.8, 4.7, 4.6, and 4.5:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;RPM&lt;/th&gt;
&lt;th&gt;Input tokens/min (ITPM)&lt;/th&gt;
&lt;th&gt;Output tokens/min (OTPM)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Start&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;2,000,000&lt;/td&gt;
&lt;td&gt;400,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build&lt;/td&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;5,000,000&lt;/td&gt;
&lt;td&gt;1,000,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;10,000,000&lt;/td&gt;
&lt;td&gt;2,000,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The standout, and the reason Anthropic's ceiling is higher than it looks, is the cache-aware ITPM rule. For most Claude models, &lt;code&gt;cache_read_input_tokens&lt;/code&gt; do not count toward ITPM. Tokens written to cache and normal input tokens still count, but tokens read back from cache are free of the rate limit. Anthropic's own worked example: a 2,000,000 ITPM limit with an 80% cache hit rate lets you push about 10,000,000 total input tokens per minute, because the 8M cached tokens don't register against the limit. Claude Haiku 3.5 is the one exception that still counts cache reads.&lt;/p&gt;

&lt;p&gt;If a big share of your input is a stable system prompt or a long document you send on every call, that rule changes your effective throughput more than a tier bump would. We worked through the money side of this in &lt;a href="https://ofox.ai/blog/prompt-caching-cost-math-anthropic-vs-openai-2026/" rel="noopener noreferrer"&gt;the prompt-caching cost math&lt;/a&gt;; the rate-limit side is the same lever pointed at throughput instead of the bill.&lt;/p&gt;

&lt;p&gt;Two footnotes that catch teams off guard: the Message Batches API has its own separate limits, and so do Managed Agents (300 RPM for create endpoints, 1,200 RPM for read). Hitting a wall on batch traffic does not mean your Messages API limit is spent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moonshot / Kimi: Pay to Climb, Four Dimensions at Once
&lt;/h2&gt;

&lt;p&gt;Moonshot is the most explicit pay-to-tier ladder of the group. Your tier is set purely by cumulative top-up, from $1 to $3,000, and each tier moves four dials together: concurrency, RPM, TPM, and tokens per day (TPD).&lt;/p&gt;

&lt;p&gt;Tiers on the international platform (&lt;code&gt;platform.kimi.ai&lt;/code&gt;), billed in USD:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Cumulative top-up&lt;/th&gt;
&lt;th&gt;Concurrency&lt;/th&gt;
&lt;th&gt;RPM&lt;/th&gt;
&lt;th&gt;TPM&lt;/th&gt;
&lt;th&gt;TPD&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tier 0&lt;/td&gt;
&lt;td&gt;$1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;500,000&lt;/td&gt;
&lt;td&gt;1,500,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 1&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;2,000,000&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 2&lt;/td&gt;
&lt;td&gt;$20&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;3,000,000&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 3&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;3,000,000&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 4&lt;/td&gt;
&lt;td&gt;$1,000&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;4,000,000&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 5&lt;/td&gt;
&lt;td&gt;$3,000&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;5,000,000&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One trap worth knowing before you compare these numbers against anything else: &lt;strong&gt;Moonshot runs two separate platforms with two separate ladders.&lt;/strong&gt; The international platform (&lt;code&gt;platform.kimi.ai&lt;/code&gt;, also reachable as &lt;code&gt;platform.moonshot.ai&lt;/code&gt;) meters in USD and requires a $1 top-up before you can call anything. The mainland platform (&lt;code&gt;platform.moonshot.cn&lt;/code&gt;) has its own RMB ladder that starts at ¥0 and steps through ¥50 / ¥100 / ¥500 / ¥5,000 / ¥20,000. Those are not currency conversions of each other, and the entry conditions differ: one gates you behind a first payment, the other does not. Check which platform your key belongs to before assuming a tier.&lt;/p&gt;

&lt;p&gt;The jump from Tier 0 to Tier 1 is the one to notice: $9 of extra top-up takes you from 3 RPM and a single concurrent request to 200 RPM and 50 concurrent, and removes the daily token ceiling entirely. Tier 0 is really just a "prove you are real" floor, not a place to build anything.&lt;/p&gt;

&lt;p&gt;One thing the tier table does not show: individual models can be capacity-constrained on top of your tier. A freshly launched model such as Kimi K3 can return &lt;code&gt;429&lt;/code&gt; from upstream capacity even when you are nowhere near your tier limits, because the constraint is the provider's total headroom for that model rather than your account's rate. When that happens, buying a higher tier does not help; the fix is a fallback to a different model, which is the routing pattern later in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  DeepSeek: No RPM at All, Just Concurrency
&lt;/h2&gt;

&lt;p&gt;DeepSeek is the outlier that breaks every comparison grid. It does not publish RPM or TPM limits. It caps concurrency, the number of requests you can have in flight at one time, at the account level:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Concurrency cap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;deepseek-v4-pro&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deepseek-v4-flash&lt;/td&gt;
&lt;td&gt;2,500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Stay under the cap and you can fire requests as fast as the model returns them. Cross it and you get a &lt;code&gt;429&lt;/code&gt;. There is no per-minute budget to pace against, which is genuinely easier to reason about for parallel workloads: you size your worker pool to the concurrency cap and stop worrying about tokens per minute.&lt;/p&gt;

&lt;p&gt;DeepSeek also handles overload differently. Instead of rejecting a request when the servers are busy, it keeps the connection alive, sending empty lines for non-streaming calls or SSE &lt;code&gt;: keep-alive&lt;/code&gt; comments for streaming ones, and only closes the connection if inference has not started after 10 minutes. Accounts with expanded quotas can also use the &lt;code&gt;user_id&lt;/code&gt; parameter to isolate concurrency per end user, which matters if you are multiplexing many customers through one key. If you run DeepSeek in an agent loop, our &lt;a href="https://ofox.ai/blog/deepseek-v4-pro-real-cost-cache-miss-thinking-2026/" rel="noopener noreferrer"&gt;DeepSeek V4 Pro real-cost breakdown&lt;/a&gt; covers how the concurrency model interacts with cache misses and thinking tokens on the bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI: Tier by Spend, Numbers Behind Glass
&lt;/h2&gt;

&lt;p&gt;OpenAI still gates by cumulative amount paid, across six tiers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Qualifies at&lt;/th&gt;
&lt;th&gt;Monthly usage cap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Allowed geography&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 1&lt;/td&gt;
&lt;td&gt;$5 paid&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 2&lt;/td&gt;
&lt;td&gt;$50 paid&lt;/td&gt;
&lt;td&gt;$500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 3&lt;/td&gt;
&lt;td&gt;$100 paid&lt;/td&gt;
&lt;td&gt;$1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 4&lt;/td&gt;
&lt;td&gt;$250 paid&lt;/td&gt;
&lt;td&gt;$5,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 5&lt;/td&gt;
&lt;td&gt;$1,000 paid&lt;/td&gt;
&lt;td&gt;$200,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The dimensions are broad: RPM, RPD, TPM, TPD, images per minute, and audio minutes per minute for some streaming models. When you are inside the limit, responses carry &lt;code&gt;x-ratelimit-limit-requests&lt;/code&gt;, &lt;code&gt;x-ratelimit-remaining-requests&lt;/code&gt;, and their token equivalents, so you can watch your headroom in real time.&lt;/p&gt;

&lt;p&gt;Here is the catch that breaks the grid: OpenAI's rate-limit docs no longer list the specific RPM or TPM numbers per model. The page sends you to the models page or your account dashboard for the actual figures. That is not an oversight to complain about; it is a data point. OpenAI has decided per-model rate limits move often enough that a static table would mislead, so the numbers live in a dashboard tied to your account and tier. Any post that prints exact OpenAI per-model RPM as if it were fixed is quoting a snapshot that may already be stale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Gemini: Tiers, Time Gates, and a 10-Minute Spend Window
&lt;/h2&gt;

&lt;p&gt;Gemini's tiers combine billing status, spend, and elapsed time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Qualifies at&lt;/th&gt;
&lt;th&gt;Spend cap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Active project or free trial&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 1&lt;/td&gt;
&lt;td&gt;Billing account linked&lt;/td&gt;
&lt;td&gt;$250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 2&lt;/td&gt;
&lt;td&gt;$100 paid + 3 days since first payment&lt;/td&gt;
&lt;td&gt;$2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier 3&lt;/td&gt;
&lt;td&gt;$1,000 paid + 30 days since first payment&lt;/td&gt;
&lt;td&gt;$20,000 to $100,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The three-days and thirty-days requirements are unusual: even if you pay the money, you cannot skip the waiting period to reach Tier 2 or Tier 3. Gemini also layers a spend-based control on top of the usual RPM / TPM / RPD, enforced per rolling 10-minute window ($10 for Tier 1, $200 for Tiers 2 and 3), so a sudden burst of spend can throttle you even when your per-minute token rate is fine. Exceed a limit and you get &lt;code&gt;429 RESOURCE_EXHAUSTED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Like OpenAI, Gemini keeps the per-model RPM / TPM / RPD numbers off the static docs and inside AI Studio, where you view your active limits. And the whole page applies only to the Gemini Developer API, not to Vertex AI, which runs its own quota system entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Units Don't Line Up (the Part Nobody Tables)
&lt;/h2&gt;

&lt;p&gt;Step back and the incompatibility is the story. Here is what a single "unit" of headroom actually buys you at each vendor, and where that unit pinches.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Used by&lt;/th&gt;
&lt;th&gt;What one unit of headroom buys&lt;/th&gt;
&lt;th&gt;Where it pinches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RPM (requests/min)&lt;/td&gt;
&lt;td&gt;All five, as one axis&lt;/td&gt;
&lt;td&gt;N calls/min regardless of size&lt;/td&gt;
&lt;td&gt;Many small calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input tokens/min (ITPM / TPM)&lt;/td&gt;
&lt;td&gt;Anthropic, Moonshot, OpenAI, Google&lt;/td&gt;
&lt;td&gt;N input tokens/min&lt;/td&gt;
&lt;td&gt;Large context, RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output tokens/min (OTPM)&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;N generated tokens/min&lt;/td&gt;
&lt;td&gt;Long generations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency (in-flight)&lt;/td&gt;
&lt;td&gt;DeepSeek, Moonshot&lt;/td&gt;
&lt;td&gt;N requests running at once, any size&lt;/td&gt;
&lt;td&gt;Parallel fan-out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly spend cap&lt;/td&gt;
&lt;td&gt;All five&lt;/td&gt;
&lt;td&gt;A hard dollar ceiling per month&lt;/td&gt;
&lt;td&gt;Sustained scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10-min rolling spend&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Dollars per rolling 10 minutes&lt;/td&gt;
&lt;td&gt;Spiky spend&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A team that sends thousands of tiny classification calls hits RPM first and could not care less about ITPM. A team that pastes a 200k-token document into every request hits token-per-minute walls while its RPM sits near zero. A team running fifty parallel agents hits concurrency. These three teams cannot use the same "best rate limits" recommendation, because they are constrained by three different units, and no single ranking can serve all three.&lt;/p&gt;

&lt;p&gt;A worked example makes the trap concrete. Say you run 50 workers, each sending a 30,000-token RAG request. On DeepSeek's deepseek-v4-pro that is 50 in-flight against a 500 concurrency cap, so you have ten times the headroom and never see a 429. Move the exact same workload to a vendor with a 2,000,000 input-tokens-per-minute limit and, if those 50 requests land inside the same minute, that is 1,500,000 input tokens in one burst, plus whatever else you are sending. You are suddenly at 75% of a limit you were not even tracking on DeepSeek, and a small traffic bump tips you over. Same concurrency, same request size, completely different wall.&lt;/p&gt;

&lt;p&gt;This is why cross-vendor migration surprises people. The limit you were never watching becomes the one that bites, and the code path that ran clean for months starts throwing 429s the day you switch providers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Limit Will Bite You First (Decision Frame)
&lt;/h2&gt;

&lt;p&gt;Before you upgrade a tier or re-architect anything, figure out which wall you are actually hitting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;When to just upgrade the tier.&lt;/strong&gt; Your 429s cluster on one axis (say, RPM), you are on a low tier, and the next tier's ceiling clears your peak with room to spare. Paying up is the cheapest fix. This is the common case for Moonshot and OpenAI, where tier is a spend dial.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;When to cache instead of upgrade.&lt;/strong&gt; You are on Anthropic, hitting ITPM, and a large slice of your input repeats across calls. Turning on prompt caching can lift effective throughput without a tier change, because cache reads do not count against ITPM. Try this before you request a limit increase.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;When to route around it.&lt;/strong&gt; Your limit is structural for the workload (a concurrency cap you keep saturating, or a model returning upstream-capacity 429s that no tier fixes). The fix is failover to a comparable model on a different provider, so a throttle degrades to a hop instead of an error. This is where the &lt;a href="https://ofox.ai/blog/ai-api-error-handling-troubleshooting-guide-2026/" rel="noopener noreferrer"&gt;general 429 handling patterns&lt;/a&gt; and a &lt;a href="https://ofox.ai/blog/multi-model-router-one-api-2026/" rel="noopener noreferrer"&gt;multi-model router&lt;/a&gt; earn their keep.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Stop rule.&lt;/strong&gt; If your 429 rate is under about 1% and clears on a single retry, you do not have a rate-limit problem, you have normal burst noise. Add jittered backoff and move on. Do not re-architect for a wall you are barely touching.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Read a 429 (Which Wall Did You Hit?)
&lt;/h2&gt;

&lt;p&gt;A 429 is not self-explanatory, and the vendors tell you which wall you hit in different ways. Reading the response before you retry saves you from waiting out a limit you did not actually break.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vendor&lt;/th&gt;
&lt;th&gt;Signal to read&lt;/th&gt;
&lt;th&gt;What it tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;retry-after&lt;/code&gt; + &lt;code&gt;anthropic-ratelimit-requests-remaining&lt;/code&gt; / &lt;code&gt;-input-tokens-remaining&lt;/code&gt; / &lt;code&gt;-output-tokens-remaining&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Exactly which axis hit zero (requests, input, or output tokens) and how many seconds to wait&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;x-ratelimit-remaining-requests&lt;/code&gt; / &lt;code&gt;x-ratelimit-remaining-tokens&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Whether you ran out of requests or tokens for the window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;429&lt;/code&gt; with no documented &lt;code&gt;retry-after&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;You are over your concurrency cap; reduce in-flight requests rather than just waiting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Gemini&lt;/td&gt;
&lt;td&gt;&lt;code&gt;429 RESOURCE_EXHAUSTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check whether it is the per-minute limit or the 10-minute spend gate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moonshot / Kimi&lt;/td&gt;
&lt;td&gt;&lt;code&gt;429&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check which tier axis you crossed: concurrency, RPM, or TPM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical split is between "wait" limits and "slow down" limits. Anthropic, OpenAI, and Google give you a per-minute budget, so a &lt;code&gt;retry-after&lt;/code&gt; or a remaining-tokens header near zero means back off for a few seconds and the bucket refills. DeepSeek's concurrency cap is a "slow down" limit: waiting does nothing if you keep the same number of requests in flight, because the wall is parallelism, not time. Retrying a concurrency 429 without shrinking your worker pool just re-hits the same wall. Get this distinction wrong and your backoff logic either sleeps when it should shed load, or sheds load when a one-second wait would have cleared it.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Endpoint, Five Rulebooks
&lt;/h2&gt;

&lt;p&gt;You cannot make Anthropic's ITPM or DeepSeek's concurrency cap disappear. What you can do is stop letting any one vendor's limit be a single point of failure. When five vendors each enforce a different rule, the practical defense is to put them behind one endpoint and fail a throttled request over to another vendor automatically. A gateway like &lt;a href="https://ofox.ai" rel="noopener noreferrer"&gt;ofox&lt;/a&gt; exposes all of them on one OpenAI-compatible API and one key, so "hit vendor A's limit" becomes "answered by vendor B" instead of a failed call. This is also the argument in &lt;a href="https://ofox.ai/blog/why-llm-api-gateway-how-to-choose-2026/" rel="noopener noreferrer"&gt;why an LLM API gateway earns its place&lt;/a&gt;, applied specifically to rate limits.&lt;/p&gt;

&lt;p&gt;The pattern is a short retry-then-hop loop. A 429 from any vendor triggers a couple of jittered retries, then a switch to the next model in a cross-vendor chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;

&lt;span class="n"&gt;OFOX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ofox.ai/v1/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HEADERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OFOX_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Same endpoint, different vendors. If one throttles, hop to the next.
&lt;/span&gt;&lt;span class="n"&gt;CHAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deepseek/deepseek-v4-pro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;z-ai/glm-5.2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moonshotai/kimi-k3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;CHAIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OFOX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;              &lt;span class="c1"&gt;# any vendor's rate limit
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;                         &lt;span class="c1"&gt;# give up on this vendor, try the next
&lt;/span&gt;                &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;               &lt;span class="c1"&gt;# 1s, 2s, 4s
&lt;/span&gt;                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;every vendor in the chain is rate-limited right now&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.ofox.ai/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OFOX_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deepseek/deepseek-v4-pro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;z-ai/glm-5.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moonshotai/kimi-k3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                &lt;span class="c1"&gt;// hop to the next vendor&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;               &lt;span class="c1"&gt;// 1s, 2s, 4s&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;every vendor in the chain is rate-limited right now&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap the &lt;code&gt;model&lt;/code&gt; string and everything else stays the same. That is the whole point: five vendors, five rulebooks, one code path. The gateway does not raise anyone's ceiling, and it will still return 429 when every vendor in the chain is full at once. It just turns "the vendor I picked is throttled" into a problem the loop solves instead of one your users see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives: Ways to Handle Five Different Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;ofox (unified endpoint + cross-vendor failover).&lt;/strong&gt; One OpenAI-compatible API over Anthropic, DeepSeek, Moonshot, Google, and more, with model IDs like &lt;code&gt;deepseek/deepseek-v4-pro&lt;/code&gt; and &lt;code&gt;moonshotai/kimi-k3&lt;/code&gt;. Best when your real risk is any single vendor's limit stalling a request and you want the failover to be a config line, not a rewrite. It does not increase a vendor's ceiling.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Direct vendor keys, one per provider.&lt;/strong&gt; The most control and the lowest per-token price, at the cost of integrating and monitoring each vendor's limit shape yourself. Reasonable if you are committed to one provider and its limit design fits your workload cleanly.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;OpenRouter and similar aggregators.&lt;/strong&gt; Also unify many models behind one endpoint. Compare on fee model and on how they handle provider-level versus model-level failover, since a single-provider model has nothing to route to. Match on your actual bottleneck rather than model count.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Roll your own router.&lt;/strong&gt; A retry-and-failover layer like the loop above, maintained in-house. Full control, but you own every vendor's quirks: DeepSeek's keep-alive, Anthropic's separate batch limits, Google's 10-minute spend gate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whichever you pick, the rule holds: nothing deletes a vendor's rate limit. The choice is how gracefully you route around the one that hits first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources Checked for This Refresh
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://platform.claude.com/docs/en/api/rate-limits" rel="noopener noreferrer"&gt;Anthropic API rate limits&lt;/a&gt; (verified 2026-07-22)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://platform.kimi.ai/docs/pricing/limits" rel="noopener noreferrer"&gt;Moonshot / Kimi API rate limits, international platform&lt;/a&gt; (verified 2026-07-22)&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://web.archive.org/web/20260717074035/https://platform.kimi.ai/docs/pricing/limits" rel="noopener noreferrer"&gt;Moonshot / Kimi rate limits, archived copy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://platform.moonshot.cn/docs/pricing/limits" rel="noopener noreferrer"&gt;Moonshot mainland platform rate limits, RMB ladder&lt;/a&gt; (verified 2026-07-23)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://api-docs.deepseek.com/quick_start/rate_limit/" rel="noopener noreferrer"&gt;DeepSeek API rate limits&lt;/a&gt; (verified 2026-07-22)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developers.openai.com/api/docs/guides/rate-limits" rel="noopener noreferrer"&gt;OpenAI API rate limits&lt;/a&gt; (verified 2026-07-22)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ai.google.dev/gemini-api/docs/rate-limits" rel="noopener noreferrer"&gt;Google Gemini API rate limits&lt;/a&gt; (verified 2026-07-22)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/llm-api-rate-limits-compared-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>ratelimits</category>
      <category>anthropic</category>
    </item>
  </channel>
</rss>
