<?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>Use DeepSeek V4.1 Flash in Claude Code: setup guide</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 13 Sep 2026 11:34:07 +0000</pubDate>
      <link>https://dev.to/owen_fox/use-deepseek-v41-flash-in-claude-code-setup-guide-2f33</link>
      <guid>https://dev.to/owen_fox/use-deepseek-v41-flash-in-claude-code-setup-guide-2f33</guid>
      <description>&lt;p&gt;&lt;strong&gt;Claude Code can connect to DeepSeek V4.1 Flash through &lt;code&gt;https://api.deepseek.com/anthropic&lt;/code&gt;. DeepSeek’s documented setup uses &lt;code&gt;deepseek-flash[1m]&lt;/code&gt; for the main, Opus and Sonnet selections, and &lt;code&gt;deepseek-flash&lt;/code&gt; for Haiku and subagents.&lt;/strong&gt; Those distinctions appear in the &lt;a href="https://api-docs.deepseek.com/quick_start/agent_integrations/claude_code/" rel="noopener noreferrer"&gt;official Claude Code integration guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This guide was checked on September 10, 2026, against the direct DeepSeek documentation. We have not run paid inference or verified a successful Claude Code task. The &lt;a href="https://ofox.ai/blog/deepseek-v4-1-flash-preview/" rel="noopener noreferrer"&gt;release overview&lt;/a&gt; and &lt;a href="https://ofox.ai/blog/deepseek-v4-1-flash-api-setup/" rel="noopener noreferrer"&gt;API setup guide&lt;/a&gt; explain the model and its direct API access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure an existing Claude Code installation
&lt;/h2&gt;

&lt;p&gt;First check that &lt;code&gt;claude --version&lt;/code&gt; works. If Claude Code is absent, install it using the current Claude Code installation instructions before applying provider settings. Obtain a DeepSeek API key from the &lt;a href="https://platform.deepseek.com/" rel="noopener noreferrer"&gt;DeepSeek Platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For macOS or Linux, use these settings in the terminal from which you will launch Claude Code. Replace the token placeholder locally. Quoting the model names keeps the &lt;code&gt;[1m]&lt;/code&gt; suffix from being interpreted as a shell filename pattern:&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;ANTHROPIC_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://api.deepseek.com/anthropic"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"REPLACE_WITH_DEEPSEEK_API_KEY"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"deepseek-flash[1m]"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_DEFAULT_OPUS_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"deepseek-flash[1m]"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_DEFAULT_SONNET_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"deepseek-flash[1m]"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_DEFAULT_HAIKU_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"deepseek-flash"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLAUDE_CODE_SUBAGENT_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"deepseek-flash"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLAUDE_CODE_EFFORT_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"max"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLAUDE_CODE_AUTO_COMPACT_WINDOW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"786432"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the values in DeepSeek’s published integration, including the effort and compaction settings. The &lt;code&gt;[1m]&lt;/code&gt; form is a client integration setting; the direct API model name remains &lt;code&gt;deepseek-flash&lt;/code&gt;. Do not append the suffix to every API request by assumption.&lt;/p&gt;

&lt;p&gt;Windows users can use the equivalent &lt;code&gt;$env:NAME="value"&lt;/code&gt; assignments listed in the official guide. Keep credentials out of project files and shared terminal transcripts. Start with session-level settings so your existing provider setup remains easy to restore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check every model selection, not just the main one
&lt;/h2&gt;

&lt;p&gt;The Opus, Sonnet, Haiku and subagent variables matter because a workflow can select more than its main model. Keeping an old default can leave some requests on a different route.&lt;/p&gt;

&lt;p&gt;DeepSeek also documents automatic mappings for incoming Claude model names: &lt;code&gt;claude-opus&lt;/code&gt; names map to V4 Pro, while &lt;code&gt;claude-haiku&lt;/code&gt; and &lt;code&gt;claude-sonnet&lt;/code&gt; names map to Flash. Its guide says the Opus mapping retains Pro billing until &lt;strong&gt;September 14, 2026, at 12:00 Beijing time (UTC+8)&lt;/strong&gt;. After that, Pro requests move to Flash and Flash billing. See the &lt;a href="https://ofox.ai/blog/deepseek-v4-pro-to-v4-1-flash-migration/" rel="noopener noreferrer"&gt;Pro migration guide&lt;/a&gt; for the scheduled change.&lt;/p&gt;

&lt;p&gt;That is why the explicit Flash settings above are preferable when your goal is to evaluate V4.1 Flash now. A familiar Claude label does not prove which DeepSeek model or rate served the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate a small workflow and its cost
&lt;/h2&gt;

&lt;p&gt;Enter a test project and run &lt;code&gt;claude&lt;/code&gt; from the configured terminal. Ask it to explain one file before requesting a bounded edit. Check the resulting diff, tool behavior and test outcome; if your normal workflow delegates work, verify that path too.&lt;/p&gt;

&lt;p&gt;Inspect the provider’s usage and billing records for the task. Our example is a setup procedure, not evidence of tested speed, savings or equivalent coding quality. The &lt;a href="https://ofox.ai/blog/deepseek-v4-1-flash-api-setup/#pricing" rel="noopener noreferrer"&gt;Flash pricing guide&lt;/a&gt; separates input cache hits, misses, output and peak/off-peak pricing.&lt;/p&gt;

&lt;p&gt;If authentication fails, check the key and endpoint together. A request-format problem needs the response’s error details; repeatedly changing model names will not repair an incorrect protocol. Codex uses a different setup through the &lt;a href="https://ofox.ai/blog/deepseek-v4-1-flash-codex-setup/" rel="noopener noreferrer"&gt;Responses API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a gateway such as Ofox, verify its actual model ID, Anthropic support and account price before replacing these direct-provider settings. The &lt;a href="https://ofox.ai/models" rel="noopener noreferrer"&gt;Ofox catalog&lt;/a&gt; is a place to begin that check; this article does not confirm that V4.1 Flash is available through Ofox or that signing up enables it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What model name should I set in Claude Code for DeepSeek V4.1 Flash?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DeepSeek's official integration sets ANTHROPIC_MODEL, ANTHROPIC_DEFAULT_OPUS_MODEL and ANTHROPIC_DEFAULT_SONNET_MODEL to deepseek-flash[1m]. It uses deepseek-flash without the suffix for Haiku and subagents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which base URL does the direct DeepSeek integration use?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set ANTHROPIC_BASE_URL to &lt;a href="https://api.deepseek.com/anthropic" rel="noopener noreferrer"&gt;https://api.deepseek.com/anthropic&lt;/a&gt; and authenticate with a DeepSeek API key in ANTHROPIC_AUTH_TOKEN. Do not substitute the Codex Responses configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does selecting a Claude Opus alias guarantee Flash billing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. DeepSeek documents claude-opus names as mapping to V4 Pro, with Pro billing until September 14, 2026, at 12:00 Beijing time. Use the explicit Flash settings and check provider usage records.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/deepseek-v4-1-flash-claude-code-setup/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>deepseek</category>
      <category>claudecode</category>
      <category>api</category>
    </item>
    <item>
      <title>DeepSeek V4.1 Flash API: pricing, providers and setup</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 13 Sep 2026 04:32:30 +0000</pubDate>
      <link>https://dev.to/owen_fox/deepseek-v41-flash-api-pricing-providers-and-setup-300l</link>
      <guid>https://dev.to/owen_fox/deepseek-v41-flash-api-pricing-providers-and-setup-300l</guid>
      <description>&lt;p&gt;&lt;strong&gt;To call DeepSeek V4.1 Flash directly, use &lt;code&gt;deepseek-flash&lt;/code&gt; at &lt;code&gt;https://api.deepseek.com&lt;/code&gt;.&lt;/strong&gt; Before buying credit, choose the provider and protocol, estimate the task cost, then configure a key issued by that same provider. This guide follows that full path, from a purchase decision to the first request.&lt;/p&gt;

&lt;p&gt;Checked against DeepSeek's official documentation on September 11, 2026. The code is documentation-checked and syntax-checked; it is not a paid end-to-end test. Running the examples can consume credit.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Choose where to obtain API access
&lt;/h2&gt;

&lt;p&gt;The official release log confirms direct API access. A third-party entry needs its own verification: DeepSeek's legacy-name routing does not establish a gateway's model mapping.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;What this check establishes&lt;/th&gt;
&lt;th&gt;What to confirm before funding&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Direct DeepSeek API&lt;/td&gt;
&lt;td&gt;Official documentation identifies &lt;code&gt;deepseek-flash&lt;/code&gt; as V4.1 Flash&lt;/td&gt;
&lt;td&gt;Your account access, current rates and required operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ofox&lt;/td&gt;
&lt;td&gt;The retrieved public catalog showed older DeepSeek entries; this check did not establish a V4.1 serving route&lt;/td&gt;
&lt;td&gt;Actual model version and ID, protocol, account price and payment terms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Another gateway&lt;/td&gt;
&lt;td&gt;Not certified by this guide&lt;/td&gt;
&lt;td&gt;Its own current catalog, protocol documentation and billing terms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Ofox result is a limit of verification, not proof of unavailability. A provider may update routing independently of display labels; a blog announcement alone does not prove a purchasable route exists. Confirm the operation you need: text chat, Codex Responses, Claude Code tools and image input are separate compatibility checks.&lt;/p&gt;

&lt;p&gt;For Ofox, inspect the catalog and authentication documentation. If a confirmed route meets your requirements, create an account and prepare an API key. A gateway account does not fund your direct DeepSeek account.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Calculate the cost before buying credit
&lt;/h2&gt;

&lt;p&gt;These are &lt;strong&gt;direct DeepSeek USD prices per one million tokens&lt;/strong&gt;, checked on the official pricing page. They are not an Ofox quote.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token category&lt;/th&gt;
&lt;th&gt;Off-peak USD / 1M tokens&lt;/th&gt;
&lt;th&gt;Peak USD / 1M tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input with a cache hit&lt;/td&gt;
&lt;td&gt;$0.003&lt;/td&gt;
&lt;td&gt;$0.006&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input with a cache miss&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;td&gt;$1.20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Peak periods are Monday–Friday, &lt;strong&gt;01:00–04:00 and 06:00–10:00 UTC&lt;/strong&gt;. Other times are off-peak. These periods are 09:00–12:00 and 14:00–18:00 in Beijing, or 10:00–13:00 and 15:00–19:00 in Tokyo and Seoul. Use timezone-aware conversion where clocks change seasonally. For a request crossing a price boundary, check the actual billing rule instead of inventing a split-charge formula.&lt;/p&gt;

&lt;p&gt;A repeated prompt does not prove the whole input was billed as cached. Check the returned usage and billing record. For mixed input, estimate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cost = cached_input_tokens / 1_000_000 × cached_input_rate
     + uncached_input_tokens / 1_000_000 × uncached_input_rate
     + billed_output_tokens / 1_000_000 × output_rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, 100 requests with 10,000 uncached input tokens and 2,000 billed output tokens each total 1 million input and 0.2 million output tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Off-peak: (1 × $0.15) + (0.2 × $0.60) = $0.27
Peak:     (1 × $0.30) + (0.2 × $1.20) = $0.54
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That budget fits 18 complete 100-request batches into $5 outside peak hours, or 9 at peak rates, excluding provider-specific fees. It does not guarantee 1,800 useful tasks: agents can make multiple calls, retry, accumulate history and consume more output than a final visible answer suggests.&lt;/p&gt;

&lt;p&gt;When comparing sellers, replace the official rates with the destination's quote. Check its minimum payment, purchase fees, time bands and refund conditions. Budget one complete representative task before increasing the balance.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Match the account, key and model
&lt;/h2&gt;

&lt;p&gt;Obtain a key from the provider you will call. A direct key from the DeepSeek Platform belongs with the DeepSeek endpoint; an Ofox key belongs with the documented Ofox route. Store the direct credential locally as &lt;code&gt;DEEPSEEK_API_KEY&lt;/code&gt;; do not commit or print it.&lt;/p&gt;

&lt;p&gt;Use the exact model ID. The official &lt;code&gt;deepseek-flash&lt;/code&gt; name now selects V4.1 Flash. Older Flash names are compatibility aliases, while an &lt;code&gt;expires-on-0910&lt;/code&gt; beta configuration belongs to an earlier rollout stage. Existing Pro users should also read the migration guidance.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Make one small Python or curl request
&lt;/h2&gt;

&lt;p&gt;Following the official quickstart, install the compatible Python client in your project environment with &lt;code&gt;python -m pip install openai&lt;/code&gt;, then use:&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="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="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;DEEPSEEK_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;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.deepseek.com&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;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;deepseek-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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reply with one short greeting.&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;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;extra_body&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;thinking&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;disabled&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;response&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="n"&gt;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts without thinking or tools so the diagnostic task is small. After the basic call works, add required capabilities one at a time and check their documented parameters.&lt;/p&gt;

&lt;p&gt;The equivalent curl request is:&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;--fail-with-body&lt;/span&gt; https://api.deepseek.com/chat/completions &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;$DEEPSEEK_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;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"model":"deepseek-flash","messages":[{"role":"user","content":"Reply with one short greeting."}],"max_tokens":128,"thinking":{"type":"disabled"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep a sanitized error body if the call fails. Do not share a verbose trace containing the authorization header. For JavaScript, the OpenAI SDK option is &lt;code&gt;baseURL&lt;/code&gt;; the model and JSON fields stay the same. Follow your installed SDK's interface rather than mechanically copying Python argument names.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Configure the protocol your client needs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client or operation&lt;/th&gt;
&lt;th&gt;What to check next&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chat Completions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/chat/completions&lt;/code&gt; with &lt;code&gt;messages&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;Responses provider settings and the complete model catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;Anthropic-compatible base path, main-model aliases and subagents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image understanding&lt;/td&gt;
&lt;td&gt;Supported image content blocks and the chosen route's visual input support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use the dedicated Codex guide or Claude Code guide for client configuration. A text reply alone does not validate a tool loop, image input or streaming parser. Main-model selection also does not establish which model every helper uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Diagnose the error before adding credit
&lt;/h2&gt;

&lt;p&gt;If a model is missing, check the destination and exact identifier first. A stale client catalog may not list &lt;code&gt;deepseek-flash&lt;/code&gt;, and a gateway may use a different ID. Do not assume all providers return the same unknown-model error.&lt;/p&gt;

&lt;p&gt;The official error reference distinguishes 401 authentication, 402 insufficient balance, 400 request format, 422 parameters and 429 rate limits. Adding credit addresses an identified balance problem; it does not fix the other categories. Limit retries and pace transient failures deliberately.&lt;/p&gt;

&lt;p&gt;After a successful representative task, record the model, provider, time, token usage and billed amount without secrets. Compare the bill with your budget and check the result's usefulness. Increase funding only after the needed operation and its cost have been verified on the actual route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What model ID calls DeepSeek V4.1 Flash?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use deepseek-flash on the direct DeepSeek API. A gateway can use its own identifier; verify the route before using or funding it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does the official V4.1 Flash API cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The September 10 direct API rates per million tokens outside peak hours are $0.003 for cached input, $0.15 for uncached input and $0.60 for output. Peak prices are twice those rates. Gateway prices must be checked separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where can I buy access?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The official DeepSeek API is documented as available. For a gateway, confirm its actual model version, supported protocol, account price and payment terms before funding it. This check has not established an Ofox V4.1 route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use a DeepSeek key on Ofox?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the credential issued by the provider receiving the request. Provider keys and balances are separate; do not combine a DeepSeek key with an Ofox endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will adding credit fix an API error?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It can address a confirmed insufficient-balance error, such as 402 on the direct API. It does not fix authentication, malformed requests, an unsupported model or client configuration.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/deepseek-v4-1-flash-api-setup/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>deepseek</category>
      <category>api</category>
      <category>pricing</category>
    </item>
    <item>
      <title>Codex GPT-5.5 model not found: diagnose the 404</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sat, 12 Sep 2026 11:34:10 +0000</pubDate>
      <link>https://dev.to/owen_fox/codex-gpt-55-model-not-found-diagnose-the-404-2j1j</link>
      <guid>https://dev.to/owen_fox/codex-gpt-55-model-not-found-diagnose-the-404-2j1j</guid>
      <description>&lt;p&gt;If Codex reports that &lt;code&gt;gpt-5.5&lt;/code&gt; does not exist or you do not have access to it, &lt;strong&gt;check the combination of model ID, provider and authentication before changing your subscription&lt;/strong&gt;. A valid ChatGPT login does not establish access through an API key, and a valid provider key does not establish that the provider accepts the model ID in your configuration.&lt;/p&gt;

&lt;p&gt;This guide is for a Codex CLI session showing an error such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unexpected status 404 Not Found: The model `gpt-5.5` does not exist or you do not have access to it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wording identifies the requested model, not the cause. It is not evidence that GPT-5.5 was retired. The steps below are based on the official Codex configuration and authentication documentation checked on September 8, 2026; they do not claim that GPT-5.5 is available to every account or provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the route, not a reinstall
&lt;/h2&gt;

&lt;p&gt;Run these inspection commands in the same terminal where Codex fails:&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="nt"&gt;--version&lt;/span&gt;
codex login status
codex &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Record the version and authentication method. Also record the directory you launched from, any &lt;code&gt;--model&lt;/code&gt;, &lt;code&gt;--profile&lt;/code&gt; or &lt;code&gt;-c&lt;/code&gt; arguments, and whether an IDE launched the session. Do not share API keys, access tokens or the contents of &lt;code&gt;auth.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;codex login status&lt;/code&gt; describes authentication; it is not a complete report of the endpoint selected by a custom provider. Read it alongside the provider configuration.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your intended connection&lt;/th&gt;
&lt;th&gt;What to check first&lt;/th&gt;
&lt;th&gt;What not to infer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT sign-in&lt;/td&gt;
&lt;td&gt;Correct account/workspace and a model offered for that session&lt;/td&gt;
&lt;td&gt;A ChatGPT subscription guarantees the same model through the API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI API key&lt;/td&gt;
&lt;td&gt;Intended API account/project, model availability and OpenAI endpoint&lt;/td&gt;
&lt;td&gt;A successful ChatGPT session proves this API key has access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third-party provider&lt;/td&gt;
&lt;td&gt;Provider URL, its model ID and the environment variable supplying its key&lt;/td&gt;
&lt;td&gt;An OpenAI model ID or OpenAI key automatically works on that provider&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OpenAI documents the distinction between &lt;a href="https://developers.openai.com/codex/auth/" rel="noopener noreferrer"&gt;ChatGPT subscription access and API-key usage-based access&lt;/a&gt;. Keep those routes separate throughout the diagnosis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the setting Codex actually reads
&lt;/h2&gt;

&lt;p&gt;A common troubleshooting mistake is editing the user configuration while the launch command still selects another model. Inspect the relevant configuration files locally and record only the fields you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;model&lt;/span&gt;
&lt;span class="err"&gt;model_provider&lt;/span&gt;
&lt;span class="err"&gt;openai_base_url&lt;/span&gt;
&lt;span class="err"&gt;model_providers.&amp;lt;provider&amp;gt;.base_url&lt;/span&gt;
&lt;span class="err"&gt;model_providers.&amp;lt;provider&amp;gt;.env_key&lt;/span&gt;
&lt;span class="err"&gt;model_providers.&amp;lt;provider&amp;gt;.requires_openai_auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the current &lt;a href="https://developers.openai.com/codex/config-basic/" rel="noopener noreferrer"&gt;configuration basics&lt;/a&gt;, precedence runs from highest to lowest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CLI flags and &lt;code&gt;--config&lt;/code&gt; overrides.&lt;/li&gt;
&lt;li&gt;Trusted project configuration, with the file closest to the working directory winning.&lt;/li&gt;
&lt;li&gt;The profile file selected with &lt;code&gt;--profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;User configuration at &lt;code&gt;~/.codex/config.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;System configuration, then built-in defaults.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is an important restriction: current &lt;a href="https://developers.openai.com/codex/config-advanced/" rel="noopener noreferrer"&gt;advanced configuration documentation&lt;/a&gt; says project configuration ignores provider-related keys such as &lt;code&gt;model_provider&lt;/code&gt;, &lt;code&gt;model_providers&lt;/code&gt; and &lt;code&gt;openai_base_url&lt;/code&gt;, with a startup warning. Keep provider definitions in user-level configuration. A project can still override other allowed settings, including the model, so inspecting only one file can miss a mismatch.&lt;/p&gt;

&lt;p&gt;The current docs describe profile files as &lt;code&gt;~/.codex/profile-name.config.toml&lt;/code&gt;. Older tutorials may use a different profile layout. Check your installed version before copying either format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repair the connection you intended to use
&lt;/h2&gt;

&lt;h3&gt;
  
  
  If you intended ChatGPT sign-in
&lt;/h3&gt;

&lt;p&gt;Confirm the account and workspace, then select a model actually available in that session. Remove an obsolete model override from the launch command or the configuration layer that supplied it. If the model is not offered, check account availability rather than assuming that manually entering &lt;code&gt;gpt-5.5&lt;/code&gt; grants access.&lt;/p&gt;

&lt;p&gt;Only reauthenticate when the active account is wrong or authentication has failed. Reinstalling Codex or deleting credentials is not a necessary first step for a model lookup error.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you intended an OpenAI API key
&lt;/h3&gt;

&lt;p&gt;Confirm that the request uses the intended OpenAI endpoint and API account/project. Compare the requested ID with that account's current model availability. Check &lt;code&gt;openai_base_url&lt;/code&gt; for an old proxy override before concluding that OpenAI rejected the request.&lt;/p&gt;

&lt;p&gt;API access and billing are separate from included ChatGPT plan credits. If another model works with the same key, that is useful evidence about the route, but it does not prove access to GPT-5.5.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you intended a third-party provider
&lt;/h3&gt;

&lt;p&gt;Treat the URL, model identifier and key as one matched set. A provider may use a namespaced model ID; use its documented value rather than adding or removing a prefix by guesswork.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;configuration template&lt;/strong&gt;, not a working endpoint or an assertion of GPT-5.5 availability. Replace both placeholders with values from your provider. Put these entries in user-level configuration, merging with existing sections rather than duplicating them:&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;"REPLACE_WITH_PROVIDER_MODEL_ID"&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;"diagnostic_provider"&lt;/span&gt;

&lt;span class="nn"&gt;[model_providers.diagnostic_provider]&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;"My provider"&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.example.com/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;"PROVIDER_API_KEY"&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;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;The selected provider must support the Responses API; the current Codex configuration reference lists &lt;code&gt;responses&lt;/code&gt; as the only supported &lt;code&gt;wire_api&lt;/code&gt; value. A provider offering only Chat Completions cannot use this template. Set &lt;code&gt;PROVIDER_API_KEY&lt;/code&gt; through your usual local secret-management method; do not paste the secret into a shared TOML file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;requires_openai_auth&lt;/code&gt; defaults to &lt;code&gt;false&lt;/code&gt;; it is explicit here to keep this template on the provider-key route. If an existing provider definition sets it to &lt;code&gt;true&lt;/code&gt;, Codex uses OpenAI authentication and ignores &lt;code&gt;env_key&lt;/code&gt;. Check this setting when a provider key appears to have no effect.&lt;/p&gt;

&lt;p&gt;Before editing, save a copy of the affected configuration. Keep unrelated settings. After editing, start a new session from the same directory and run a small request that does not ask Codex to edit files. API usage may be billed. Restore the saved configuration if the change breaks a previously working route.&lt;/p&gt;

&lt;p&gt;For a broader setup walkthrough, see &lt;a href="https://ofox.ai/blog/codex-cli-custom-model-providers-byo-setup/" rel="noopener noreferrer"&gt;custom model providers in Codex&lt;/a&gt;. If you use Ofox, check the &lt;a href="https://ofox.ai/models" rel="noopener noreferrer"&gt;current model catalog&lt;/a&gt; for the exact ID and supported connection before configuring it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the next response to narrow the cause
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Result after the change&lt;/th&gt;
&lt;th&gt;Next step&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Same model-specific 404&lt;/td&gt;
&lt;td&gt;Recheck effective model ID, host and account access; avoid repeated identical retries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML 404 or a generic route-not-found response&lt;/td&gt;
&lt;td&gt;Check URL/path construction and proxy routing before blaming model permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;401 authentication error&lt;/td&gt;
&lt;td&gt;Check the credential for the selected provider; follow the &lt;a href="https://ofox.ai/blog/codex-cli-401-unauthorized-fix-2026/" rel="noopener noreferrer"&gt;Codex 401 guide&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;429 or a usage-limit message&lt;/td&gt;
&lt;td&gt;Model lookup is no longer the only issue; inspect the actual quota/rate-limit response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A successful response&lt;/td&gt;
&lt;td&gt;Confirm the intended account/provider and request record before resuming the larger job&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you compare a direct API request with Codex, use the same host, key, model and Responses endpoint. A successful Chat Completions request to another host does not isolate a Codex problem. A direct success on the matched route shifts attention toward Codex configuration or request differences; it does not prove which difference caused the error.&lt;/p&gt;

&lt;p&gt;A local &lt;code&gt;model metadata ... not found&lt;/code&gt; warning is also distinct from an HTTP 404. Capture the final server response rather than assuming those messages have the same cause. For non-Codex SDKs and Azure cases, use the &lt;a href="https://ofox.ai/blog/openai-api-model-not-found-errors-troubleshooting/" rel="noopener noreferrer"&gt;general OpenAI model-not-found guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to include if you still need support
&lt;/h2&gt;

&lt;p&gt;Send a redacted report containing the Codex version, operating system, authentication type, selected model/provider, endpoint host and path, working-directory context, relevant startup warnings and the exact final error. Include the request ID if the provider supplies one. Exclude secrets and private prompts.&lt;/p&gt;

&lt;p&gt;That report lets support distinguish account availability from a stale override or provider mismatch. It is a better next step than changing the account, model and endpoint all at once and losing the original evidence.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/codex/auth/" rel="noopener noreferrer"&gt;OpenAI Codex authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/codex/config-basic/" rel="noopener noreferrer"&gt;OpenAI Codex configuration basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/codex/config-advanced/" rel="noopener noreferrer"&gt;OpenAI Codex advanced configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/codex/config-reference/" rel="noopener noreferrer"&gt;OpenAI Codex configuration reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/codex/cli/reference/" rel="noopener noreferrer"&gt;OpenAI Codex CLI reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does a GPT-5.5 404 mean the model was removed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. The error alone does not distinguish an unavailable model from the wrong provider, model ID or account access. Check the request route and that account's current model availability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a ChatGPT subscription pay for API requests?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Codex authentication with an API key uses API billing rather than included ChatGPT plan credits. Check which authentication route your session actually uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I delete auth.json to fix this?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start with codex login status and your selected provider. Deleting credentials does not fix a wrong model ID or endpoint and can interrupt a working login.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/codex-gpt-5-5-model-not-found-404-fix-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codex</category>
      <category>troubleshooting</category>
      <category>apiguide</category>
    </item>
    <item>
      <title>Codex Errors: 15 Symptoms Mapped to a Tested Fix (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sat, 12 Sep 2026 04:34:14 +0000</pubDate>
      <link>https://dev.to/owen_fox/codex-errors-15-symptoms-mapped-to-a-tested-fix-2026-31i</link>
      <guid>https://dev.to/owen_fox/codex-errors-15-symptoms-mapped-to-a-tested-fix-2026-31i</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Most Codex errors are misfiled. The message names the symptom, not the cause, so people spend an afternoon rotating an API key when the real problem is a Windows Store install path or a missing &lt;code&gt;bubblewrap&lt;/code&gt; package. This page is the index: 15 failures we have reproduced, each mapped to the thing that is actually broken and to the page with the tested fix. Start with your version, then find your string.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Last updated 2026-08-31. Version numbers and issue states on this page were read from npm, GitHub and OpenAI’s own docs on that date.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For configuration rather than an error, go directly to &lt;a href="https://ofox.ai/blog/codex-cli-config-toml-deep-dive/" rel="noopener noreferrer"&gt;config.toml paths and examples&lt;/a&gt; or &lt;a href="https://ofox.ai/blog/codex-cli-custom-model-providers-byo-setup/" rel="noopener noreferrer"&gt;custom providers and profiles&lt;/a&gt;. For an API model 404, use the &lt;a href="https://ofox.ai/blog/openai-api-model-not-found-errors-troubleshooting/" rel="noopener noreferrer"&gt;model ID, access and endpoint checks&lt;/a&gt;. Match the actual error text before changing credentials or reinstalling.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you check before any Codex fix?
&lt;/h2&gt;

&lt;p&gt;Three of the biggest error families in this list are regressions with a known fixed build. If you are on the broken build, the fix is the upgrade and nothing else on this page applies.&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="nt"&gt;--version&lt;/span&gt;                    &lt;span class="c"&gt;# CLI&lt;/span&gt;
npm view @openai/codex version     &lt;span class="c"&gt;# latest published: 0.151.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The editor extension carries its own version, and it is the one that matters for the “couldn’t load its resources” family: the break landed in &lt;code&gt;26.803.41515&lt;/code&gt; and the fix landed in &lt;code&gt;26.810.41047&lt;/code&gt;. AGENTS.md loading in symlinked workspaces was fixed in CLI &lt;code&gt;v0.138&lt;/code&gt;. Upgrade first, reproduce second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Codex are you running?
&lt;/h2&gt;

&lt;p&gt;Five surfaces ship under the same name and they fail in different places. Getting this wrong is the most common reason a fix does not work.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Surface&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Where its errors come from&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@openai/codex&lt;/code&gt;, a Rust binary with an npm wrapper&lt;/td&gt;
&lt;td&gt;PATH, &lt;code&gt;~/.codex/config.toml&lt;/code&gt;, the sandbox, auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Editor extension&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the Codex panel in VS Code and forks&lt;/td&gt;
&lt;td&gt;resource loading, the app-server handshake, the native host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chrome extension&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;browser control, installed from the ChatGPT desktop app&lt;/td&gt;
&lt;td&gt;native host version, permissions, browser support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChatGPT mobile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Codex inside the phone app&lt;/td&gt;
&lt;td&gt;nothing local; it is a remote session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Desktop app&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the ChatGPT desktop client that hosts the above&lt;/td&gt;
&lt;td&gt;model picker, &lt;code&gt;model_catalog_json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your error mentions resources, a native host, or an app-server, you are in extension territory even if you also use the CLI. If it mentions &lt;code&gt;config.toml&lt;/code&gt;, a sandbox, or a provider, you are in CLI territory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Codex error do you have?
&lt;/h2&gt;

&lt;p&gt;Every string below is quoted as it appears. Find yours, then follow the link for the reproduction and the fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why will Codex not install or start?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error message&lt;/th&gt;
&lt;th&gt;What is actually wrong&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;zsh: command not found: codex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;npm installed it somewhere not on your PATH, usually because of NVM, Volta, or a custom &lt;code&gt;npm prefix -g&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-command-not-found-fix-npm-install-2026/" rel="noopener noreferrer"&gt;codex: command not found&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;failed to start codex app-server (os error 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Windows cannot resolve the path it was handed, most often a Microsoft Store install under &lt;code&gt;WindowsApps\&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-failed-to-start-app-server-windows-2026/" rel="noopener noreferrer"&gt;failed to start codex app-server on Windows&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manifest entry is missing required path nodePath/resourcesPath&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the launcher read an install manifest whose recorded paths no longer exist&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-failed-to-start-app-server-windows-2026/" rel="noopener noreferrer"&gt;same page, fix 6&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unable to locate the codex cli binary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the extension is looking for a CLI that was never installed, or was installed under a different user&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-failed-to-start-app-server-windows-2026/" rel="noopener noreferrer"&gt;failed to start codex app-server on Windows&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Codex could not start the extension. Codex couldn't load its resources.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the &lt;code&gt;26.803.41515&lt;/code&gt; regression, which breaks five different ways behind one message&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-couldnt-load-its-resources-fix-2026/" rel="noopener noreferrer"&gt;couldn’t load its resources&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;codex chrome native host is out of date&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the browser extension and the desktop app are on mismatched builds&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-couldnt-load-its-resources-fix-2026/" rel="noopener noreferrer"&gt;couldn’t load its resources&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Windows deserves its own note, because a lot of advice still says WSL2 is mandatory. It is not. The project README gives Windows its own one-liner:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run the following on Windows to install Codex CLI: &lt;code&gt;powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That installer needs no Node at all. WSL2 is a choice rather than a requirement, but the two paths get different sandboxes. &lt;a href="https://ofox.ai/blog/codex-windows-wsl-installation/" rel="noopener noreferrer"&gt;Native versus WSL2&lt;/a&gt; has the trade-off; &lt;a href="https://ofox.ai/blog/codex-official-installation-complete/" rel="noopener noreferrer"&gt;the install guide&lt;/a&gt; has all the routes including the standalone installer that needs no Node at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why can Codex not authenticate?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error message&lt;/th&gt;
&lt;th&gt;What is actually wrong&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 key was sent at all, usually an env var that never made it into the shell Codex runs in&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-cli-401-unauthorized-fix-2026/" rel="noopener noreferrer"&gt;Codex CLI 401: 9 tested causes&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Incorrect API key provided&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a key was sent and rejected, which is a different problem with a different fix&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-cli-401-unauthorized-fix-2026/" rel="noopener noreferrer"&gt;Codex CLI 401: 9 tested causes&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;requests hang and then time out on connect&lt;/td&gt;
&lt;td&gt;a PAC or WPAD corporate proxy that Codex does not discover, or a missing CA certificate&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-cli-corporate-proxy-pac-wpad/" rel="noopener noreferrer"&gt;Codex behind a corporate proxy&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nine failures return something a user reads as a 401, and only some of them are literally 401. Read the message body, not the status code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why has Codex run out of quota?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error message&lt;/th&gt;
&lt;th&gt;What is actually wrong&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;You've hit your usage limit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a subscription window closed; the reset is a server-side &lt;code&gt;resetsAt&lt;/code&gt; timestamp, not a clock rule&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-weekly-limit-drained-2026/" rel="noopener noreferrer"&gt;Codex reset: when your limit clears&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;429 Too Many Requests&lt;/code&gt; on a metered key&lt;/td&gt;
&lt;td&gt;rate limiting or a spend cap on the API side, which is a separate system from the subscription window&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-weekly-limit-cap-spend-api-2026/" rel="noopener noreferrer"&gt;cap your spend with a drop-in API&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is the single biggest source of Codex searches we see, and most of the advice online is wrong about it. There is no fixed number of days to wait, there are exactly two windows, and an earned reset is a credit you can redeem rather than a date you wait for. A 429 on a metered key is not the same event at all: for what the code means per provider, see &lt;a href="https://ofox.ai/blog/llm-api-error-codes-reference-2026/" rel="noopener noreferrer"&gt;LLM API error codes&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does Codex refuse to run commands or read your files?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error message&lt;/th&gt;
&lt;th&gt;What is actually wrong&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;command failed; retry without sandbox&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;on Linux, &lt;code&gt;bubblewrap&lt;/code&gt; is missing or cannot open the paths it needs; on any OS, &lt;code&gt;sandbox_mode&lt;/code&gt; is stricter than the task&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-command-failed-retry-without-sandbox-fix-2026/" rel="noopener noreferrer"&gt;command failed; retry without sandbox&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AGENTS.md is ignored, no error at all&lt;/td&gt;
&lt;td&gt;the workspace path traverses a symlink, on CLI builds before v0.138&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-agents-md-not-loading-symlinked-workspaces-2026/" rel="noopener noreferrer"&gt;AGENTS.md not loading in symlinked workspaces&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The sandbox one has a trap worth knowing: Codex prints a bubblewrap warning whose match string does not exist on every distribution, so a broken sandbox can fail silently on some Linux installs. The fix page has the five-distribution test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why will your model or provider not appear?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error message&lt;/th&gt;
&lt;th&gt;What is actually wrong&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;custom models missing from the Codex Desktop picker&lt;/td&gt;
&lt;td&gt;the &lt;code&gt;model_catalog_json&lt;/code&gt; bug; the picker has nothing to describe when the model is set inline&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/codex-desktop-not-showing-custom-models-2026/" rel="noopener noreferrer"&gt;Codex Desktop not showing custom models&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;an unknown model silently caps at 258K context&lt;/td&gt;
&lt;td&gt;Codex falls back to a default context size for models not in its catalog&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ofox.ai/blog/qwen-3-8-max-codex-cli-config-cost-2026/" rel="noopener noreferrer"&gt;Qwen 3.8 Max in Codex CLI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pointing Codex at a provider other than OpenAI is a supported path, not a hack, but there are three places to do it and they behave differently. &lt;a href="https://ofox.ai/blog/codex-cli-config-toml-deep-dive/" rel="noopener noreferrer"&gt;The &lt;code&gt;config.toml&lt;/code&gt; reference&lt;/a&gt; is the full surface. &lt;a href="https://ofox.ai/blog/codex-cli-custom-model-providers-byo-setup/" rel="noopener noreferrer"&gt;The &lt;code&gt;[model_providers]&lt;/code&gt; block&lt;/a&gt; is how you keep several providers side by side. &lt;a href="https://ofox.ai/blog/codex-cli-api-configuration-guide-2026/" rel="noopener noreferrer"&gt;The custom endpoint guide&lt;/a&gt; is the two-variable version if you only want one. One constraint that catches people: Codex only accepts &lt;code&gt;wire_api = "responses"&lt;/code&gt; for custom providers, so a chat-completions-only gateway will not work no matter how the rest is configured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which changes need evidence first?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Changing API keys.&lt;/strong&gt; For a rejected key, verify the selected provider, credential and account. For a missing-header error, inspect whether the client actually sends authentication. A 429 needs rate-limit or quota checks, not automatic key rotation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reinstalling.&lt;/strong&gt; For a command-not-found error, inspect PATH and the installed binary before reinstalling. Installation damage and path configuration are different causes; use the logs to distinguish them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An open GitHub issue.&lt;/strong&gt; An issue still marked open does not mean the feature is missing. Codex issue #22638 asks for Chromium browser support and is still open, while the docs list five supported browsers and the feature shipped. Check the product, then the tracker.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you set Codex up from scratch?
&lt;/h2&gt;

&lt;p&gt;If nothing is broken yet and you are here to configure rather than repair:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://ofox.ai/blog/codex-official-installation-complete/" rel="noopener noreferrer"&gt;Install it&lt;/a&gt;, on any of npm, Homebrew, the standalone installer, or a raw binary.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://ofox.ai/blog/codex-cli-config-toml-deep-dive/" rel="noopener noreferrer"&gt;Write a &lt;code&gt;config.toml&lt;/code&gt;&lt;/a&gt; and understand the three approval modes and three sandbox levels before you loosen either.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://ofox.ai/blog/codex-cli-custom-model-providers-byo-setup/" rel="noopener noreferrer"&gt;Point it at the model you actually want&lt;/a&gt;, whether that is an OpenAI model or something else through an OpenAI-compatible gateway.&lt;/li&gt;
&lt;li&gt; &lt;a href="https://ofox.ai/blog/codex-cli-real-world-coding-workflow/" rel="noopener noreferrer"&gt;Learn the loop&lt;/a&gt;: AGENTS.md, plan mode, worktrees, and the seven mistakes that waste the first week.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Coming from somewhere else, &lt;a href="https://ofox.ai/blog/migrate-claude-code-to-codex-2026/" rel="noopener noreferrer"&gt;the Claude Code migration&lt;/a&gt; maps all 12 config surfaces and names the one dead end. Choosing rather than migrating, &lt;a href="https://ofox.ai/blog/claude-code-vs-codex-cli-vs-cursor-vs-deepseek-tui-2026/" rel="noopener noreferrer"&gt;Claude Code vs Codex vs Cursor vs DeepSeek TUI&lt;/a&gt; and &lt;a href="https://ofox.ai/blog/opencode-vs-codex-cli-terminal-coding-agent-2026/" rel="noopener noreferrer"&gt;OpenCode vs Codex CLI&lt;/a&gt; are the head-to-heads.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the browser, mobile and desktop surfaces?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ofox.ai/blog/codex-chrome-extension-codex-app-2026/" rel="noopener noreferrer"&gt;The Chrome extension&lt;/a&gt; now covers Chrome, Edge, Brave, Opera and Vivaldi and installs from the ChatGPT desktop app. &lt;a href="https://ofox.ai/blog/codex-mobile-app-iphone-android-2026/" rel="noopener noreferrer"&gt;Codex on iPhone and Android&lt;/a&gt; is a remote session, so nothing about PATH or sandboxes applies there. &lt;a href="https://ofox.ai/blog/codex-goal-mode-remote-computer-use-2026/" rel="noopener noreferrer"&gt;Goal Mode and remote computer use&lt;/a&gt; is the long-running agentic mode and its own safety model.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/config-file/config-basic" rel="noopener noreferrer"&gt;Codex configuration reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openai/codex/releases" rel="noopener noreferrer"&gt;openai/codex releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;openai/codex on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/error-codes" rel="noopener noreferrer"&gt;OpenAI API error codes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why does Codex fail with a different error on Windows than on macOS?
&lt;/h3&gt;

&lt;p&gt;Operating systems and installation methods use different paths, permissions and process launchers. On Windows, os error 3 points to a path lookup failure; inspect the actual executable path and application logs. Do not assume every Windows failure has the same cause.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I check before working through any Codex fix?
&lt;/h3&gt;

&lt;p&gt;Your version. Run &lt;code&gt;codex --version&lt;/code&gt; for the CLI and check the extension version in your editor. Several of the most-reported 2026 errors are regressions with a known fixed build: the 'couldn't load its resources' family was introduced in 26.803.41515 and fixed in 26.810.41047, and AGENTS.md in symlinked workspaces was fixed in CLI v0.138. Upgrading is the whole fix in those cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is a Codex 401 always an authentication problem?
&lt;/h3&gt;

&lt;p&gt;No. Nine distinct failures return something that looks like a 401, and they split into three groups that need different fixes: no key was sent at all ('Missing bearer or basic authentication in header'), a key was sent and rejected ('Incorrect API key provided'), and a key that is correct but carries a trailing newline from a shell export. The status code is the same; the message body is what tells them apart.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does hitting the Codex weekly limit mean I have to wait a fixed number of days?
&lt;/h3&gt;

&lt;p&gt;No. The reset is a server-side &lt;code&gt;resetsAt&lt;/code&gt; timestamp attached to your account, not a clock rule you can compute, and there are only two windows (primary and secondary). You can read the actual timestamp rather than guessing, and an earned reset credit can be redeemed early.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which Codex surface am I actually using?
&lt;/h3&gt;

&lt;p&gt;There are five and they fail differently: the CLI (&lt;code&gt;@openai/codex&lt;/code&gt; on npm, currently 0.151.0), the editor extension, the Chrome extension driven by the ChatGPT desktop app, Codex inside the ChatGPT mobile app, and the desktop app itself. An error about resources or a native host is an extension problem; an error about &lt;code&gt;config.toml&lt;/code&gt; or a sandbox is a CLI problem.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/codex-errors-fixes-index-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codex</category>
      <category>troubleshooting</category>
      <category>openai</category>
    </item>
    <item>
      <title>Connect Codex CLI and Claude Code to Ofox with CC Switch</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sat, 12 Sep 2026 01:22:26 +0000</pubDate>
      <link>https://dev.to/owen_fox/connect-codex-cli-and-claude-code-to-ofox-with-cc-switch-47ik</link>
      <guid>https://dev.to/owen_fox/connect-codex-cli-and-claude-code-to-ofox-with-cc-switch-47ik</guid>
      <description>&lt;p&gt;CC Switch sets up Codex CLI and Claude Code against Ofox from one place. The two need different base URLs and API formats — mixing them up is the usual failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two clients, two protocols
&lt;/h2&gt;

&lt;p&gt;Codex CLI and Claude Code speak &lt;strong&gt;different protocols&lt;/strong&gt;. CC Switch keeps both entries side by side, which is the main reason to use it — pasting the Claude Code base URL into the Codex tab, or the reverse, is an easy mistake to make by hand.&lt;/p&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;Codex CLI&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;OpenAI-compatible&lt;/td&gt;
&lt;td&gt;Anthropic native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ofox base URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API format in CC Switch&lt;/td&gt;
&lt;td&gt;OpenAI Compatible&lt;/td&gt;
&lt;td&gt;Anthropic Messages (Native)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth field&lt;/td&gt;
&lt;td&gt;not applicable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ANTHROPIC_AUTH_TOKEN (Default)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CC Switch tab&lt;/td&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;(provider management page)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither URL takes a trailing slash, and one Ofox key authenticates both. Note that this table describes the &lt;strong&gt;client&lt;/strong&gt;, not the model — every Claude model in the Ofox catalog, Fable 5.1 included, accepts either protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing CC Switch
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS&lt;/span&gt;
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; cc-switch

&lt;span class="c"&gt;# Debian / Ubuntu — download the .deb from Releases first&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;downloaded-file&amp;gt;.deb

&lt;span class="c"&gt;# Fedora / RHEL&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;rpm &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;downloaded-file&amp;gt;.rpm

&lt;span class="c"&gt;# AppImage&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x &amp;lt;downloaded-file&amp;gt;.AppImage &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./&amp;lt;downloaded-file&amp;gt;.AppImage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows ships an &lt;code&gt;.msi&lt;/code&gt; installer, and macOS has a &lt;code&gt;.dmg&lt;/code&gt; on the releases page if you would rather not use Homebrew. For the full install walkthrough, see &lt;a href="https://ofox.ai/blog/cc-switch-install-multi-cli-setup-2026/" rel="noopener noreferrer"&gt;the CC Switch setup guide&lt;/a&gt;. Minimum supported versions are macOS 12, Windows 10, and Ubuntu 22.04 / Debian 11 / Fedora 34.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the Codex CLI provider
&lt;/h2&gt;

&lt;p&gt;Switch to the &lt;strong&gt;Codex&lt;/strong&gt; tab at the top, then use the &lt;code&gt;+&lt;/code&gt; button in the top-right corner.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Provider Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ofoxai-codex&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Website URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://ofox.ai&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Key&lt;/td&gt;
&lt;td&gt;your Ofox key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Format&lt;/td&gt;
&lt;td&gt;OpenAI Compatible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write to Global Config&lt;/td&gt;
&lt;td&gt;checked&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Leaving "Write to Global Config" checked applies the provider across all projects rather than just the current one. Add the provider, then activate it from the list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the Claude Code provider
&lt;/h2&gt;

&lt;p&gt;Same tool, different page and different values.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Provider Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ofoxai-claude&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Website URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://ofox.ai&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Key&lt;/td&gt;
&lt;td&gt;your Ofox key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Format / Auth Field&lt;/td&gt;
&lt;td&gt;Anthropic Messages (Native) / &lt;code&gt;ANTHROPIC_AUTH_TOKEN (Default)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model Configuration&lt;/td&gt;
&lt;td&gt;leave empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write to Global Config&lt;/td&gt;
&lt;td&gt;checked&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Leave Model Configuration empty.&lt;/strong&gt; It falls through to the default Claude model, which is what you want unless you are deliberately pinning one. CC Switch writes the result to &lt;code&gt;~/.claude/settings.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are two optional toggles on this page, "Hide AI Signature" and "Teammates Mode". Neither affects routing or billing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning on usage query
&lt;/h2&gt;

&lt;p&gt;CC Switch can poll Ofox for consumption figures and show them in its dashboard. Four things to set: toggle &lt;strong&gt;Enable Usage Query&lt;/strong&gt; on, paste the same Ofox API key, set the request endpoint to &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;, and pick the Universal Template (&lt;strong&gt;通用模板&lt;/strong&gt;) option, which the Ofox documentation recommends for best compatibility.&lt;/p&gt;

&lt;p&gt;Two things to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does &lt;strong&gt;not&lt;/strong&gt; consume API quota — it uses a dedicated statistics API rather than your call budget.&lt;/li&gt;
&lt;li&gt;Figures lag the calls that produced them by a few minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Turning it off later does not disturb normal API calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Fable 5.1 specifically
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fable 5.1 landed in the Ofox catalog on 3 September 2026&lt;/strong&gt;, as &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt;. Nothing above changes for it: same two base URLs, same two API formats, same key. The model string is the only difference.&lt;/p&gt;

&lt;p&gt;The setup is worth doing regardless of which model you land on: it gives you a working two-protocol path where switching models is a string change. Alongside Fable 5.1, the catalog has &lt;code&gt;anthropic/claude-fable-5&lt;/code&gt;, &lt;code&gt;anthropic/claude-opus-5&lt;/code&gt; and &lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt; at Anthropic list prices with no markup, and all four are reachable over either protocol on the same key.&lt;/p&gt;

&lt;p&gt;That matters for Fable 5.1 in particular, because its only price change is the cache read — $1 down to $0.25. Whether that is worth anything to you depends entirely on your cache-hit ratio, and the way to find out is to run your real workload through this setup and read the number off your own usage. The &lt;a href="https://ofox.ai/blog/claude-fable-5-1-api-guide-2026/" rel="noopener noreferrer"&gt;API reference&lt;/a&gt; has the rate table and the TTL arithmetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  When something does not connect
&lt;/h2&gt;

&lt;p&gt;Three common failure modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A trailing slash on the request URL.&lt;/strong&gt; The Ofox documentation calls this out for both providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The wrong API format for the tab.&lt;/strong&gt; Codex CLI with "Anthropic Messages (Native)" selected will not work, and neither will the reverse. Check the format field before the key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A model string the catalog does not have.&lt;/strong&gt; Note that the Ofox ID for Fable 5.1 is &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt; with a dot, not a hyphen — though the alias &lt;code&gt;anthropic/claude-fable-5-1&lt;/code&gt; also resolves. The live catalog is the authority: &lt;code&gt;GET /v1/models&lt;/code&gt; returns exactly what you can call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;CC Switch installation targets, provider field values, base URLs and usage-query behaviour verified against the Ofox integration documentation on 3 September 2026. Catalog contents checked against the live &lt;code&gt;/v1/models&lt;/code&gt; endpoint the same day.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is CC Switch?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An open-source provider manager with a visual interface. It writes the config files for Claude Code and Codex CLI, so you do not have to edit JSON or environment variables by hand. For Claude Code it writes &lt;code&gt;~/.claude/settings.json&lt;/code&gt;. It runs on macOS 12+, Windows 10+, and Ubuntu 22.04+ / Debian 11+ / Fedora 34+.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do Codex CLI and Claude Code use the same Ofox base URL?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No — and this is where setups usually go wrong. Codex CLI is an OpenAI-protocol client and takes &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt; with the API format set to OpenAI Compatible. Claude Code is an Anthropic-protocol client and takes &lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt; with the format set to Anthropic Messages (Native). Neither URL takes a trailing slash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run Claude Fable 5.1 through this setup?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, as of 3 September 2026. Fable 5.1 is in the Ofox catalog as &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt;. Nothing in the setup changes for it — same base URLs, same API formats, same key. Only the model string differs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does CC Switch's usage query burn API quota?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Per the Ofox integration documentation it uses a dedicated statistics API and does not count against your API call limits. Usage figures typically appear within a few minutes of the calls that produced them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I keep more than one Ofox account in CC Switch?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. You can add multiple Ofox provider entries with different API keys and switch between them from the list.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/codex-cli-cc-switch-fable-5-1-setup-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codex</category>
      <category>claudecode</category>
      <category>ccswitch</category>
    </item>
    <item>
      <title>ChatGPT DeviceCheck Registration Failed (403, 500, 503): Real Fixes</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Mon, 07 Sep 2026 04:34:54 +0000</pubDate>
      <link>https://dev.to/owen_fox/chatgpt-devicecheck-registration-failed-403-500-503-real-fixes-3cn</link>
      <guid>https://dev.to/owen_fox/chatgpt-devicecheck-registration-failed-403-500-503-real-fixes-3cn</guid>
      <description>&lt;h1&gt;
  
  
  ChatGPT DeviceCheck Registration Failed (403, 500, 503): Real Fixes
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;DeviceCheck errors block ChatGPT login before your password is ever checked, and the official advice about date and time fixes almost none of them.&lt;/strong&gt; The error means your device could not produce an attestation token proving it is genuine hardware. That is a conversation between your device and Apple or Google — OpenAI is only the party that gets told "no".&lt;/p&gt;

&lt;p&gt;Which is why the same account signs in fine on the website. This page covers what each variant means and the fixes that actually resolve reports, ordered by how often they work.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error family:   DeviceCheckError / "DeviceCheck registration failed"
Also seen as:   Token generation failed · Preauth PlayIntegrity verification failed
                DeviceCheck token generation is unavailable (macOS)
Codes attached: 403, 500, 503 — these are transport codes, not distinct root causes
Blocks:         native app login only. Browser login is unaffected.
Root cause:     device attestation, not your OpenAI account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Sources are OpenAI's own help article, OpenAI Developer Community threads, and openai/codex issue #33463. Read 6 September 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What DeviceCheck Actually Is
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Apple's DeviceCheck and Google's Play Integrity let an app ask the OS vendor "is this a real, unmodified device?"&lt;/strong&gt; OpenAI uses that to stop bulk account creation on emulators and modified phones.&lt;/p&gt;

&lt;p&gt;The sequence when it fails:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You tap Log in. The app asks the OS for an attestation token.&lt;/li&gt;
&lt;li&gt;The OS tries to produce one, talking to Apple or Google in the process.&lt;/li&gt;
&lt;li&gt;Something in that chain fails.&lt;/li&gt;
&lt;li&gt;The app never gets a token, so it never sends your credentials, and you see a DeviceCheck error.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Your account is never involved.&lt;/strong&gt; That is the single most useful thing to understand here, because it rules out password resets, account recovery and support tickets about billing — none of which touch this.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 403, 500 and 503 in the search results
&lt;/h3&gt;

&lt;p&gt;People search for &lt;code&gt;devicecheck registration failed (403)&lt;/code&gt;, &lt;code&gt;(500)&lt;/code&gt; and &lt;code&gt;(503)&lt;/code&gt; because those numbers appear in the error text. They are HTTP statuses from the attestation call, not separate bugs with separate fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;403&lt;/strong&gt; — the request was rejected. Usually integrity: a modified device, or an edge/WAF layer refusing the client. Several iPhone reports trace 403 to a Cloudflare challenge during login.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;500 / 503&lt;/strong&gt; — the attestation service failed or was unavailable. Often transient on the provider side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you see 503, wait and retry before changing anything. If you see 403 repeatedly, it is more likely one of the device-side causes below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: Clear Your Browser Cache (Most Reported Success)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The ChatGPT app hands login to your system browser, so a poisoned browser cache breaks the app while the website still works.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is counterintuitive enough that people skip it, and it is the fix that resolves the most reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iPhone:&lt;/strong&gt; clear the cache in &lt;em&gt;both&lt;/em&gt; Safari and Chrome, not just your default.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Settings → Safari → Clear History and Website Data&lt;/li&gt;
&lt;li&gt;Chrome → ⋯ → Delete Browsing Data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Android:&lt;/strong&gt; switch your default browser to Chrome and retry. Multiple reports resolve immediately on moving off Brave or a custom browser.&lt;/p&gt;

&lt;p&gt;One community report after months of failed attempts: after clearing both Safari and Chrome caches, "it magically started working perfectly." The mechanism is that login runs through the system browser in the background, so the browser's state is the app's state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 2: Install Pending OS Updates, Then Restart
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A pending security update that could not install is a documented cause.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One iPhone report worked through switching Wi-Fi, hotspot, reinstalling, private mode, and logging out and in — none of it helped. The actual cause was an iOS update blocked by low storage. After freeing space, installing, and letting the phone reboot, login worked immediately.&lt;/p&gt;

&lt;p&gt;Check Settings → General → Software Update, install anything pending including security responses, and restart before trying again. Outdated security components can cause the edge layer to reject the device during login.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: Device Integrity (And Why Retrying Does Not Help)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If your device is rooted or jailbroken, DeviceCheck failing is the system working as designed.&lt;/strong&gt; OpenAI's help article names this directly: "Modifications like rooting or jailbreaking may cause this error."&lt;/p&gt;

&lt;p&gt;The detail that wastes people's time is in the same article: &lt;strong&gt;integrity check results can be cached for up to 24 hours.&lt;/strong&gt; So if you fix the underlying problem and retry immediately, you are testing against a cached failure. Clear the app data before retrying.&lt;/p&gt;

&lt;p&gt;On rooted Android with Magisk, the community fix is the Play Integrity Fix module, then reboot. That is a workaround for a check that is deliberately failing, so treat it accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 4: Clear App and Play Services Data (Android)
&lt;/h2&gt;

&lt;p&gt;Ordered from least to most disruptive:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Settings → Apps → ChatGPT → Storage → &lt;strong&gt;Clear cache&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Same screen → &lt;strong&gt;Clear data&lt;/strong&gt; (this signs you out)&lt;/li&gt;
&lt;li&gt;Settings → Apps → &lt;strong&gt;Play Store&lt;/strong&gt; → Clear data&lt;/li&gt;
&lt;li&gt;Settings → Apps → &lt;strong&gt;Google Play Services&lt;/strong&gt; → Clear cache&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then reboot and retry. Doing all four at once works but tells you nothing about the cause; going in order costs a few minutes and identifies it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 5: macOS "DeviceCheck Token Generation Is Unavailable"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This variant has a different root cause from every fix above, and none of them will resolve it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The macOS symptom is distinct: authentication succeeds, the app launches and restores your session, and then Chat fails. From the diagnostics in &lt;a href="https://github.com/openai/codex/issues/33463" rel="noopener noreferrer"&gt;openai/codex issue #33463&lt;/a&gt;, the system logs show:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;failed to do a bootstrap look-up: xpc_error=[3: No such process]
Could not find service "com.apple.devicecheckd" in domain for system

preauth_cookie_failed=APIClient.DeviceCheckError: Token generation failed
MobileActivation.ErrorDomain Code=-4 "UCRT is unavailable."
devicecheckd: Failed to fetch client certificate.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;One reporter confirmed no HTTP 401, no 403 and no TLS failures — the failure is after authentication, during initialisation. The Secure Enclave key generation and attestation steps succeed; what fails is MobileActivation supplying the client certificate DeviceCheck needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What resolved it in that thread:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A plain reboot&lt;/strong&gt;, for two reporters on an older app version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updating macOS and restarting.&lt;/strong&gt; One persistent case survived 26.5 → 26.6 and multiple app updates, then recovered on 26.6.1 with a restart. The logs flipped to &lt;code&gt;Performing UCRT OOB. Successfully performed UCRT OOB.&lt;/code&gt; and &lt;code&gt;devicecheckd&lt;/code&gt; immediately obtained new attestation certificates.&lt;/li&gt;
&lt;li&gt;That same reporter had also &lt;strong&gt;changed their Apple Account password&lt;/strong&gt; and could not tell which action fixed it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What did not help:&lt;/strong&gt; creating a new macOS user account (the failure followed), and toggling Find My.&lt;/p&gt;

&lt;p&gt;If you are hitting this, update macOS and restart first. It is an Apple-side certificate problem, so reinstalling ChatGPT is not the lever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do While It Is Broken
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Log in through a browser.&lt;/strong&gt; The web app does not require device attestation, which is exactly why it keeps working when the native app does not. Every community thread on this confirms the website is unaffected.&lt;/p&gt;

&lt;p&gt;If you signed up with email and password, do not try Google, Microsoft or Apple sign-in on the app — mixing methods causes its own separate failure. Use the same method you registered with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you need API access rather than the consumer app&lt;/strong&gt;, DeviceCheck is not in the path at all. API keys authenticate with a bearer token and never touch device attestation, so this class of error cannot occur:&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;-X&lt;/span&gt; POST https://api.ofox.ai/v1/chat/completions &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.6-sol",
    "messages": [{"role": "user", "content": "..."}]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a different product from the ChatGPT app, not a workaround for it — worth knowing only if what you actually needed was programmatic access.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does Not Fix It
&lt;/h2&gt;

&lt;p&gt;Collected from threads where people tried these repeatedly without success, so you can skip them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reinstalling the app.&lt;/strong&gt; Frequently tried, rarely the fix, and on macOS it cannot be the fix because the problem is in Apple's certificate chain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password resets and account recovery.&lt;/strong&gt; Your credentials are never sent. The failure is upstream of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switching Wi-Fi to cellular.&lt;/strong&gt; Occasionally helps if a network is genuinely blocking the attestation endpoint, but it is far down the list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrying immediately after a change.&lt;/strong&gt; Integrity verdicts cache for up to 24 hours. Clear app data or you are re-reading a stale result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more, for completeness: a firewall can cause this. One macOS user resolved it by allowing ChatGPT four specific connections in Little Snitch. If you run a per-app firewall, check it before anything else on this page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Errors
&lt;/h2&gt;

&lt;p&gt;If your problem is authentication rather than attestation, these are different failures with different fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ofox.ai/blog/codex-cli-401-unauthorized-fix-2026/" rel="noopener noreferrer"&gt;Codex CLI 401 Unauthorized&lt;/a&gt; — a real credential rejection, unlike DeviceCheck.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ofox.ai/blog/codex-command-not-found-fix-npm-install-2026/" rel="noopener noreferrer"&gt;&lt;code&gt;codex: command not found&lt;/code&gt; and EACCES&lt;/a&gt; — install-path problems, not login.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ofox.ai/blog/codex-failed-to-start-app-server-windows-2026/" rel="noopener noreferrer"&gt;Codex "failed to start app-server" on Windows&lt;/a&gt; — the Windows desktop equivalent of "the app will not start", with a completely separate cause list.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.openai.com/en/articles/9945489-something-went-wrong-please-make-sure-your-device-s-date-and-time-are-set-properly-check-that-your-internet-connection-is-stable-then-restart-the-app-and-try-again-devicecheckerror" rel="noopener noreferrer"&gt;OpenAI help article: DeviceCheckError&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openai/codex/issues/33463" rel="noopener noreferrer"&gt;openai/codex issue #33463&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.openai.com/t/when-i-log-in-to-chatgpt-i-am-prompted-for-a-login-failure-and-a-message-something-went-wrong-please-make-sure-your-devices-date-and-time-are-set-properly/508758" rel="noopener noreferrer"&gt;OpenAI Developer Community: login failure thread&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.openai.com/t/fix-for-network-error-cloudflare-403-504-on-iphone-worked-for-me/1379385" rel="noopener noreferrer"&gt;OpenAI Developer Community: Cloudflare 403/504 on iPhone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.openai.com/t/unable-to-log-into-chatgpt-mac-app/780030" rel="noopener noreferrer"&gt;OpenAI Developer Community: unable to log into ChatGPT Mac app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Official causes and the 24-hour integrity cache note are from OpenAI's help article. The macOS &lt;code&gt;devicecheckd&lt;/code&gt; / UCRT diagnostics and the recovery accounts are quoted from openai/codex issue #33463. Remaining fixes are drawn from OpenAI Developer Community threads where a reporter confirmed the fix worked; they are community reports rather than vendor-documented solutions, and none of this is our own reproduction — DeviceCheck failures depend on individual device state and cannot be reliably reproduced on demand.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What does DeviceCheck registration failed mean in ChatGPT?
&lt;/h3&gt;

&lt;p&gt;It means the app could not generate a device attestation token, so OpenAI cannot verify the device is genuine and blocks the login before your credentials are ever checked. DeviceCheck is Apple's device-integrity API and Play Integrity is the Android equivalent. The failure is about your device's relationship with Apple or Google, not about your OpenAI account, which is why the same account signs in fine in a browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does OpenAI tell me to check my date and time?
&lt;/h3&gt;

&lt;p&gt;Because attestation tokens are time-sensitive and a badly skewed clock will break them. That is a real cause but a rare one. In practice most reports come from a stale browser cache, a pending OS update, a modified device that fails integrity checks, or on macOS a broken devicecheckd certificate. Set the clock to automatic, then move on to the causes below rather than retrying.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I fix DeviceCheck error on iPhone?
&lt;/h3&gt;

&lt;p&gt;Clear the Safari and Chrome caches first. The ChatGPT app hands login to the system browser, so a poisoned browser cache breaks the app while the website still works. Then install any pending iOS update and restart; several reports trace the failure to a security update that could not install for lack of storage. If it persists, sign in through the browser and use a different sign-in method than the one that is failing.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I fix DeviceCheck error on Android?
&lt;/h3&gt;

&lt;p&gt;Switch your default browser and retry — reports resolve on Android by moving from Brave or a custom browser to Chrome, because login is handed to the default browser. Then clear the ChatGPT app cache and data, and clear Play Store and Play Services data. If the device is rooted, Play Integrity will fail by design; that is the cause, not a bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  What causes DeviceCheck token generation is unavailable on macOS?
&lt;/h3&gt;

&lt;p&gt;A broken Apple attestation chain rather than anything in ChatGPT. In openai/codex issue #33463 the logs show devicecheckd failing to reach com.apple.devicecheckd, then MobileActivation error code -4, UCRT is unavailable, and Failed to fetch client certificate. Authentication itself succeeds with no 401 or 403; the failure happens after login during initialisation. Reporters recovered by updating macOS and restarting, one after refreshing the Apple Account password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a jailbroken or rooted device cause DeviceCheck errors?
&lt;/h3&gt;

&lt;p&gt;Yes, and OpenAI says so directly. Its help article lists device integrity as a cause and notes that rooting or jailbreaking may trigger the error. It also warns that integrity check results can be cached for up to 24 hours, so clear the app data before retrying or you will be testing against a stale verdict.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use ChatGPT while DeviceCheck is broken?
&lt;/h3&gt;

&lt;p&gt;Yes. Log in through a browser — the web app does not require device attestation, which is why it keeps working when the native app does not. If you need API access rather than the consumer app, an OpenAI-compatible gateway such as api.ofox.ai is unaffected because API keys do not go through DeviceCheck at all.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/chatgpt-devicecheck-registration-failed-fix-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>chatgpt</category>
      <category>openai</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>Fable 5.1 vs Fable 5 vs Opus 5: It's All in the Cache</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 06 Sep 2026 11:33:11 +0000</pubDate>
      <link>https://dev.to/owen_fox/fable-51-vs-fable-5-vs-opus-5-its-all-in-the-cache-3ja5</link>
      <guid>https://dev.to/owen_fox/fable-51-vs-fable-5-vs-opus-5-its-all-in-the-cache-3ja5</guid>
      <description>&lt;h1&gt;
  
  
  Fable 5.1 vs Fable 5 vs Opus 5: It's All in the Cache
&lt;/h1&gt;

&lt;p&gt;Claude Fable 5.1 shipped on 1 September 2026 as the cheaper Fable. &lt;strong&gt;Base rates did not move: input is still $10 per million tokens and output $50, the same as Fable 5. The entire cut is one line, cache reads, $1 to $0.25.&lt;/strong&gt; That 75% cut is what Anthropic's estimates of 25% for typical workloads and up to 45% for agentic ones rest on.&lt;/p&gt;

&lt;p&gt;It reaches your invoice only in proportion to how much of your input is actually served from cache. Read the price table before acting on the headline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The table everyone is skipping
&lt;/h2&gt;

&lt;p&gt;Anthropic publishes five rates per model, and most summaries quote one. Here is the whole thing, in dollars 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;Base input&lt;/th&gt;
&lt;th&gt;5m cache write&lt;/th&gt;
&lt;th&gt;1h cache write&lt;/th&gt;
&lt;th&gt;Cache read&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;Fable 5.1&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;0.25&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fable 5&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opus 5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6.25&lt;/td&gt;
&lt;td&gt;10&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;Sonnet 5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2.50&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0.20&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the two Fable rows side by side. Four of the five numbers are identical. Fable 5.1 is not a cheaper model — it is the same model at the same price, with a cheaper cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that means for your bill
&lt;/h2&gt;

&lt;p&gt;Cache savings compound with reuse, which is why one rate change lands so differently across workloads. Take one 1M-token prefix — a codebase, a document set, a long system prompt — write it to cache once, then read it back N times. The no-caching column is what the same N+1 full passes cost at $10 per million:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reads&lt;/th&gt;
&lt;th&gt;Fable 5&lt;/th&gt;
&lt;th&gt;Fable 5.1&lt;/th&gt;
&lt;th&gt;No caching&lt;/th&gt;
&lt;th&gt;5.1 advantage&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;$13.50&lt;/td&gt;
&lt;td&gt;$12.75&lt;/td&gt;
&lt;td&gt;$20.00&lt;/td&gt;
&lt;td&gt;1.06x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$22.50&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;td&gt;$110.00&lt;/td&gt;
&lt;td&gt;1.50x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;$112.50&lt;/td&gt;
&lt;td&gt;$37.50&lt;/td&gt;
&lt;td&gt;$1,010.00&lt;/td&gt;
&lt;td&gt;3.00x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;$512.50&lt;/td&gt;
&lt;td&gt;$137.50&lt;/td&gt;
&lt;td&gt;$5,010.00&lt;/td&gt;
&lt;td&gt;3.73x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Assumes a single 5-minute cache write with no expiry between reads — reads refresh the entry for free, so this holds for a continuously active agent. If the prefix goes cold and has to be rewritten, add $12.50 per rewrite to both Fable columns; see the TTL section below.&lt;/p&gt;

&lt;p&gt;At one read the two versions are within 6% of each other. At a hundred reads Fable 5.1 costs a third of what Fable 5 costs. Nothing about the model changed between those rows — only how many times you came back to the same cached context.&lt;/p&gt;

&lt;p&gt;This is why Anthropic's two figures sit so far apart. A workload that touches cached context a handful of times per session lands near 25%. A long-running agent that re-reads the same repository hundreds of times over an afternoon is what the "up to approximately 45%" end of that range describes. To know which applies to you, count cache hits, not requests.&lt;/p&gt;

&lt;p&gt;Take a concrete case: 1M input tokens of which 90% are cache reads, plus 20K output.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Fable 5 — $0.90 cache + $1.00 fresh input + $1.00 output = &lt;strong&gt;$2.90&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Fable 5.1 — $0.225 cache + $1.00 fresh input + $1.00 output = &lt;strong&gt;$2.225&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 23% saving, lining up with Anthropic's estimated 25% for typical usage. Note where it comes from: the cache line fell by three quarters, but it was only about 31% of the bill to begin with.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TTL choice costs more than the price cut
&lt;/h2&gt;

&lt;p&gt;Anthropic sells two cache-write durations, and this is the part most cost models leave out. A 5-minute cache write is $12.50 per million tokens; a 1-hour write is $20.&lt;/p&gt;

&lt;p&gt;The 5-minute clock is looser than it sounds. Anthropic's prompt-caching documentation is explicit: "The cache is refreshed for no additional cost each time the cached content is used." The lifetime is measured from the start of each request that writes &lt;em&gt;or reads&lt;/em&gt; the entry. An agent hammering the same prefix continuously keeps a 5-minute entry alive on reads alone and pays for exactly one write.&lt;/p&gt;

&lt;p&gt;The money leaks in the gaps. A planning turn, slow tool calls, a human reviewing a diff — any quiet stretch longer than five minutes lets the entry expire, and the next call pays the write again. An hour of that pattern costs at worst 12 × $12.50 = &lt;strong&gt;$150&lt;/strong&gt;, against &lt;strong&gt;$20&lt;/strong&gt; for a single 1-hour write.&lt;/p&gt;

&lt;p&gt;That worst case is a $130 gap per prefix per hour, larger than the entire cache-read reduction Fable 5.1 shipped — and it is decided by the shape of your traffic, not by which model you picked. A continuously busy agent may never reach it; one that idles between turns will. Work out which you are running before you bank the new pricing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fable 5.1 versus Opus 5: the trap in the numbers
&lt;/h2&gt;

&lt;p&gt;One line does invert: &lt;strong&gt;Fable 5.1 reads cached tokens at $0.25, half of Opus 5's $0.50&lt;/strong&gt; — even though Fable's base input is twice Opus 5's and its output is twice as expensive too.&lt;/p&gt;

&lt;p&gt;It is tempting to conclude that cache-heavy agents should now move up to Fable. The algebra says otherwise. With input I, cache-read fraction f, and output O, Fable 5.1 is cheaper only when:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10(1−f)·I + 0.25f·I + 50·O  &amp;lt;  5(1−f)·I + 0.50f·I + 25·O
→  5I − 5.25f·I + 25O &amp;lt; 0
→  f &amp;gt; (5 + 25·(O/I)) / 5.25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set output to zero — a workload producing nothing at all — and you still need &lt;strong&gt;f &amp;gt; 95.2%&lt;/strong&gt;. Every token you actually generate pushes the threshold higher. There is no realistic mix in which Fable 5.1 undercuts Opus 5 on total cost.&lt;/p&gt;

&lt;p&gt;The worked example above shows it plainly: Fable 5.1 costs $2.225 and Opus 5 costs $1.45 for identical traffic. One cheaper line does not carry a model that is 2x on everything else.&lt;/p&gt;

&lt;p&gt;So the decision does not change, it just costs less on one axis: &lt;strong&gt;choose Fable 5.1 when you need its capability, not to undercut Opus 5 on cost.&lt;/strong&gt; What the new cache pricing buys is that the premium for staying on a Mythos-level model through a long agentic run is smaller than it was on Fable 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  An independent measurement points the same way
&lt;/h2&gt;

&lt;p&gt;Artificial Analysis, which supported Anthropic with pre-release evaluation of the model, published cost-per-task figures on 1 September that land on exactly this point. Their headline: Fable 5.1 "tops the Artificial Analysis Intelligence Index but costs 20% more per task than Fable 5 despite a 75% cache read price cut".&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model (max effort)&lt;/th&gt;
&lt;th&gt;Intelligence Index&lt;/th&gt;
&lt;th&gt;Cost per task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fable 5.1&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;td&gt;$3.76&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opus 5&lt;/td&gt;
&lt;td&gt;63&lt;/td&gt;
&lt;td&gt;$2.34&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fable 5&lt;/td&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;td&gt;$3.14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The reason is the half of the equation this article has been circling: Fable 5.1 uses roughly &lt;strong&gt;1.7x the output tokens&lt;/strong&gt; of Fable 5 at max effort. Output is the $50 line, and no discount on the $0.25 line reaches it. A cheaper cache did not make it a cheaper model — measured end to end on the same task set, it got 20% more expensive than its own predecessor and 1.6x Opus 5.&lt;/p&gt;

&lt;p&gt;It also scored highest of anything they have measured. That is the actual trade: you are buying the top of the index and paying more per task than before, not less.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Anthropic says changed besides price
&lt;/h2&gt;

&lt;p&gt;The Claude Fable product page is specific about behavior rather than benchmarks. It says Fable 5.1 "avoids easy-seeming shortcuts, fixes the root causes of problems rather than the symptoms, and keeps you updated as it works". (The separate launch announcement words this differently, so it is worth naming which page a quote comes from.) The strongest concrete claim is not Anthropic's own. Josh Boyer, Distinguished Engineer at Red Hat, is quoted on the same page: "Using Claude Code, it correctly identified the root cause of every broken build we tested, across all the effort levels."&lt;/p&gt;

&lt;p&gt;The first is the vendor describing its own model; the second is a customer describing its own tests. Neither is a benchmark, and both are worth reproducing on your own broken builds before you rewrite a routing policy around them. Anthropic's announcement page does carry a full benchmark table — Terminal-Bench-Science, Terminal-Bench, OSWorld, HLE and more. This piece deliberately leaves those alone and sticks to the money, because the cost story is the one the launch coverage got wrong.&lt;/p&gt;

&lt;p&gt;Two safeguard changes are easy to conflate, and several write-ups have. On 7 August 2026 Anthropic retuned &lt;strong&gt;Claude Fable 5's&lt;/strong&gt; biology safeguards and reported that the update "reduced biology-related fallbacks by about 85% across our product surfaces". Separately, the 1 September launch announcement says that in cybersecurity Fable 5.1's "newest safeguards block 60% fewer false positives than before". So "fewer false positives" is a genuine 5.1 launch claim — on the cyber side. It is not the August biology change, and the two numbers should not be added together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specs, and a detail that gets overlooked
&lt;/h2&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;Fable 5.1&lt;/th&gt;
&lt;th&gt;Opus 5&lt;/th&gt;
&lt;th&gt;Sonnet 5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Thinking&lt;/td&gt;
&lt;td&gt;Adaptive (always on)&lt;/td&gt;
&lt;td&gt;Adaptive&lt;/td&gt;
&lt;td&gt;Adaptive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default effort&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;high&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&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;128K&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliable knowledge cutoff&lt;/td&gt;
&lt;td&gt;Jun 2026&lt;/td&gt;
&lt;td&gt;May 2026&lt;/td&gt;
&lt;td&gt;Jan 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The model ID is &lt;code&gt;claude-fable-5-1&lt;/code&gt;. Context and output limits are identical across all three, so the differentiators are price, behavior, and that last row — &lt;strong&gt;Fable 5.1 has the most recent reliable knowledge cutoff of the three models here&lt;/strong&gt;, a month ahead of Opus 5 and five months ahead of Sonnet 5. For anything touching recent library versions or APIs, that gap does real work.&lt;/p&gt;

&lt;p&gt;Mythos 5.1 appears in the same pricing table at identical rates. Anthropic's announcement states the two "are the same underlying model" and that the gap between them "reflects the tasks on which our earlier, less precise cyber safeguards intervened". Access runs through trusted-access programs, and the two are not at the same stage: the Life Sciences Verification Program is an invite-only beta that grants access now, while the Cyber Verification Program currently covers Opus- and Sonnet-class models with reduced cyber safeguards. Of Mythos, Anthropic writes: "In the near future, this program will also include access to Claude Mythos-class models." Availability is currently limited to a set of US organizations. Not a drop-in option for general use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking one
&lt;/h2&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;Take&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Long agentic runs, heavy cache reuse, hardest tasks&lt;/td&gt;
&lt;td&gt;Fable 5.1 — the premium is smaller now, but it is still a premium (on Ofox as &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex agentic coding, enterprise work, cost matters&lt;/td&gt;
&lt;td&gt;Opus 5 — cheaper on every realistic mix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High volume, latency-sensitive, good enough quality&lt;/td&gt;
&lt;td&gt;Sonnet 5 — $2/$10 with the same 1M context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Already on Fable 5&lt;/td&gt;
&lt;td&gt;Same base price, cheaper cache, newer cutoff — worth moving. Now in the Ofox catalog as &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Then go and check your cache TTL. On an hour-long agent that single setting swings more money than the price change this article is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fable 5.1 was added to the Ofox catalog on 3 September 2026&lt;/strong&gt;, as &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt; (the alias &lt;code&gt;claude-fable-5-1&lt;/code&gt; also resolves). All five rates match Anthropic's list prices with no markup, so every figure in this article applies unchanged. It sits alongside &lt;code&gt;anthropic/claude-fable-5&lt;/code&gt;, &lt;code&gt;anthropic/claude-opus-5&lt;/code&gt; and &lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt;, and all four are reachable on a single Ofox key over either protocol — the OpenAI-compatible base URL &lt;code&gt;https://api.ofox.ai/v1&lt;/code&gt;, or the native Anthropic base URL &lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prices and specifications verified against Anthropic's pricing, model documentation, product page and launch announcement on 2 September 2026 and re-checked on 3 September 2026. Cost-per-task figures from Artificial Analysis, published 1 September 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Claude Fable 5.1 cheaper than Fable 5?
&lt;/h3&gt;

&lt;p&gt;Only on cached input. Base input stays at $10 per million tokens and output stays at $50, both identical to Fable 5. The one line that changed is cache reads, from $1 to $0.25 per million tokens. Anthropic states this is 75% less and reduces the cost of typical workloads by an estimated 25%, and highly agentic workloads by up to approximately 45%. If your workload rarely reads from cache, your bill barely moves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fable 5.1 cache reads cost less than Opus 5's. Does that make it cheaper overall?
&lt;/h3&gt;

&lt;p&gt;No. Fable 5.1 reads cached tokens at $0.25 against Opus 5's $0.50, but its base input ($10 vs $5) and output ($50 vs $25) are both double. Working the algebra through, Fable 5.1 only wins on total cost when cache reads exceed roughly 95% of your input and output is close to zero. That is not a real workload. Pick Fable 5.1 for capability, not to undercut Opus 5 on cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the Claude Fable 5.1 model ID and context window?
&lt;/h3&gt;

&lt;p&gt;The model ID is claude-fable-5-1. It has a 1M-token context window, 128K maximum output, adaptive thinking always on, and a default effort level of high. Its reliable knowledge cutoff is June 2026, one month later than Opus 5 and five months later than Sonnet 5.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Claude Mythos 5.1?
&lt;/h3&gt;

&lt;p&gt;Anthropic states that Mythos 5.1 and Fable 5.1 are the same underlying model, differing in safeguards, and lists them at identical rates. Mythos runs through trusted-access programs at different stages — the Life Sciences Verification Program is an invite-only beta granting access now, while the Cyber Verification Program will include Mythos access in the near future — and availability is currently limited to a set of US organizations, so it is not something you can simply call from a standard API key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I call Fable 5.1 through Ofox today?
&lt;/h3&gt;

&lt;p&gt;Yes. Fable 5.1 was added to the Ofox catalog on 3 September 2026 as anthropic/claude-fable-5.1, at Anthropic list prices with no markup — all five rates match. It is reachable over either the OpenAI-compatible or the native Anthropic protocol on the same key as Fable 5, Opus 5 and Sonnet 5.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/claude-fable-5-1-vs-fable-5-vs-opus-5-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>pricing</category>
      <category>anthropic</category>
    </item>
    <item>
      <title>Claude Fable 5.1 API: Model ID, Rates, Effort and Cache TTL</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 06 Sep 2026 00:33:13 +0000</pubDate>
      <link>https://dev.to/owen_fox/claude-fable-51-api-model-id-rates-effort-and-cache-ttl-5af</link>
      <guid>https://dev.to/owen_fox/claude-fable-51-api-model-id-rates-effort-and-cache-ttl-5af</guid>
      <description>&lt;h1&gt;
  
  
  Claude Fable 5.1 API: Model ID, Rates, Effort and Cache TTL
&lt;/h1&gt;

&lt;p&gt;Claude Fable 5.1 shipped on 1 September 2026. This post is the reference: the identifiers, the five published rates, and the cache-TTL choice that costs more than the price cut saves. For the cost argument against Opus 5, see &lt;a href="https://ofox.ai/blog/claude-fable-5-1-vs-fable-5-vs-opus-5-2026/" rel="noopener noreferrer"&gt;Fable 5.1 vs Fable 5 vs Opus 5&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The identifiers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude-fable-5-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;1M tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max output&lt;/td&gt;
&lt;td&gt;128K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thinking&lt;/td&gt;
&lt;td&gt;Adaptive, always on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default effort&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliable knowledge cutoff&lt;/td&gt;
&lt;td&gt;June 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Adaptive thinking cannot be switched off on this model. That matters for budgeting, because thinking tokens are billed as output — the $50 line, not the $10 line.&lt;/p&gt;

&lt;h2&gt;
  
  
  All five rates
&lt;/h2&gt;

&lt;p&gt;Anthropic publishes five rates per model. Most write-ups quote one of them. Dollars 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;Rate&lt;/th&gt;
&lt;th&gt;Fable 5.1&lt;/th&gt;
&lt;th&gt;Fable 5&lt;/th&gt;
&lt;th&gt;Opus 5&lt;/th&gt;
&lt;th&gt;Sonnet 5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base input&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5m cache write&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;td&gt;6.25&lt;/td&gt;
&lt;td&gt;2.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1h cache write&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache read&lt;/td&gt;
&lt;td&gt;0.25&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;0.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the two Fable columns against each other. Four of the five numbers are identical. The version bump moved exactly one line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Effort does not change the rate — it changes the token count
&lt;/h2&gt;

&lt;p&gt;Effort is not a pricing tier. The per-token rates above hold at every effort level. What effort changes is how much the model writes before it answers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/ArtificialAnlys/status/2094881171066978525" rel="noopener noreferrer"&gt;Artificial Analysis&lt;/a&gt;, which took part in pre-release evaluation of the model, measured Fable 5.1 at max effort using roughly &lt;strong&gt;1.7x the output tokens&lt;/strong&gt; of Fable 5. Output is the $50 line. That is why their cost-per-task figure came out at $3.76 against Fable 5's $3.14 — 20% higher — even though the cache read got 75% cheaper.&lt;/p&gt;

&lt;p&gt;So the budgeting rule is: raising effort raises your bill through volume, not through rate. If you are cost-sensitive, cap effort before you optimize anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What caching is worth
&lt;/h2&gt;

&lt;p&gt;A cache read at $0.25 is one-fortieth the price of base input at $10. The saving compounds with reuse.&lt;/p&gt;

&lt;p&gt;Take one 1M-token prefix — a codebase, a document set, a long system prompt. Write it once, read it back N times:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reads&lt;/th&gt;
&lt;th&gt;Fable 5.1&lt;/th&gt;
&lt;th&gt;Fable 5&lt;/th&gt;
&lt;th&gt;No caching&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;$12.75&lt;/td&gt;
&lt;td&gt;$13.50&lt;/td&gt;
&lt;td&gt;$20.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;td&gt;$22.50&lt;/td&gt;
&lt;td&gt;$110.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;$37.50&lt;/td&gt;
&lt;td&gt;$112.50&lt;/td&gt;
&lt;td&gt;$1,010.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;$137.50&lt;/td&gt;
&lt;td&gt;$512.50&lt;/td&gt;
&lt;td&gt;$5,010.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table assumes a single 5-minute write with no expiry between reads. The "no caching" column is the same N+1 full passes at $10 per million.&lt;/p&gt;

&lt;p&gt;At a single read the two versions are within 6% of each other. At a hundred reads Fable 5.1 costs a third of Fable 5. The model is identical across those rows; only the cache-hit count changes. That is the number to measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TTL decision
&lt;/h2&gt;

&lt;p&gt;Anthropic sells two cache-write durations: $12.50 per million for five minutes, $20 for an hour. The five-minute clock resets on reads. &lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;Anthropic's prompt-caching documentation&lt;/a&gt; is explicit that the cache is refreshed for no additional cost each time the cached content is used, and that the lifetime is measured from each request that &lt;em&gt;writes or reads&lt;/em&gt; the entry. An agent that keeps hitting the same prefix holds a five-minute entry open on reads alone and pays for exactly one write.&lt;/p&gt;

&lt;p&gt;The money leaks in the gaps. Any pause over five minutes — a slow tool call, a human reading a diff — lets the entry expire, and the next call pays the write again. An hour of that costs at worst 12 × $12.50 = &lt;strong&gt;$150&lt;/strong&gt;, against &lt;strong&gt;$20&lt;/strong&gt; for one 1-hour write.&lt;/p&gt;

&lt;p&gt;That $130 gap per prefix per hour is decided by your traffic pattern rather than your model choice, which is why it survives the version bump entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating from Fable 5
&lt;/h2&gt;

&lt;p&gt;The change is a string. Base rates, context window, output ceiling and default effort are all unchanged, so a swap of the model ID is the whole migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- model="claude-fable-5"
&lt;/span&gt;&lt;span class="gi"&gt;+ model="claude-fable-5-1"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things to re-check after the swap, because neither is visible in the diff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Your output budget.&lt;/strong&gt; Same rate, but Artificial Analysis measured roughly 1.7x the output tokens at max effort. If you had alerts calibrated on Fable 5's output volume, they will fire.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Your knowledge-cutoff assumptions.&lt;/strong&gt; A June 2026 cutoff means prompts that patched around stale library knowledge may now be redundant or, worse, actively wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Anthropic says changed besides price
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.anthropic.com/claude/fable" rel="noopener noreferrer"&gt;Claude Fable product page&lt;/a&gt; describes behavior rather than benchmarks. It says Fable 5.1 "avoids easy-seeming shortcuts, fixes the root causes of problems rather than the symptoms, and keeps you updated as it works".&lt;/p&gt;

&lt;p&gt;Two safeguard changes are easy to conflate, and several write-ups have. On &lt;a href="https://www.anthropic.com/news/improving-fable-5-s-biology-safeguards" rel="noopener noreferrer"&gt;7 August 2026&lt;/a&gt; Anthropic retuned &lt;strong&gt;Fable 5's&lt;/strong&gt; biology safeguards and reported that the update "reduced biology-related fallbacks by about 85% across our product surfaces". Separately, the &lt;a href="https://www.anthropic.com/claude-fable-and-mythos-5-1" rel="noopener noreferrer"&gt;1 September launch announcement&lt;/a&gt; says that in cybersecurity Fable 5.1's "newest safeguards block 60% fewer false positives than before". So "fewer false positives" is a genuine 5.1 launch claim — on the cyber side. It is not the August biology change, and the two numbers should not be added together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calling it through Ofox
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fable 5.1 is in the Ofox catalog as of 3 September 2026&lt;/strong&gt;, listed as &lt;code&gt;anthropic/claude-fable-5.1&lt;/code&gt;. The alias &lt;code&gt;claude-fable-5-1&lt;/code&gt; — Anthropic's own model ID — also resolves, so a migration from Anthropic direct needs no string change beyond the provider prefix.&lt;/p&gt;

&lt;p&gt;The same key also covers &lt;code&gt;anthropic/claude-fable-5&lt;/code&gt;, &lt;code&gt;anthropic/claude-opus-5&lt;/code&gt; and &lt;code&gt;anthropic/claude-sonnet-5&lt;/code&gt;, all at Anthropic list prices with no markup. All four are reachable over either protocol:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Base URL&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic native&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.ofox.ai/anthropic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The native path gives you the Messages API. Ofox's documentation lists extended thinking and tool use on it explicitly but does not call out caching separately, so check that &lt;code&gt;usage.cache_read_input_tokens&lt;/code&gt; is non-zero on your first repeated call before you bank the TTL arithmetic above.&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;&amp;lt;OFOX_API_KEY&amp;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="n"&gt;message&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;anthropic/claude-fable-5.1&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;1024&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 repository.&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;All five rates match Anthropic's list with no markup, so every figure in this article applies unchanged. What still decides whether the cheaper read is worth anything to you is your cache-hit ratio — measure that on your own traffic before you assume the 25% lands.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rates and specifications verified against Anthropic's &lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;pricing documentation&lt;/a&gt;, &lt;a href="https://platform.claude.com/docs/en/about-claude/models/overview" rel="noopener noreferrer"&gt;model overview&lt;/a&gt;, &lt;a href="https://www.anthropic.com/claude/fable" rel="noopener noreferrer"&gt;product page&lt;/a&gt; and &lt;a href="https://www.anthropic.com/claude-fable-and-mythos-5-1" rel="noopener noreferrer"&gt;launch announcement&lt;/a&gt; on 3 September 2026. Cost-per-task figures from &lt;a href="https://x.com/ArtificialAnlys/status/2094881171066978525" rel="noopener noreferrer"&gt;Artificial Analysis&lt;/a&gt;, retrieved the same day. Ofox catalog and protocol base URLs checked against the live &lt;code&gt;/v1/models&lt;/code&gt; endpoint and the Ofox documentation on 3 September 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the Claude Fable 5.1 model ID?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;claude-fable-5-1. It has a 1M-token context window and produces up to 128K output tokens. Adaptive thinking is always on and cannot be turned off, and the default effort level is high. The reliable knowledge cutoff is June 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does Claude Fable 5.1 cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Anthropic publishes five rates per million tokens: $10 base input, $12.50 for a 5-minute cache write, $20 for a 1-hour cache write, $0.25 for a cache read, and $50 output. Four of those five are identical to Fable 5 — only the cache read changed, from $1 to $0.25.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does raising the effort level change the price per token?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. The per-token rates are fixed. What changes is how many output tokens the model produces. Artificial Analysis measured Fable 5.1 using roughly 1.7x the output tokens of Fable 5 at max effort, which is why its cost per task came out 20% higher despite the cheaper cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use the 5-minute or the 1-hour cache TTL?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends on whether your agent idles. Anthropic's documentation states the cache is refreshed for no additional cost each time the cached content is used, and the lifetime restarts on every request that writes or reads the entry. A continuously busy agent keeps a 5-minute entry alive on reads alone. One that pauses longer than five minutes pays the write again — at worst 12 rewrites an hour, $150 against $20 for a single 1-hour write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I call Fable 5.1 through Ofox today?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, as of 3 September 2026. The Ofox catalog lists it as anthropic/claude-fable-5.1, with claude-fable-5-1 as an alias. All five rates match Anthropic's list prices with no markup, and it is callable over either the OpenAI-compatible or the native Anthropic protocol on one key.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/claude-fable-5-1-api-guide-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>api</category>
      <category>pricing</category>
    </item>
    <item>
      <title>Video Generation API Polling: 202, polling_url, Wait Times (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Fri, 28 Aug 2026 04:38:10 +0000</pubDate>
      <link>https://dev.to/owen_fox/video-generation-api-polling-202-pollingurl-wait-times-2026-344c</link>
      <guid>https://dev.to/owen_fox/video-generation-api-polling-202-pollingurl-wait-times-2026-344c</guid>
      <description>&lt;p&gt;&lt;strong&gt;The 202 arrives in under a second. The video takes another two to four minutes, and how long is not something you can predict from the request.&lt;/strong&gt; Everything hard about video generation APIs lives in the gap between those two facts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Submit:        POST /v1/videos -&amp;gt; 202 in 0.82s
Response body: {id, status: "queued", polling_url}   three fields, nothing else
Wait, 5s clip: 83.3s to 253.2s across 8 identical jobs, median 104.6s
Poll limit:    5 req/s per key, burst 20, 429 + Retry-After: 1 over it
Terminal:      completed | failed | cancelled | expired   (all four, or you spin)
Cancel:        400 cancel_failed once upstream is running
Result URL:    unsigned_urls signed for 24h. mirror_urls absent on Seedance.
Measured:      2026-08-24, 13 jobs through POST /v1/videos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Last updated 2026-08-24. Timings are from one afternoon on one route and will not match yours; the shape of the distribution is the transferable part, not the seconds.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does POST /v1/videos Actually Return?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A 202 with three fields.&lt;/strong&gt; No video, no percentage, no estimate:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5e6f69b1-8ffe-430c-a687-8241366a90f5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"queued"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"polling_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.ofox.ai/v1/videos/5e6f69b1-8ffe-430c-a687-8241366a90f5"&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;p&gt;That call took 0.82 seconds. The &lt;code&gt;polling_url&lt;/code&gt; is a convenience: it is the same &lt;code&gt;GET /v1/videos/{id}&lt;/code&gt; you would build yourself, and the &lt;a href="https://ofox.ai/docs/api/videos/create" rel="noopener noreferrer"&gt;Create Video reference&lt;/a&gt; says as much. Use the field rather than string-building the URL, because the id format is a UUID today and there is no promise it stays one.&lt;/p&gt;

&lt;p&gt;While a job is in flight, the status body is deliberately thin:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"in_progress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bytedance/seedance-2.0-mini"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1787567608&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1787567608&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;p&gt;There is no progress field to render a bar from. If your UI needs one, it has to be a fake based on elapsed time against a historical median, and after reading the next section you will understand why that bar has to be honest about being a guess.&lt;/p&gt;

&lt;p&gt;When the job completes, two keys appear: &lt;code&gt;unsigned_urls&lt;/code&gt; and &lt;code&gt;usage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One 4-second 480p clip, start to finish. The 8-job table below is a separate set of 5-second clips, so read the 105.9 seconds here as one more sample rather than a row of that table.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Long Does a Video Generation Job Actually Take?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;83 to 253 seconds for the same request.&lt;/strong&gt; Eight jobs, all 5-second 480p clips on &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt;, all through one key on one afternoon:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;What it was&lt;/th&gt;
&lt;th&gt;Seconds to terminal&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;text-to-video, 16:9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;83.3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;text-to-video, 9:16, one of three submitted together&lt;/td&gt;
&lt;td&gt;85.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;two reference images&lt;/td&gt;
&lt;td&gt;95.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;first and last frame, ratio set&lt;/td&gt;
&lt;td&gt;103.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;first and last frame, no ratio&lt;/td&gt;
&lt;td&gt;105.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;text-to-video, 9:16, one of three submitted together&lt;/td&gt;
&lt;td&gt;126.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;text-to-video, 16:9&lt;/td&gt;
&lt;td&gt;139.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;text-to-video, 9:16, one of three submitted together&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;253.2&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Median 104.6 seconds. Slowest over fastest: 3.0x. The three slowest and the three fastest are not separated by anything in the request; runs 2, 6 and 8 are the same model, the same duration, the same resolution and the same aspect ratio, submitted in the same second, and they finished 85s, 127s and 253s later.&lt;/p&gt;

&lt;p&gt;Two practical consequences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set the timeout at the tail.&lt;/strong&gt; A 120-second client timeout would have killed run 8 with the job still generating upstream and still billing. We use 900 seconds as a hard ceiling and treat anything past 300 as worth logging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not promise an ETA.&lt;/strong&gt; A queue of clips finishes when it finishes. If your product shows a countdown, base it on a rolling median of your own recent jobs and let it overrun rather than lie.&lt;/p&gt;

&lt;p&gt;Larger models are not automatically slower, which surprises people. On the same afternoon, a 5-second 480p job on &lt;a href="https://ofox.ai/models/bytedance/seedance-2.5" rel="noopener noreferrer"&gt;&lt;code&gt;bytedance/seedance-2.5&lt;/code&gt;&lt;/a&gt; finished in 53.1 seconds, faster than every Mini run above, while its first-and-last-frame variant took 212.9 seconds. Mode moves the number more than model tier does. The &lt;a href="https://ofox.ai/blog/seedance-2-5-first-last-frame-image-to-video-2026/" rel="noopener noreferrer"&gt;first and last frame walkthrough&lt;/a&gt; has the rest of that comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Often Should You Poll?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Every 2 to 5 seconds.&lt;/strong&gt; The &lt;a href="https://ofox.ai/docs/api/videos/retrieve" rel="noopener noreferrer"&gt;status endpoint&lt;/a&gt; documents a per-key limit of 5 requests per second with a burst of 20; over it you get &lt;code&gt;429 rate_limited&lt;/code&gt; with a &lt;code&gt;Retry-After: 1&lt;/code&gt; header. Creating and cancelling are exempt. The docs also ask for no faster than once per second, so there is a comfortable band between "polite" and "throttled".&lt;/p&gt;

&lt;p&gt;At 2 to 3 second intervals across the runs in this article, no poll returned an error.&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;requests&lt;/span&gt;

&lt;span class="n"&gt;H&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 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;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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wait&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="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&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;t0&lt;/span&gt; &lt;span class="o"&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;time&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;s&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;job&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="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;H&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;s&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
        &lt;span class="k"&gt;if&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;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;timeout&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;TimeoutError&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;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&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="s"&gt; still &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="si"&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="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;interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things that loop gets right and most published examples get wrong. It breaks on all four terminal states. It has a ceiling, so a stuck job cannot hang a worker forever. And it reads &lt;code&gt;polling_url&lt;/code&gt; from the submit response instead of rebuilding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Statuses Are Terminal?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Four out of seven.&lt;/strong&gt; The documented state machine:&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;Terminal&lt;/th&gt;
&lt;th&gt;Meaning&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;&lt;/td&gt;
&lt;td&gt;Accepted, not yet submitted upstream&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;&lt;/td&gt;
&lt;td&gt;Submitted upstream, waiting in a queue&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;&lt;/td&gt;
&lt;td&gt;Generating&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;✓&lt;/td&gt;
&lt;td&gt;Video URLs available&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;✓&lt;/td&gt;
&lt;td&gt;Failed, including timeouts, which arrive as &lt;code&gt;error.code: "expired"&lt;/code&gt;
&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;✓&lt;/td&gt;
&lt;td&gt;Cancelled&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;✓&lt;/td&gt;
&lt;td&gt;Expired&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no &lt;code&gt;processing&lt;/code&gt;. Loops copied from other vendors' SDKs often check for it and then wait forever.&lt;/p&gt;

&lt;p&gt;In practice we never observed &lt;code&gt;pending&lt;/code&gt;. How long &lt;code&gt;queued&lt;/code&gt; lasts moves around: in most of our runs the first poll, 0.3 seconds after submit, already said &lt;code&gt;in_progress&lt;/code&gt;, while the run in the screenshot above sat in &lt;code&gt;queued&lt;/code&gt; for 14 seconds first. Neither is a bug, it is queue depth. Handle &lt;code&gt;pending&lt;/code&gt; anyway; the state you never see in testing is the one that turns up the week you scale.&lt;/p&gt;

&lt;p&gt;A note on the timeout case. A generation that times out arrives as &lt;code&gt;failed&lt;/code&gt; with &lt;code&gt;error.code: "expired"&lt;/code&gt;, not as the standalone &lt;code&gt;expired&lt;/code&gt; status, so both spellings of the same word exist and mean different things. Branch on &lt;code&gt;error.code&lt;/code&gt;, which the &lt;a href="https://ofox.ai/docs/api/videos/errors" rel="noopener noreferrer"&gt;error reference&lt;/a&gt; describes as the stable field to match on, rather than on message text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can You Cancel a Running Video Job?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Usually not, and the refusal is the honest answer.&lt;/strong&gt; We submitted a job, waited six seconds, and sent &lt;code&gt;DELETE /v1/videos/{id}&lt;/code&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cancel_failed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"upstream cancel failed: cancel failed: status 409, body:
    {&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;InvalidAction.RunningTaskDeletion&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,
     &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Cannot delete task `cgt-...` because it is currently running.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;p&gt;Two things worth knowing before you build a stop button.&lt;/p&gt;

&lt;p&gt;The docs describe &lt;code&gt;cancel_failed&lt;/code&gt; as the code for a job already in a terminal state, and &lt;code&gt;cancel_not_supported&lt;/code&gt; for providers that cannot interrupt. What we hit was neither: a running job whose provider refused the deletion, surfaced as &lt;code&gt;cancel_failed&lt;/code&gt; carrying the upstream 409. If you branch on that code, allow for both meanings.&lt;/p&gt;

&lt;p&gt;And at that exact moment, &lt;code&gt;GET&lt;/code&gt; still reported the job as &lt;code&gt;queued&lt;/code&gt;. So &lt;code&gt;queued&lt;/code&gt; in the status body does not imply the job is cancellable, because the upstream had already started. There is no status you can read that reliably tells you a cancel will work. Try it, check for 204, and if you get a 400 assume you are paying for the clip.&lt;/p&gt;

&lt;p&gt;The design conclusion is unpopular but simple: &lt;strong&gt;treat submission as the commit point&lt;/strong&gt;. Validate the prompt, the reference images and the duration before you POST, because the moment you have an id you have probably bought the clip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Did My Video URL Stop Working?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Because &lt;code&gt;unsigned_urls&lt;/code&gt; is a signed upstream address with a lifetime.&lt;/strong&gt; Ours came back with &lt;code&gt;X-Tos-Expires=86400&lt;/code&gt; in the query string, which is 24 hours, and the docs describe the field as temporary and expiring in about 24 hours.&lt;/p&gt;

&lt;p&gt;There is a second field, &lt;code&gt;mirror_urls&lt;/code&gt;, described as persistent and preferred, present when the provider has CDN mirroring enabled. On every Seedance response we pulled today the completed body had exactly these keys:&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;created_at,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;id,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;model,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;prompt,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;status,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unsigned_urls,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;updated_at,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;usage&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;mirror_urls&lt;/code&gt;. So on this model family, "prefer mirror_urls" resolves to "there is only one URL and it expires". Download the bytes in the same worker that observed &lt;code&gt;completed&lt;/code&gt; and put them in your own storage. Do not persist the URL to a database and call the job done, which is how a content pipeline ends up with a table of dead links a day later.&lt;/p&gt;

&lt;p&gt;While you are there, read &lt;code&gt;usage&lt;/code&gt;:&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="nl"&gt;"usage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"video_seconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"video_cost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.1000000000"&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;p&gt;&lt;code&gt;video_cost&lt;/code&gt; is a string, not a number, and deliberately so: it is documented as a fixed-point 10-decimal string to avoid precision loss. Parse it as a decimal, not a float, and bill from &lt;code&gt;video_seconds&lt;/code&gt; rather than from the duration you asked for, because a 5-second request comes back as a 5.04-second file.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Write One Polling Loop for Every Video Model?
&lt;/h2&gt;

&lt;p&gt;The loop above is about 15 lines, and the reason it is worth writing carefully once is that every video vendor has invented its own version of it. One returns a job object and a separate results endpoint, one wants you to poll a URL from a header, one has a status enum with a different set of names, and one bills for the cancel you thought worked. Supporting three video models natively means three loops, three sets of terminal states and three billing edge cases, none of which is interesting work.&lt;/p&gt;

&lt;p&gt;The clips in this post all came back through the same &lt;code&gt;POST /v1/videos&lt;/code&gt; and the same &lt;code&gt;GET /v1/videos/{id}&lt;/code&gt; regardless of which model generated them, which is why the wait-time table can put Seedance 2.5 and 2.0 Mini in the same column. That normalisation is what a video gateway is for; &lt;a href="https://ofox.ai/video" rel="noopener noreferrer"&gt;ofox's video endpoint&lt;/a&gt; is the one we run on, and the property to check on any of them is that the status enum and the &lt;code&gt;usage&lt;/code&gt; shape stay identical when you change the model field. If they do not, you still have three loops, just hidden behind one hostname.&lt;/p&gt;

&lt;p&gt;For picking the model that goes in the loop, our guide to &lt;a href="https://ofox.ai/blog/how-to-choose-a-video-generation-api-by-use-case/" rel="noopener noreferrer"&gt;choosing a video generation API by use case&lt;/a&gt; covers the quality and price axes, and the &lt;a href="https://ofox.ai/blog/fal-vs-replicate-vs-ofox-video-api-pricing-2026/" rel="noopener noreferrer"&gt;fal against Replicate against ofox pricing comparison&lt;/a&gt; has the per-second numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Use a Webhook Instead?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you have a public HTTPS endpoint, yes.&lt;/strong&gt; Pass &lt;code&gt;callback_url&lt;/code&gt; at creation and one POST arrives per task when it settles, carrying the full task object, an &lt;code&gt;X-Ofox-Signature&lt;/code&gt; HMAC-SHA256 header and an &lt;code&gt;X-Ofox-Idempotency-Key&lt;/code&gt;. The events map one-to-one onto the terminal states.&lt;/p&gt;

&lt;p&gt;The validation happens at submit time, not at delivery time. We sent a private-network HTTP address and got this back immediately:&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="mi"&gt;400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;invalid_callback_url&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"callback_url must be a public HTTPS URL: ssrf blocked: target is private,
 reserved, or scheme not allowed: scheme must be https"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is worth knowing during development, because the natural thing to try, a localhost or LAN address, is exactly what the SSRF check rejects. Use a tunnel with a real HTTPS hostname, or poll while developing and switch to webhooks in production. Belt and braces is fine too: register the webhook and keep a slow sweeper that polls anything still open after ten minutes, since a webhook you never received is indistinguishable from a job that never finished.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.rfc-editor.org/rfc/rfc9110#status.202" rel="noopener noreferrer"&gt;RFC 9110: 202 Accepted&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/202" rel="noopener noreferrer"&gt;MDN: HTTP 202 Accepted&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After" rel="noopener noreferrer"&gt;MDN: Retry-After header&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP: Server Side Request Forgery prevention&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/docs/api/videos/create" rel="noopener noreferrer"&gt;ofox: Create Video API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/docs/api/videos/retrieve" rel="noopener noreferrer"&gt;ofox: Get Video Status API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/docs/api/videos/cancel" rel="noopener noreferrer"&gt;ofox: Cancel Video API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/docs/api/videos/webhooks" rel="noopener noreferrer"&gt;ofox: Video webhooks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://ofox.ai/docs/api/videos/errors" rel="noopener noreferrer"&gt;ofox: Video API error codes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What does POST /v1/videos return?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTTP 202 with three fields and nothing else: id, status set to queued, and polling_url. Our submit call took 0.82 seconds. There is no video, no progress figure and no estimated completion in that response, which is the point of a 202: the work has been accepted, not done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does a video generation job take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Longer than you expect and less predictably. Eight identical 5-second 480p jobs on Seedance 2.0 Mini, all on the same afternoon through the same key, finished between 83.3 and 253.2 seconds, a 3x spread with a median of 104.6. Design the timeout for the tail, not the median.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should you poll a video generation job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once every 2 to 5 seconds is plenty. The endpoint is rate-limited per API key at 5 requests per second with a burst of 20, and the docs ask you to poll no faster than once per second. Over the limit you get 429 rate_limited with a Retry-After: 1 header. Creating and cancelling are not subject to that limit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which video job statuses are terminal?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Four: completed, failed, cancelled and expired. The full state machine has seven states, with pending, queued and in_progress as the non-terminal ones. A polling loop that only breaks on completed and failed will spin forever on a job that was cancelled or expired.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I cancel a running video generation job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Often not. Our DELETE on a job that had been running for six seconds returned 400 cancel_failed, wrapping an upstream 409 saying the task cannot be deleted because it is currently running. Cancellation depends on whether the upstream provider supports interruption, and the gateway refuses to fake a local cancel while the upstream keeps generating and billing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why did my generated video URL stop working?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because unsigned_urls is a temporary signed upstream address. The one we got back carried X-Tos-Expires=86400 in its query string, so it dies 24 hours after signing. Download the file, or use mirror_urls when the provider has CDN mirroring enabled. On the Seedance responses we pulled, mirror_urls was absent entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do failed video jobs cost money?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The usage object is documented as present only when a job completes, and failed jobs we have run returned usage null. A timeout arrives as status failed with error.code set to expired, not as a distinct status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use a webhook instead of polling?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have a public HTTPS endpoint, yes. Pass callback_url at creation and you get one POST per task at its terminal state, with an HMAC-SHA256 signature and an idempotency key header. The URL is validated at creation time: our http:// address on a private IP was rejected immediately with 400 invalid_callback_url.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/video-generation-api-polling-202-wait-times-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>videoapi</category>
      <category>webhooks</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>"Transparent Background Is Not Supported for This Model": 3 Fixes</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Thu, 27 Aug 2026 11:33:47 +0000</pubDate>
      <link>https://dev.to/owen_fox/transparent-background-is-not-supported-for-this-model-3-fixes-5b1l</link>
      <guid>https://dev.to/owen_fox/transparent-background-is-not-supported-for-this-model-3-fixes-5b1l</guid>
      <description>&lt;p&gt;The error message is straightforward, and the solution involves a single model swap. The &lt;code&gt;background: "transparent"&lt;/code&gt; parameter represents a preview capability available only on specific image model deployments, not all of them. Notably, the model used in OpenAI's official cookbook is not the one supporting this feature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error:        400, "Transparent background is not supported for this model."
Type:         image_generation_user_error
Fires on:     openai/gpt-image-2  (1.1s, before any generation)
Works on:     openai/gpt-image-1.5  (200, RGBA PNG, 67.3% alpha-zero pixels)
Silent fail:  gemini-3-pro-image, qwen-image-3.0, mai-image-2.5-flash
              all 200, all colour type 2, no alpha channel
Format rule:  PNG only. jpeg is a 400, webp is a 400.
Prompt rule:  prompt beats parameter. Scene words put the scene back.
Measured:     2026-08-24, POST /v1/images/generations, 1024x1024, n=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Three Fixes in Priority Order
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Switch the model.&lt;/strong&gt; The transparency capability is tied to the specific deployment, not the request parameters. Switching to a different model ID yields a 200 response with genuine alpha channel support.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintain PNG output format.&lt;/strong&gt; Both &lt;code&gt;jpeg&lt;/code&gt; and &lt;code&gt;webp&lt;/code&gt; formats return 400 errors, but for different reasons. JPEG cannot store alpha channels, while WebP is not supported by this endpoint at all.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rewrite the prompt.&lt;/strong&gt; The prompt text carries more weight than the parameter setting. Prompts mentioning scenes, backgrounds, or specific environments result in opaque backgrounds despite the transparency parameter.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Last updated 2026-08-24. OpenAI describes transparent assets as preview functionality, so model capability availability may change. Re-test before relying on any model list.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Does gpt-image-2 Say Transparent Background Is Not Supported?
&lt;/h2&gt;

&lt;p&gt;The deployment serving that model ID does not have the transparency preview feature enabled. The error message reflects an actual capability limitation, not a parameter syntax issue.&lt;/p&gt;

&lt;p&gt;Complete error response:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&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="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transparent background is not supported for this model."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"param"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image_generation_user_error"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two critical details eliminate common explanations. The error arrives within 1.1 seconds—far too quickly for image generation and rejection. Additionally, the identical request with &lt;code&gt;background: "opaque"&lt;/code&gt; returns 200 with a normal image on the same model using the same API key. This proves the parameter is reaching the provider and only the transparent value is rejected.&lt;/p&gt;

&lt;p&gt;The widespread confusion stems from OpenAI's cookbook example being written against &lt;code&gt;gpt-image-2&lt;/code&gt;. The documentation does mention requiring access to a transparency-capable image model, but many users miss this distinction between model name and actual feature availability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which Image Models Return Transparent PNGs?
&lt;/h2&gt;

&lt;p&gt;Only one of five tested models successfully returned a transparent PNG.&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;HTTP&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;PNG Colour Type&lt;/th&gt;
&lt;th&gt;Transparent Pixels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-image-1.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;29.0s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6, truecolour + alpha&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;67.3%&lt;/strong&gt;&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;400&lt;/td&gt;
&lt;td&gt;1.1s&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;google/gemini-3-pro-image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;25.8s&lt;/td&gt;
&lt;td&gt;2, no alpha&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bailian/qwen-image-3.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;49.7s&lt;/td&gt;
&lt;td&gt;2, no alpha&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;microsoft/mai-image-2.5-flash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;15.4s&lt;/td&gt;
&lt;td&gt;2, no alpha&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The bottom three rows represent dangerous scenarios. A 400 error provides immediate feedback about what needs changing. A 200 response returning an opaque PNG silently passes validation checks, consumes generation credits, and appears as a white box in presentations days later.&lt;/p&gt;

&lt;p&gt;Testing confirmed the behavior directly rather than inferring it. Sending &lt;code&gt;background: "bogus"&lt;/code&gt; to &lt;code&gt;gpt-image-1.5&lt;/code&gt; returns a 400 error listing valid values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invalid value: 'bogus'. Supported values are: 'transparent', 'opaque', and 'auto'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sending identical invalid input to &lt;code&gt;gemini-3-pro-image&lt;/code&gt; returns 200 with an image. A validating endpoint rejects garbage input; one accepting garbage was never going to honor &lt;code&gt;transparent&lt;/code&gt; either.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 1: Which Model to Switch To
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;openai/gpt-image-1.5&lt;/code&gt;—nothing else in the request requires modification. The body that fails on &lt;code&gt;gpt-image-2&lt;/code&gt; works unchanged:&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_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;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;openai/gpt-image-1.5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# gpt-image-2 returns 400 here
&lt;/span&gt;    &lt;span class="n"&gt;prompt&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;A single glossy red ceramic coffee mug, isolated product cutout, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no backdrop, no scene, no shadow, no reflection, transparent background, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no text, no letters, no logos, no watermarks&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;background&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transparent&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;For catalog pipelines, explicitly specify the model ID and fail loudly when responses lack alpha channels rather than allowing fallback models to generate thousands of opaque cutouts silently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 2: Which Output Formats Support Alpha
&lt;/h2&gt;

&lt;p&gt;Only PNG supports alpha channels on this endpoint. JPEG and WebP both return 400 errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;output_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jpeg"&lt;/span&gt;  &lt;span class="s"&gt;-&amp;gt;  400  Transparent background is not supported for JPEG output format&lt;/span&gt;
&lt;span class="na"&gt;output_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;webp"&lt;/span&gt;  &lt;span class="na"&gt;-&amp;gt;  400  Invalid value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;webp'&lt;/span&gt;&lt;span class="na"&gt;. Supported values are&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;png'&lt;/span&gt; &lt;span class="s"&gt;and 'jpeg'.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These represent different failure modes. The JPEG rejection reflects the format's inherent limitation—it cannot store transparency. The WebP rejection indicates this endpoint simply does not offer that format. For production pipelines, generate PNG files and convert downstream rather than requesting WebP directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 3: Why Is Transparent Image Still Full of Background
&lt;/h2&gt;

&lt;p&gt;The prompt parameter outweighs the API setting by a substantial margin. OpenAI's documentation mentions this; testing quantified the impact.&lt;/p&gt;

&lt;p&gt;With identical model and &lt;code&gt;background: "transparent"&lt;/code&gt; settings, two different prompts produced vastly different results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prompt&lt;/th&gt;
&lt;th&gt;Fully Transparent Pixels&lt;/th&gt;
&lt;th&gt;Fully Opaque Pixels&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;Isolated subject, "no backdrop, no scene, no shadow"&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;67.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;24.1%&lt;/td&gt;
&lt;td&gt;Clean cutout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"on a marble kitchen counter at sunrise, soft window light"&lt;/td&gt;
&lt;td&gt;43.5%&lt;/td&gt;
&lt;td&gt;21.7%&lt;/td&gt;
&lt;td&gt;Mug, counter, window frame, sunrise sky knocked out&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The second image is not a feature failure—the transparency system worked as designed. It produced alpha around the scene explicitly requested in the prompt text, which proves useless for product catalogs and worse if unreviewed files enter production.&lt;/p&gt;

&lt;p&gt;Practical guidance: describe only the object, then add negative constraints. Words like "counter," "studio," "gradient," "table," "sunset," and "shadow" reintroduce backgrounds. Reflections have the same effect.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Check PNG Transparency
&lt;/h2&gt;

&lt;p&gt;Read a single byte. PNG stores colour type in the IHDR chunk at offset 25 in the file:&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;-c&lt;/span&gt; &lt;span class="s2"&gt;"print('colour type', open('out.png','rb').read(26)[25])"&lt;/span&gt;
&lt;span class="c"&gt;# 6 = truecolour + alpha   4 = greyscale + alpha&lt;/span&gt;
&lt;span class="c"&gt;# 2 = truecolour, no alpha 3 = indexed (transparency may live in a tRNS chunk)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Colour type is necessary but insufficient. An RGBA file with alpha channel values of 255 everywhere is technically opaque despite having an alpha channel. Count pixels instead:&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;PIL&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;

&lt;span class="n"&gt;im&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&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;out.png&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;im&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                                     &lt;span class="c1"&gt;# RGBA if an alpha channel exists
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RGBA&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;hist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getchannel&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;histogram&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;px&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&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="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;hist&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="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&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;% fully transparent&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="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="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;hist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&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;% fully opaque&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;Every statistic in this article came from these two checks. Include alpha validation in CI pipelines. When a generation service silently switches which deployment backs a model ID, it will not announce the change; a test asserting "more than 30% of pixels are fully transparent" will catch it.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Test Multiple Image Models Without Multiple Accounts
&lt;/h2&gt;

&lt;p&gt;The genuine difficulty is not the code—it is accessing five different vendor accounts, SDKs, and billing relationships simultaneously just to answer one yes-or-no question about a parameter.&lt;/p&gt;

&lt;p&gt;All models in the comparison table respond to the same &lt;code&gt;POST /v1/images/generations&lt;/code&gt; endpoint using the same API key because they are exposed through the OpenAI-compatible interface. The matrix exists because changing &lt;code&gt;model=&lt;/code&gt; was the complete difference between rows. The tests ran through ofox, and any gateway that passes the field through rather than normalizing it will produce identical results. Verify this passthrough before trusting results: if &lt;code&gt;background: "bogus"&lt;/code&gt; does not return 400, the route is not truthfully reporting the parameter state.&lt;/p&gt;




&lt;h2&gt;
  
  
  What If Your Required Model Lacks Transparency
&lt;/h2&gt;

&lt;p&gt;When locked to a model that drops the field, three options exist: two honest approaches and one to avoid.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate on solid background and cut it out.&lt;/strong&gt; A flat, unnatural background color absent from the subject makes downstream matting far simpler. Slower and lossy at edges, but predictable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate once on a capable model and reuse.&lt;/strong&gt; Transparency is a file property, not pipeline-dependent. One quality cutout beats repeated re-renders.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do not ship the opaque 200 response.&lt;/strong&gt; Unreviewed opaque images surface as white rectangles on colored slides, and by then the batch reaches thousands of files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Does One Transparent Image Cost
&lt;/h2&gt;

&lt;p&gt;A successful 1024x1024 generation on &lt;code&gt;gpt-image-1.5&lt;/code&gt; billed 46 input tokens and 4,415 output tokens (4,160 image, 255 text). At published rates—$5 per million input, $32 per million output image, $10 per million output text—the cost is approximately &lt;strong&gt;$0.136&lt;/strong&gt; per cutout image.&lt;/p&gt;

&lt;p&gt;One caveat: &lt;code&gt;gpt-image-2&lt;/code&gt; with &lt;code&gt;background: "opaque"&lt;/code&gt; reported only 196 image output tokens for the same size. Different models reporting wildly different token counts per megapixel means pricing should derive from measured usage per model rather than assuming constant rates. The same principle applies to text models.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why does gpt-image-2 say transparent background is not supported?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transparent image assets represent a preview feature gated per model deployment. The tested gpt-image-2 route lacks this capability. The same request with &lt;code&gt;background: "opaque"&lt;/code&gt; or &lt;code&gt;"auto"&lt;/code&gt; returns 200 on the same model, proving the parameter reaches the provider. Only the transparent value faces rejection in approximately 1.1 seconds—impossibly fast for post-generation rejection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which OpenAI image model supports background transparent?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the tested route, &lt;code&gt;openai/gpt-image-1.5&lt;/code&gt; returns PNG with IHDR colour type 6 and 67.3% transparent pixels. OpenAI's cookbook uses gpt-image-2, explaining user surprise. The documentation states you need access to a transparency-capable model—access determines capability, not model name alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I get a transparent JPEG?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. JPEG lacks alpha channel support, and the API rejects this combination up front with the error message. PNG remains the only option; &lt;code&gt;output_format: "webp"&lt;/code&gt; returns an error stating that format is unsupported.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My call returned 200 but the PNG has white background. What happened?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The model likely never received the parameter. Three non-OpenAI image models tested with &lt;code&gt;background: "transparent"&lt;/code&gt; all returned 200 with colour type 2 PNGs lacking alpha. One also accepted &lt;code&gt;background: "bogus"&lt;/code&gt; and returned 200—the telltale sign a route drops the field entirely rather than validating it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is there still background in my transparent image?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prompt text outranks the parameter setting. Testing demonstrated the same model and background setting produced 67.3% transparent pixels with an isolated-subject prompt versus 43.5% with scene descriptions. Describe only the subject and specify "no backdrop, no scene, no shadow" in negatives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I check PNG transparency really exists?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Read byte 25: 6 means truecolour with alpha, 2 means no alpha. Colour type 3 (indexed) may carry transparency in a separate chunk, treat as uncertain. Then count pixels at alpha zero, since an RGBA file with alpha entirely 255 is opaque despite having a channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does an image gateway strip the background parameter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not on the tested route. &lt;code&gt;gpt-image-2&lt;/code&gt; accepted &lt;code&gt;background: "opaque"&lt;/code&gt; and &lt;code&gt;"auto"&lt;/code&gt; with 200 and rejected only transparent; &lt;code&gt;gpt-image-1.5&lt;/code&gt; rejected invalid value &lt;code&gt;"bogus"&lt;/code&gt; with a 400 listing legal options. Both behaviors require the field reaching the provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does one transparent image cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A 1024x1024 transparent generation on &lt;code&gt;gpt-image-1.5&lt;/code&gt; billed 46 input and 4,415 output tokens (4,160 image). At published rates, approximately &lt;strong&gt;$0.136&lt;/strong&gt; per image.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/transparent-background-not-supported-for-this-model-fix-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>imagegeneration</category>
      <category>troubleshooting</category>
      <category>api</category>
    </item>
    <item>
      <title>Seedance 2.5 Image-to-Video: First and Last Frame Control (2026)</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Wed, 26 Aug 2026 04:35:20 +0000</pubDate>
      <link>https://dev.to/owen_fox/seedance-25-image-to-video-first-and-last-frame-control-2026-2684</link>
      <guid>https://dev.to/owen_fox/seedance-25-image-to-video-first-and-last-frame-control-2026-2684</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seedance 2.5 treats the last frame as a destination, not a hint.&lt;/strong&gt; Give it both ends of a shot and it arrives at the one you asked for, which is the thing 2.0 Mini would not do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint: &lt;code&gt;POST /v1/videos&lt;/code&gt; → 202 + polling_url&lt;/li&gt;
&lt;li&gt;Field: &lt;code&gt;frame_images[]&lt;/code&gt; with frame_type &lt;code&gt;first_frame&lt;/code&gt; / &lt;code&gt;last_frame&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ratio rule: &lt;code&gt;aspect_ratio&lt;/code&gt; is a 400 on 2.5 frame jobs. Omit it, or send adaptive.&lt;/li&gt;
&lt;li&gt;Same on 2.0: no. 2.0-mini accepts &lt;code&gt;aspect_ratio&lt;/code&gt; with frames.&lt;/li&gt;
&lt;li&gt;Closing frame error (0-255 mean absolute difference, lower is closer):

&lt;ul&gt;
&lt;li&gt;Seedance 2.5 at 720p: 2.0&lt;/li&gt;
&lt;li&gt;Seedance 2.5 at 480p: 5.4&lt;/li&gt;
&lt;li&gt;Seedance 2.0 Mini: 35.9&lt;/li&gt;
&lt;li&gt;Two unrelated images: 39.0 (the ceiling)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Billed: $0.11/s at 480p, $0.24/s at 720p, at the text-to-video row&lt;/li&gt;
&lt;li&gt;Measured: 2026-08-24, one 5s clip per configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Do You Send a First and Last Frame to Seedance 2.5?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Two elements in &lt;code&gt;frame_images&lt;/code&gt;, each tagged with a &lt;code&gt;frame_type&lt;/code&gt;.&lt;/strong&gt; There is no mode switch; the endpoint infers image-to-video from the body.&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;data_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data:image/jpeg;base64,&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;path&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;body&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.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;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 woman stops walking on the rain-slicked street, turns toward the &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
              &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;camera, and the shot pushes in to her face. Hand-painted 2D animation style.&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="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;480p&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# no aspect_ratio here on purpose: see the next section
&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="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="nf"&gt;data_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wide.jpg&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_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;first_frame&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="nf"&gt;data_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;close.jpg&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_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;last_frame&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="n"&gt;r&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;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&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 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="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;status_code&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="c1"&gt;# 202 {'id': ..., 'status': 'queued', 'polling_url': ...}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data URIs work, which matters more than it sounds: it means you can test first-last-frame generation without standing up a public image host first. Then poll &lt;code&gt;polling_url&lt;/code&gt; until the status is terminal, which is its own set of traps worth reading before you write the loop.&lt;/p&gt;

&lt;p&gt;The prompt still does work here. It is not decoration between two fixed images: it decides what happens on the way, and how many camera moves get spent doing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does Seedance 2.5 Actually Land on the Last Frame?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes, and the gap against 2.0 Mini is not subtle.&lt;/strong&gt; Same two images, same prompt, same duration, same day.&lt;/p&gt;

&lt;p&gt;To put a number on it, we pulled frame 0 and the final frame out of each clip, resized both the frame and the source image to 256x144, and took the mean absolute per-channel difference on a 0 to 255 scale. Low is close.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;Opening frame error&lt;/th&gt;
&lt;th&gt;Closing frame error&lt;/th&gt;
&lt;th&gt;Billed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Seedance 2.5, 720p&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$1.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seedance 2.5, 1080p&lt;/td&gt;
&lt;td&gt;1.8&lt;/td&gt;
&lt;td&gt;3.1&lt;/td&gt;
&lt;td&gt;$2.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seedance 2.5, 480p&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;5.4&lt;/td&gt;
&lt;td&gt;$0.55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seedance 2.0 Mini, 480p&lt;/td&gt;
&lt;td&gt;9.5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;35.9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seedance 2.0 Mini, 480p, no ratio field&lt;/td&gt;
&lt;td&gt;9.6&lt;/td&gt;
&lt;td&gt;37.1&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference: two unrelated images&lt;/td&gt;
&lt;td&gt;38.6&lt;/td&gt;
&lt;td&gt;39.0&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the bottom row first. Two images that have nothing to do with each other score about 39. Mini's closing frame scores 35.9, which is to say it ended somewhere of its own choosing: same rainy palette, different character, different framing. The opening frame is a different story, and both models hold it tightly, which fits the older behaviour we saw on the 2.0 line where the first frame is honoured and the last frame drifts.&lt;/p&gt;

&lt;p&gt;Two caveats before you build on this. Each configuration is one run, not a distribution, so treat the ordering as the finding and the exact decimals as one sample. And the difference metric is deliberately crude: it will punish a correct composition that is two frames early. That crudeness is also why the 35.9 is convincing. Nothing that mild could produce a number that close to unrelated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does aspect_ratio Return 400 on a 2.5 Frame Job?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Because the ratio is derived from the first-frame image, so sending it is an error rather than a redundancy.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /v1/videos  {model: bytedance/seedance-2.5, resolution: 480p,
                  aspect_ratio: "16:9", frame_images: [first, last]}

400 invalid_request
"The parameter ratio specified in the request is not valid. For first-frame or
 first-last-frame generation, the output ratio follows the first-frame image."
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part that catches people: our first-frame image is exactly 1280x720, so the &lt;code&gt;16:9&lt;/code&gt; we sent was correct. It is still refused. The API is not comparing your value against the image, it is refusing to accept a value at all in this mode.&lt;/p&gt;

&lt;p&gt;Three things follow, and all three are measured rather than assumed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Request&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;2.5 + &lt;code&gt;frame_images&lt;/code&gt; + &lt;code&gt;aspect_ratio: "16:9"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;400, ratio not valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5 + &lt;code&gt;frame_images&lt;/code&gt; + &lt;code&gt;aspect_ratio: "adaptive"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;202, output 854x480&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5 + &lt;code&gt;frame_images&lt;/code&gt;, field omitted&lt;/td&gt;
&lt;td&gt;202, output 1280x720 at 720p&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5 text-to-video + &lt;code&gt;aspect_ratio: "16:9"&lt;/code&gt;, no frames&lt;/td&gt;
&lt;td&gt;202&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;2.0 Mini&lt;/strong&gt; + &lt;code&gt;frame_images&lt;/code&gt; + &lt;code&gt;aspect_ratio: "16:9"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;202&lt;/strong&gt;, output 864x496&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So the restriction belongs to 2.5's frame-based tasks specifically. It is not a rule about video generation, it is not a rule about the whole model, and it is not a rule about the gateway. Code that has worked for months against Seedance 2.0 will start returning 400 on the day someone edits the model ID to 2.5, and the error message will talk about a parameter nobody changed. ByteDance documents this directly. The Seedance 2.5 prompt guide splits tasks into locked and unlocked, puts "Editing, first and last frames, and extension" in the locked group, and describes locked as "the output video's aspect ratio, and in some cases its duration, are locked". The same page adds the line that explains our 2.0 result: "Seedance 2.0 does not make this distinction."&lt;/p&gt;

&lt;h2&gt;
  
  
  What Else Does the frame_images Validator Reject?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Four shapes, all caught before the request goes upstream.&lt;/strong&gt; Each came back in roughly a second and cost nothing.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you send&lt;/th&gt;
&lt;th&gt;HTTP&lt;/th&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Two elements both &lt;code&gt;first_frame&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;&lt;code&gt;frame_images: at most one first_frame and one last_frame&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only a &lt;code&gt;last_frame&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;&lt;code&gt;frame_images: last_frame requires a first_frame&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;frame_type: "start_frame"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;&lt;code&gt;frame_images[0]: frame_type must be first_frame or last_frame&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;frame_images&lt;/code&gt; and &lt;code&gt;input_references&lt;/code&gt; together&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;&lt;code&gt;frame_images and input_references are mutually exclusive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the indexed path in the third one. When you are generating request bodies in a loop, &lt;code&gt;frame_images[0]&lt;/code&gt; tells you which element to look at, which is more than most video APIs give you.&lt;/p&gt;

&lt;p&gt;The second rule is the one worth designing around. There is no last-frame-only mode, so a pipeline that wants to end on a known image has to also decide where it starts. If you only care about the ending, generate a plausible opening still first and pass both.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does an Image-to-Video Clip Actually Cost?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It bills at the text-to-video row for that resolution.&lt;/strong&gt; The model page prices Seedance 2.5 by resolution and mode, and there is no image-to-video row, so the natural fear is that you land on the "all other combinations" line at $0.568/s. You do not.&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;Model page, text-to-video&lt;/th&gt;
&lt;th&gt;Our 5s frame job billed&lt;/th&gt;
&lt;th&gt;Implied&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.11/s&lt;/td&gt;
&lt;td&gt;$0.55&lt;/td&gt;
&lt;td&gt;$0.11/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;720p&lt;/td&gt;
&lt;td&gt;$0.24/s&lt;/td&gt;
&lt;td&gt;$1.20&lt;/td&gt;
&lt;td&gt;$0.24/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1080p&lt;/td&gt;
&lt;td&gt;$0.48/s&lt;/td&gt;
&lt;td&gt;$2.40&lt;/td&gt;
&lt;td&gt;$0.48/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three resolutions, three exact matches. The files came back at 854x480, 1280x720 and 1920x1080, all 24 fps with an AAC track at 32 kHz. Duration lands at 5.04s rather than exactly 5, so bill on the &lt;code&gt;usage.video_seconds&lt;/code&gt; field rather than on your own arithmetic.&lt;/p&gt;

&lt;p&gt;For comparison, the same request on &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt; at 480p billed $0.10 for the clip, which is why Mini stays the right tool for throughput work where nobody is checking the closing frame. It is five and a half times cheaper and, on this task, the difference shows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Resolutions Does Seedance 2.5 Accept?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ask the pricing table, not the description.&lt;/strong&gt; The model page currently prints a prose summary saying 480p or 720p, while the pricing table on the same page lists 1080p rows for text-to-video and video-to-video, and a 1080p first-last-frame job ran to completion.&lt;/p&gt;

&lt;p&gt;That kind of disagreement is normal in the weeks after a resolution tier opens, and the resolution field is the cheapest possible thing to test: send the request, read the status code. A rejection is instant and free.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Says&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model page prose&lt;/td&gt;
&lt;td&gt;480p or 720p, 720p by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model page pricing table&lt;/td&gt;
&lt;td&gt;480p, 720p, 1080p rows, 1080p at $0.48/s text-to-video&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live API, first-last-frame at 1080p&lt;/td&gt;
&lt;td&gt;Accepted, finished in 176.2s, billed $2.40&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One thing changes at 1080p that nothing on the page mentions: the file came back as &lt;strong&gt;HEVC&lt;/strong&gt;, where the 480p and 720p outputs were H.264. If you concatenate clips with stream copy, or serve them straight to a browser, a mixed-codec batch will bite. Check the codec on the file rather than assuming it from the model.&lt;/p&gt;

&lt;p&gt;Duration is the other axis that changed between generations: 2.5 takes 4 to 30 seconds where the 2.0 line stops at 15, and a 30-second clip needs roughly ten beats of action in the prompt or the model will stretch one moment across ten seconds. We covered that pacing problem in the 2.5 prompting guide, and the 2.5 against 2.0 comparison has the rest of the capability deltas.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Compare Two Video Models Without Two Consoles?
&lt;/h2&gt;

&lt;p&gt;The comparison in this post required exactly one thing that is annoying to arrange: running the same body against &lt;code&gt;seedance-2.5&lt;/code&gt; and &lt;code&gt;seedance-2.0-mini&lt;/code&gt; with nothing else changed. Two model IDs, one key, one endpoint shape. Done natively, that is two provider consoles, two credit balances and two request schemas, at which point most people compare one model against their memory of another one and call it a benchmark.&lt;/p&gt;

&lt;p&gt;Both models here answer on the same &lt;code&gt;POST /v1/videos&lt;/code&gt; because the video endpoint is model-agnostic; the diff between the two runs in this article was the &lt;code&gt;model&lt;/code&gt; field and nothing else. We used ofox's video endpoint for it, and the same trick works on any gateway that keeps the request shape stable across vendors. The thing to check before trusting a cross-model comparison is that the gateway is not normalising fields on the way through: if &lt;code&gt;aspect_ratio&lt;/code&gt; behaved identically on 2.5 and 2.0, that would be the smell. It did not, which is the evidence the field is reaching each model untouched.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.byteplus.com/en/docs/ModelArk/2607688" rel="noopener noreferrer"&gt;BytePlus ModelArk: Seedance 2.5 tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.byteplus.com/en/docs/ModelArk/2607689" rel="noopener noreferrer"&gt;BytePlus ModelArk: Seedance 2.5 prompt guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ffmpeg.org/ffprobe.html" rel="noopener noreferrer"&gt;ffmpeg: ffprobe documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pillow.readthedocs.io/en/stable/reference/ImageChops.html" rel="noopener noreferrer"&gt;Pillow: ImageChops reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/docs/api/videos/create" rel="noopener noreferrer"&gt;ofox: Create Video API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/docs/api/videos/retrieve" rel="noopener noreferrer"&gt;ofox: Get Video Status API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/models/bytedance/seedance-2.5" rel="noopener noreferrer"&gt;ofox model page: Seedance 2.5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ofox.ai/models/bytedance/seedance-2.0-mini" rel="noopener noreferrer"&gt;ofox model page: Seedance 2.0 Mini&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I send a first and last frame to Seedance 2.5?
&lt;/h3&gt;

&lt;p&gt;Put both images in the &lt;code&gt;frame_images&lt;/code&gt; array on &lt;code&gt;POST /v1/videos&lt;/code&gt;, each element carrying an &lt;code&gt;image_url&lt;/code&gt; and a &lt;code&gt;frame_type&lt;/code&gt; of &lt;code&gt;first_frame&lt;/code&gt; or &lt;code&gt;last_frame&lt;/code&gt;. The mode is inferred from the body, so there is no mode parameter to set. Images can be public URLs or data URIs; base64 data URIs work, which saves standing up an image host for a test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Seedance 2.5 actually land on the last frame you give it?
&lt;/h3&gt;

&lt;p&gt;Yes, closely. We compared the closing frame of the output against the requested last frame and got a mean absolute pixel error of 5.4 at 480p and 2.0 at 720p, on a 0 to 255 scale. The same request on Seedance 2.0 Mini scored 35.9, against a 39.0 baseline for two unrelated images. On Mini the last frame reads as a suggestion; on 2.5 it is a target.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does aspect_ratio return 400 on a Seedance 2.5 first-last-frame job?
&lt;/h3&gt;

&lt;p&gt;Because the output ratio is taken from the first-frame image, so the field is refused rather than ignored. The error reads "The parameter ratio specified in the request is not valid. For first-frame or first-last-frame generation, the output ratio follows the first-frame image." It fires even when the ratio you send matches the image exactly. Omit &lt;code&gt;aspect_ratio&lt;/code&gt;, or send &lt;code&gt;adaptive&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the same aspect_ratio rule apply to Seedance 2.0?
&lt;/h3&gt;

&lt;p&gt;No. The identical body with &lt;code&gt;frame_images&lt;/code&gt; and &lt;code&gt;aspect_ratio&lt;/code&gt; 16:9 was accepted on &lt;code&gt;bytedance/seedance-2.0-mini&lt;/code&gt; and returned an 864x496 clip. The restriction is specific to 2.5's locked task types, not to frame-based generation in general, which is why code that works on 2.0 breaks the day you switch the model ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I send only a last frame?
&lt;/h3&gt;

&lt;p&gt;No. It returns 400 with "frame_images: last_frame requires a first_frame". You also cannot send two first frames: that is 400 with "at most one first_frame and one last_frame". Both of those are validated before the request goes upstream, so they cost nothing and come back in about a second.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does a Seedance 2.5 image-to-video clip cost?
&lt;/h3&gt;

&lt;p&gt;It bills at the text-to-video rate for that resolution, not at the 'all other combinations' row. Our 5-second 480p job billed $0.55 and the 720p job billed $1.20, which is exactly $0.11/s and $0.24/s from the model page. Failed jobs return usage null and are not billed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Seedance 2.5 support 1080p?
&lt;/h3&gt;

&lt;p&gt;The pricing table on the model page lists 1080p rows for both text-to-video and video-to-video, and our 1080p first-last-frame job completed in 176.2 seconds and billed $2.40, which is the $0.48/s text-to-video rate. The prose description on the same page still says 480p or 720p. Trust the pricing table and a live request over the description.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the output have audio?
&lt;/h3&gt;

&lt;p&gt;Yes, by default. Every clip we pulled back carried an AAC track at 32 kHz alongside H.264 video at 24 fps. If you are stitching clips later, that matters: the audio streams have to match too, or ffmpeg concat with stream copy will refuse.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/seedance-2-5-first-last-frame-image-to-video-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>seedance</category>
      <category>imagetovideo</category>
      <category>bytedance</category>
    </item>
    <item>
      <title>AI Video API Cost in 2026: List Price vs Usable-Clip Cost</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Wed, 26 Aug 2026 00:34:49 +0000</pubDate>
      <link>https://dev.to/owen_fox/ai-video-api-cost-in-2026-list-price-vs-usable-clip-cost-38af</link>
      <guid>https://dev.to/owen_fox/ai-video-api-cost-in-2026-list-price-vs-usable-clip-cost-38af</guid>
      <description>&lt;p&gt;Nobody overspends on video generation because they picked the wrong rate card. They overspend because they budgeted for the clips they wanted and paid for the clips they threw away. The per-second rate is the term everyone compares and the smallest term in the bill. The term that actually moved in 2026 is how many generations it takes to get one shot you can cut into a timeline, and that number roughly tripled without a single price change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The formula:  effective cost = list rate x seconds x attempts per usable clip
What moved:   attempts per keeper went 2-3 -&amp;gt; 7-8 during 2026 congestion (36kr, 2026-04-01)
What did not: the rate card
Measured:     6s 480p Seedance 2.5 billed $0.66 in 103s; 30s billed $3.30 in 200s
Delivered:    that same 6s clip is $1.32 at 2 attempts and $5.28 at 8
Expiring:     the 1080p launch discount ends 2026-09-17 on every gateway that mirrored it
Snapshot:     2026-08-25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything below is either a rate card we read on 2026-08-25, a generation we ran and were billed for, or reporting we cite by name. Where the number people repeat does not survive a check, we say so rather than repeating it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is the Rate Card the Wrong Number?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Because it prices generations, and you ship keepers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every video API bills per output second of whatever comes back, including the takes you delete. So the unit that matters is not the per-second rate but the per-second rate multiplied by your reject ratio:&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;effective_cost_per_delivered_second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_rate&lt;/span&gt; &lt;span class="nf"&gt;x &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generations&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;accepted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second factor is the one nobody puts in a pricing comparison, because no vendor can quote it. It depends on the model, your prompt discipline, how specific your brief is, and, uncomfortably, on how busy the provider is that week.&lt;/p&gt;

&lt;p&gt;Here is what that does to a real bill. We generated a 6-second 480p clip on Seedance 2.5 on 2026-08-13 and were billed $0.66:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attempts per keeper&lt;/th&gt;
&lt;th&gt;Cost per delivered 6s clip&lt;/th&gt;
&lt;th&gt;Cost per delivered minute&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (never happens)&lt;/td&gt;
&lt;td&gt;$0.66&lt;/td&gt;
&lt;td&gt;$6.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;$1.32&lt;/td&gt;
&lt;td&gt;$13.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;$1.98&lt;/td&gt;
&lt;td&gt;$19.80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;$3.30&lt;/td&gt;
&lt;td&gt;$33.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;$5.28&lt;/td&gt;
&lt;td&gt;$52.80&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The spread between the top and bottom of that table is 8x. The spread between the cheapest and most expensive rate card on the market for the same model is under 3x. If you are optimising the rate card while ignoring the attempt count, you are tuning the smaller dial.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changed in 2026?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The attempt count, and it changed for reasons outside your pipeline.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the part with real reporting behind it. In April, &lt;a href="https://36kr.com/p/3747480996053507" rel="noopener noreferrer"&gt;36kr documented&lt;/a&gt; what Seedance users were seeing: where creators had previously generated two or three clips and picked one usable take, they were now often generating seven or eight to find one. Same prompts, same model name, roughly triple the burn.&lt;/p&gt;

&lt;p&gt;The surrounding conditions were not subtle. That same reporting describes queue numbers reaching into six figures. &lt;a href="https://www.21jingji.com/article/20260420/herald/33ccb7a55ac6327b11d2a776271563d9.html" rel="noopener noreferrer"&gt;21jingji reported&lt;/a&gt; queue positions climbing from 1,900 to 50,000 and waits stretching to 68 hours, alongside capacity management that Chinese coverage named 降智, roughly "dumbing down": throttling output quality on some task types to clear the backlog. Consumer-side pricing moved at the same time, with early-adopter discounts withdrawn and the cost of a 15-second generation for paying members rising about 167%.&lt;/p&gt;

&lt;p&gt;You do not have to accept any editorial framing to use this. The operational lesson stands on its own: &lt;strong&gt;your provider's capacity state is an input to your unit economics, and it is not on the rate card.&lt;/strong&gt; A quarter where attempts per keeper drifts from 3 to 6 doubles your content cost while your finance dashboard shows a flat price per second.&lt;/p&gt;

&lt;p&gt;That is also why a cost model with a single hardcoded multiplier is worthless. Instrument the ratio and recompute it weekly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Do the Rate Cards Actually Say?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Read on 2026-08-25, for the same model, so the comparison is real.&lt;/strong&gt;&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;480p&lt;/th&gt;
&lt;th&gt;720p&lt;/th&gt;
&lt;th&gt;1080p&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;Gateway (&lt;a href="https://ofox.ai/models/bytedance/seedance-2.5" rel="noopener noreferrer"&gt;ofox&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;$0.11/s&lt;/td&gt;
&lt;td&gt;$0.24/s&lt;/td&gt;
&lt;td&gt;$0.48/s&lt;/td&gt;
&lt;td&gt;1080p is 20% off a $0.60 list, promo ends 2026-09-17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runway API&lt;/td&gt;
&lt;td&gt;$0.20/s&lt;/td&gt;
&lt;td&gt;$0.30/s&lt;/td&gt;
&lt;td&gt;not listed&lt;/td&gt;
&lt;td&gt;20 and 30 credits/s, plus a surcharge per input-video second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Higgsfield&lt;/td&gt;
&lt;td&gt;3 cr/s&lt;/td&gt;
&lt;td&gt;6.5 cr/s&lt;/td&gt;
&lt;td&gt;not listed&lt;/td&gt;
&lt;td&gt;gated to the $49 Plus plan and above&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BytePlus ModelArk&lt;/td&gt;
&lt;td&gt;billed per token, $10.70 / M tokens&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;official international console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volcano Engine Ark&lt;/td&gt;
&lt;td&gt;approx CNY 1.51/s at 720P&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;China console, 1080P at 72% of list to 2026-09-17&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Four things in that table are worth more than the cheapest cell.&lt;/p&gt;

&lt;p&gt;The first is that &lt;strong&gt;the same model is not the same product on every route.&lt;/strong&gt; ModelArk and Volcano Engine Ark are separate consoles with separate model IDs, &lt;code&gt;dreamina-seedance-2-5-260628&lt;/code&gt; internationally and &lt;code&gt;doubao-seedance-2.5&lt;/code&gt; in China, and you cannot mix credentials or IDs between them.&lt;/p&gt;

&lt;p&gt;The second is that &lt;strong&gt;credit pricing is rate pricing wearing a costume.&lt;/strong&gt; Runway's &lt;a href="https://docs.dev.runwayml.com/guides/pricing/" rel="noopener noreferrer"&gt;API credit&lt;/a&gt; is one cent, so 30 credits per second is thirty cents per second, before the surcharge it adds for each second of input video you supply. Higgsfield's credits only convert through a subscription, which means its effective rate depends on how much of your monthly allowance you actually burn. A plan you use at 40% is a rate card 2.5x worse than the one advertised.&lt;/p&gt;

&lt;p&gt;The third is that &lt;strong&gt;token billing and per-second billing answer different questions.&lt;/strong&gt; ByteDance bills its own API per token, which is honest to how the model works and useless for forecasting a 25-shot episode until you have run the token formula against real prompts. Per-second gateway pricing is a markup on that, bought for predictability.&lt;/p&gt;

&lt;p&gt;The fourth is the one with a date attached, and it is below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Did We Actually Get Billed?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Three runs on 2026-08-13, and the numbers are less flattering than the rate card implies.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Billed&lt;/th&gt;
&lt;th&gt;Wall clock&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6s, 480p&lt;/td&gt;
&lt;td&gt;Seedance 2.5&lt;/td&gt;
&lt;td&gt;$0.66&lt;/td&gt;
&lt;td&gt;103 s&lt;/td&gt;
&lt;td&gt;audio track included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30s, 480p&lt;/td&gt;
&lt;td&gt;Seedance 2.5&lt;/td&gt;
&lt;td&gt;$3.30&lt;/td&gt;
&lt;td&gt;200 s&lt;/td&gt;
&lt;td&gt;returned 30.08 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6s, 480p&lt;/td&gt;
&lt;td&gt;Seedance 2.0&lt;/td&gt;
&lt;td&gt;$0.378&lt;/td&gt;
&lt;td&gt;289 s&lt;/td&gt;
&lt;td&gt;same prompt, same second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6s, 1080p&lt;/td&gt;
&lt;td&gt;Seedance 2.5&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;HTTP 400, resolution rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row is the good news and it is worth building for. When Seedance 2.5 was still capped at 720p, a 1080p request returned &lt;code&gt;resolution 1080p not supported; allowed: [480p 720p]&lt;/code&gt; rather than quietly downscaling and billing you. A synchronous 400 costs nothing. &lt;strong&gt;Any parameter you can get rejected at submit time is a parameter that cannot become a wasted generation&lt;/strong&gt;, so validate aggressively and prefer providers that fail loudly.&lt;/p&gt;

&lt;p&gt;The 2.0 versus 2.5 pair is the sharper lesson. Seedance 2.0 bills 36% less per second at 480p and took 2.8x longer to return. If 2.0 also needs one extra attempt on your shot list, its price advantage is gone and you have paid for the privilege in latency. We wrote up where each model still wins in &lt;a href="https://ofox.ai/blog/seedance-2-5-vs-2-0-what-changed-2026/" rel="noopener noreferrer"&gt;Seedance 2.5 vs 2.0&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Actually Cut the Bill?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Attack attempts. The rate card has maybe 30% of movement in it; the attempt count has 400%.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Four levers, in the order we would apply them to an existing pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Draft cheap, deliver expensive.&lt;/strong&gt; At $0.11 against $0.48, 480p costs less than a quarter of 1080p on the same model. Iterate the composition, the beats and the camera at 480p, then re-render only the approved shot at delivery resolution. A 25-shot episode that iterates four times at 480p and renders once at 1080p costs meaningfully less than one that iterates twice at 1080p, and it is the same finished episode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove the model's freedom to reinterpret.&lt;/strong&gt; Every degree of freedom you leave open is a coin flip you pay for. Reference assets pin identity and setting; Seedance 2.5 accepts up to 50 of them as 30 images, 10 videos and 10 audio clips. First and last frames pin where a shot starts and ends, and in our &lt;a href="https://ofox.ai/blog/seedance-2-5-first-last-frame-image-to-video-2026/" rel="noopener noreferrer"&gt;first and last frame test&lt;/a&gt; the 2.5 last-frame error was 5.4 against 35.9 on 2.0 Mini. Integer-second timestamps pin when beats land. None of these lower the rate. All of them lower how often you re-roll.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get your task type right the first time.&lt;/strong&gt; On Seedance 2.5 the task is inferred from words in your prompt, so an edit request without an edit trigger word is classified as a reference-to-video job and returns a brand new clip. It is a perfectly good clip. It is also a full billed generation that answered a question you did not ask. Setting the task type explicitly moves that failure to submit time, where it is free. The trigger words and the failure modes are in &lt;a href="https://ofox.ai/blog/how-to-use-seedance-2-5-prompts-timestamps-cost-2026/" rel="noopener noreferrer"&gt;how to use Seedance 2.5&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure the ratio, not the average.&lt;/strong&gt; Log billed amount and generation count per &lt;em&gt;accepted shot&lt;/em&gt;, not per request. A per-request average tells you the rate card, which you already knew. Cost per accepted shot tells you when your provider's capacity state has quietly moved, usually two weeks before anyone notices in the finance review. If you are polling asynchronously, the same log gives you queue behaviour for free; we broke that pattern down in &lt;a href="https://ofox.ai/blog/video-generation-api-polling-202-wait-times-2026/" rel="noopener noreferrer"&gt;video generation API polling&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Expires on 2026-09-17?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The 1080p price, everywhere.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seedance 2.5 shipped without 1080p and gained it on 2026-08-17 Beijing time. ByteDance attached a launch discount running to 2026-09-17, and the gateways mirrored it at various depths: 20% off at ofox and Atlas Cloud, 28% off at EvoLink, 72% of list on Volcano Engine Ark. Different numbers, one shared expiry date.&lt;/p&gt;

&lt;p&gt;If you are building a cost model this month, &lt;strong&gt;carry both the promotional and the post-promotional 1080p rate&lt;/strong&gt;, because a spreadsheet anchored on $0.48 per second silently becomes wrong on September 17th and nothing in your pipeline will tell you. On a 25-shot, 60-second episode delivered at 1080p, the difference between $0.48 and $0.60 per second is $7.20 per episode before attempts, and $28.80 to $57.60 after a realistic multiplier. At 1,000 episodes that is a budget line, not a rounding error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Numbers We Could Not Verify
&lt;/h2&gt;

&lt;p&gt;Cost claims travel further than their sources, and this topic has three in wide circulation that we could not stand behind, so we are not repeating them as facts.&lt;/p&gt;

&lt;p&gt;A widely quoted V2EX post said to be titled along the lines of "it's not the model, it's your budget" does not appear to exist under that title. The closest real thread, &lt;a href="https://www.v2ex.com/t/1222073" rel="noopener noreferrer"&gt;a June discussion of pricing, failure and waiting&lt;/a&gt;, argues that unpredictable pricing hurts more than model quality does, which is a fair point, but it contains no cost figures at all. The commonly repeated per-clip and per-ad figures attached to it have no traceable origin.&lt;/p&gt;

&lt;p&gt;A per-episode figure of roughly $7.6 for a 60-second, 25-shot production is often attributed to Tencent Cloud. Tencent Cloud's own pipeline write-ups publish &lt;a href="https://cloud.tencent.com/developer/article/2694995" rel="noopener noreferrer"&gt;cost reduction percentages and per-task unit costs&lt;/a&gt;, such as storyboard splitting at CNY 2.8 against CNY 9, and &lt;a href="https://cloud.tencent.com/developer/article/2648983" rel="noopener noreferrer"&gt;production timings&lt;/a&gt; of about three hours per 2-3 minute episode. They do not publish a total per-episode cost. The $7.6 may be someone's arithmetic; it is not a vendor figure.&lt;/p&gt;

&lt;p&gt;And the queue number frequently cited as 80,000 is not what the reporting says. 36kr describes queue numbers reaching around 100,000; 21jingji describes a rise from 1,900 to 50,000. Both are worse than 80,000 in different ways, and neither is 80,000.&lt;/p&gt;

&lt;p&gt;If you are building a business case on any of these, build it on your own logs instead. The one number that matters is one only your pipeline can produce.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Short Version
&lt;/h2&gt;

&lt;p&gt;The rate card is a starting point that vendors compete on and a term you have almost no leverage over. Attempts per usable clip is the term that moved 3x in 2026, that varies with your provider's capacity state, that responds to reference assets and explicit task types and resolution laddering, and that nobody will quote you.&lt;/p&gt;

&lt;p&gt;Price it, log it, and recompute it weekly. Then compare rate cards, with the multiplier already in the sheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much does an AI video generation API actually cost per second?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;List rates for Seedance 2.5 on a gateway run $0.11 per output second at 480p, $0.24 at 720p, and $0.48 at 1080p during the launch discount window. Runway's API bills the same model at 20 credits per second at 480p and 30 at 720p, which is $0.20 and $0.30 at the API's one-cent credit. Those are the numbers on the rate card. What you actually pay per clip you can ship is that rate multiplied by how many generations you burn to get one keeper, which in 2026 has been anywhere from 2 to 8.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the effective cost of an AI video clip?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Effective cost is the list rate times the number of generations per usable output. A 6-second 480p Seedance 2.5 clip billed us $0.66. At the 2-3 attempts per keeper creators reported before the 2026 congestion, that clip costs $1.32 to $1.98 delivered. At the 7-8 attempts 36kr reported during the worst of it, the same clip costs $4.62 to $5.28. The rate card did not move. The bill tripled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do I need so many generations to get one usable clip?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three causes, and only one of them is your prompt. Capacity throttling degrades output quality during congestion, which Chinese coverage in 2026 labelled 降智. Underspecified prompts leave the model free to choose, and it chooses differently every seed. And ambiguous task typing sends an edit request down a reference-to-video path, so you get a technically fine clip that answers the wrong question. The second and third are fixable in your pipeline. The first is not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a cheaper per-second model actually cheaper?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only if its attempt count holds. Seedance 2.0 at 480p bills $0.07 per second against $0.11 for 2.5, so 2.0 looks 36% cheaper. If 2.0 needs four attempts for a shot that 2.5 lands in two, 2.0 costs more per delivered second and takes longer. We measured 289 seconds of wall clock on 2.0 against 103 on 2.5 for the same 6-second prompt, so the slower model also spends more of your pipeline's time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I lower video API costs without changing models?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cut attempts, not rate. Draft on 480p and only re-render the approved shot at delivery resolution, since 480p is a fifth of the 1080p rate. Pin the parts you are not iterating on with reference assets and first and last frames. Write integer-second beats so the model is not inventing structure. And log the billed amount per accepted shot rather than per request, because a per-request average hides exactly the number you need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the 1080p discount on Seedance 2.5 last?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Seedance 2.5 gained 1080p on 2026-08-17 Beijing time, and ByteDance attached a launch discount that runs to 2026-09-17. Gateways mirrored it at varying depth, from 20% off to 28% off. Every one of those prices reverts on the same date, so a cost model built on the promotional 1080p rate breaks in September. Model both numbers now.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ofox.ai/blog/ai-video-generation-api-cost-per-usable-clip-2026/" rel="noopener noreferrer"&gt;ofox.ai/blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>videogeneration</category>
      <category>seedance</category>
      <category>costanalysis</category>
    </item>
  </channel>
</rss>
